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