1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3 * Bloom filter support
4 *
5 * Copyright (C) 1999-2019, Broadcom.
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 *
26 * <<Broadcom-WL-IPTag/Open:>>
27 *
28 * $Id: bcmbloom.c 788740 2018-11-13 21:45:01Z $
29 */
30
31 #include <typedefs.h>
32 #include <bcmdefs.h>
33
34 #include <stdarg.h>
35
36 #ifdef BCMDRIVER
37 #include <osl.h>
38 #include <bcmutils.h>
39 #else /* !BCMDRIVER */
40 #include <stdio.h>
41 #include <string.h>
42 #ifndef ASSERT
43 #define ASSERT(exp)
44 #endif // endif
45 #endif /* !BCMDRIVER */
46 #include <bcmutils.h>
47
48 #include <bcmbloom.h>
49
50 #define BLOOM_BIT_LEN(_x) ((_x) << 3)
51
52 struct bcm_bloom_filter {
53 void *cb_ctx;
54 uint max_hash;
55 bcm_bloom_hash_t *hash; /* array of hash functions */
56 uint filter_size; /* in bytes */
57 uint8 *filter; /* can be NULL for validate only */
58 };
59
60 /* public interface */
61 int
bcm_bloom_create(bcm_bloom_alloc_t alloc_cb,bcm_bloom_free_t free_cb,void * cb_ctx,uint max_hash,uint filter_size,bcm_bloom_filter_t ** bloom)62 bcm_bloom_create(bcm_bloom_alloc_t alloc_cb,
63 bcm_bloom_free_t free_cb, void *cb_ctx, uint max_hash,
64 uint filter_size, bcm_bloom_filter_t **bloom)
65 {
66 int err = BCME_OK;
67 bcm_bloom_filter_t *bp = NULL;
68
69 if (!bloom || !alloc_cb || (max_hash == 0)) {
70 err = BCME_BADARG;
71 goto done;
72 }
73
74 bp = (*alloc_cb)(cb_ctx, sizeof(*bp));
75 if (!bp) {
76 err = BCME_NOMEM;
77 goto done;
78 }
79
80 memset(bp, 0, sizeof(*bp));
81 bp->cb_ctx = cb_ctx;
82 bp->max_hash = max_hash;
83 bp->hash = (*alloc_cb)(cb_ctx, sizeof(*bp->hash) * max_hash);
84 memset(bp->hash, 0, sizeof(*bp->hash) * max_hash);
85
86 if (!bp->hash) {
87 err = BCME_NOMEM;
88 goto done;
89 }
90
91 if (filter_size > 0) {
92 bp->filter = (*alloc_cb)(cb_ctx, filter_size);
93 if (!bp->filter) {
94 err = BCME_NOMEM;
95 goto done;
96 }
97 bp->filter_size = filter_size;
98 memset(bp->filter, 0, filter_size);
99 }
100
101 *bloom = bp;
102
103 done:
104 if (err != BCME_OK)
105 bcm_bloom_destroy(&bp, free_cb);
106
107 return err;
108 }
109
110 int
bcm_bloom_destroy(bcm_bloom_filter_t ** bloom,bcm_bloom_free_t free_cb)111 bcm_bloom_destroy(bcm_bloom_filter_t **bloom, bcm_bloom_free_t free_cb)
112 {
113 int err = BCME_OK;
114 bcm_bloom_filter_t *bp;
115
116 if (!bloom || !*bloom || !free_cb)
117 goto done;
118
119 bp = *bloom;
120 *bloom = NULL;
121
122 if (bp->filter)
123 (*free_cb)(bp->cb_ctx, bp->filter, bp->filter_size);
124 if (bp->hash)
125 (*free_cb)(bp->cb_ctx, bp->hash,
126 sizeof(*bp->hash) * bp->max_hash);
127 (*free_cb)(bp->cb_ctx, bp, sizeof(*bp));
128
129 done:
130 return err;
131 }
132
133 int
bcm_bloom_add_hash(bcm_bloom_filter_t * bp,bcm_bloom_hash_t hash,uint * idx)134 bcm_bloom_add_hash(bcm_bloom_filter_t *bp, bcm_bloom_hash_t hash, uint *idx)
135 {
136 uint i;
137
138 if (!bp || !hash || !idx)
139 return BCME_BADARG;
140
141 for (i = 0; i < bp->max_hash; ++i) {
142 if (bp->hash[i] == NULL)
143 break;
144 }
145
146 if (i >= bp->max_hash)
147 return BCME_NORESOURCE;
148
149 bp->hash[i] = hash;
150 *idx = i;
151 return BCME_OK;
152 }
153
154 int
bcm_bloom_remove_hash(bcm_bloom_filter_t * bp,uint idx)155 bcm_bloom_remove_hash(bcm_bloom_filter_t *bp, uint idx)
156 {
157 if (!bp)
158 return BCME_BADARG;
159
160 if (idx >= bp->max_hash)
161 return BCME_NOTFOUND;
162
163 bp->hash[idx] = NULL;
164 return BCME_OK;
165 }
166
167 bool
bcm_bloom_is_member(bcm_bloom_filter_t * bp,const uint8 * tag,uint tag_len,const uint8 * buf,uint buf_len)168 bcm_bloom_is_member(bcm_bloom_filter_t *bp,
169 const uint8 *tag, uint tag_len, const uint8 *buf, uint buf_len)
170 {
171 uint i;
172 int err = BCME_OK;
173
174 if (!tag || (tag_len == 0)) /* empty tag is always a member */
175 goto done;
176
177 /* use internal buffer if none was specified */
178 if (!buf || (buf_len == 0)) {
179 if (!bp->filter) /* every one is a member of empty filter */
180 goto done;
181
182 buf = bp->filter;
183 buf_len = bp->filter_size;
184 }
185
186 for (i = 0; i < bp->max_hash; ++i) {
187 uint pos;
188 if (!bp->hash[i])
189 continue;
190 pos = (*bp->hash[i])(bp->cb_ctx, i, tag, tag_len);
191
192 /* all bits must be set for a match */
193 CLANG_DIAGNOSTIC_PUSH_SUPPRESS_CAST()
194 if (isclr(buf, pos % BLOOM_BIT_LEN(buf_len))) {
195 CLANG_DIAGNOSTIC_POP()
196 err = BCME_NOTFOUND;
197 break;
198 }
199 }
200
201 done:
202 return err;
203 }
204
205 int
bcm_bloom_add_member(bcm_bloom_filter_t * bp,const uint8 * tag,uint tag_len)206 bcm_bloom_add_member(bcm_bloom_filter_t *bp, const uint8 *tag, uint tag_len)
207 {
208 uint i;
209
210 if (!bp || !tag || (tag_len == 0))
211 return BCME_BADARG;
212
213 if (!bp->filter) /* validate only */
214 return BCME_UNSUPPORTED;
215
216 for (i = 0; i < bp->max_hash; ++i) {
217 uint pos;
218 if (!bp->hash[i])
219 continue;
220 pos = (*bp->hash[i])(bp->cb_ctx, i, tag, tag_len);
221 setbit(bp->filter, pos % BLOOM_BIT_LEN(bp->filter_size));
222 }
223
224 return BCME_OK;
225 }
226
bcm_bloom_get_filter_data(bcm_bloom_filter_t * bp,uint buf_size,uint8 * buf,uint * buf_len)227 int bcm_bloom_get_filter_data(bcm_bloom_filter_t *bp,
228 uint buf_size, uint8 *buf, uint *buf_len)
229 {
230 if (!bp)
231 return BCME_BADARG;
232
233 if (buf_len)
234 *buf_len = bp->filter_size;
235
236 if (buf_size < bp->filter_size)
237 return BCME_BUFTOOSHORT;
238
239 if (bp->filter && bp->filter_size)
240 memcpy(buf, bp->filter, bp->filter_size);
241
242 return BCME_OK;
243 }
244