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