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