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