1 /*
2 * Driver O/S-independent utility routines
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: bcmutils.c 813798 2019-04-08 10:20:21Z $
28 */
29
30 #include <bcm_cfg.h>
31 #include <typedefs.h>
32 #include <bcmdefs.h>
33 #include <stdarg.h>
34 #ifdef BCMDRIVER
35 #include <osl.h>
36 #include <bcmutils.h>
37
38 #else /* !BCMDRIVER */
39
40 #include <stdio.h>
41 #include <string.h>
42 #include <bcm_math.h>
43 #include <bcmutils.h>
44
45 #if defined(BCMEXTSUP)
46 #include <bcm_osl.h>
47 #endif // endif
48
49 #ifndef ASSERT
50 #define ASSERT(exp)
51 #endif // endif
52
53 #endif /* !BCMDRIVER */
54
55 #ifdef WL_UNITTEST
56 #ifdef ASSERT
57 #undef ASSERT
58 #endif /* ASSERT */
59 #define ASSERT(exp)
60 #endif /* WL_UNITTEST */
61
62 #include <bcmstdlib_s.h>
63 #include <bcmendian.h>
64 #include <bcmdevs.h>
65 #include <ethernet.h>
66 #include <vlan.h>
67 #include <bcmip.h>
68 #include <802.1d.h>
69 #include <802.11.h>
70 #include <bcmip.h>
71 #include <bcmipv6.h>
72 #include <bcmtcp.h>
73 #include <wl_android.h>
74
75 #ifdef BCMDRIVER
76
77 /* return total length of buffer chain */
pkttotlen(osl_t * osh,void * p)78 uint BCMFASTPATH pkttotlen(osl_t *osh, void *p)
79 {
80 uint total;
81 int len;
82
83 total = 0;
84 for (; p; p = PKTNEXT(osh, p)) {
85 len = PKTLEN(osh, p);
86 total += (uint)len;
87 #ifdef BCMLFRAG
88 if (BCMLFRAG_ENAB()) {
89 if (PKTISFRAG(osh, p)) {
90 total += PKTFRAGTOTLEN(osh, p);
91 }
92 }
93 #endif // endif
94 }
95
96 return (total);
97 }
98
99 /* return the last buffer of chained pkt */
pktlast(osl_t * osh,void * p)100 void *pktlast(osl_t *osh, void *p)
101 {
102 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p)) {
103 ;
104 }
105
106 return (p);
107 }
108
109 /* count segments of a chained packet */
pktsegcnt(osl_t * osh,void * p)110 uint BCMFASTPATH pktsegcnt(osl_t *osh, void *p)
111 {
112 uint cnt;
113
114 for (cnt = 0; p; p = PKTNEXT(osh, p)) {
115 cnt++;
116 #ifdef BCMLFRAG
117 if (BCMLFRAG_ENAB()) {
118 if (PKTISFRAG(osh, p)) {
119 cnt += PKTFRAGTOTNUM(osh, p);
120 }
121 }
122 #endif // endif
123 }
124
125 return cnt;
126 }
127
128 /* copy a pkt buffer chain into a buffer */
pktcopy(osl_t * osh,void * p,uint offset,int len,uchar * buf)129 uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
130 {
131 uint n, ret = 0;
132
133 if (len < 0) {
134 len = 0x1000; /* "infinite" */
135 }
136
137 /* skip 'offset' bytes */
138 for (; p && offset; p = PKTNEXT(osh, p)) {
139 if (offset < (uint)PKTLEN(osh, p)) {
140 break;
141 }
142 offset -= (uint)PKTLEN(osh, p);
143 }
144
145 if (!p) {
146 return 0;
147 }
148
149 /* copy the data */
150 for (; p && len; p = PKTNEXT(osh, p)) {
151 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
152 bcopy(PKTDATA(osh, p) + offset, buf, n);
153 buf += n;
154 len -= n;
155 ret += n;
156 offset = 0;
157 }
158
159 return ret;
160 }
161
162 /* copy a buffer into a pkt buffer chain */
pktfrombuf(osl_t * osh,void * p,uint offset,int len,uchar * buf)163 uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
164 {
165 uint n, ret = 0;
166
167 /* skip 'offset' bytes */
168 for (; p && offset; p = PKTNEXT(osh, p)) {
169 if (offset < (uint)PKTLEN(osh, p)) {
170 break;
171 }
172 offset -= (uint)PKTLEN(osh, p);
173 }
174
175 if (!p) {
176 return 0;
177 }
178
179 /* copy the data */
180 for (; p && len; p = PKTNEXT(osh, p)) {
181 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
182 bcopy(buf, PKTDATA(osh, p) + offset, n);
183 buf += n;
184 len -= n;
185 ret += n;
186 offset = 0;
187 }
188
189 return ret;
190 }
191
pktdataoffset(osl_t * osh,void * p,uint offset)192 uint8 *BCMFASTPATH pktdataoffset(osl_t *osh, void *p, uint offset)
193 {
194 uint total = pkttotlen(osh, p);
195 uint pkt_off = 0, len = 0;
196 uint8 *pdata = (uint8 *)PKTDATA(osh, p);
197
198 if (offset > total) {
199 return NULL;
200 }
201
202 for (; p; p = PKTNEXT(osh, p)) {
203 pdata = (uint8 *)PKTDATA(osh, p);
204 pkt_off = offset - len;
205 len += (uint)PKTLEN(osh, p);
206 if (len > offset) {
207 break;
208 }
209 }
210 return (uint8 *)(pdata + pkt_off);
211 }
212
213 /* given a offset in pdata, find the pkt seg hdr */
pktoffset(osl_t * osh,void * p,uint offset)214 void *pktoffset(osl_t *osh, void *p, uint offset)
215 {
216 uint total = pkttotlen(osh, p);
217 uint len = 0;
218
219 if (offset > total) {
220 return NULL;
221 }
222
223 for (; p; p = PKTNEXT(osh, p)) {
224 len += (uint)PKTLEN(osh, p);
225 if (len > offset) {
226 break;
227 }
228 }
229 return p;
230 }
231
bcm_mdelay(uint ms)232 void bcm_mdelay(uint ms)
233 {
234 uint i;
235
236 for (i = 0; i < ms; i++) {
237 OSL_DELAY(0x3E8);
238 }
239 }
240
241 #if defined(DHD_DEBUG)
242 /* pretty hex print a pkt buffer chain */
prpkt(const char * msg,osl_t * osh,void * p0)243 void prpkt(const char *msg, osl_t *osh, void *p0)
244 {
245 void *p;
246
247 if (msg && (msg[0] != '\0')) {
248 printf("%s:\n", msg);
249 }
250
251 for (p = p0; p; p = PKTNEXT(osh, p)) {
252 prhex(NULL, PKTDATA(osh, p), (uint)PKTLEN(osh, p));
253 }
254 }
255 #endif // endif
256
257 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
258 * Also updates the inplace vlan tag if requested.
259 * For debugging, it returns an indication of what it did.
260 */
pktsetprio(void * pkt,bool update_vtag)261 uint BCMFASTPATH pktsetprio(void *pkt, bool update_vtag)
262 {
263 struct ether_header *eh;
264 struct ethervlan_header *evh;
265 uint8 *pktdata;
266 uint priority = 0;
267 uint rc = 0;
268
269 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
270 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
271
272 eh = (struct ether_header *)pktdata;
273
274 if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) {
275 uint16 vlan_tag;
276 uint vlan_prio, dscp_prio = 0;
277
278 evh = (struct ethervlan_header *)eh;
279
280 vlan_tag = ntoh16(evh->vlan_tag);
281 vlan_prio = (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
282
283 if ((evh->ether_type == hton16(ETHER_TYPE_IP)) ||
284 (evh->ether_type == hton16(ETHER_TYPE_IPV6))) {
285 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
286 uint8 tos_tc = (uint8)IP_TOS46(ip_body);
287 dscp_prio = tos_tc >> IPV4_TOS_PREC_SHIFT;
288 }
289
290 /* DSCP priority gets precedence over 802.1P (vlan tag) */
291 if (dscp_prio != 0) {
292 priority = dscp_prio;
293 rc |= PKTPRIO_VDSCP;
294 } else {
295 priority = vlan_prio;
296 rc |= PKTPRIO_VLAN;
297 }
298 /*
299 * If the DSCP priority is not the same as the VLAN priority,
300 * then overwrite the priority field in the vlan tag, with the
301 * DSCP priority value. This is required for Linux APs because
302 * the VLAN driver on Linux, overwrites the skb->priority field
303 * with the priority value in the vlan tag
304 */
305 if (update_vtag && (priority != vlan_prio)) {
306 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
307 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
308 evh->vlan_tag = hton16(vlan_tag);
309 rc |= PKTPRIO_UPD;
310 }
311 #if defined(EAPOL_PKT_PRIO) || defined(DHD_LOSSLESS_ROAMING)
312 } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
313 priority = PRIO_8021D_NC;
314 rc = PKTPRIO_DSCP;
315 #endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */
316 } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) ||
317 (eh->ether_type == hton16(ETHER_TYPE_IPV6))) {
318 uint8 *ip_body = pktdata + sizeof(struct ether_header);
319 uint8 tos_tc = (uint8)IP_TOS46(ip_body);
320 uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT;
321 switch (dscp) {
322 case DSCP_EF:
323 case DSCP_VA:
324 priority = PRIO_8021D_VO;
325 break;
326 case DSCP_AF31:
327 case DSCP_AF32:
328 case DSCP_AF33:
329 case DSCP_CS3:
330 priority = PRIO_8021D_CL;
331 break;
332 case DSCP_AF21:
333 case DSCP_AF22:
334 case DSCP_AF23:
335 priority = PRIO_8021D_EE;
336 break;
337 case DSCP_AF11:
338 case DSCP_AF12:
339 case DSCP_AF13:
340 case DSCP_CS2:
341 priority = PRIO_8021D_BE;
342 break;
343 case DSCP_CS6:
344 case DSCP_CS7:
345 priority = PRIO_8021D_NC;
346 break;
347 default:
348 priority = tos_tc >> IPV4_TOS_PREC_SHIFT;
349 break;
350 }
351
352 rc |= PKTPRIO_DSCP;
353 }
354
355 ASSERT(priority <= MAXPRIO);
356 PKTSETPRIO(pkt, (int)priority);
357 return (rc | priority);
358 }
359
360 /* lookup user priority for specified DSCP */
dscp2up(uint8 * up_table,uint8 dscp)361 static uint8 dscp2up(uint8 *up_table, uint8 dscp)
362 {
363 uint8 user_priority = 255;
364
365 /* lookup up from table if parameters valid */
366 if (up_table != NULL && dscp < UP_TABLE_MAX) {
367 user_priority = up_table[dscp];
368 }
369
370 /* 255 is unused value so return up from dscp */
371 if (user_priority == 255) {
372 user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT);
373 }
374
375 return user_priority;
376 }
377
378 /* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX
379 */
pktsetprio_qms(void * pkt,uint8 * up_table,bool update_vtag)380 uint BCMFASTPATH pktsetprio_qms(void *pkt, uint8 *up_table, bool update_vtag)
381 {
382 if (up_table) {
383 uint8 *pktdata;
384 uint pktlen;
385 uint8 dscp;
386 uint user_priority = 0;
387 uint rc = 0;
388
389 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
390 pktlen = (uint)PKTLEN(OSH_NULL, pkt);
391 if (pktgetdscp(pktdata, pktlen, &dscp)) {
392 rc = PKTPRIO_DSCP;
393 user_priority = dscp2up(up_table, dscp);
394 PKTSETPRIO(pkt, (int)user_priority);
395 }
396
397 return (rc | user_priority);
398 } else {
399 return pktsetprio(pkt, update_vtag);
400 }
401 }
402
403 /* Returns TRUE and DSCP if IP header found, FALSE otherwise.
404 */
pktgetdscp(uint8 * pktdata,uint pktlen,uint8 * dscp)405 bool BCMFASTPATH pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp)
406 {
407 struct ether_header *eh;
408 struct ethervlan_header *evh;
409 uint8 *ip_body;
410 bool rc = FALSE;
411
412 /* minimum length is ether header and IP header */
413 if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN) {
414 return FALSE;
415 }
416
417 eh = (struct ether_header *)pktdata;
418
419 if (eh->ether_type == HTON16(ETHER_TYPE_IP)) {
420 ip_body = pktdata + sizeof(struct ether_header);
421 *dscp = (uint8)IP_DSCP46(ip_body);
422 rc = TRUE;
423 } else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) {
424 evh = (struct ethervlan_header *)eh;
425
426 /* minimum length is ethervlan header and IP header */
427 if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN &&
428 evh->ether_type == HTON16(ETHER_TYPE_IP)) {
429 ip_body = pktdata + sizeof(struct ethervlan_header);
430 *dscp = (uint8)IP_DSCP46(ip_body);
431 rc = TRUE;
432 }
433 }
434
435 return rc;
436 }
437
438 /* usr_prio range from low to high with usr_prio value */
up_table_set(uint8 * up_table,uint8 usr_prio,uint8 low,uint8 high)439 static bool up_table_set(uint8 *up_table, uint8 usr_prio, uint8 low, uint8 high)
440 {
441 int i;
442
443 if (usr_prio > 0x7 || low > high || low >= UP_TABLE_MAX ||
444 high >= UP_TABLE_MAX) {
445 return FALSE;
446 }
447
448 for (i = low; i <= high; i++) {
449 up_table[i] = usr_prio;
450 }
451
452 return TRUE;
453 }
454
455 /* set user priority table */
wl_set_up_table(uint8 * up_table,bcm_tlv_t * qos_map_ie)456 int BCMFASTPATH wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie)
457 {
458 uint8 len;
459
460 if (up_table == NULL || qos_map_ie == NULL) {
461 return BCME_ERROR;
462 }
463
464 /* clear table to check table was set or not */
465 memset(up_table, 0xff, UP_TABLE_MAX);
466
467 /* length of QoS Map IE must be 16+n*2, n is number of exceptions */
468 if (qos_map_ie != NULL && qos_map_ie->id == DOT11_MNG_QOS_MAP_ID &&
469 (len = qos_map_ie->len) >= QOS_MAP_FIXED_LENGTH && (len % 2) == 0) {
470 uint8 *except_ptr = (uint8 *)qos_map_ie->data;
471 uint8 except_len = len - QOS_MAP_FIXED_LENGTH;
472 uint8 *range_ptr = except_ptr + except_len;
473 uint8 i;
474
475 /* fill in ranges */
476 for (i = 0; i < QOS_MAP_FIXED_LENGTH; i += 2) {
477 uint8 low = range_ptr[i];
478 uint8 high = range_ptr[i + 1];
479 if (low == 255 && high == 255) {
480 continue;
481 }
482
483 if (!up_table_set(up_table, i / 2, low, high)) {
484 /* clear the table on failure */
485 memset(up_table, 0xff, UP_TABLE_MAX);
486 return BCME_ERROR;
487 }
488 }
489
490 /* update exceptions */
491 for (i = 0; i < except_len; i += 2) {
492 uint8 dscp = except_ptr[i];
493 uint8 usr_prio = except_ptr[i + 1];
494
495 /* exceptions with invalid dscp/usr_prio are ignored */
496 up_table_set(up_table, usr_prio, dscp, dscp);
497 }
498 }
499
500 return BCME_OK;
501 }
502
503 /* The 0.5KB string table is not removed by compiler even though it's unused */
504
505 static char bcm_undeferrstr[32];
506 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
507
508 /* Convert the error codes into related error strings */
BCMRAMFN(bcmerrorstr)509 const char *BCMRAMFN(bcmerrorstr)(int bcmerror)
510 {
511 /* check if someone added a bcmerror code but forgot to add errorstring */
512 ASSERT((uint)ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
513
514 if (bcmerror > 0 || bcmerror < BCME_LAST) {
515 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d",
516 bcmerror);
517 return bcm_undeferrstr;
518 }
519
520 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
521
522 return bcmerrorstrtable[-bcmerror];
523 }
524
525 /* iovar table lookup */
526 /* could mandate sorted tables and do a binary search */
bcm_iovar_lookup(const bcm_iovar_t * table,const char * name)527 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
528 {
529 const bcm_iovar_t *vi;
530 const char *lookup_name;
531
532 /* skip any ':' delimited option prefixes */
533 lookup_name = strrchr(name, ':');
534 if (lookup_name != NULL) {
535 lookup_name++;
536 } else {
537 lookup_name = name;
538 }
539
540 ASSERT(table != NULL);
541
542 for (vi = table; vi->name; vi++) {
543 if (!strcmp(vi->name, lookup_name)) {
544 return vi;
545 }
546 }
547 /* ran to end of table */
548
549 return NULL; /* var name not found */
550 }
551
bcm_iovar_lencheck(const bcm_iovar_t * vi,void * arg,int len,bool set)552 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
553 {
554 int bcmerror = 0;
555 BCM_REFERENCE(arg);
556
557 /* length check on io buf */
558 switch (vi->type) {
559 case IOVT_BOOL:
560 case IOVT_INT8:
561 case IOVT_INT16:
562 case IOVT_INT32:
563 case IOVT_UINT8:
564 case IOVT_UINT16:
565 case IOVT_UINT32:
566 /* all integers are int32 sized args at the ioctl interface */
567 if (len < (int)sizeof(int)) {
568 bcmerror = BCME_BUFTOOSHORT;
569 }
570 break;
571
572 case IOVT_BUFFER:
573 /* buffer must meet minimum length requirement */
574 if (len < vi->minlen) {
575 bcmerror = BCME_BUFTOOSHORT;
576 }
577 break;
578
579 case IOVT_VOID:
580 if (!set) {
581 /* Cannot return nil... */
582 bcmerror = BCME_UNSUPPORTED;
583 }
584 break;
585
586 default:
587 /* unknown type for length check in iovar info */
588 ASSERT(0);
589 bcmerror = BCME_UNSUPPORTED;
590 }
591
592 return bcmerror;
593 }
594
595 #if !defined(_CFEZ_)
596 /*
597 * Hierarchical Multiword bitmap based small id allocator.
598 *
599 * Multilevel hierarchy bitmap. (maximum 2 levels)
600 * First hierarchy uses a multiword bitmap to identify 32bit words in the
601 * second hierarchy that have at least a single bit set. Each bit in a word of
602 * the second hierarchy represents a unique ID that may be allocated.
603 *
604 * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed.
605 * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word
606 * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs.
607 * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non
608 * non-zero bitmap word carrying at least one free ID.
609 * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations.
610 * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID
611 *
612 * Design Notes:
613 * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many
614 * bits are computed each time on allocation and deallocation, requiring 4
615 * array indexed access and 3 arithmetic operations. When not defined, a runtime
616 * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed.
617 * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation.
618 * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may
619 * be used by defining BCM_MWBMAP_USE_CNTSETBITS.
620 *
621 * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array
622 * size is fixed. No intention to support larger than 4K indice allocation. ID
623 * allocators for ranges smaller than 4K will have a wastage of only 12Bytes
624 * with savings in not having to use an indirect access, had it been dynamically
625 * allocated.
626 */
627 #define BCM_MWBMAP_ITEMS_MAX (64 * 1024) /* May increase to 64K */
628
629 #define BCM_MWBMAP_BITS_WORD (NBITS(uint32))
630 #define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD)
631 #define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD)
632 #define BCM_MWBMAP_SHIFT_OP (5)
633 #define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1))
634 #define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP)
635 #define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP)
636
637 /* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */
638 #define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl))
639 #define BCM_MWBMAP_HDL(ptr) ((void *)(ptr))
640
641 #if defined(BCM_MWBMAP_DEBUG)
642 #define BCM_MWBMAP_AUDIT(mwb) \
643 do { \
644 ASSERT((mwb != NULL) && \
645 (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \
646 bcm_mwbmap_audit(mwb); \
647 } while (0)
648 #define MWBMAP_ASSERT(exp) ASSERT(exp)
649 #define MWBMAP_DBG(x) printf x
650 #else /* !BCM_MWBMAP_DEBUG */
651 #define BCM_MWBMAP_AUDIT(mwb) \
652 do { \
653 } while (0)
654 #define MWBMAP_ASSERT(exp) \
655 do { \
656 } while (0)
657 #define MWBMAP_DBG(x)
658 #endif /* !BCM_MWBMAP_DEBUG */
659
660 typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */
661 uint16 wmaps; /* Total number of words in free wd bitmap */
662 uint16 imaps; /* Total number of words in free id bitmap */
663 int32 ifree; /* Count of free indices. Used only in audits */
664 uint16 total; /* Total indices managed by multiword bitmap */
665
666 void *magic; /* Audit handle parameter from user */
667
668 uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */
669 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
670 int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */
671 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
672
673 uint32 id_bitmap[0]; /* Second level bitmap */
674 } bcm_mwbmap_t;
675
676 /* Incarnate a hierarchical multiword bitmap based small index allocator. */
bcm_mwbmap_init(osl_t * osh,uint32 items_max)677 struct bcm_mwbmap *bcm_mwbmap_init(osl_t *osh, uint32 items_max)
678 {
679 struct bcm_mwbmap *mwbmap_p;
680 uint32 wordix, size, words, extra;
681
682 /* Implementation Constraint: Uses 32bit word bitmap */
683 MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U);
684 MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U);
685 MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX));
686 MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U);
687
688 ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX);
689
690 /* Determine the number of words needed in the multiword bitmap */
691 extra = BCM_MWBMAP_MODOP(items_max);
692 words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U);
693
694 /* Allocate runtime state of multiword bitmap */
695 /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */
696 size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words);
697 mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size);
698 if (mwbmap_p == (bcm_mwbmap_t *)NULL) {
699 ASSERT(0);
700 goto error1;
701 }
702 memset(mwbmap_p, 0, size);
703
704 /* Initialize runtime multiword bitmap state */
705 mwbmap_p->imaps = (uint16)words;
706 mwbmap_p->ifree = (int32)items_max;
707 mwbmap_p->total = (uint16)items_max;
708
709 /* Setup magic, for use in audit of handle */
710 mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p);
711
712 /* Setup the second level bitmap of free indices */
713 /* Mark all indices as available */
714 for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) {
715 mwbmap_p->id_bitmap[wordix] = (uint32)(~0U);
716 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
717 mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD;
718 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
719 }
720
721 /* Ensure that extra indices are tagged as un-available */
722 if (extra) { /* fixup the free ids in last bitmap and wd_count */
723 uint32 *bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1];
724 *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
725 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
726 mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */
727 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
728 }
729
730 /* Setup the first level bitmap hierarchy */
731 extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps);
732 words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U);
733
734 mwbmap_p->wmaps = (uint16)words;
735
736 for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++) {
737 mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U);
738 }
739 if (extra) {
740 uint32 *bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1];
741 *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
742 }
743
744 return mwbmap_p;
745
746 error1:
747 return BCM_MWBMAP_INVALID_HDL;
748 }
749
750 /* Release resources used by multiword bitmap based small index allocator. */
bcm_mwbmap_fini(osl_t * osh,struct bcm_mwbmap * mwbmap_hdl)751 void bcm_mwbmap_fini(osl_t *osh, struct bcm_mwbmap *mwbmap_hdl)
752 {
753 bcm_mwbmap_t *mwbmap_p;
754
755 BCM_MWBMAP_AUDIT(mwbmap_hdl);
756 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
757
758 MFREE(osh, mwbmap_p,
759 sizeof(struct bcm_mwbmap) + (sizeof(uint32) * mwbmap_p->imaps));
760 return;
761 }
762
763 /* Allocate a unique small index using a multiword bitmap index allocator. */
bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl)764 uint32 BCMFASTPATH bcm_mwbmap_alloc(struct bcm_mwbmap *mwbmap_hdl)
765 {
766 bcm_mwbmap_t *mwbmap_p;
767 uint32 wordix, bitmap;
768
769 BCM_MWBMAP_AUDIT(mwbmap_hdl);
770 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
771
772 /* Start with the first hierarchy */
773 for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) {
774 bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */
775 if (bitmap != 0U) {
776 uint32 count, bitix, *bitmap_p;
777
778 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
779
780 /* clear all except trailing 1 */
781 bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
782 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
783 bcm_count_leading_zeros(bitmap));
784 bitix = (BCM_MWBMAP_BITS_WORD - 1) -
785 (uint32)bcm_count_leading_zeros(bitmap); /* use asm clz */
786 wordix = BCM_MWBMAP_MULOP(wordix) + bitix;
787
788 /* Clear bit if wd count is 0, without conditional branch */
789 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
790 count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1;
791 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
792 mwbmap_p->wd_count[wordix]--;
793 count = (uint32)mwbmap_p->wd_count[wordix];
794 MWBMAP_ASSERT(count ==
795 (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1));
796 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
797 MWBMAP_ASSERT(count >= 0);
798
799 /* clear wd_bitmap bit if id_map count is 0 */
800 bitmap = ((uint32)(count == 0)) << BCM_MWBMAP_MODOP(bitix);
801
802 MWBMAP_DBG((
803 "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
804 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count));
805
806 *bitmap_p ^= bitmap;
807
808 /* Use bitix in the second hierarchy */
809 bitmap_p = &mwbmap_p->id_bitmap[wordix];
810
811 bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */
812 MWBMAP_ASSERT(bitmap != 0U);
813
814 /* clear all except trailing 1 */
815 bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
816 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
817 bcm_count_leading_zeros(bitmap));
818 bitix = BCM_MWBMAP_MULOP(wordix) + (BCM_MWBMAP_BITS_WORD - 1) -
819 (uint32)bcm_count_leading_zeros(bitmap); /* use asm clz */
820
821 mwbmap_p->ifree--; /* decrement system wide free count */
822 MWBMAP_ASSERT(mwbmap_p->ifree >= 0);
823
824 MWBMAP_DBG(
825 ("Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d",
826 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
827 mwbmap_p->ifree));
828
829 *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */
830
831 return bitix;
832 }
833 }
834
835 ASSERT(mwbmap_p->ifree == 0);
836
837 return BCM_MWBMAP_INVALID_IDX;
838 }
839
840 /* Force an index at a specified position to be in use */
bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl,uint32 bitix)841 void bcm_mwbmap_force(struct bcm_mwbmap *mwbmap_hdl, uint32 bitix)
842 {
843 bcm_mwbmap_t *mwbmap_p;
844 uint32 count, wordix, bitmap, *bitmap_p;
845
846 BCM_MWBMAP_AUDIT(mwbmap_hdl);
847 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
848
849 ASSERT(bitix < mwbmap_p->total);
850
851 /* Start with second hierarchy */
852 wordix = BCM_MWBMAP_DIVOP(bitix);
853 bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix));
854 bitmap_p = &mwbmap_p->id_bitmap[wordix];
855
856 ASSERT((*bitmap_p & bitmap) == bitmap);
857
858 mwbmap_p->ifree--; /* update free count */
859 ASSERT(mwbmap_p->ifree >= 0);
860
861 MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d",
862 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
863 mwbmap_p->ifree));
864
865 *bitmap_p ^= bitmap; /* mark as in use */
866
867 /* Update first hierarchy */
868 bitix = wordix;
869
870 wordix = BCM_MWBMAP_DIVOP(bitix);
871 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
872
873 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
874 count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
875 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
876 mwbmap_p->wd_count[bitix]--;
877 count = (uint32)mwbmap_p->wd_count[bitix];
878 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
879 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
880 MWBMAP_ASSERT(count >= 0);
881
882 bitmap = (uint32)(count == 0) << BCM_MWBMAP_MODOP(bitix);
883
884 MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
885 BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap,
886 (*bitmap_p) ^ bitmap, count));
887
888 *bitmap_p ^= bitmap; /* mark as in use */
889
890 return;
891 }
892
893 /* Free a previously allocated index back into the multiword bitmap allocator */
bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl,uint32 bitix)894 void BCMFASTPATH bcm_mwbmap_free(struct bcm_mwbmap *mwbmap_hdl, uint32 bitix)
895 {
896 bcm_mwbmap_t *mwbmap_p;
897 uint32 wordix, bitmap, *bitmap_p;
898
899 BCM_MWBMAP_AUDIT(mwbmap_hdl);
900 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
901
902 ASSERT(bitix < mwbmap_p->total);
903
904 /* Start with second level hierarchy */
905 wordix = BCM_MWBMAP_DIVOP(bitix);
906 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
907 bitmap_p = &mwbmap_p->id_bitmap[wordix];
908
909 ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */
910
911 mwbmap_p->ifree++; /* update free count */
912 ASSERT(mwbmap_p->ifree <= mwbmap_p->total);
913
914 MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d",
915 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap,
916 mwbmap_p->ifree));
917
918 *bitmap_p |= bitmap; /* mark as available */
919
920 /* Now update first level hierarchy */
921
922 bitix = wordix;
923
924 wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */
925 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
926 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
927
928 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
929 mwbmap_p->wd_count[bitix]++;
930 #endif // endif
931
932 #if defined(BCM_MWBMAP_DEBUG)
933 {
934 uint32 count;
935 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
936 count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
937 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
938 count = mwbmap_p->wd_count[bitix];
939 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
940 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
941
942 MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD);
943
944 MWBMAP_DBG(
945 ("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d",
946 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count));
947 }
948 #endif /* BCM_MWBMAP_DEBUG */
949
950 *bitmap_p |= bitmap;
951
952 return;
953 }
954
955 /* Fetch the toal number of free indices in the multiword bitmap allocator */
bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl)956 uint32 bcm_mwbmap_free_cnt(struct bcm_mwbmap *mwbmap_hdl)
957 {
958 bcm_mwbmap_t *mwbmap_p;
959
960 BCM_MWBMAP_AUDIT(mwbmap_hdl);
961 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
962
963 ASSERT(mwbmap_p->ifree >= 0);
964
965 return (uint32)mwbmap_p->ifree;
966 }
967
968 /* Determine whether an index is inuse or free */
bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl,uint32 bitix)969 bool bcm_mwbmap_isfree(struct bcm_mwbmap *mwbmap_hdl, uint32 bitix)
970 {
971 bcm_mwbmap_t *mwbmap_p;
972 uint32 wordix, bitmap;
973
974 BCM_MWBMAP_AUDIT(mwbmap_hdl);
975 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
976
977 ASSERT(bitix < mwbmap_p->total);
978
979 wordix = BCM_MWBMAP_DIVOP(bitix);
980 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
981
982 return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U);
983 }
984
985 /* Debug dump a multiword bitmap allocator */
bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl)986 void bcm_mwbmap_show(struct bcm_mwbmap *mwbmap_hdl)
987 {
988 uint32 ix, count;
989 bcm_mwbmap_t *mwbmap_p;
990
991 BCM_MWBMAP_AUDIT(mwbmap_hdl);
992 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
993
994 printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n",
995 OSL_OBFUSCATE_BUF((void *)mwbmap_p), mwbmap_p->wmaps,
996 mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total);
997 for (ix = 0U; ix < mwbmap_p->wmaps; ix++) {
998 printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]);
999 bcm_bitprint32(mwbmap_p->wd_bitmap[ix]);
1000 printf("\n");
1001 }
1002 for (ix = 0U; ix < mwbmap_p->imaps; ix++) {
1003 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
1004 count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]);
1005 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
1006 count = (uint32)mwbmap_p->wd_count[ix];
1007 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix]));
1008 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
1009 printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix],
1010 count);
1011 bcm_bitprint32(mwbmap_p->id_bitmap[ix]);
1012 printf("\n");
1013 }
1014
1015 return;
1016 }
1017
1018 /* Audit a hierarchical multiword bitmap */
bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)1019 void bcm_mwbmap_audit(struct bcm_mwbmap *mwbmap_hdl)
1020 {
1021 bcm_mwbmap_t *mwbmap_p;
1022 uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p;
1023
1024 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
1025
1026 for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) {
1027 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
1028
1029 for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) {
1030 if ((*bitmap_p) & (1 << bitix)) {
1031 idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix;
1032 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
1033 count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]);
1034 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
1035 count = (uint32)mwbmap_p->wd_count[idmap_ix];
1036 ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]));
1037 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
1038 ASSERT(count != 0U);
1039 free_cnt += count;
1040 }
1041 }
1042 }
1043
1044 ASSERT((int)free_cnt == mwbmap_p->ifree);
1045 }
1046 /* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
1047
1048 /* Simple 16bit Id allocator using a stack implementation. */
1049 typedef struct id16_map {
1050 uint32 failures; /* count of failures */
1051 void *dbg; /* debug placeholder */
1052 uint16 total; /* total number of ids managed by allocator */
1053 uint16 start; /* start value of 16bit ids to be managed */
1054 int stack_idx; /* index into stack of available ids */
1055 uint16 stack[0]; /* stack of 16 bit ids */
1056 } id16_map_t;
1057
1058 #define ID16_MAP_SZ(items) (sizeof(id16_map_t) + (sizeof(uint16) * (items)))
1059
1060 #if defined(BCM_DBG)
1061
1062 typedef struct id16_map_dbg {
1063 uint16 total;
1064 bool avail[0];
1065 } id16_map_dbg_t;
1066 #define ID16_MAP_DBG_SZ(items) \
1067 (sizeof(id16_map_dbg_t) + (sizeof(bool) * (items)))
1068 #define ID16_MAP_MSG(x) print x
1069 #else
1070 #define ID16_MAP_MSG(x)
1071 #endif /* BCM_DBG */
1072
1073 void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */
id16_map_init(osl_t * osh,uint16 total_ids,uint16 start_val16)1074 id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16)
1075 {
1076 uint16 idx, val16;
1077 id16_map_t *id16_map;
1078
1079 ASSERT(total_ids > 0);
1080
1081 /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
1082 * with random values.
1083 */
1084 ASSERT((start_val16 == ID16_UNDEFINED) ||
1085 (start_val16 + total_ids) < ID16_INVALID);
1086
1087 id16_map = (id16_map_t *)MALLOC(osh, ID16_MAP_SZ(total_ids));
1088 if (id16_map == NULL) {
1089 return NULL;
1090 }
1091
1092 id16_map->total = total_ids;
1093 id16_map->start = start_val16;
1094 id16_map->failures = 0;
1095 id16_map->dbg = NULL;
1096
1097 /*
1098 * Populate stack with 16bit id values, commencing with start_val16.
1099 * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map.
1100 */
1101 id16_map->stack_idx = -1;
1102
1103 if (id16_map->start != ID16_UNDEFINED) {
1104 val16 = start_val16;
1105
1106 for (idx = 0; idx < total_ids; idx++, val16++) {
1107 id16_map->stack_idx = idx;
1108 id16_map->stack[id16_map->stack_idx] = val16;
1109 }
1110 }
1111
1112 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1113 if (id16_map->start != ID16_UNDEFINED) {
1114 id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids));
1115
1116 if (id16_map->dbg) {
1117 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
1118
1119 id16_map_dbg->total = total_ids;
1120 for (idx = 0; idx < total_ids; idx++) {
1121 id16_map_dbg->avail[idx] = TRUE;
1122 }
1123 }
1124 }
1125 #endif /* BCM_DBG && BCM_DBG_ID16 */
1126
1127 return (void *)id16_map;
1128 }
1129
1130 void * /* Destruct an id16 allocator instance */
id16_map_fini(osl_t * osh,void * id16_map_hndl)1131 id16_map_fini(osl_t *osh, void *id16_map_hndl)
1132 {
1133 uint16 total_ids;
1134 id16_map_t *id16_map;
1135
1136 if (id16_map_hndl == NULL) {
1137 return NULL;
1138 }
1139
1140 id16_map = (id16_map_t *)id16_map_hndl;
1141
1142 total_ids = id16_map->total;
1143 ASSERT(total_ids > 0);
1144
1145 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1146 if (id16_map->dbg) {
1147 MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids));
1148 id16_map->dbg = NULL;
1149 }
1150 #endif /* BCM_DBG && BCM_DBG_ID16 */
1151
1152 id16_map->total = 0;
1153 MFREE(osh, id16_map, ID16_MAP_SZ(total_ids));
1154
1155 return NULL;
1156 }
1157
id16_map_clear(void * id16_map_hndl,uint16 total_ids,uint16 start_val16)1158 void id16_map_clear(void *id16_map_hndl, uint16 total_ids, uint16 start_val16)
1159 {
1160 uint16 idx, val16;
1161 id16_map_t *id16_map;
1162
1163 ASSERT(total_ids > 0);
1164 /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
1165 * with random values.
1166 */
1167 ASSERT((start_val16 == ID16_UNDEFINED) ||
1168 (start_val16 + total_ids) < ID16_INVALID);
1169
1170 id16_map = (id16_map_t *)id16_map_hndl;
1171 if (id16_map == NULL) {
1172 return;
1173 }
1174
1175 id16_map->total = total_ids;
1176 id16_map->start = start_val16;
1177 id16_map->failures = 0;
1178
1179 /* Populate stack with 16bit id values, commencing with start_val16 */
1180 id16_map->stack_idx = -1;
1181
1182 if (id16_map->start != ID16_UNDEFINED) {
1183 val16 = start_val16;
1184
1185 for (idx = 0; idx < total_ids; idx++, val16++) {
1186 id16_map->stack_idx = idx;
1187 id16_map->stack[id16_map->stack_idx] = val16;
1188 }
1189 }
1190
1191 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1192 if (id16_map->start != ID16_UNDEFINED) {
1193 if (id16_map->dbg) {
1194 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
1195
1196 id16_map_dbg->total = total_ids;
1197 for (idx = 0; idx < total_ids; idx++) {
1198 id16_map_dbg->avail[idx] = TRUE;
1199 }
1200 }
1201 }
1202 #endif /* BCM_DBG && BCM_DBG_ID16 */
1203 }
1204
1205 uint16 BCMFASTPATH /* Allocate a unique 16bit id */
id16_map_alloc(void * id16_map_hndl)1206 id16_map_alloc(void *id16_map_hndl)
1207 {
1208 uint16 val16;
1209 id16_map_t *id16_map;
1210
1211 ASSERT(id16_map_hndl != NULL);
1212 if (!id16_map_hndl) {
1213 return ID16_INVALID;
1214 }
1215 id16_map = (id16_map_t *)id16_map_hndl;
1216
1217 ASSERT(id16_map->total > 0);
1218
1219 if (id16_map->stack_idx < 0) {
1220 id16_map->failures++;
1221 return ID16_INVALID;
1222 }
1223
1224 val16 = id16_map->stack[id16_map->stack_idx];
1225 id16_map->stack_idx--;
1226
1227 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1228 ASSERT((id16_map->start == ID16_UNDEFINED) ||
1229 (val16 < (id16_map->start + id16_map->total)));
1230
1231 if (id16_map->dbg) { /* Validate val16 */
1232 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
1233
1234 ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE);
1235 id16_map_dbg->avail[val16 - id16_map->start] = FALSE;
1236 }
1237 #endif /* BCM_DBG && BCM_DBG_ID16 */
1238
1239 return val16;
1240 }
1241
1242 void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */
id16_map_free(void * id16_map_hndl,uint16 val16)1243 id16_map_free(void *id16_map_hndl, uint16 val16)
1244 {
1245 id16_map_t *id16_map;
1246
1247 ASSERT(id16_map_hndl != NULL);
1248
1249 id16_map = (id16_map_t *)id16_map_hndl;
1250
1251 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1252 ASSERT((id16_map->start == ID16_UNDEFINED) ||
1253 (val16 < (id16_map->start + id16_map->total)));
1254
1255 if (id16_map->dbg) { /* Validate val16 */
1256 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
1257
1258 ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE);
1259 id16_map_dbg->avail[val16 - id16_map->start] = TRUE;
1260 }
1261 #endif /* BCM_DBG && BCM_DBG_ID16 */
1262
1263 id16_map->stack_idx++;
1264 id16_map->stack[id16_map->stack_idx] = val16;
1265 }
1266
1267 uint32 /* Returns number of failures to allocate an unique id16 */
id16_map_failures(void * id16_map_hndl)1268 id16_map_failures(void *id16_map_hndl)
1269 {
1270 ASSERT(id16_map_hndl != NULL);
1271 return ((id16_map_t *)id16_map_hndl)->failures;
1272 }
1273
id16_map_audit(void * id16_map_hndl)1274 bool id16_map_audit(void *id16_map_hndl)
1275 {
1276 int idx;
1277 int insane = 0;
1278 id16_map_t *id16_map;
1279
1280 ASSERT(id16_map_hndl != NULL);
1281 if (!id16_map_hndl) {
1282 goto done;
1283 }
1284 id16_map = (id16_map_t *)id16_map_hndl;
1285
1286 ASSERT(id16_map->stack_idx >= -1);
1287 ASSERT(id16_map->stack_idx < (int)id16_map->total);
1288
1289 if (id16_map->start == ID16_UNDEFINED) {
1290 goto done;
1291 }
1292
1293 for (idx = 0; idx <= id16_map->stack_idx; idx++) {
1294 ASSERT(id16_map->stack[idx] >= id16_map->start);
1295 ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total));
1296
1297 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1298 if (id16_map->dbg) {
1299 uint16 val16 = id16_map->stack[idx];
1300 if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) {
1301 insane |= 1;
1302 ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n",
1303 OSL_OBFUSATE_BUF(id16_map_hndl), idx, val16));
1304 }
1305 }
1306 #endif /* BCM_DBG && BCM_DBG_ID16 */
1307 }
1308
1309 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1310 if (id16_map->dbg) {
1311 uint16 avail = 0; /* Audit available ids counts */
1312 for (idx = 0; idx < id16_map_dbg->total; idx++) {
1313 if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE) {
1314 avail++;
1315 }
1316 }
1317 if (avail && (avail != (id16_map->stack_idx + 1))) {
1318 insane |= 1;
1319 ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n",
1320 OSL_OBFUSCATE_BUF(id16_map_hndl), avail,
1321 id16_map->stack_idx));
1322 }
1323 }
1324 #endif /* BCM_DBG && BCM_DBG_ID16 */
1325
1326 done:
1327 /* invoke any other system audits */
1328 return (!!insane);
1329 }
1330 /* END: Simple id16 allocator */
1331
dll_pool_detach(void * osh,dll_pool_t * pool,uint16 elems_max,uint16 elem_size)1332 void dll_pool_detach(void *osh, dll_pool_t *pool, uint16 elems_max,
1333 uint16 elem_size)
1334 {
1335 uint32 memsize;
1336 memsize = sizeof(dll_pool_t) + (elems_max * elem_size);
1337 if (pool) {
1338 MFREE(osh, pool, memsize);
1339 }
1340 }
dll_pool_init(void * osh,uint16 elems_max,uint16 elem_size)1341 dll_pool_t *dll_pool_init(void *osh, uint16 elems_max, uint16 elem_size)
1342 {
1343 uint32 memsize, i;
1344 dll_pool_t *dll_pool_p;
1345 dll_t *elem_p;
1346
1347 ASSERT(elem_size > sizeof(dll_t));
1348
1349 memsize = sizeof(dll_pool_t) + (elems_max * elem_size);
1350
1351 if ((dll_pool_p = (dll_pool_t *)MALLOCZ(osh, memsize)) == NULL) {
1352 printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n",
1353 elems_max, elem_size);
1354 ASSERT(0);
1355 return dll_pool_p;
1356 }
1357
1358 dll_init(&dll_pool_p->free_list);
1359 dll_pool_p->elems_max = elems_max;
1360 dll_pool_p->elem_size = elem_size;
1361
1362 elem_p = dll_pool_p->elements;
1363 for (i = 0; i < elems_max; i++) {
1364 dll_append(&dll_pool_p->free_list, elem_p);
1365 elem_p = (dll_t *)((uintptr)elem_p + elem_size);
1366 }
1367
1368 dll_pool_p->free_count = elems_max;
1369
1370 return dll_pool_p;
1371 }
1372
dll_pool_alloc(dll_pool_t * dll_pool_p)1373 void *dll_pool_alloc(dll_pool_t *dll_pool_p)
1374 {
1375 dll_t *elem_p;
1376
1377 if (dll_pool_p->free_count == 0) {
1378 ASSERT(dll_empty(&dll_pool_p->free_list));
1379 return NULL;
1380 }
1381
1382 elem_p = dll_head_p(&dll_pool_p->free_list);
1383 dll_delete(elem_p);
1384 dll_pool_p->free_count -= 1;
1385
1386 return (void *)elem_p;
1387 }
1388
dll_pool_free(dll_pool_t * dll_pool_p,void * elem_p)1389 void dll_pool_free(dll_pool_t *dll_pool_p, void *elem_p)
1390 {
1391 dll_t *node_p = (dll_t *)elem_p;
1392 dll_prepend(&dll_pool_p->free_list, node_p);
1393 dll_pool_p->free_count += 1;
1394 }
1395
dll_pool_free_tail(dll_pool_t * dll_pool_p,void * elem_p)1396 void dll_pool_free_tail(dll_pool_t *dll_pool_p, void *elem_p)
1397 {
1398 dll_t *node_p = (dll_t *)elem_p;
1399 dll_append(&dll_pool_p->free_list, node_p);
1400 dll_pool_p->free_count += 1;
1401 }
1402
1403 #endif // endif
1404
1405 #endif /* BCMDRIVER */
1406
1407 #if defined(BCMDRIVER) || defined(WL_UNITTEST)
1408
1409 /* triggers bcm_bprintf to print to kernel log */
1410 bool bcm_bprintf_bypass = FALSE;
1411
1412 /* Initialization of bcmstrbuf structure */
bcm_binit(struct bcmstrbuf * b,char * buf,uint size)1413 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1414 {
1415 b->origsize = b->size = size;
1416 b->origbuf = b->buf = buf;
1417 if (size > 0) {
1418 buf[0] = '\0';
1419 }
1420 }
1421
1422 /* Buffer sprintf wrapper to guard against buffer overflow */
bcm_bprintf(struct bcmstrbuf * b,const char * fmt,...)1423 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1424 {
1425 va_list ap;
1426 int r;
1427
1428 va_start(ap, fmt);
1429
1430 r = vsnprintf(b->buf, b->size, fmt, ap);
1431 if (bcm_bprintf_bypass == TRUE) {
1432 printf("%s", b->buf);
1433 goto exit;
1434 }
1435
1436 /* Non Ansi C99 compliant returns -1,
1437 * Ansi compliant return r >= b->size,
1438 * bcmstdlib returns 0, handle all
1439 */
1440 /* r == 0 is also the case when strlen(fmt) is zero.
1441 * typically the case when "" is passed as argument.
1442 */
1443 if ((r == -1) || (r >= (int)b->size)) {
1444 b->size = 0;
1445 } else {
1446 b->size -= (uint)r;
1447 b->buf += r;
1448 }
1449
1450 exit:
1451 va_end(ap);
1452
1453 return r;
1454 }
1455
bcm_bprhex(struct bcmstrbuf * b,const char * msg,bool newline,const uint8 * buf,int len)1456 void bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline,
1457 const uint8 *buf, int len)
1458 {
1459 int i;
1460
1461 if (msg != NULL && msg[0] != '\0') {
1462 bcm_bprintf(b, "%s", msg);
1463 }
1464 for (i = 0; i < len; i++) {
1465 bcm_bprintf(b, "%02X", buf[i]);
1466 }
1467 if (newline) {
1468 bcm_bprintf(b, "\n");
1469 }
1470 }
1471
bcm_inc_bytes(uchar * num,int num_bytes,uint8 amount)1472 void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
1473 {
1474 int i;
1475
1476 for (i = 0; i < num_bytes; i++) {
1477 num[i] += amount;
1478 if (num[i] >= amount) {
1479 break;
1480 }
1481 amount = 1;
1482 }
1483 }
1484
bcm_cmp_bytes(const uchar * arg1,const uchar * arg2,uint8 nbytes)1485 int bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes)
1486 {
1487 int i;
1488
1489 for (i = nbytes - 1; i >= 0; i--) {
1490 if (arg1[i] != arg2[i]) {
1491 return (arg1[i] - arg2[i]);
1492 }
1493 }
1494 return 0;
1495 }
1496
bcm_print_bytes(const char * name,const uchar * data,int len)1497 void bcm_print_bytes(const char *name, const uchar *data, int len)
1498 {
1499 int i;
1500 int per_line = 0;
1501
1502 printf("%s: %d \n", name ? name : "", len);
1503 for (i = 0; i < len; i++) {
1504 printf("%02x ", *data++);
1505 per_line++;
1506 if (per_line == 0x10) {
1507 per_line = 0;
1508 printf("\n");
1509 }
1510 }
1511 printf("\n");
1512 }
1513
1514 /* Look for vendor-specific IE with specified OUI and optional type */
bcm_find_vendor_ie(const void * tlvs,uint tlvs_len,const char * voui,uint8 * type,uint type_len)1515 bcm_tlv_t *bcm_find_vendor_ie(const void *tlvs, uint tlvs_len, const char *voui,
1516 uint8 *type, uint type_len)
1517 {
1518 const bcm_tlv_t *ie;
1519 uint8 ie_len;
1520
1521 ie = (const bcm_tlv_t *)tlvs;
1522
1523 /* make sure we are looking at a valid IE */
1524 if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) {
1525 return NULL;
1526 }
1527
1528 /* Walk through the IEs looking for an OUI match */
1529 do {
1530 ie_len = ie->len;
1531 if ((ie->id == DOT11_MNG_VS_ID) &&
1532 (ie_len >= (DOT11_OUI_LEN + type_len)) &&
1533 !bcmp(ie->data, voui, DOT11_OUI_LEN)) {
1534 /* compare optional type */
1535 if (type_len == 0 ||
1536 !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) {
1537 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1538 return (bcm_tlv_t *)(ie); /* a match */
1539 GCC_DIAGNOSTIC_POP();
1540 }
1541 }
1542 } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL);
1543
1544 return NULL;
1545 }
1546
1547 #if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
1548 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
1549 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
1550
bcm_format_ssid(char * buf,const uchar ssid[],uint ssid_len)1551 int bcm_format_ssid(char *buf, const uchar ssid[], uint ssid_len)
1552 {
1553 uint i, c;
1554 char *p = buf;
1555 char *endp = buf + SSID_FMT_BUF_LEN;
1556
1557 if (ssid_len > DOT11_MAX_SSID_LEN) {
1558 ssid_len = DOT11_MAX_SSID_LEN;
1559 }
1560
1561 for (i = 0; i < ssid_len; i++) {
1562 c = (uint)ssid[i];
1563 if (c == '\\') {
1564 *p++ = '\\';
1565 *p++ = '\\';
1566 } else if (bcm_isprint((uchar)c)) {
1567 *p++ = (char)c;
1568 } else {
1569 p += snprintf(p, (size_t)(endp - p), "\\x%02X", c);
1570 }
1571 }
1572 *p = '\0';
1573 ASSERT(p < endp);
1574
1575 return (int)(p - buf);
1576 }
1577 #endif // endif
1578
1579 #endif /* BCMDRIVER || WL_UNITTEST */
1580
bcm_ether_ntoa(const struct ether_addr * ea,char * buf)1581 char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
1582 {
1583 static const char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
1584 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
1585 const uint8 *octet = ea->octet;
1586 char *p = buf;
1587 int i;
1588
1589 for (i = 0; i < 0x6; i++, octet++) {
1590 *p++ = hex[(*octet >> 0x4) & 0xf];
1591 *p++ = hex[*octet & 0xf];
1592 *p++ = ':';
1593 }
1594
1595 *(p - 1) = '\0';
1596
1597 return (buf);
1598 }
1599
1600 /* Find the position of first bit set
1601 * in the given number.
1602 */
bcm_find_fsb(uint32 num)1603 int bcm_find_fsb(uint32 num)
1604 {
1605 uint8 pos = 0;
1606 if (!num) {
1607 return pos;
1608 }
1609 while (!(num & 1)) {
1610 num >>= 1;
1611 pos++;
1612 }
1613 return (pos + 1);
1614 }
1615
bcm_ip_ntoa(struct ipv4_addr * ia,char * buf)1616 char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
1617 {
1618 snprintf(buf, 0x10, "%d.%d.%d.%d", ia->addr[0], ia->addr[1], ia->addr[0x2],
1619 ia->addr[0x3]);
1620 return (buf);
1621 }
1622
bcm_ipv6_ntoa(void * ipv6,char * buf)1623 char *bcm_ipv6_ntoa(void *ipv6, char *buf)
1624 {
1625 /* Implementing RFC 5952 Sections 4 + 5 */
1626 /* Not thoroughly tested */
1627 uint16 tmp[8];
1628 uint16 *a = &tmp[0];
1629 char *p = buf;
1630 int i, i_max = -1, cnt = 0, cnt_max = 1;
1631 uint8 *a4 = NULL;
1632 memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN);
1633
1634 for (i = 0; i < IPV6_ADDR_LEN / 0x2; i++) {
1635 if (a[i]) {
1636 if (cnt > cnt_max) {
1637 cnt_max = cnt;
1638 i_max = i - cnt;
1639 }
1640 cnt = 0;
1641 } else {
1642 cnt++;
1643 }
1644 }
1645 if (cnt > cnt_max) {
1646 cnt_max = cnt;
1647 i_max = i - cnt;
1648 }
1649 if (i_max == 0 &&
1650 /* IPv4-translated: ::ffff:0:a.b.c.d */
1651 ((cnt_max == 0x4 && a[0x4] == 0xffff && a[0x5] == 0) ||
1652 /* IPv4-mapped: ::ffff:a.b.c.d */
1653 (cnt_max == 0x5 && a[0x5] == 0xffff))) {
1654 a4 = (uint8 *)(a + 0x6);
1655 }
1656
1657 for (i = 0; i < IPV6_ADDR_LEN / 0x2; i++) {
1658 if ((uint8 *)(a + i) == a4) {
1659 snprintf(p, 0x10, ":%u.%u.%u.%u", a4[0], a4[1], a4[0x2], a4[0x3]);
1660 break;
1661 } else if (i == i_max) {
1662 *p++ = ':';
1663 i += cnt_max - 1;
1664 p[0] = ':';
1665 p[1] = '\0';
1666 } else {
1667 if (i) {
1668 *p++ = ':';
1669 }
1670 p += snprintf(p, 0x8, "%x", ntoh16(a[i]));
1671 }
1672 }
1673
1674 return buf;
1675 }
1676
1677 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
1678 const unsigned char bcm_ctype[] = {
1679
1680 _BCM_C,
1681 _BCM_C,
1682 _BCM_C,
1683 _BCM_C,
1684 _BCM_C,
1685 _BCM_C,
1686 _BCM_C,
1687 _BCM_C, /* 0-7 */
1688 _BCM_C,
1689 _BCM_C | _BCM_S,
1690 _BCM_C | _BCM_S,
1691 _BCM_C | _BCM_S,
1692 _BCM_C | _BCM_S,
1693 _BCM_C | _BCM_S,
1694 _BCM_C,
1695 _BCM_C, /* 8-15 */
1696 _BCM_C,
1697 _BCM_C,
1698 _BCM_C,
1699 _BCM_C,
1700 _BCM_C,
1701 _BCM_C,
1702 _BCM_C,
1703 _BCM_C, /* 16-23 */
1704 _BCM_C,
1705 _BCM_C,
1706 _BCM_C,
1707 _BCM_C,
1708 _BCM_C,
1709 _BCM_C,
1710 _BCM_C,
1711 _BCM_C, /* 24-31 */
1712 _BCM_S | _BCM_SP,
1713 _BCM_P,
1714 _BCM_P,
1715 _BCM_P,
1716 _BCM_P,
1717 _BCM_P,
1718 _BCM_P,
1719 _BCM_P, /* 32-39 */
1720 _BCM_P,
1721 _BCM_P,
1722 _BCM_P,
1723 _BCM_P,
1724 _BCM_P,
1725 _BCM_P,
1726 _BCM_P,
1727 _BCM_P, /* 40-47 */
1728 _BCM_D,
1729 _BCM_D,
1730 _BCM_D,
1731 _BCM_D,
1732 _BCM_D,
1733 _BCM_D,
1734 _BCM_D,
1735 _BCM_D, /* 48-55 */
1736 _BCM_D,
1737 _BCM_D,
1738 _BCM_P,
1739 _BCM_P,
1740 _BCM_P,
1741 _BCM_P,
1742 _BCM_P,
1743 _BCM_P, /* 56-63 */
1744 _BCM_P,
1745 _BCM_U | _BCM_X,
1746 _BCM_U | _BCM_X,
1747 _BCM_U | _BCM_X,
1748 _BCM_U | _BCM_X,
1749 _BCM_U | _BCM_X,
1750 _BCM_U | _BCM_X,
1751 _BCM_U, /* 64-71 */
1752 _BCM_U,
1753 _BCM_U,
1754 _BCM_U,
1755 _BCM_U,
1756 _BCM_U,
1757 _BCM_U,
1758 _BCM_U,
1759 _BCM_U, /* 72-79 */
1760 _BCM_U,
1761 _BCM_U,
1762 _BCM_U,
1763 _BCM_U,
1764 _BCM_U,
1765 _BCM_U,
1766 _BCM_U,
1767 _BCM_U, /* 80-87 */
1768 _BCM_U,
1769 _BCM_U,
1770 _BCM_U,
1771 _BCM_P,
1772 _BCM_P,
1773 _BCM_P,
1774 _BCM_P,
1775 _BCM_P, /* 88-95 */
1776 _BCM_P,
1777 _BCM_L | _BCM_X,
1778 _BCM_L | _BCM_X,
1779 _BCM_L | _BCM_X,
1780 _BCM_L | _BCM_X,
1781 _BCM_L | _BCM_X,
1782 _BCM_L | _BCM_X,
1783 _BCM_L, /* 96-103 */
1784 _BCM_L,
1785 _BCM_L,
1786 _BCM_L,
1787 _BCM_L,
1788 _BCM_L,
1789 _BCM_L,
1790 _BCM_L,
1791 _BCM_L, /* 104-111 */
1792 _BCM_L,
1793 _BCM_L,
1794 _BCM_L,
1795 _BCM_L,
1796 _BCM_L,
1797 _BCM_L,
1798 _BCM_L,
1799 _BCM_L, /* 112-119 */
1800 _BCM_L,
1801 _BCM_L,
1802 _BCM_L,
1803 _BCM_P,
1804 _BCM_P,
1805 _BCM_P,
1806 _BCM_P,
1807 _BCM_C, /* 120-127 */
1808 0,
1809 0,
1810 0,
1811 0,
1812 0,
1813 0,
1814 0,
1815 0,
1816 0,
1817 0,
1818 0,
1819 0,
1820 0,
1821 0,
1822 0,
1823 0, /* 128-143 */
1824 0,
1825 0,
1826 0,
1827 0,
1828 0,
1829 0,
1830 0,
1831 0,
1832 0,
1833 0,
1834 0,
1835 0,
1836 0,
1837 0,
1838 0,
1839 0, /* 144-159 */
1840 _BCM_S | _BCM_SP,
1841 _BCM_P,
1842 _BCM_P,
1843 _BCM_P,
1844 _BCM_P,
1845 _BCM_P,
1846 _BCM_P,
1847 _BCM_P,
1848 _BCM_P,
1849 _BCM_P,
1850 _BCM_P,
1851 _BCM_P,
1852 _BCM_P,
1853 _BCM_P,
1854 _BCM_P,
1855 _BCM_P, /* 160-175 */
1856 _BCM_P,
1857 _BCM_P,
1858 _BCM_P,
1859 _BCM_P,
1860 _BCM_P,
1861 _BCM_P,
1862 _BCM_P,
1863 _BCM_P,
1864 _BCM_P,
1865 _BCM_P,
1866 _BCM_P,
1867 _BCM_P,
1868 _BCM_P,
1869 _BCM_P,
1870 _BCM_P,
1871 _BCM_P, /* 176-191 */
1872 _BCM_U,
1873 _BCM_U,
1874 _BCM_U,
1875 _BCM_U,
1876 _BCM_U,
1877 _BCM_U,
1878 _BCM_U,
1879 _BCM_U,
1880 _BCM_U,
1881 _BCM_U,
1882 _BCM_U,
1883 _BCM_U,
1884 _BCM_U,
1885 _BCM_U,
1886 _BCM_U,
1887 _BCM_U, /* 192-207 */
1888 _BCM_U,
1889 _BCM_U,
1890 _BCM_U,
1891 _BCM_U,
1892 _BCM_U,
1893 _BCM_U,
1894 _BCM_U,
1895 _BCM_P,
1896 _BCM_U,
1897 _BCM_U,
1898 _BCM_U,
1899 _BCM_U,
1900 _BCM_U,
1901 _BCM_U,
1902 _BCM_U,
1903 _BCM_L, /* 208-223 */
1904 _BCM_L,
1905 _BCM_L,
1906 _BCM_L,
1907 _BCM_L,
1908 _BCM_L,
1909 _BCM_L,
1910 _BCM_L,
1911 _BCM_L,
1912 _BCM_L,
1913 _BCM_L,
1914 _BCM_L,
1915 _BCM_L,
1916 _BCM_L,
1917 _BCM_L,
1918 _BCM_L,
1919 _BCM_L, /* 224-239 */
1920 _BCM_L,
1921 _BCM_L,
1922 _BCM_L,
1923 _BCM_L,
1924 _BCM_L,
1925 _BCM_L,
1926 _BCM_L,
1927 _BCM_P,
1928 _BCM_L,
1929 _BCM_L,
1930 _BCM_L,
1931 _BCM_L,
1932 _BCM_L,
1933 _BCM_L,
1934 _BCM_L,
1935 _BCM_L /* 240-255 */
1936 };
1937
bcm_strtoull(const char * cp,char ** endp,uint base)1938 uint64 bcm_strtoull(const char *cp, char **endp, uint base)
1939 {
1940 uint64 result, last_result = 0, value;
1941 bool minus;
1942
1943 minus = FALSE;
1944
1945 while (bcm_isspace(*cp)) {
1946 cp++;
1947 }
1948
1949 if (cp[0] == '+') {
1950 cp++;
1951 } else if (cp[0] == '-') {
1952 minus = TRUE;
1953 cp++;
1954 }
1955
1956 if (base == 0) {
1957 if (cp[0] == '0') {
1958 if ((cp[1] == 'x') || (cp[1] == 'X')) {
1959 base = 0x10;
1960 cp = &cp[0x2];
1961 } else {
1962 base = 0x8;
1963 cp = &cp[1];
1964 }
1965 } else {
1966 base = 0xA;
1967 }
1968 } else if (base == 0x10 && (cp[0] == '0') &&
1969 ((cp[1] == 'x') || (cp[1] == 'X'))) {
1970 cp = &cp[0x2];
1971 }
1972
1973 result = 0;
1974
1975 while (bcm_isxdigit(*cp) &&
1976 (value = (uint64)(bcm_isdigit(*cp) ? *cp - '0' : bcm_toupper(*cp) - 'A' + 0xA)) < base) {
1977 result = result * base + value;
1978 /* Detected overflow */
1979 if (result < last_result && !minus) {
1980 if (endp) {
1981 /* Go to the end of current number */
1982 while (bcm_isxdigit(*cp)) {
1983 cp++;
1984 }
1985 *endp = DISCARD_QUAL(cp, char);
1986 }
1987 return (ulong)-1;
1988 }
1989 last_result = result;
1990 cp++;
1991 }
1992
1993 if (minus) {
1994 result = (ulong)(-(long)result);
1995 }
1996
1997 if (endp) {
1998 *endp = DISCARD_QUAL(cp, char);
1999 }
2000
2001 return (result);
2002 }
2003
bcm_strtoul(const char * cp,char ** endp,uint base)2004 ulong bcm_strtoul(const char *cp, char **endp, uint base)
2005 {
2006 return (ulong)bcm_strtoull(cp, endp, base);
2007 }
2008
bcm_atoi(const char * s)2009 int bcm_atoi(const char *s)
2010 {
2011 return (int)bcm_strtoul(s, NULL, 10);
2012 }
2013
2014 /* return pointer to location of substring 'needle' in 'haystack' */
bcmstrstr(const char * haystack,const char * needle)2015 char *bcmstrstr(const char *haystack, const char *needle)
2016 {
2017 int len, nlen;
2018 int i;
2019
2020 if ((haystack == NULL) || (needle == NULL)) {
2021 return DISCARD_QUAL(haystack, char);
2022 }
2023
2024 nlen = (int)strlen(needle);
2025 len = (int)strlen(haystack) - nlen + 1;
2026
2027 for (i = 0; i < len; i++) {
2028 if (memcmp(needle, &haystack[i], (size_t)nlen) == 0) {
2029 return DISCARD_QUAL(&haystack[i], char);
2030 }
2031 }
2032 return (NULL);
2033 }
2034
bcmstrnstr(const char * s,uint s_len,const char * substr,uint substr_len)2035 char *bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len)
2036 {
2037 for (; s_len >= substr_len; s++, s_len--) {
2038 if (strncmp(s, substr, substr_len) == 0) {
2039 return DISCARD_QUAL(s, char);
2040 }
2041 }
2042
2043 return NULL;
2044 }
2045
bcmstrcat(char * dest,const char * src)2046 char *bcmstrcat(char *dest, const char *src)
2047 {
2048 char *p;
2049
2050 p = dest + strlen(dest);
2051
2052 while ((*p++ = *src++) != '\0') {
2053 ;
2054 }
2055
2056 return (dest);
2057 }
2058
bcmstrncat(char * dest,const char * src,uint size)2059 char *bcmstrncat(char *dest, const char *src, uint size)
2060 {
2061 char *endp;
2062 char *p;
2063
2064 p = dest + strlen(dest);
2065 endp = p + size;
2066
2067 while (p != endp && (*p++ = *src++) != '\0') {
2068 ;
2069 }
2070
2071 return (dest);
2072 }
2073
2074 /****************************************************************************
2075 * Function: bcmstrtok
2076 *
2077 * Purpose:
2078 * Tokenizes a string. This function is conceptually similiar to ANSI C
2079 * strtok(), but allows strToken() to be used by different strings or callers at
2080 * the same time. Each call modifies '*string' by substituting a NULL character
2081 * for the first delimiter that is encountered, and updates 'string' to point to
2082 * the char after the delimiter. Leading delimiters are skipped.
2083 *
2084 * Parameters:
2085 * string (mod) Ptr to string ptr, updated by token.
2086 * delimiters (in) Set of delimiter characters.
2087 * tokdelim (out) Character that delimits the returned token. (May
2088 * be set to NULL if token delimiter is not required).
2089 *
2090 * Returns: Pointer to the next token found. NULL when no more tokens are
2091 * found.
2092 *****************************************************************************
2093 */
bcmstrtok(char ** string,const char * delimiters,char * tokdelim)2094 char *bcmstrtok(char **string, const char *delimiters, char *tokdelim)
2095 {
2096 unsigned char *str;
2097 unsigned long map[8];
2098 int count;
2099 char *nextoken;
2100
2101 if (tokdelim != NULL) {
2102 /* Prime the token delimiter */
2103 *tokdelim = '\0';
2104 }
2105
2106 /* Clear control map */
2107 for (count = 0; count < 0x8; count++) {
2108 map[count] = 0;
2109 }
2110
2111 /* Set bits in delimiter table */
2112 do {
2113 map[*delimiters >> 0x5] |= (1 << (*delimiters & 0x1F));
2114 } while (*delimiters++);
2115
2116 str = (unsigned char *)*string;
2117
2118 /* Find beginning of token (skip over leading delimiters). Note that
2119 * there is no token iff this loop sets str to point to the terminal
2120 * null (*str == '\0')
2121 */
2122 while (((map[*str >> 0x5] & (1 << (*str & 0x1F))) && *str) || (*str == ' ')) {
2123 str++;
2124 }
2125
2126 nextoken = (char *)str;
2127
2128 /* Find the end of the token. If it is not the end of the string,
2129 * put a null there.
2130 */
2131 for (; *str; str++) {
2132 if (map[*str >> 0x5] & (1 << (*str & 0x1F))) {
2133 if (tokdelim != NULL) {
2134 *tokdelim = (char)*str;
2135 }
2136
2137 *str++ = '\0';
2138 break;
2139 }
2140 }
2141
2142 *string = (char *)str;
2143
2144 /* Determine if a token has been found. */
2145 if (nextoken == (char *)str) {
2146 return NULL;
2147 } else {
2148 return nextoken;
2149 }
2150 }
2151
2152 #define xToLower(C) \
2153 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
2154
2155 /****************************************************************************
2156 * Function: bcmstricmp
2157 *
2158 * Purpose: Compare to strings case insensitively.
2159 *
2160 * Parameters: s1 (in) First string to compare.
2161 * s2 (in) Second string to compare.
2162 *
2163 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
2164 * t1 > t2, when ignoring case sensitivity.
2165 *****************************************************************************
2166 */
bcmstricmp(const char * s1,const char * s2)2167 int bcmstricmp(const char *s1, const char *s2)
2168 {
2169 char dc, sc;
2170
2171 while (*s2 && *s1) {
2172 dc = xToLower(*s1);
2173 sc = xToLower(*s2);
2174 if (dc < sc) {
2175 return -1;
2176 }
2177 if (dc > sc) {
2178 return 1;
2179 }
2180 s1++;
2181 s2++;
2182 }
2183
2184 if (*s1 && !*s2) {
2185 return 1;
2186 }
2187 if (!*s1 && *s2) {
2188 return -1;
2189 }
2190 return 0;
2191 }
2192
2193 /****************************************************************************
2194 * Function: bcmstrnicmp
2195 *
2196 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
2197 * characters.
2198 *
2199 * Parameters: s1 (in) First string to compare.
2200 * s2 (in) Second string to compare.
2201 * cnt (in) Max characters to compare.
2202 *
2203 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
2204 * t1 > t2, when ignoring case sensitivity.
2205 *****************************************************************************
2206 */
bcmstrnicmp(const char * s1,const char * s2,int cnt)2207 int bcmstrnicmp(const char *s1, const char *s2, int cnt)
2208 {
2209 char dc, sc;
2210
2211 while (*s2 && *s1 && cnt) {
2212 dc = xToLower(*s1);
2213 sc = xToLower(*s2);
2214 if (dc < sc) {
2215 return -1;
2216 }
2217 if (dc > sc) {
2218 return 1;
2219 }
2220 s1++;
2221 s2++;
2222 cnt--;
2223 }
2224
2225 if (!cnt) {
2226 return 0;
2227 }
2228 if (*s1 && !*s2) {
2229 return 1;
2230 }
2231 if (!*s1 && *s2) {
2232 return -1;
2233 }
2234 return 0;
2235 }
2236
2237 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
bcm_ether_atoe(const char * p,struct ether_addr * ea)2238 int bcm_ether_atoe(const char *p, struct ether_addr *ea)
2239 {
2240 int i = 0;
2241 char *ep;
2242
2243 for (;;) {
2244 ea->octet[i++] = (uint8)bcm_strtoul(p, &ep, 0x10);
2245 p = ep;
2246 if (!*p++ || i == 0x6) {
2247 break;
2248 }
2249 }
2250
2251 return (i == 0x6);
2252 }
2253
bcm_atoipv4(const char * p,struct ipv4_addr * ip)2254 int bcm_atoipv4(const char *p, struct ipv4_addr *ip)
2255 {
2256 int i = 0;
2257 char *c;
2258 for (;;) {
2259 ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0);
2260 if (*c++ != '.' || i == IPV4_ADDR_LEN) {
2261 break;
2262 }
2263 p = c;
2264 }
2265 return (i == IPV4_ADDR_LEN);
2266 }
2267 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
2268
2269 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
2270 /* registry routine buffer preparation utility functions:
2271 * parameter order is like strncpy, but returns count
2272 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
2273 */
wchar2ascii(char * abuf,ushort * wbuf,ushort wbuflen,ulong abuflen)2274 ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
2275 {
2276 ulong copyct = 1;
2277 ushort i;
2278
2279 if (abuflen == 0) {
2280 return 0;
2281 }
2282
2283 /* wbuflen is in bytes */
2284 wbuflen /= sizeof(ushort);
2285
2286 for (i = 0; i < wbuflen; ++i) {
2287 if (--abuflen == 0) {
2288 break;
2289 }
2290 *abuf++ = (char)*wbuf++;
2291 ++copyct;
2292 }
2293 *abuf = '\0';
2294
2295 return copyct;
2296 }
2297 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
2298
2299 #ifdef BCM_OBJECT_TRACE
2300
2301 #define BCM_OBJECT_MERGE_SAME_OBJ 0
2302
2303 /* some place may add / remove the object to trace list for Linux: */
2304 /* add: osl_alloc_skb dev_alloc_skb skb_realloc_headroom dhd_start_xmit */
2305 /* remove: osl_pktfree dev_kfree_skb netif_rx */
2306
2307 #define BCM_OBJDBG_COUNT (1024 * 100)
2308 static spinlock_t dbgobj_lock;
2309 #define BCM_OBJDBG_LOCK_INIT() spin_lock_init(&dbgobj_lock)
2310 #define BCM_OBJDBG_LOCK_DESTROY()
2311 #define BCM_OBJDBG_LOCK spin_lock_irqsave
2312 #define BCM_OBJDBG_UNLOCK spin_unlock_irqrestore
2313
2314 #define BCM_OBJDBG_ADDTOHEAD 0
2315 #define BCM_OBJDBG_ADDTOTAIL 1
2316
2317 #define BCM_OBJDBG_CALLER_LEN 32
2318 struct bcm_dbgobj {
2319 struct bcm_dbgobj *prior;
2320 struct bcm_dbgobj *next;
2321 uint32 flag;
2322 void *obj;
2323 uint32 obj_sn;
2324 uint32 obj_state;
2325 uint32 line;
2326 char caller[BCM_OBJDBG_CALLER_LEN];
2327 };
2328
2329 static struct bcm_dbgobj *dbgobj_freehead = NULL;
2330 static struct bcm_dbgobj *dbgobj_freetail = NULL;
2331 static struct bcm_dbgobj *dbgobj_objhead = NULL;
2332 static struct bcm_dbgobj *dbgobj_objtail = NULL;
2333
2334 static uint32 dbgobj_sn = 0;
2335 static int dbgobj_count = 0;
2336 static struct bcm_dbgobj bcm_dbg_objs[BCM_OBJDBG_COUNT];
2337
bcm_object_trace_init(void)2338 void bcm_object_trace_init(void)
2339 {
2340 int i = 0;
2341 BCM_OBJDBG_LOCK_INIT();
2342 memset(&bcm_dbg_objs, 0x00, sizeof(struct bcm_dbgobj) * BCM_OBJDBG_COUNT);
2343 dbgobj_freehead = &bcm_dbg_objs[0];
2344 dbgobj_freetail = &bcm_dbg_objs[BCM_OBJDBG_COUNT - 1];
2345
2346 for (i = 0; i < BCM_OBJDBG_COUNT; ++i) {
2347 bcm_dbg_objs[i].next = (i == (BCM_OBJDBG_COUNT - 1))
2348 ? dbgobj_freehead
2349 : &bcm_dbg_objs[i + 1];
2350 bcm_dbg_objs[i].prior =
2351 (i == 0) ? dbgobj_freetail : &bcm_dbg_objs[i - 1];
2352 }
2353 }
2354
bcm_object_trace_deinit(void)2355 void bcm_object_trace_deinit(void)
2356 {
2357 if (dbgobj_objhead || dbgobj_objtail) {
2358 printf("%s: not all objects are released\n", __FUNCTION__);
2359 ASSERT(0);
2360 }
2361 BCM_OBJDBG_LOCK_DESTROY();
2362 }
2363
bcm_object_rm_list(struct bcm_dbgobj ** head,struct bcm_dbgobj ** tail,struct bcm_dbgobj * dbgobj)2364 static void bcm_object_rm_list(struct bcm_dbgobj **head,
2365 struct bcm_dbgobj **tail,
2366 struct bcm_dbgobj *dbgobj)
2367 {
2368 if ((dbgobj == *head) && (dbgobj == *tail)) {
2369 *head = NULL;
2370 *tail = NULL;
2371 } else if (dbgobj == *head) {
2372 *head = (*head)->next;
2373 } else if (dbgobj == *tail) {
2374 *tail = (*tail)->prior;
2375 }
2376 dbgobj->next->prior = dbgobj->prior;
2377 dbgobj->prior->next = dbgobj->next;
2378 }
2379
bcm_object_add_list(struct bcm_dbgobj ** head,struct bcm_dbgobj ** tail,struct bcm_dbgobj * dbgobj,int addtotail)2380 static void bcm_object_add_list(struct bcm_dbgobj **head,
2381 struct bcm_dbgobj **tail,
2382 struct bcm_dbgobj *dbgobj, int addtotail)
2383 {
2384 if (!(*head) && !(*tail)) {
2385 *head = dbgobj;
2386 *tail = dbgobj;
2387 dbgobj->next = dbgobj;
2388 dbgobj->prior = dbgobj;
2389 } else if ((*head) && (*tail)) {
2390 (*tail)->next = dbgobj;
2391 (*head)->prior = dbgobj;
2392 dbgobj->next = *head;
2393 dbgobj->prior = *tail;
2394 if (addtotail == BCM_OBJDBG_ADDTOTAIL) {
2395 *tail = dbgobj;
2396 } else {
2397 *head = dbgobj;
2398 }
2399 } else {
2400 ASSERT(0); /* can't be this case */
2401 }
2402 }
2403
bcm_object_movetoend(struct bcm_dbgobj ** head,struct bcm_dbgobj ** tail,struct bcm_dbgobj * dbgobj,int movetotail)2404 static INLINE void bcm_object_movetoend(struct bcm_dbgobj **head,
2405 struct bcm_dbgobj **tail,
2406 struct bcm_dbgobj *dbgobj,
2407 int movetotail)
2408 {
2409 if ((*head) && (*tail)) {
2410 if (movetotail == BCM_OBJDBG_ADDTOTAIL) {
2411 if (dbgobj != (*tail)) {
2412 bcm_object_rm_list(head, tail, dbgobj);
2413 bcm_object_add_list(head, tail, dbgobj, movetotail);
2414 }
2415 } else {
2416 if (dbgobj != (*head)) {
2417 bcm_object_rm_list(head, tail, dbgobj);
2418 bcm_object_add_list(head, tail, dbgobj, movetotail);
2419 }
2420 }
2421 } else {
2422 ASSERT(0); /* can't be this case */
2423 }
2424 }
2425
bcm_object_trace_opr(void * obj,uint32 opt,const char * caller,int line)2426 void bcm_object_trace_opr(void *obj, uint32 opt, const char *caller, int line)
2427 {
2428 struct bcm_dbgobj *dbgobj;
2429 unsigned long flags;
2430
2431 BCM_REFERENCE(flags);
2432 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
2433
2434 if (opt == BCM_OBJDBG_ADD_PKT || opt == BCM_OBJDBG_ADD) {
2435 dbgobj = dbgobj_objtail;
2436 while (dbgobj) {
2437 if (dbgobj->obj == obj) {
2438 printf("%s: obj %p allocated from %s(%d),"
2439 " allocate again from %s(%d)\n",
2440 __FUNCTION__, dbgobj->obj, dbgobj->caller, dbgobj->line,
2441 caller, line);
2442 ASSERT(0);
2443 goto EXIT;
2444 }
2445 dbgobj = dbgobj->prior;
2446 if (dbgobj == dbgobj_objtail) {
2447 break;
2448 }
2449 }
2450
2451 #if BCM_OBJECT_MERGE_SAME_OBJ
2452 dbgobj = dbgobj_freetail;
2453 while (dbgobj) {
2454 if (dbgobj->obj == obj) {
2455 goto FREED_ENTRY_FOUND;
2456 }
2457 dbgobj = dbgobj->prior;
2458 if (dbgobj == dbgobj_freetail) {
2459 break;
2460 }
2461 }
2462 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
2463
2464 dbgobj = dbgobj_freehead;
2465 #if BCM_OBJECT_MERGE_SAME_OBJ
2466 FREED_ENTRY_FOUND:
2467 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
2468 if (!dbgobj) {
2469 printf("%s: already got %d objects ?????????????????????\n",
2470 __FUNCTION__, BCM_OBJDBG_COUNT);
2471 ASSERT(0);
2472 goto EXIT;
2473 }
2474
2475 bcm_object_rm_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj);
2476 dbgobj->obj = obj;
2477 strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN);
2478 dbgobj->caller[BCM_OBJDBG_CALLER_LEN - 1] = '\0';
2479 dbgobj->line = line;
2480 dbgobj->flag = 0;
2481 if (opt == BCM_OBJDBG_ADD_PKT) {
2482 dbgobj->obj_sn = dbgobj_sn++;
2483 dbgobj->obj_state = 0;
2484 /* first 4 bytes is pkt sn */
2485 if (((unsigned long)PKTTAG(obj)) & 0x3) {
2486 printf("pkt tag address not aligned by 4: %p\n", PKTTAG(obj));
2487 }
2488 *(uint32 *)PKTTAG(obj) = dbgobj->obj_sn;
2489 }
2490 bcm_object_add_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj,
2491 BCM_OBJDBG_ADDTOTAIL);
2492
2493 dbgobj_count++;
2494 } else if (opt == BCM_OBJDBG_REMOVE) {
2495 dbgobj = dbgobj_objtail;
2496 while (dbgobj) {
2497 if (dbgobj->obj == obj) {
2498 if (dbgobj->flag) {
2499 printf("%s: rm flagged obj %p flag 0x%08x from %s(%d)\n",
2500 __FUNCTION__, obj, dbgobj->flag, caller, line);
2501 }
2502 bcm_object_rm_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj);
2503 memset(dbgobj->caller, 0x00, BCM_OBJDBG_CALLER_LEN);
2504 strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN);
2505 dbgobj->caller[BCM_OBJDBG_CALLER_LEN - 1] = '\0';
2506 dbgobj->line = line;
2507 bcm_object_add_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj,
2508 BCM_OBJDBG_ADDTOTAIL);
2509 dbgobj_count--;
2510 goto EXIT;
2511 }
2512 dbgobj = dbgobj->prior;
2513 if (dbgobj == dbgobj_objtail) {
2514 break;
2515 }
2516 }
2517
2518 dbgobj = dbgobj_freetail;
2519 while (dbgobj && dbgobj->obj) {
2520 if (dbgobj->obj == obj) {
2521 printf("%s: obj %p already freed from from %s(%d),"
2522 " try free again from %s(%d)\n",
2523 __FUNCTION__, obj, dbgobj->caller, dbgobj->line, caller,
2524 line);
2525 // ASSERT(0); /* release same obj more than one time? */
2526 goto EXIT;
2527 }
2528 dbgobj = dbgobj->prior;
2529 if (dbgobj == dbgobj_freetail) {
2530 break;
2531 }
2532 }
2533
2534 printf("%s: ################### release none-existing obj %p from "
2535 "%s(%d)\n",
2536 __FUNCTION__, obj, caller, line);
2537 // ASSERT(0); /* release same obj more than one time? */
2538 }
2539
2540 EXIT:
2541 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
2542 return;
2543 }
2544
bcm_object_trace_upd(void * obj,void * obj_new)2545 void bcm_object_trace_upd(void *obj, void *obj_new)
2546 {
2547 struct bcm_dbgobj *dbgobj;
2548 unsigned long flags;
2549
2550 BCM_REFERENCE(flags);
2551 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
2552
2553 dbgobj = dbgobj_objtail;
2554 while (dbgobj) {
2555 if (dbgobj->obj == obj) {
2556 dbgobj->obj = obj_new;
2557 if (dbgobj != dbgobj_objtail) {
2558 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail, dbgobj,
2559 BCM_OBJDBG_ADDTOTAIL);
2560 }
2561 goto EXIT;
2562 }
2563 dbgobj = dbgobj->prior;
2564 if (dbgobj == dbgobj_objtail) {
2565 break;
2566 }
2567 }
2568
2569 EXIT:
2570 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
2571 return;
2572 }
2573
bcm_object_trace_chk(void * obj,uint32 chksn,uint32 sn,const char * caller,int line)2574 void bcm_object_trace_chk(void *obj, uint32 chksn, uint32 sn,
2575 const char *caller, int line)
2576 {
2577 struct bcm_dbgobj *dbgobj;
2578 unsigned long flags;
2579
2580 BCM_REFERENCE(flags);
2581 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
2582
2583 dbgobj = dbgobj_objtail;
2584 while (dbgobj) {
2585 if ((dbgobj->obj == obj) && ((!chksn) || (dbgobj->obj_sn == sn))) {
2586 if (dbgobj != dbgobj_objtail) {
2587 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail, dbgobj,
2588 BCM_OBJDBG_ADDTOTAIL);
2589 }
2590 goto EXIT;
2591 }
2592 dbgobj = dbgobj->prior;
2593 if (dbgobj == dbgobj_objtail) {
2594 break;
2595 }
2596 }
2597
2598 dbgobj = dbgobj_freetail;
2599 while (dbgobj) {
2600 if ((dbgobj->obj == obj) && ((!chksn) || (dbgobj->obj_sn == sn))) {
2601 printf(
2602 "%s: (%s:%d) obj %p (sn %d state %d) was freed from %s(%d)\n",
2603 __FUNCTION__, caller, line, dbgobj->obj, dbgobj->obj_sn,
2604 dbgobj->obj_state, dbgobj->caller, dbgobj->line);
2605 goto EXIT;
2606 } else if (dbgobj->obj == NULL) {
2607 break;
2608 }
2609 dbgobj = dbgobj->prior;
2610 if (dbgobj == dbgobj_freetail) {
2611 break;
2612 }
2613 }
2614
2615 printf("%s: obj %p not found, check from %s(%d), chksn %s, sn %d\n",
2616 __FUNCTION__, obj, caller, line, chksn ? "yes" : "no", sn);
2617 dbgobj = dbgobj_objtail;
2618 while (dbgobj) {
2619 printf("%s: (%s:%d) obj %p sn %d was allocated from %s(%d)\n",
2620 __FUNCTION__, caller, line, dbgobj->obj, dbgobj->obj_sn,
2621 dbgobj->caller, dbgobj->line);
2622 dbgobj = dbgobj->prior;
2623 if (dbgobj == dbgobj_objtail) {
2624 break;
2625 }
2626 }
2627
2628 EXIT:
2629 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
2630 return;
2631 }
2632
bcm_object_feature_set(void * obj,uint32 type,uint32 value)2633 void bcm_object_feature_set(void *obj, uint32 type, uint32 value)
2634 {
2635 struct bcm_dbgobj *dbgobj;
2636 unsigned long flags;
2637
2638 BCM_REFERENCE(flags);
2639 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
2640
2641 dbgobj = dbgobj_objtail;
2642 while (dbgobj) {
2643 if (dbgobj->obj == obj) {
2644 if (type == BCM_OBJECT_FEATURE_FLAG) {
2645 if (value & BCM_OBJECT_FEATURE_CLEAR) {
2646 dbgobj->flag &= ~(value);
2647 } else {
2648 dbgobj->flag |= (value);
2649 }
2650 } else if (type == BCM_OBJECT_FEATURE_PKT_STATE) {
2651 dbgobj->obj_state = value;
2652 }
2653 if (dbgobj != dbgobj_objtail) {
2654 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail, dbgobj,
2655 BCM_OBJDBG_ADDTOTAIL);
2656 }
2657 goto EXIT;
2658 }
2659 dbgobj = dbgobj->prior;
2660 if (dbgobj == dbgobj_objtail) {
2661 break;
2662 }
2663 }
2664
2665 printf("%s: obj %p not found in active list\n", __FUNCTION__, obj);
2666 ASSERT(0);
2667
2668 EXIT:
2669 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
2670 return;
2671 }
2672
bcm_object_feature_get(void * obj,uint32 type,uint32 value)2673 int bcm_object_feature_get(void *obj, uint32 type, uint32 value)
2674 {
2675 int rtn = 0;
2676 struct bcm_dbgobj *dbgobj;
2677 unsigned long flags;
2678
2679 BCM_REFERENCE(flags);
2680 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
2681
2682 dbgobj = dbgobj_objtail;
2683 while (dbgobj) {
2684 if (dbgobj->obj == obj) {
2685 if (type == BCM_OBJECT_FEATURE_FLAG) {
2686 rtn = (dbgobj->flag & value) & (~BCM_OBJECT_FEATURE_CLEAR);
2687 }
2688 if (dbgobj != dbgobj_objtail) {
2689 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail, dbgobj,
2690 BCM_OBJDBG_ADDTOTAIL);
2691 }
2692 goto EXIT;
2693 }
2694 dbgobj = dbgobj->prior;
2695 if (dbgobj == dbgobj_objtail) {
2696 break;
2697 }
2698 }
2699
2700 printf("%s: obj %p not found in active list\n", __FUNCTION__, obj);
2701 ASSERT(0);
2702
2703 EXIT:
2704 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
2705 return rtn;
2706 }
2707
2708 #endif /* BCM_OBJECT_TRACE */
2709
bcm_write_tlv(int type,const void * data,int datalen,uint8 * dst)2710 uint8 *bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst)
2711 {
2712 uint8 *new_dst = dst;
2713 bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst;
2714
2715 /* dst buffer should always be valid */
2716 ASSERT(dst);
2717
2718 /* data len must be within valid range */
2719 ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE));
2720
2721 /* source data buffer pointer should be valid, unless datalen is 0
2722 * meaning no data with this TLV
2723 */
2724 ASSERT((data != NULL) || (datalen == 0));
2725
2726 /* only do work if the inputs are valid
2727 * - must have a dst to write to AND
2728 * - datalen must be within range AND
2729 * - the source data pointer must be non-NULL if datalen is non-zero
2730 * (this last condition detects datalen > 0 with a NULL data pointer)
2731 */
2732 if ((dst != NULL) &&
2733 ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) &&
2734 ((data != NULL) || (datalen == 0))) {
2735 /* write type, len fields */
2736 dst_tlv->id = (uint8)type;
2737 dst_tlv->len = (uint8)datalen;
2738
2739 /* if data is present, copy to the output buffer and update
2740 * pointer to output buffer
2741 */
2742 if (datalen > 0) {
2743 memcpy(dst_tlv->data, data, (size_t)datalen);
2744 }
2745
2746 /* update the output destination poitner to point past
2747 * the TLV written
2748 */
2749 new_dst = dst + BCM_TLV_HDR_SIZE + datalen;
2750 }
2751
2752 return (new_dst);
2753 }
2754
bcm_write_tlv_ext(uint8 type,uint8 ext,const void * data,uint8 datalen,uint8 * dst)2755 uint8 *bcm_write_tlv_ext(uint8 type, uint8 ext, const void *data, uint8 datalen,
2756 uint8 *dst)
2757 {
2758 uint8 *new_dst = dst;
2759 bcm_tlv_ext_t *dst_tlv = (bcm_tlv_ext_t *)dst;
2760
2761 /* dst buffer should always be valid */
2762 ASSERT(dst);
2763
2764 /* data len must be within valid range */
2765 ASSERT(datalen <= BCM_TLV_EXT_MAX_DATA_SIZE);
2766
2767 /* source data buffer pointer should be valid, unless datalen is 0
2768 * meaning no data with this TLV
2769 */
2770 ASSERT((data != NULL) || (datalen == 0));
2771
2772 /* only do work if the inputs are valid
2773 * - must have a dst to write to AND
2774 * - datalen must be within range AND
2775 * - the source data pointer must be non-NULL if datalen is non-zero
2776 * (this last condition detects datalen > 0 with a NULL data pointer)
2777 */
2778 if ((dst != NULL) && (datalen <= BCM_TLV_EXT_MAX_DATA_SIZE) &&
2779 ((data != NULL) || (datalen == 0))) {
2780 /* write type, len fields */
2781 dst_tlv->id = (uint8)type;
2782 dst_tlv->ext = ext;
2783 dst_tlv->len = 1 + (uint8)datalen;
2784
2785 /* if data is present, copy to the output buffer and update
2786 * pointer to output buffer
2787 */
2788 if (datalen > 0) {
2789 memcpy(dst_tlv->data, data, datalen);
2790 }
2791
2792 /* update the output destination poitner to point past
2793 * the TLV written
2794 */
2795 new_dst = dst + BCM_TLV_EXT_HDR_SIZE + datalen;
2796 }
2797
2798 return (new_dst);
2799 }
2800
bcm_write_tlv_safe(int type,const void * data,int datalen,uint8 * dst,int dst_maxlen)2801 uint8 *bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst,
2802 int dst_maxlen)
2803 {
2804 uint8 *new_dst = dst;
2805
2806 if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) {
2807 /* if len + tlv hdr len is more than destlen, don't do anything
2808 * just return the buffer untouched
2809 */
2810 if ((int)(datalen + (int)BCM_TLV_HDR_SIZE) <= dst_maxlen) {
2811 new_dst = bcm_write_tlv(type, data, datalen, dst);
2812 }
2813 }
2814
2815 return (new_dst);
2816 }
2817
bcm_copy_tlv(const void * src,uint8 * dst)2818 uint8 *bcm_copy_tlv(const void *src, uint8 *dst)
2819 {
2820 uint8 *new_dst = dst;
2821 const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
2822 uint totlen;
2823
2824 ASSERT(dst && src);
2825 if (dst && src) {
2826 totlen = BCM_TLV_HDR_SIZE + src_tlv->len;
2827 memcpy(dst, src_tlv, totlen);
2828 new_dst = dst + totlen;
2829 }
2830
2831 return (new_dst);
2832 }
2833
bcm_copy_tlv_safe(const void * src,uint8 * dst,int dst_maxlen)2834 uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen)
2835 {
2836 uint8 *new_dst = dst;
2837 const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
2838
2839 ASSERT(src);
2840 if (src) {
2841 if (bcm_valid_tlv(src_tlv, dst_maxlen)) {
2842 new_dst = bcm_copy_tlv(src, dst);
2843 }
2844 }
2845
2846 return (new_dst);
2847 }
2848
2849 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
2850 /*******************************************************************************
2851 * crc8
2852 *
2853 * Computes a crc8 over the input data using the polynomial:
2854 *
2855 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
2856 *
2857 * The caller provides the initial value (either CRC8_INIT_VALUE
2858 * or the previous returned value) to allow for processing of
2859 * discontiguous blocks of data. When generating the CRC the
2860 * caller is responsible for complementing the final return value
2861 * and inserting it into the byte stream. When checking, a final
2862 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
2863 *
2864 * Reference: Dallas Semiconductor Application Note 27
2865 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2866 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2867 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2868 *
2869 * ****************************************************************************
2870 */
2871
2872 static const uint8 crc8_table[256] = {
2873 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, 0x4A, 0xBD, 0xF3, 0x04,
2874 0x6F, 0x98, 0xD6, 0x21, 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
2875 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, 0x7F, 0x88, 0xC6, 0x31,
2876 0x5A, 0xAD, 0xE3, 0x14, 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
2877 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, 0xA1, 0x56, 0x18, 0xEF,
2878 0x84, 0x73, 0x3D, 0xCA, 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
2879 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, 0x6A, 0x9D, 0xD3, 0x24,
2880 0x4F, 0xB8, 0xF6, 0x01, 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
2881 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, 0xCB, 0x3C, 0x72, 0x85,
2882 0xEE, 0x19, 0x57, 0xA0, 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
2883 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, 0xAB, 0x5C, 0x12, 0xE5,
2884 0x8E, 0x79, 0x37, 0xC0, 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
2885 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, 0x75, 0x82, 0xCC, 0x3B,
2886 0x50, 0xA7, 0xE9, 0x1E, 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
2887 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, 0x40, 0xB7, 0xF9, 0x0E,
2888 0x65, 0x92, 0xDC, 0x2B, 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
2889 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, 0x1F, 0xE8, 0xA6, 0x51,
2890 0x3A, 0xCD, 0x83, 0x74, 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
2891 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, 0x2A, 0xDD, 0x93, 0x64,
2892 0x0F, 0xF8, 0xB6, 0x41, 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
2893 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, 0xF4, 0x03, 0x4D, 0xBA,
2894 0xD1, 0x26, 0x68, 0x9F};
2895
2896 #define CRC_INNER_LOOP(n, c, x) \
2897 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
2898
hndcrc8(const uint8 * pdata,uint nbytes,uint8 crc)2899 uint8 hndcrc8(const uint8 *pdata, /* pointer to array of data to process */
2900 uint nbytes, /* number of input data bytes to process */
2901 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
2902 )
2903 {
2904 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
2905 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
2906 */
2907 while (nbytes-- > 0) {
2908 crc = crc8_table[(crc ^ *pdata++) & 0xff];
2909 }
2910
2911 return crc;
2912 }
2913
2914 /*******************************************************************************
2915 * crc16
2916 *
2917 * Computes a crc16 over the input data using the polynomial:
2918 *
2919 * x^16 + x^12 +x^5 + 1
2920 *
2921 * The caller provides the initial value (either CRC16_INIT_VALUE
2922 * or the previous returned value) to allow for processing of
2923 * discontiguous blocks of data. When generating the CRC the
2924 * caller is responsible for complementing the final return value
2925 * and inserting it into the byte stream. When checking, a final
2926 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
2927 *
2928 * Reference: Dallas Semiconductor Application Note 27
2929 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2930 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2931 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2932 *
2933 * ****************************************************************************
2934 */
2935
2936 static const uint16 crc16_table[256] = {
2937 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 0x8C48,
2938 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, 0x1081, 0x0108,
2939 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, 0x9CC9, 0x8D40, 0xBFDB,
2940 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, 0x2102, 0x308B, 0x0210, 0x1399,
2941 0x6726, 0x76AF, 0x4434, 0x55BD, 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E,
2942 0xFAE7, 0xC87C, 0xD9F5, 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E,
2943 0x54B5, 0x453C, 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD,
2944 0xC974, 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
2945 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, 0x5285,
2946 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, 0xDECD, 0xCF44,
2947 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, 0x6306, 0x728F, 0x4014,
2948 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5,
2949 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3,
2950 0x242A, 0x16B1, 0x0738, 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862,
2951 0x9AF9, 0x8B70, 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E,
2952 0xF0B7, 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
2953 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, 0x18C1,
2954 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, 0xA50A, 0xB483,
2955 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, 0x2942, 0x38CB, 0x0A50,
2956 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, 0xB58B, 0xA402, 0x9699, 0x8710,
2957 0xF3AF, 0xE226, 0xD0BD, 0xC134, 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7,
2958 0x6E6E, 0x5CF5, 0x4D7C, 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1,
2959 0xA33A, 0xB2B3, 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72,
2960 0x3EFB, 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
2961 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, 0xE70E,
2962 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, 0x6B46, 0x7ACF,
2963 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, 0xF78F, 0xE606, 0xD49D,
2964 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, 0x7BC7, 0x6A4E, 0x58D5, 0x495C,
2965 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78};
2966
2967 uint16
hndcrc16(const uint8 * pdata,uint nbytes,uint16 crc)2968 hndcrc16(const uint8 *pdata, /* pointer to array of data to process */
2969 uint nbytes, /* number of input data bytes to process */
2970 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
2971 )
2972 {
2973 while (nbytes-- > 0) {
2974 CRC_INNER_LOOP(16, crc, *pdata++);
2975 }
2976 return crc;
2977 }
2978
2979 static const uint32 crc32_table[256] = {
2980 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
2981 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
2982 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
2983 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
2984 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
2985 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
2986 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
2987 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
2988 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
2989 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
2990 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
2991 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
2992 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
2993 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
2994 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
2995 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
2996 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
2997 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
2998 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
2999 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
3000 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
3001 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
3002 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
3003 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
3004 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
3005 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
3006 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
3007 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
3008 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
3009 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
3010 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
3011 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
3012 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
3013 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
3014 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
3015 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
3016 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
3017 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
3018 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
3019 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
3020 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
3021 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
3022 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};
3023
3024 /*
3025 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
3026 * accumulating over multiple pieces.
3027 */
hndcrc32(const uint8 * pdata,uint nbytes,uint32 crc)3028 uint32 hndcrc32(const uint8 *pdata, uint nbytes, uint32 crc)
3029 {
3030 const uint8 *pend;
3031 pend = pdata + nbytes;
3032 while (pdata < pend) {
3033 CRC_INNER_LOOP(32, crc, *pdata++);
3034 }
3035
3036 return crc;
3037 }
3038
3039 #ifdef notdef
3040 #define CLEN 1499 /* CRC Length */
3041 #define CBUFSIZ (CLEN + 4)
3042 #define CNBUFS 5 /* # of bufs */
3043
testcrc32(void)3044 void testcrc32(void)
3045 {
3046 uint j, k, l;
3047 uint8 *buf;
3048 uint len[CNBUFS];
3049 uint32 crcr;
3050 uint32 crc32tv[CNBUFS] = {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20,
3051 0x00343110};
3052
3053 ASSERT((buf = MALLOC(CBUFSIZ * CNBUFS)) != NULL);
3054
3055 /* step through all possible alignments */
3056 for (l = 0; l <= 0x4; l++) {
3057 for (j = 0; j < CNBUFS; j++) {
3058 len[j] = CLEN;
3059 for (k = 0; k < len[j]; k++) {
3060 *(buf + j * CBUFSIZ + (k + l)) = (j + k) & 0xff;
3061 }
3062 }
3063
3064 for (j = 0; j < CNBUFS; j++) {
3065 crcr = crc32(buf + j * CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
3066 ASSERT(crcr == crc32tv[j]);
3067 }
3068 }
3069
3070 MFREE(buf, CBUFSIZ * CNBUFS);
3071 return;
3072 }
3073 #endif /* notdef */
3074
3075 /*
3076 * Advance from the current 1-byte tag/1-byte length/variable-length value
3077 * triple, to the next, returning a pointer to the next.
3078 * If the current or next TLV is invalid (does not fit in given buffer length),
3079 * NULL is returned.
3080 * *buflen is not modified if the TLV elt parameter is invalid, or is
3081 * decremented by the TLV parameter's length if it is valid.
3082 */
bcm_next_tlv(const bcm_tlv_t * elt,uint * buflen)3083 bcm_tlv_t *bcm_next_tlv(const bcm_tlv_t *elt, uint *buflen)
3084 {
3085 uint len;
3086
3087 /* validate current elt */
3088 if (!bcm_valid_tlv(elt, *buflen)) {
3089 return NULL;
3090 }
3091
3092 /* advance to next elt */
3093 len = elt->len;
3094 elt = (const bcm_tlv_t *)(elt->data + len);
3095 *buflen -= (TLV_HDR_LEN + len);
3096
3097 /* validate next elt */
3098 if (!bcm_valid_tlv(elt, *buflen)) {
3099 return NULL;
3100 }
3101
3102 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3103 return (bcm_tlv_t *)(elt);
3104 GCC_DIAGNOSTIC_POP();
3105 }
3106
3107 /**
3108 * Advance a const tlv buffer pointer and length up to the given tlv element
3109 * pointer 'elt'. The function checks that elt is a valid tlv; the elt pointer
3110 * and data are all in the range of the buffer/length.
3111 *
3112 * @param elt pointer to a valid bcm_tlv_t in the buffer
3113 * @param buffer pointer to a tlv buffer
3114 * @param buflen length of the buffer in bytes
3115 *
3116 * On return, if elt is not a tlv in the buffer bounds, the *buffer parameter
3117 * will be set to NULL and *buflen parameter will be set to zero. Otherwise,
3118 * *buffer will point to elt, and *buflen will have been adjusted by the the
3119 * difference between *buffer and elt.
3120 */
bcm_tlv_buffer_advance_to(const bcm_tlv_t * elt,const uint8 ** buffer,uint * buflen)3121 void bcm_tlv_buffer_advance_to(const bcm_tlv_t *elt, const uint8 **buffer,
3122 uint *buflen)
3123 {
3124 uint new_buflen;
3125 const uint8 *new_buffer;
3126
3127 new_buffer = (const uint8 *)elt;
3128
3129 /* make sure the input buffer pointer is non-null, that (buffer + buflen)
3130 * does not wrap, and that the elt pointer is in the range of [buffer,
3131 * buffer + buflen]
3132 */
3133 if ((*buffer != NULL) &&
3134 ((uintptr)*buffer < ((uintptr)*buffer + *buflen)) &&
3135 (new_buffer >= *buffer) && (new_buffer < (*buffer + *buflen))) {
3136 /* delta between buffer and new_buffer is <= *buflen, so truncating cast
3137 * to uint from ptrdiff is ok
3138 */
3139 uint delta = (uint)(new_buffer - *buffer);
3140
3141 /* New buffer length is old len minus the delta from the buffer start to
3142 * elt. The check just above guarantees that the subtractions does not
3143 * underflow.
3144 */
3145 new_buflen = *buflen - delta;
3146
3147 /* validate current elt */
3148 if (bcm_valid_tlv(elt, new_buflen)) {
3149 /* All good, so update the input/output parameters */
3150 *buffer = new_buffer;
3151 *buflen = new_buflen;
3152 return;
3153 }
3154 }
3155
3156 /* something did not check out, clear out the buffer info */
3157 *buffer = NULL;
3158 *buflen = 0;
3159
3160 return;
3161 }
3162
3163 /**
3164 * Advance a const tlv buffer pointer and length past the given tlv element
3165 * pointer 'elt'. The function checks that elt is a valid tlv; the elt pointer
3166 * and data are all in the range of the buffer/length. The function also checks
3167 * that the remaining buffer starts with a valid tlv.
3168 *
3169 * @param elt pointer to a valid bcm_tlv_t in the buffer
3170 * @param buffer pointer to a tlv buffer
3171 * @param buflen length of the buffer in bytes
3172 *
3173 * On return, if elt is not a tlv in the buffer bounds, or the remaining buffer
3174 * following the elt does not begin with a tlv in the buffer bounds, the *buffer
3175 * parameter will be set to NULL and *buflen parameter will be set to zero.
3176 * Otherwise, *buffer will point to the first byte past elt, and *buflen will
3177 * have the remaining buffer length.
3178 */
bcm_tlv_buffer_advance_past(const bcm_tlv_t * elt,const uint8 ** buffer,uint * buflen)3179 void bcm_tlv_buffer_advance_past(const bcm_tlv_t *elt, const uint8 **buffer,
3180 uint *buflen)
3181 {
3182 /* Start by advancing the buffer up to the given elt */
3183 bcm_tlv_buffer_advance_to(elt, buffer, buflen);
3184
3185 /* if that did not work, bail out */
3186 if (*buflen == 0) {
3187 return;
3188 }
3189
3190 #if defined(__COVERITY__)
3191 /* The elt has been verified by bcm_tlv_buffer_advance_to() to be a valid
3192 * element, so its elt->len is in the bounds of the buffer. The following
3193 * check prevents Coverity from flagging the (elt->data + elt->len)
3194 * statement below as using a tainted elt->len to index into array
3195 * 'elt->data'.
3196 */
3197 if (elt->len > *buflen) {
3198 return;
3199 }
3200 #endif /* __COVERITY__ */
3201
3202 /* We know we are advanced up to a good tlv.
3203 * Now just advance to the following tlv.
3204 */
3205 elt = (const bcm_tlv_t *)(elt->data + elt->len);
3206
3207 bcm_tlv_buffer_advance_to(elt, buffer, buflen);
3208
3209 return;
3210 }
3211
3212 /*
3213 * Traverse a string of 1-byte tag/1-byte length/variable-length value
3214 * triples, returning a pointer to the substring whose first element
3215 * matches tag
3216 */
bcm_parse_tlvs(const void * buf,uint buflen,uint key)3217 bcm_tlv_t *bcm_parse_tlvs(const void *buf, uint buflen, uint key)
3218 {
3219 const bcm_tlv_t *elt;
3220 int totlen;
3221
3222 if ((elt = (const bcm_tlv_t *)buf) == NULL) {
3223 return NULL;
3224 }
3225 totlen = (int)buflen;
3226
3227 /* find tagged parameter */
3228 while (totlen >= TLV_HDR_LEN) {
3229 uint len = elt->len;
3230
3231 /* validate remaining totlen */
3232 if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
3233 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3234 return (bcm_tlv_t *)(elt);
3235 GCC_DIAGNOSTIC_POP();
3236 }
3237
3238 elt = (const bcm_tlv_t *)((const uint8 *)elt + (len + TLV_HDR_LEN));
3239 totlen -= (len + TLV_HDR_LEN);
3240 }
3241
3242 return NULL;
3243 }
3244
bcm_parse_tlvs_dot11(const void * buf,int buflen,uint key,bool id_ext)3245 bcm_tlv_t *bcm_parse_tlvs_dot11(const void *buf, int buflen, uint key,
3246 bool id_ext)
3247 {
3248 bcm_tlv_t *elt;
3249 int totlen;
3250
3251 /*
3252 ideally, we don't want to do that, but returning a const pointer
3253 from these parse function spreads casting everywhere in the code
3254 */
3255 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3256 elt = (bcm_tlv_t *)buf;
3257 GCC_DIAGNOSTIC_POP();
3258
3259 totlen = buflen;
3260
3261 /* find tagged parameter */
3262 while (totlen >= TLV_HDR_LEN) {
3263 int len = elt->len;
3264
3265 do {
3266 /* validate remaining totlen */
3267 if (totlen < (int)(len + TLV_HDR_LEN)) {
3268 break;
3269 }
3270
3271 if (id_ext) {
3272 if (!DOT11_MNG_IE_ID_EXT_MATCH(elt, key)) {
3273 break;
3274 }
3275 } else if (elt->id != key) {
3276 break;
3277 }
3278
3279 return (bcm_tlv_t *)(elt); /* a match */
3280 } while (0);
3281
3282 elt = (bcm_tlv_t *)((uint8 *)elt + (len + TLV_HDR_LEN));
3283 totlen -= (len + TLV_HDR_LEN);
3284 }
3285
3286 return NULL;
3287 }
3288
3289 /*
3290 * Traverse a string of 1-byte tag/1-byte length/variable-length value
3291 * triples, returning a pointer to the substring whose first element
3292 * matches tag
3293 * return NULL if not found or length field < min_varlen
3294 */
bcm_parse_tlvs_min_bodylen(const void * buf,int buflen,uint key,int min_bodylen)3295 bcm_tlv_t *bcm_parse_tlvs_min_bodylen(const void *buf, int buflen, uint key,
3296 int min_bodylen)
3297 {
3298 bcm_tlv_t *ret;
3299 ret = bcm_parse_tlvs(buf, (uint)buflen, key);
3300 if (ret == NULL || ret->len < min_bodylen) {
3301 return NULL;
3302 }
3303 return ret;
3304 }
3305
3306 /*
3307 * Traverse a string of 1-byte tag/1-byte length/variable-length value
3308 * triples, returning a pointer to the substring whose first element
3309 * matches tag. Stop parsing when we see an element whose ID is greater
3310 * than the target key.
3311 */
bcm_parse_ordered_tlvs(const void * buf,int buflen,uint key)3312 const bcm_tlv_t *bcm_parse_ordered_tlvs(const void *buf, int buflen, uint key)
3313 {
3314 const bcm_tlv_t *elt;
3315 int totlen;
3316
3317 elt = (const bcm_tlv_t *)buf;
3318 totlen = buflen;
3319
3320 /* find tagged parameter */
3321 while (totlen >= TLV_HDR_LEN) {
3322 uint id = elt->id;
3323 int len = elt->len;
3324
3325 /* Punt if we start seeing IDs > than target key */
3326 if (id > key) {
3327 return (NULL);
3328 }
3329
3330 /* validate remaining totlen */
3331 if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
3332 return (elt);
3333 }
3334
3335 elt = (const bcm_tlv_t *)((const uint8 *)elt + (len + TLV_HDR_LEN));
3336 totlen -= (len + TLV_HDR_LEN);
3337 }
3338 return NULL;
3339 }
3340 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
3341
3342 #if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
3343 defined(DHD_DEBUG)
bcm_format_field(const bcm_bit_desc_ex_t * bd,uint32 flags,char * buf,int len)3344 int bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char *buf,
3345 int len)
3346 {
3347 int i, slen = 0;
3348 uint32 bit, mask;
3349 const char *name;
3350 mask = bd->mask;
3351 if (len < 0x2 || !buf) {
3352 return 0;
3353 }
3354
3355 buf[0] = '\0';
3356
3357 for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) {
3358 bit = bd->bitfield[i].bit;
3359 if ((flags & mask) == bit) {
3360 if (len > (int)strlen(name)) {
3361 slen = (int)strlen(name);
3362 strncpy(buf, name, (size_t)len);
3363 }
3364 break;
3365 }
3366 }
3367 return slen;
3368 }
3369
bcm_format_flags(const bcm_bit_desc_t * bd,uint32 flags,char * buf,int len)3370 int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char *buf, int len)
3371 {
3372 int i;
3373 char *p = buf;
3374 char hexstr[16];
3375 int slen = 0, nlen = 0;
3376 uint32 bit;
3377 const char *name;
3378
3379 if (len < 0x2 || !buf) {
3380 return 0;
3381 }
3382
3383 buf[0] = '\0';
3384
3385 for (i = 0; flags != 0; i++) {
3386 bit = bd[i].bit;
3387 name = bd[i].name;
3388 if (bit == 0 && flags != 0) {
3389 /* print any unnamed bits */
3390 snprintf(hexstr, 0x10, "0x%X", flags);
3391 name = hexstr;
3392 flags = 0; /* exit loop */
3393 } else if ((flags & bit) == 0) {
3394 continue;
3395 }
3396 flags &= ~bit;
3397 nlen = (int)strlen(name);
3398 slen += nlen;
3399 /* count btwn flag space */
3400 if (flags != 0) {
3401 slen += 1;
3402 }
3403 /* need NULL char as well */
3404 if (len <= slen) {
3405 break;
3406 }
3407 /* copy NULL char but don't count it */
3408 strncpy(p, name, (size_t)len);
3409 p += nlen;
3410 /* copy btwn flag space and NULL char */
3411 if (flags != 0) {
3412 p += snprintf(p, 0x2, " ");
3413 }
3414 }
3415
3416 /* indicate the str was too short */
3417 if (flags != 0) {
3418 p += snprintf(p, 0x2, ">");
3419 }
3420
3421 return (int)(p - buf);
3422 }
3423
3424 /* print out whcih bits in octet array 'addr' are set. bcm_bit_desc_t:bit is a
3425 * bit offset. */
bcm_format_octets(const bcm_bit_desc_t * bd,uint bdsz,const uint8 * addr,uint size,char * buf,int len)3426 int bcm_format_octets(const bcm_bit_desc_t *bd, uint bdsz, const uint8 *addr,
3427 uint size, char *buf, int len)
3428 {
3429 uint i;
3430 char *p = buf;
3431 int slen = 0, nlen = 0;
3432 uint32 bit;
3433 const char *name;
3434 bool more = FALSE;
3435
3436 BCM_REFERENCE(size);
3437
3438 if (len < 0x2 || !buf) {
3439 return 0;
3440 }
3441
3442 buf[0] = '\0';
3443
3444 for (i = 0; i < bdsz; i++) {
3445 bit = bd[i].bit;
3446 name = bd[i].name;
3447 CLANG_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3448 if (isset(addr, bit)) {
3449 CLANG_DIAGNOSTIC_POP();
3450 nlen = (int)strlen(name);
3451 slen += nlen;
3452 /* need SPACE - for simplicity */
3453 slen += 1;
3454 /* need NULL as well */
3455 if (len < slen + 1) {
3456 more = TRUE;
3457 break;
3458 }
3459 memcpy(p, name, (size_t)nlen);
3460 p += nlen;
3461 p[0] = ' ';
3462 p += 1;
3463 p[0] = '\0';
3464 }
3465 }
3466
3467 if (more) {
3468 p[0] = '>';
3469 p += 1;
3470 p[0] = '\0';
3471 }
3472
3473 return (int)(p - buf);
3474 }
3475 #endif // endif
3476
3477 /* print bytes formatted as hex to a string. return the resulting string length
3478 */
bcm_format_hex(char * str,const void * bytes,int len)3479 int bcm_format_hex(char *str, const void *bytes, int len)
3480 {
3481 int i;
3482 char *p = str;
3483 const uint8 *src = (const uint8 *)bytes;
3484
3485 for (i = 0; i < len; i++) {
3486 p += snprintf(p, 0x3, "%02X", *src);
3487 src++;
3488 }
3489 return (int)(p - str);
3490 }
3491
3492 /* pretty hex print a contiguous buffer */
prhex(const char * msg,const uchar * buf,uint nbytes)3493 void prhex(const char *msg, const uchar *buf, uint nbytes)
3494 {
3495 char line[128], *p;
3496 int len = sizeof(line);
3497 int nchar;
3498 uint i;
3499
3500 if (msg && (msg[0] != '\0')) {
3501 printf("%s:\n", msg);
3502 }
3503
3504 p = line;
3505 for (i = 0; i < nbytes; i++) {
3506 if (i % 0x10 == 0) {
3507 nchar = snprintf(p, (size_t)len, " %04x: ", i); /* line prefix */
3508 p += nchar;
3509 len -= nchar;
3510 }
3511 if (len > 0) {
3512 nchar = snprintf(p, (size_t)len, "%02x ", buf[i]);
3513 p += nchar;
3514 len -= nchar;
3515 }
3516
3517 if (i % 0x10 == 0xF) {
3518 printf("%s\n", line); /* flush line */
3519 p = line;
3520 len = sizeof(line);
3521 }
3522 }
3523
3524 /* flush last partial line */
3525 if (p != line) {
3526 printf("%s\n", line);
3527 }
3528 }
3529
3530 static const char *crypto_algo_names[] = {
3531 "NONE", "WEP1", "TKIP", "WEP128", "AES_CCM",
3532 "AES_OCB_MSDU", "AES_OCB_MPDU",
3533 #ifdef BCMCCX
3534 "CKIP", "CKIP_MMH", "WEP_MMH", "NALG",
3535 #else
3536 "NALG", "UNDEF", "UNDEF", "UNDEF",
3537 #endif /* BCMCCX */
3538 #ifdef BCMWAPI_WAI
3539 "WAPI",
3540 #else
3541 "UNDEF",
3542 #endif // endif
3543 "PMK", "BIP", "AES_GCM", "AES_CCM256", "AES_GCM256",
3544 "BIP_CMAC256", "BIP_GMAC", "BIP_GMAC256", "UNDEF"};
3545
bcm_crypto_algo_name(uint algo)3546 const char *bcm_crypto_algo_name(uint algo)
3547 {
3548 return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo]
3549 : "ERR";
3550 }
3551
bcm_chipname(uint chipid,char * buf,uint len)3552 char *bcm_chipname(uint chipid, char *buf, uint len)
3553 {
3554 const char *fmt;
3555
3556 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
3557 /*
3558 * The following call to snprintf generates a compiler warning
3559 * due to -Wformat-nonliteral. However, the format string is coming
3560 * from internal callers rather than external data input, and is a
3561 * useful debugging tool serving a variety of diagnostics. Rather
3562 * than expand code size by replicating multiple functions with different
3563 * argument lists, or disabling the warning globally, let's consider
3564 * if we can just disable the warning for this one instance.
3565 */
3566 CLANG_DIAGNOSTIC_PUSH_SUPPRESS_FORMAT()
3567 snprintf(buf, len, fmt, chipid);
3568 CLANG_DIAGNOSTIC_POP()
3569 return buf;
3570 }
3571
3572 /* Produce a human-readable string for boardrev */
bcm_brev_str(uint32 brev,char * buf)3573 char *bcm_brev_str(uint32 brev, char *buf)
3574 {
3575 if (brev < 0x100) {
3576 snprintf(buf, 0x8, "%d.%d", (brev & 0xf0) >> 0x4, brev & 0xf);
3577 } else {
3578 snprintf(buf, 0x8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A',
3579 brev & 0xfff);
3580 }
3581
3582 return (buf);
3583 }
3584
3585 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
3586
3587 /* dump large strings to console */
printbig(char * buf)3588 void printbig(char *buf)
3589 {
3590 uint len, max_len;
3591 char c;
3592
3593 len = (uint)strlen(buf);
3594
3595 max_len = BUFSIZE_TODUMP_ATONCE;
3596
3597 while (len > max_len) {
3598 c = buf[max_len];
3599 buf[max_len] = '\0';
3600 printf("%s", buf);
3601 buf[max_len] = c;
3602
3603 buf += max_len;
3604 len -= max_len;
3605 }
3606 /* print the remaining string */
3607 printf("%s\n", buf);
3608 return;
3609 }
3610
3611 /* routine to dump fields in a fileddesc structure */
bcmdumpfields(bcmutl_rdreg_rtn read_rtn,void * arg0,uint arg1,struct fielddesc * fielddesc_array,char * buf,uint32 bufsize)3612 uint bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1,
3613 struct fielddesc *fielddesc_array, char *buf, uint32 bufsize)
3614 {
3615 uint filled_len;
3616 int len;
3617 struct fielddesc *cur_ptr;
3618
3619 filled_len = 0;
3620 cur_ptr = fielddesc_array;
3621
3622 while (bufsize > 1) {
3623 if (cur_ptr->nameandfmt == NULL) {
3624 break;
3625 }
3626
3627 /*
3628 * The following call to snprintf generates a compiler warning
3629 * due to -Wformat-nonliteral. However, the format string is coming
3630 * from internal callers rather than external data input, and is a
3631 * useful debugging tool serving a variety of diagnostics. Rather
3632 * than expand code size by replicating multiple functions with
3633 * different argument lists, or disabling the warning globally, let's
3634 * consider if we can just disable the warning for this one instance.
3635 */
3636 CLANG_DIAGNOSTIC_PUSH_SUPPRESS_FORMAT()
3637 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
3638 read_rtn(arg0, arg1, cur_ptr->offset));
3639 CLANG_DIAGNOSTIC_POP()
3640 /* check for snprintf overflow or error */
3641 if (len < 0 || (uint32)len >= bufsize) {
3642 len = (int)(bufsize - 1);
3643 }
3644 buf += len;
3645 bufsize -= (uint32)len;
3646 filled_len += (uint32)len;
3647 cur_ptr++;
3648 }
3649 return filled_len;
3650 }
3651
bcm_mkiovar(const char * name,const char * data,uint datalen,char * buf,uint buflen)3652 uint bcm_mkiovar(const char *name, const char *data, uint datalen, char *buf,
3653 uint buflen)
3654 {
3655 uint len;
3656
3657 len = (uint)strlen(name) + 1;
3658 if ((len + datalen) > buflen) {
3659 return 0;
3660 }
3661
3662 strncpy(buf, name, buflen);
3663
3664 /* append data onto the end of the name string */
3665 if (data && datalen != 0) {
3666 memcpy(&buf[len], data, datalen);
3667 len += datalen;
3668 }
3669
3670 return len;
3671 }
3672
3673 /* Quarter dBm units to mW
3674 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
3675 * Table is offset so the last entry is largest mW value that fits in
3676 * a uint16.
3677 */
3678
3679 #define QDBM_OFFSET 153 /* Offset for first entry */
3680 #define QDBM_TABLE_LEN 40 /* Table size */
3681
3682 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
3683 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
3684 */
3685 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
3686
3687 /* Largest mW value that will round down to the last table entry,
3688 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
3689 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET +
3690 * QDBM_TABLE_LEN) ) / 2.
3691 */
3692 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
3693
3694 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
3695 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
3696 6683, /* 153: */
3697 7079,
3698 7499,
3699 7943,
3700 8414,
3701 8913,
3702 9441,
3703 10000,
3704 10593, /* 161: */
3705 11220,
3706 11885,
3707 12589,
3708 13335,
3709 14125,
3710 14962,
3711 15849,
3712 16788, /* 169: */
3713 17783,
3714 18836,
3715 19953,
3716 21135,
3717 22387,
3718 23714,
3719 25119,
3720 26607, /* 177: */
3721 28184,
3722 29854,
3723 31623,
3724 33497,
3725 35481,
3726 37584,
3727 39811,
3728 42170, /* 185: */
3729 44668,
3730 47315,
3731 50119,
3732 53088,
3733 56234,
3734 59566,
3735 63096};
3736
bcm_qdbm_to_mw(uint8 qdbm)3737 uint16 bcm_qdbm_to_mw(uint8 qdbm)
3738 {
3739 uint factor = 1;
3740 int idx = qdbm - QDBM_OFFSET;
3741
3742 if (idx >= QDBM_TABLE_LEN) {
3743 /* clamp to max uint16 mW value */
3744 return 0xFFFF;
3745 }
3746
3747 /* scale the qdBm index up to the range of the table 0-40
3748 * where an offset of 40 qdBm equals a factor of 10 mW.
3749 */
3750 while (idx < 0) {
3751 idx += 0x28;
3752 factor *= 0xA;
3753 }
3754
3755 /* return the mW value scaled down to the correct factor of 10,
3756 * adding in factor/2 to get proper rounding.
3757 */
3758 return (uint16)((nqdBm_to_mW_map[idx] + factor / 0x2) / factor);
3759 }
3760
bcm_mw_to_qdbm(uint16 mw)3761 uint8 bcm_mw_to_qdbm(uint16 mw)
3762 {
3763 uint8 qdbm;
3764 int offset;
3765 uint mw_uint = mw;
3766 uint boundary;
3767
3768 /* handle boundary case */
3769 if (mw_uint <= 1) {
3770 return 0;
3771 }
3772
3773 offset = QDBM_OFFSET;
3774
3775 /* move mw into the range of the table */
3776 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
3777 mw_uint *= 0xA;
3778 offset -= 0x28;
3779 }
3780
3781 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
3782 boundary = nqdBm_to_mW_map[qdbm] +
3783 (nqdBm_to_mW_map[qdbm + 1] - nqdBm_to_mW_map[qdbm]) / 0x2;
3784 if (mw_uint < boundary) {
3785 break;
3786 }
3787 }
3788
3789 qdbm += (uint8)offset;
3790
3791 return (qdbm);
3792 }
3793
bcm_bitcount(uint8 * bitmap,uint length)3794 uint bcm_bitcount(uint8 *bitmap, uint length)
3795 {
3796 uint bitcount = 0, i;
3797 uint8 tmp;
3798 for (i = 0; i < length; i++) {
3799 tmp = bitmap[i];
3800 while (tmp) {
3801 bitcount++;
3802 tmp &= (tmp - 1);
3803 }
3804 }
3805 return bitcount;
3806 }
3807
dump_nvram(char * varbuf,int column,unsigned int n,unsigned int len)3808 void dump_nvram(char *varbuf, int column, unsigned int n, unsigned int len)
3809 {
3810 unsigned int m;
3811 char vars[128];
3812
3813 if (((n == 0) && (varbuf[0] == '#')) ||
3814 ((column == 0) && (android_msg_level & ANDROID_INFO_LEVEL))) {
3815 memset(vars, 0x00, sizeof(vars));
3816 for (m = n; m < len && (m - n) < (sizeof(vars) - 1); m++) {
3817 if (varbuf[m] == '\n') {
3818 break;
3819 }
3820 vars[m - n] = varbuf[m];
3821 }
3822 printf("%s\n", vars);
3823 }
3824 }
3825
3826 /*
3827 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and
3828 * ending in a NUL. also accepts nvram files which are already in the format of
3829 * <var1>=<value>\0\<var2>=<value2>\0 Removes carriage returns, empty lines,
3830 * comment lines, and converts newlines to NULs. Shortens buffer as needed and
3831 * pads with NULs. End of buffer is marked by two NULs.
3832 */
3833
process_nvram_vars(char * varbuf,unsigned int len)3834 unsigned int process_nvram_vars(char *varbuf, unsigned int len)
3835 {
3836 char *dp;
3837 bool findNewline;
3838 int column;
3839 unsigned int buf_len, n;
3840 unsigned int pad = 0;
3841
3842 dp = varbuf;
3843
3844 findNewline = FALSE;
3845 column = 0;
3846
3847 dump_nvram(varbuf, 0, 0, len);
3848 for (n = 0; n < len; n++) {
3849 if (varbuf[n] == '\r') {
3850 continue;
3851 }
3852 if (findNewline && varbuf[n] != '\n') {
3853 continue;
3854 }
3855 findNewline = FALSE;
3856 if (varbuf[n] == '#') {
3857 findNewline = TRUE;
3858 continue;
3859 }
3860 if (varbuf[n] == '\n') {
3861 if (column == 0) {
3862 continue;
3863 }
3864 *dp++ = 0;
3865 column = 0;
3866 continue;
3867 }
3868 dump_nvram(varbuf, column, n, len);
3869 *dp++ = varbuf[n];
3870 column++;
3871 }
3872 buf_len = (unsigned int)(dp - varbuf);
3873 if (buf_len % 0x4) {
3874 pad = 0x4 - buf_len % 0x4;
3875 if (pad && (buf_len + pad <= len)) {
3876 buf_len += pad;
3877 }
3878 }
3879
3880 while (dp < varbuf + n) {
3881 *dp++ = 0;
3882 }
3883
3884 return buf_len;
3885 }
3886
3887 #ifndef setbit /* As in the header file */
3888 #ifdef BCMUTILS_BIT_MACROS_USE_FUNCS
3889 /* Set bit in byte array. */
setbit(void * array,uint bit)3890 void setbit(void *array, uint bit)
3891 {
3892 ((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY);
3893 }
3894
3895 /* Clear bit in byte array. */
clrbit(void * array,uint bit)3896 void clrbit(void *array, uint bit)
3897 {
3898 ((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY));
3899 }
3900
3901 /* Test if bit is set in byte array. */
isset(const void * array,uint bit)3902 bool isset(const void *array, uint bit)
3903 {
3904 return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY)));
3905 }
3906
3907 /* Test if bit is clear in byte array. */
isclr(const void * array,uint bit)3908 bool isclr(const void *array, uint bit)
3909 {
3910 return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0);
3911 }
3912 #endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */
3913 #endif /* setbit */
3914
set_bitrange(void * array,uint start,uint end,uint maxbit)3915 void set_bitrange(void *array, uint start, uint end, uint maxbit)
3916 {
3917 uint startbyte = start / NBBY;
3918 uint endbyte = end / NBBY;
3919 uint i, startbytelastbit, endbytestartbit;
3920
3921 if (end >= start) {
3922 if (endbyte - startbyte > 1) {
3923 startbytelastbit = (startbyte + 1) * NBBY - 1;
3924 endbytestartbit = endbyte * NBBY;
3925 for (i = startbyte + 1; i < endbyte; i++) {
3926 ((uint8 *)array)[i] = 0xFF;
3927 }
3928 for (i = start; i <= startbytelastbit; i++) {
3929 setbit(array, i);
3930 }
3931 for (i = endbytestartbit; i <= end; i++) {
3932 setbit(array, i);
3933 }
3934 } else {
3935 for (i = start; i <= end; i++) {
3936 setbit(array, i);
3937 }
3938 }
3939 } else {
3940 set_bitrange(array, start, maxbit, maxbit);
3941 set_bitrange(array, 0, end, maxbit);
3942 }
3943 }
3944
bcm_bitprint32(const uint32 u32arg)3945 void bcm_bitprint32(const uint32 u32arg)
3946 {
3947 int i;
3948 for (i = NBITS(uint32) - 1; i >= 0; i--) {
3949 if (isbitset(u32arg, i)) {
3950 printf("1");
3951 } else {
3952 printf("0");
3953 }
3954
3955 if ((i % NBBY) == 0) {
3956 printf(" ");
3957 }
3958 }
3959 printf("\n");
3960 }
3961
3962 /* calculate checksum for ip header, tcp / udp header / data */
bcm_ip_cksum(uint8 * buf,uint32 len,uint32 sum)3963 uint16 bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum)
3964 {
3965 while (len > 1) {
3966 sum += (uint32)((buf[0] << 0x8) | buf[1]);
3967 buf += 0x2;
3968 len -= 0x2;
3969 }
3970
3971 if (len > 0) {
3972 sum += (uint32)((*buf) << 0x8);
3973 }
3974
3975 while (sum >> 0x10) {
3976 sum = (sum & 0xffff) + (sum >> 0x10);
3977 }
3978
3979 return ((uint16)~sum);
3980 }
3981
BCMRAMFN(valid_bcmerror)3982 int BCMRAMFN(valid_bcmerror)(int e)
3983 {
3984 return ((e <= 0) && (e >= BCME_LAST));
3985 }
3986
3987 #ifdef DEBUG_COUNTER
3988 #if (OSL_SYSUPTIME_SUPPORT == TRUE)
counter_printlog(counter_tbl_t * ctr_tbl)3989 void counter_printlog(counter_tbl_t *ctr_tbl)
3990 {
3991 uint32 now;
3992
3993 if (!ctr_tbl->enabled) {
3994 return;
3995 }
3996
3997 now = OSL_SYSUPTIME();
3998 if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) {
3999 uint8 i = 0;
4000 printf("counter_print(%s %d):", ctr_tbl->name,
4001 now - ctr_tbl->prev_log_print);
4002
4003 for (i = 0; i < ctr_tbl->needed_cnt; i++) {
4004 printf(" %u", ctr_tbl->cnt[i]);
4005 }
4006 printf("\n");
4007
4008 ctr_tbl->prev_log_print = now;
4009 bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint));
4010 }
4011 }
4012 #else
4013 /* OSL_SYSUPTIME is not supported so no way to get time */
4014 #define counter_printlog(a) \
4015 do { \
4016 } while (0)
4017 #endif /* OSL_SYSUPTIME_SUPPORT == TRUE */
4018 #endif /* DEBUG_COUNTER */
4019
4020 /* calculate partial checksum */
ip_cksum_partial(uint32 sum,uint8 * val8,uint32 count)4021 static uint32 ip_cksum_partial(uint32 sum, uint8 *val8, uint32 count)
4022 {
4023 uint32 i;
4024 uint16 *val16 = (uint16 *)val8;
4025
4026 ASSERT(val8 != NULL);
4027 /* partial chksum calculated on 16-bit values */
4028 ASSERT((count % 0x2) == 0);
4029
4030 count /= 0x2;
4031
4032 for (i = 0; i < count; i++) {
4033 sum += *val16++;
4034 }
4035 return sum;
4036 }
4037
4038 /* calculate IP checksum */
ip_cksum(uint32 sum,uint8 * val8,uint32 count)4039 static uint16 ip_cksum(uint32 sum, uint8 *val8, uint32 count)
4040 {
4041 uint16 *val16 = (uint16 *)val8;
4042
4043 ASSERT(val8 != NULL);
4044
4045 while (count > 1) {
4046 sum += *val16++;
4047 count -= 0x2;
4048 }
4049 /* add left-over byte, if any */
4050 if (count > 0) {
4051 sum += (*(uint8 *)val16);
4052 }
4053
4054 /* fold 32-bit sum to 16 bits */
4055 sum = (sum >> 0x10) + (sum & 0xffff);
4056 sum += (sum >> 0x10);
4057 return ((uint16)~sum);
4058 }
4059
4060 /* calculate IPv4 header checksum
4061 * - input ip points to IP header in network order
4062 * - output cksum is in network order
4063 */
ipv4_hdr_cksum(uint8 * ip,int ip_len)4064 uint16 ipv4_hdr_cksum(uint8 *ip, int ip_len)
4065 {
4066 uint32 sum = 0;
4067 uint8 *ptr = ip;
4068
4069 ASSERT(ip != NULL);
4070 ASSERT(ip_len >= IPV4_MIN_HEADER_LEN);
4071
4072 /* partial cksum skipping the hdr_chksum field */
4073 sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct ipv4_hdr, hdr_chksum));
4074 ptr += OFFSETOF(struct ipv4_hdr, hdr_chksum) + 2;
4075
4076 /* return calculated chksum */
4077 return ip_cksum(sum, ptr,
4078 (uint32)((uint)ip_len - OFFSETOF(struct ipv4_hdr, src_ip)));
4079 }
4080
4081 /* calculate TCP header checksum using partial sum */
tcp_hdr_chksum(uint32 sum,uint8 * tcp_hdr,uint16 tcp_len)4082 static uint16 tcp_hdr_chksum(uint32 sum, uint8 *tcp_hdr, uint16 tcp_len)
4083 {
4084 uint8 *ptr = tcp_hdr;
4085
4086 ASSERT(tcp_hdr != NULL);
4087 ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
4088
4089 /* partial TCP cksum skipping the chksum field */
4090 sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct bcmtcp_hdr, chksum));
4091 ptr += OFFSETOF(struct bcmtcp_hdr, chksum) + 2;
4092
4093 /* return calculated chksum */
4094 return ip_cksum(sum, ptr, tcp_len - OFFSETOF(struct bcmtcp_hdr, urg_ptr));
4095 }
4096
4097 struct tcp_pseudo_hdr {
4098 uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */
4099 uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */
4100 uint8 zero;
4101 uint8 prot;
4102 uint16 tcp_size;
4103 };
4104
4105 /* calculate IPv4 TCP header checksum
4106 * - input ip and tcp points to IP and TCP header in network order
4107 * - output cksum is in network order
4108 */
ipv4_tcp_hdr_cksum(uint8 * ip,uint8 * tcp,uint16 tcp_len)4109 uint16 ipv4_tcp_hdr_cksum(uint8 *ip, uint8 *tcp, uint16 tcp_len)
4110 {
4111 struct ipv4_hdr *ip_hdr = (struct ipv4_hdr *)ip;
4112 struct tcp_pseudo_hdr tcp_ps;
4113 uint32 sum = 0;
4114
4115 ASSERT(ip != NULL);
4116 ASSERT(tcp != NULL);
4117 ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
4118
4119 if (!ip || !tcp || !(tcp_len >= TCP_MIN_HEADER_LEN)) {
4120 return 0;
4121 }
4122 /* pseudo header cksum */
4123 memset(&tcp_ps, 0, sizeof(tcp_ps));
4124 memcpy(&tcp_ps.dst_ip, ip_hdr->dst_ip, IPV4_ADDR_LEN);
4125 memcpy(&tcp_ps.src_ip, ip_hdr->src_ip, IPV4_ADDR_LEN);
4126 tcp_ps.zero = 0;
4127 tcp_ps.prot = ip_hdr->prot;
4128 tcp_ps.tcp_size = hton16(tcp_len);
4129 sum = ip_cksum_partial(sum, (uint8 *)&tcp_ps, sizeof(tcp_ps));
4130
4131 /* return calculated TCP header chksum */
4132 return tcp_hdr_chksum(sum, tcp, tcp_len);
4133 }
4134
4135 struct ipv6_pseudo_hdr {
4136 uint8 saddr[IPV6_ADDR_LEN];
4137 uint8 daddr[IPV6_ADDR_LEN];
4138 uint16 payload_len;
4139 uint8 zero;
4140 uint8 next_hdr;
4141 };
4142
4143 /* calculate IPv6 TCP header checksum
4144 * - input ipv6 and tcp points to IPv6 and TCP header in network order
4145 * - output cksum is in network order
4146 */
ipv6_tcp_hdr_cksum(uint8 * ipv6,uint8 * tcp,uint16 tcp_len)4147 uint16 ipv6_tcp_hdr_cksum(uint8 *ipv6, uint8 *tcp, uint16 tcp_len)
4148 {
4149 struct ipv6_hdr *ipv6_hdr = (struct ipv6_hdr *)ipv6;
4150 struct ipv6_pseudo_hdr ipv6_pseudo;
4151 uint32 sum = 0;
4152
4153 ASSERT(ipv6 != NULL);
4154 ASSERT(tcp != NULL);
4155 ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
4156
4157 if (!ipv6 || !tcp || !(tcp_len >= TCP_MIN_HEADER_LEN)) {
4158 return 0;
4159 }
4160 /* pseudo header cksum */
4161 memset((char *)&ipv6_pseudo, 0, sizeof(ipv6_pseudo));
4162 memcpy((char *)ipv6_pseudo.saddr, (char *)ipv6_hdr->saddr.addr,
4163 sizeof(ipv6_pseudo.saddr));
4164 memcpy((char *)ipv6_pseudo.daddr, (char *)ipv6_hdr->daddr.addr,
4165 sizeof(ipv6_pseudo.daddr));
4166 ipv6_pseudo.payload_len = ipv6_hdr->payload_len;
4167 ipv6_pseudo.next_hdr = ipv6_hdr->nexthdr;
4168 sum = ip_cksum_partial(sum, (uint8 *)&ipv6_pseudo, sizeof(ipv6_pseudo));
4169
4170 /* return calculated TCP header chksum */
4171 return tcp_hdr_chksum(sum, tcp, tcp_len);
4172 }
4173
4174 void *_bcmutils_dummy_fn = NULL;
4175
4176 /* GROUP 1 --- start
4177 * These function under GROUP 1 are general purpose functions to do complex
4178 * number calculations and square root calculation.
4179 */
4180
sqrt_int(uint32 value)4181 uint32 sqrt_int(uint32 value)
4182 {
4183 uint32 root = 0, shift = 0;
4184
4185 /* Compute integer nearest to square root of input integer value */
4186 for (shift = 0; shift < 0x20; shift += 0x2) {
4187 if (((0x40000000 >> shift) + root) <= value) {
4188 value -= ((0x40000000 >> shift) + root);
4189 root = (root >> 1) | (0x40000000 >> shift);
4190 } else {
4191 root = root >> 1;
4192 }
4193 }
4194
4195 /* round to the nearest integer */
4196 if (root < value) {
4197 ++root;
4198 }
4199
4200 return root;
4201 }
4202 /* GROUP 1 --- end */
4203
4204 /* read/write field in a consecutive bits in an octet array.
4205 * 'addr' is the octet array's start byte address
4206 * 'size' is the octet array's byte size
4207 * 'stbit' is the value's start bit offset
4208 * 'nbits' is the value's bit size
4209 * This set of utilities are for convenience. Don't use them
4210 * in time critical/data path as there's a great overhead in them.
4211 */
setbits(uint8 * addr,uint size,uint stbit,uint nbits,uint32 val)4212 void setbits(uint8 *addr, uint size, uint stbit, uint nbits, uint32 val)
4213 {
4214 uint fbyte = stbit >> 3; /* first byte */
4215 uint lbyte = (stbit + nbits - 1) >> 3; /* last byte */
4216 uint fbit = stbit & 7; /* first bit in the first byte */
4217 uint rbits = (nbits > 8 - fbit ? nbits - (8 - fbit) : 0) &
4218 7; /* remaining bits of the last byte when not 0 */
4219 uint8 mask;
4220 uint byte;
4221
4222 BCM_REFERENCE(size);
4223
4224 ASSERT(fbyte < size);
4225 ASSERT(lbyte < size);
4226 ASSERT(nbits <= (sizeof(val) << 3));
4227
4228 /* all bits are in the same byte */
4229 if (fbyte == lbyte) {
4230 mask = (uint8)(((1 << nbits) - 1) << fbit);
4231 addr[fbyte] &= ~mask;
4232 addr[fbyte] |= (uint8)(val << fbit);
4233 return;
4234 }
4235
4236 /* first partial byte */
4237 if (fbit > 0) {
4238 mask = (uint8)(0xff << fbit);
4239 addr[fbyte] &= ~mask;
4240 addr[fbyte] |= (uint8)(val << fbit);
4241 val >>= (0x8 - fbit);
4242 nbits -= (0x8 - fbit);
4243 fbyte++; /* first full byte */
4244 }
4245
4246 /* last partial byte */
4247 if (rbits > 0) {
4248 mask = (uint8)((1 << rbits) - 1);
4249 addr[lbyte] &= ~mask;
4250 addr[lbyte] |= (uint8)(val >> (nbits - rbits));
4251 lbyte--; /* last full byte */
4252 }
4253
4254 /* remaining full byte(s) */
4255 for (byte = fbyte; byte <= lbyte; byte++) {
4256 addr[byte] = (uint8)val;
4257 val >>= 0x8;
4258 }
4259 }
4260
getbits(const uint8 * addr,uint size,uint stbit,uint nbits)4261 uint32 getbits(const uint8 *addr, uint size, uint stbit, uint nbits)
4262 {
4263 uint fbyte = stbit >> 3; /* first byte */
4264 uint lbyte = (stbit + nbits - 1) >> 3; /* last byte */
4265 uint fbit = stbit & 7; /* first bit in the first byte */
4266 uint rbits = (nbits > 8 - fbit ? nbits - (8 - fbit) : 0) &
4267 7; /* remaining bits of the last byte when not 0 */
4268 uint32 val = 0;
4269 uint bits = 0; /* bits in first partial byte */
4270 uint8 mask;
4271 uint byte;
4272
4273 BCM_REFERENCE(size);
4274
4275 ASSERT(fbyte < size);
4276 ASSERT(lbyte < size);
4277 ASSERT(nbits <= (sizeof(val) << 3));
4278
4279 /* all bits are in the same byte */
4280 if (fbyte == lbyte) {
4281 mask = (uint8)(((1 << nbits) - 1) << fbit);
4282 val = (addr[fbyte] & mask) >> fbit;
4283 return val;
4284 }
4285
4286 /* first partial byte */
4287 if (fbit > 0) {
4288 bits = 0x8 - fbit;
4289 mask = (uint8)(0xFFu << fbit);
4290 val |= (addr[fbyte] & mask) >> fbit;
4291 fbyte++; /* first full byte */
4292 }
4293
4294 /* last partial byte */
4295 if (rbits > 0) {
4296 mask = (uint8)((1 << rbits) - 1);
4297 val |= (uint32)((addr[lbyte] & mask) << (nbits - rbits));
4298 lbyte--; /* last full byte */
4299 }
4300
4301 /* remaining full byte(s) */
4302 for (byte = fbyte; byte <= lbyte; byte++) {
4303 val |= (uint32)((addr[byte] << (((byte - fbyte) << 0x3) + bits)));
4304 }
4305
4306 return val;
4307 }
4308
4309 #ifdef BCMDRIVER
4310
4311 /** allocate variable sized data with 'size' bytes. note: vld should NOT be
4312 * null.
4313 */
bcm_vdata_alloc(osl_t * osh,var_len_data_t * vld,uint32 size)4314 int bcm_vdata_alloc(osl_t *osh, var_len_data_t *vld, uint32 size)
4315 {
4316 int ret = BCME_ERROR;
4317 uint8 *dat = NULL;
4318
4319 if (vld == NULL) {
4320 ASSERT(0);
4321 goto done;
4322 }
4323
4324 /* trying to allocate twice? */
4325 if (vld->vdata != NULL) {
4326 ASSERT(0);
4327 goto done;
4328 }
4329
4330 /* trying to allocate 0 size? */
4331 if (size == 0) {
4332 ASSERT(0);
4333 ret = BCME_BADARG;
4334 goto done;
4335 }
4336
4337 dat = MALLOCZ(osh, size);
4338 if (dat == NULL) {
4339 ret = BCME_NOMEM;
4340 goto done;
4341 }
4342 vld->vlen = size;
4343 vld->vdata = dat;
4344 ret = BCME_OK;
4345 done:
4346 return ret;
4347 }
4348
4349 /** free memory associated with variable sized data. note: vld should NOT be
4350 * null.
4351 */
bcm_vdata_free(osl_t * osh,var_len_data_t * vld)4352 int bcm_vdata_free(osl_t *osh, var_len_data_t *vld)
4353 {
4354 int ret = BCME_ERROR;
4355
4356 if (vld == NULL) {
4357 ASSERT(0);
4358 goto done;
4359 }
4360
4361 if (vld->vdata) {
4362 MFREE(osh, vld->vdata, vld->vlen);
4363 vld->vdata = NULL;
4364 vld->vlen = 0;
4365 ret = BCME_OK;
4366 }
4367 done:
4368 return ret;
4369 }
4370
4371 #endif /* BCMDRIVER */
4372
4373 /* Count the number of elements not matching a given value in a null terminated
4374 * array */
array_value_mismatch_count(uint8 value,uint8 * array,int array_size)4375 int array_value_mismatch_count(uint8 value, uint8 *array, int array_size)
4376 {
4377 int i;
4378 int count = 0;
4379
4380 for (i = 0; i < array_size; i++) {
4381 /* exit if a null terminator is found */
4382 if (array[i] == 0) {
4383 break;
4384 }
4385 if (array[i] != value) {
4386 count++;
4387 }
4388 }
4389 return count;
4390 }
4391
4392 /* Count the number of non-zero elements in an uint8 array */
array_nonzero_count(uint8 * array,int array_size)4393 int array_nonzero_count(uint8 *array, int array_size)
4394 {
4395 return array_value_mismatch_count(0, array, array_size);
4396 }
4397
4398 /* Count the number of non-zero elements in an int16 array */
array_nonzero_count_int16(int16 * array,int array_size)4399 int array_nonzero_count_int16(int16 *array, int array_size)
4400 {
4401 int i;
4402 int count = 0;
4403
4404 for (i = 0; i < array_size; i++) {
4405 if (array[i] != 0) {
4406 count++;
4407 }
4408 }
4409 return count;
4410 }
4411
4412 /* Count the number of zero elements in an uint8 array */
array_zero_count(uint8 * array,int array_size)4413 int array_zero_count(uint8 *array, int array_size)
4414 {
4415 int i;
4416 int count = 0;
4417
4418 for (i = 0; i < array_size; i++) {
4419 if (array[i] == 0) {
4420 count++;
4421 }
4422 }
4423 return count;
4424 }
4425
4426 /* Validate an array that can be 1 of 2 data types.
4427 * One of array1 or array2 should be non-NULL. The other should be NULL.
4428 */
verify_ordered_array(uint8 * array1,int16 * array2,int array_size,int range_lo,int range_hi,bool err_if_no_zero_term,bool is_ordered)4429 static int verify_ordered_array(uint8 *array1, int16 *array2, int array_size,
4430 int range_lo, int range_hi,
4431 bool err_if_no_zero_term, bool is_ordered)
4432 {
4433 int ret;
4434 int i;
4435 int val = 0;
4436 int prev_val = 0;
4437
4438 ret = err_if_no_zero_term ? BCME_NOTFOUND : BCME_OK;
4439
4440 /* Check that:
4441 * - values are in strict descending order.
4442 * - values are within the valid range.
4443 */
4444 for (i = 0; i < array_size; i++) {
4445 if (array1) {
4446 val = (int)array1[i];
4447 } else if (array2) {
4448 val = (int)array2[i];
4449 } else {
4450 /* both array parameters are NULL */
4451 return BCME_NOTFOUND;
4452 }
4453 if (val == 0) {
4454 /* array is zero-terminated */
4455 ret = BCME_OK;
4456 break;
4457 }
4458
4459 if (is_ordered && i > 0 && val >= prev_val) {
4460 /* array is not in descending order */
4461 ret = BCME_BADOPTION;
4462 break;
4463 }
4464 prev_val = val;
4465
4466 if (val < range_lo || val > range_hi) {
4467 /* array value out of range */
4468 ret = BCME_RANGE;
4469 break;
4470 }
4471 }
4472
4473 return ret;
4474 }
4475
4476 /* Validate an ordered uint8 configuration array */
verify_ordered_array_uint8(uint8 * array,int array_size,uint8 range_lo,uint8 range_hi)4477 int verify_ordered_array_uint8(uint8 *array, int array_size, uint8 range_lo,
4478 uint8 range_hi)
4479 {
4480 return verify_ordered_array(array, NULL, array_size, (int)range_lo,
4481 (int)range_hi, TRUE, TRUE);
4482 }
4483
4484 /* Validate an ordered int16 non-zero-terminated configuration array */
verify_ordered_array_int16(int16 * array,int array_size,int16 range_lo,int16 range_hi)4485 int verify_ordered_array_int16(int16 *array, int array_size, int16 range_lo,
4486 int16 range_hi)
4487 {
4488 return verify_ordered_array(NULL, array, array_size, (int)range_lo,
4489 (int)range_hi, FALSE, TRUE);
4490 }
4491
4492 /* Validate all values in an array are in range */
verify_array_values(uint8 * array,int array_size,int range_lo,int range_hi,bool zero_terminated)4493 int verify_array_values(uint8 *array, int array_size, int range_lo,
4494 int range_hi, bool zero_terminated)
4495 {
4496 int ret = BCME_OK;
4497 int i;
4498 int val = 0;
4499
4500 /* Check that:
4501 * - values are in strict descending order.
4502 * - values are within the valid range.
4503 */
4504 for (i = 0; i < array_size; i++) {
4505 val = (int)array[i];
4506 if (val == 0 && zero_terminated) {
4507 ret = BCME_OK;
4508 break;
4509 }
4510 if (val < range_lo || val > range_hi) {
4511 /* array value out of range */
4512 ret = BCME_RANGE;
4513 break;
4514 }
4515 }
4516 return ret;
4517 }
4518
4519 /* Adds/replaces NVRAM variable with given value
4520 * varbuf[in,out] - Buffer with NVRAM variables (sequence of zero-terminated
4521 * 'name=value' records, terminated with additional zero) buflen[in] -
4522 * Length of buffer (may, even should, have some unused space) variable[in] -
4523 * Variable to add/replace in 'name=value' form datalen[out,opt] - Optional
4524 * output parameter - resulting length of data in buffer Returns TRUE on
4525 * success, FALSE if buffer too short or variable specified incorrectly
4526 */
replace_nvram_variable(char * varbuf,unsigned int buflen,const char * variable,unsigned int * datalen)4527 bool replace_nvram_variable(char *varbuf, unsigned int buflen,
4528 const char *variable, unsigned int *datalen)
4529 {
4530 char *p;
4531 int variable_heading_len, record_len,
4532 variable_record_len = (int)strlen(variable) + 1;
4533 char *buf_end = varbuf + buflen;
4534 p = strchr(variable, '=');
4535 if (!p) {
4536 return FALSE;
4537 }
4538 /* Length of given variable name, followed by '=' */
4539 variable_heading_len = (int)((const char *)(p + 1) - variable);
4540 /* Scanning NVRAM, record by record up to trailing 0 */
4541 for (p = varbuf; *p; p += strlen(p) + 1) {
4542 /* If given variable found - remove it */
4543 if (!strncmp(p, variable, (size_t)variable_heading_len)) {
4544 record_len = (int)strlen(p) + 1;
4545 memmove_s(p, buf_end - p, p + record_len,
4546 (size_t)(buf_end - (p + record_len)));
4547 }
4548 }
4549 /* If buffer does not have space for given variable - return FALSE */
4550 if ((p + variable_record_len + 1) > buf_end) {
4551 return FALSE;
4552 }
4553 /* Copy given variable to end of buffer */
4554 memmove_s(p, buf_end - p, variable, (size_t)variable_record_len);
4555 /* Adding trailing 0 */
4556 p[variable_record_len] = 0;
4557 /* Setting optional output parameter - length of data in buffer */
4558 if (datalen) {
4559 *datalen = (unsigned int)(p + variable_record_len + 1 - varbuf);
4560 }
4561 return TRUE;
4562 }
4563
4564 /* Add to adjust the 802.1x priority */
pktset8021xprio(void * pkt,int prio)4565 void pktset8021xprio(void *pkt, int prio)
4566 {
4567 struct ether_header *eh;
4568 uint8 *pktdata;
4569 if (prio == PKTPRIO(pkt)) {
4570 return;
4571 }
4572 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
4573 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
4574 eh = (struct ether_header *)pktdata;
4575 if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
4576 ASSERT(prio >= 0 && prio <= MAXPRIO);
4577 PKTSETPRIO(pkt, prio);
4578 }
4579 }
4580