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