2 * Driver O/S-independent utility routines
4 * Copyright (C) 1999-2017, Broadcom Corporation
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:
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.
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.
25 * <<Broadcom-WL-IPTag/Open:>>
27 * $Id: bcmutils.c 699163 2017-05-12 05:18:23Z $
39 #else /* !BCMDRIVER */
45 #if defined(BCMEXTSUP)
53 #endif /* !BCMDRIVER */
55 #include <bcmendian.h>
66 /* Look-up table to calculate head room present in a number */
67 static const uint8 msb_table
[] = {
68 0, 1, 2, 2, 3, 3, 3, 3,
69 4, 4, 4, 4, 4, 4, 4, 4,
70 5, 5, 5, 5, 5, 5, 5, 5,
71 5, 5, 5, 5, 5, 5, 5, 5,
72 6, 6, 6, 6, 6, 6, 6, 6,
73 6, 6, 6, 6, 6, 6, 6, 6,
74 6, 6, 6, 6, 6, 6, 6, 6,
75 6, 6, 6, 6, 6, 6, 6, 6,
76 7, 7, 7, 7, 7, 7, 7, 7,
77 7, 7, 7, 7, 7, 7, 7, 7,
78 7, 7, 7, 7, 7, 7, 7, 7,
79 7, 7, 7, 7, 7, 7, 7, 7,
80 7, 7, 7, 7, 7, 7, 7, 7,
81 7, 7, 7, 7, 7, 7, 7, 7,
82 7, 7, 7, 7, 7, 7, 7, 7,
83 7, 7, 7, 7, 7, 7, 7, 7,
84 8, 8, 8, 8, 8, 8, 8, 8,
85 8, 8, 8, 8, 8, 8, 8, 8,
86 8, 8, 8, 8, 8, 8, 8, 8,
87 8, 8, 8, 8, 8, 8, 8, 8,
88 8, 8, 8, 8, 8, 8, 8, 8,
89 8, 8, 8, 8, 8, 8, 8, 8,
90 8, 8, 8, 8, 8, 8, 8, 8,
91 8, 8, 8, 8, 8, 8, 8, 8,
92 8, 8, 8, 8, 8, 8, 8, 8,
93 8, 8, 8, 8, 8, 8, 8, 8,
94 8, 8, 8, 8, 8, 8, 8, 8,
95 8, 8, 8, 8, 8, 8, 8, 8,
96 8, 8, 8, 8, 8, 8, 8, 8,
97 8, 8, 8, 8, 8, 8, 8, 8,
98 8, 8, 8, 8, 8, 8, 8, 8,
99 8, 8, 8, 8, 8, 8, 8, 8,
102 void *_bcmutils_dummy_fn
= NULL
;
110 /* copy a pkt buffer chain into a buffer */
112 pktcopy(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
117 len
= 4096; /* "infinite" */
119 /* skip 'offset' bytes */
120 for (; p
&& offset
; p
= PKTNEXT(osh
, p
)) {
121 if (offset
< (uint
)PKTLEN(osh
, p
))
123 offset
-= PKTLEN(osh
, p
);
130 for (; p
&& len
; p
= PKTNEXT(osh
, p
)) {
131 n
= MIN((uint
)PKTLEN(osh
, p
) - offset
, (uint
)len
);
132 bcopy(PKTDATA(osh
, p
) + offset
, buf
, n
);
142 /* copy a buffer into a pkt buffer chain */
144 pktfrombuf(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
149 /* skip 'offset' bytes */
150 for (; p
&& offset
; p
= PKTNEXT(osh
, p
)) {
151 if (offset
< (uint
)PKTLEN(osh
, p
))
153 offset
-= PKTLEN(osh
, p
);
160 for (; p
&& len
; p
= PKTNEXT(osh
, p
)) {
161 n
= MIN((uint
)PKTLEN(osh
, p
) - offset
, (uint
)len
);
162 bcopy(buf
, PKTDATA(osh
, p
) + offset
, n
);
174 /* return total length of buffer chain */
176 pkttotlen(osl_t
*osh
, void *p
)
182 for (; p
; p
= PKTNEXT(osh
, p
)) {
183 len
= PKTLEN(osh
, p
);
186 if (BCMLFRAG_ENAB()) {
187 if (PKTISFRAG(osh
, p
)) {
188 total
+= PKTFRAGTOTLEN(osh
, p
);
197 /* return the last buffer of chained pkt */
199 pktlast(osl_t
*osh
, void *p
)
201 for (; PKTNEXT(osh
, p
); p
= PKTNEXT(osh
, p
))
207 /* count segments of a chained packet */
209 pktsegcnt(osl_t
*osh
, void *p
)
213 for (cnt
= 0; p
; p
= PKTNEXT(osh
, p
)) {
216 if (BCMLFRAG_ENAB()) {
217 if (PKTISFRAG(osh
, p
)) {
218 cnt
+= PKTFRAGTOTNUM(osh
, p
);
228 /* count segments of a chained packet */
230 pktsegcnt_war(osl_t
*osh
, void *p
)
234 uint len
, remain
, align64
;
236 for (cnt
= 0; p
; p
= PKTNEXT(osh
, p
)) {
238 len
= PKTLEN(osh
, p
);
240 pktdata
= (uint8
*)PKTDATA(osh
, p
); /* starting address of data */
241 /* Check for page boundary straddle (2048B) */
242 if (((uintptr
)pktdata
& ~0x7ff) != ((uintptr
)(pktdata
+len
) & ~0x7ff))
245 align64
= (uint
)((uintptr
)pktdata
& 0x3f); /* aligned to 64B */
246 align64
= (64 - align64
) & 0x3f;
247 len
-= align64
; /* bytes from aligned 64B to end */
248 /* if aligned to 128B, check for MOD 128 between 1 to 4B */
250 if (remain
> 0 && remain
<= 4)
251 cnt
++; /* add extra seg */
259 pktdataoffset(osl_t
*osh
, void *p
, uint offset
)
261 uint total
= pkttotlen(osh
, p
);
262 uint pkt_off
= 0, len
= 0;
263 uint8
*pdata
= (uint8
*) PKTDATA(osh
, p
);
268 for (; p
; p
= PKTNEXT(osh
, p
)) {
269 pdata
= (uint8
*) PKTDATA(osh
, p
);
270 pkt_off
= offset
- len
;
271 len
+= PKTLEN(osh
, p
);
275 return (uint8
*) (pdata
+pkt_off
);
279 /* given a offset in pdata, find the pkt seg hdr */
281 pktoffset(osl_t
*osh
, void *p
, uint offset
)
283 uint total
= pkttotlen(osh
, p
);
289 for (; p
; p
= PKTNEXT(osh
, p
)) {
290 len
+= PKTLEN(osh
, p
);
297 #endif /* BCMDRIVER */
299 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
300 const unsigned char bcm_ctype
[] = {
302 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 0-7 */
303 _BCM_C
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
,
305 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 16-23 */
306 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 24-31 */
307 _BCM_S
|_BCM_SP
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 32-39 */
308 _BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 40-47 */
309 _BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
, /* 48-55 */
310 _BCM_D
,_BCM_D
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 56-63 */
311 _BCM_P
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
,
312 _BCM_U
|_BCM_X
, _BCM_U
, /* 64-71 */
313 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
, /* 72-79 */
314 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
, /* 80-87 */
315 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 88-95 */
316 _BCM_P
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
,
317 _BCM_L
|_BCM_X
, _BCM_L
, /* 96-103 */
318 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
, /* 104-111 */
319 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
, /* 112-119 */
320 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_C
, /* 120-127 */
321 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
322 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
323 _BCM_S
|_BCM_SP
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
,
324 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 160-175 */
325 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
,
326 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 176-191 */
327 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
,
328 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, /* 192-207 */
329 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_P
, _BCM_U
, _BCM_U
, _BCM_U
,
330 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_L
, /* 208-223 */
331 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
,
332 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, /* 224-239 */
333 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_P
, _BCM_L
, _BCM_L
, _BCM_L
,
334 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
/* 240-255 */
338 bcm_strtoul(const char *cp
, char **endp
, uint base
)
340 ulong result
, last_result
= 0, value
;
345 while (bcm_isspace(*cp
))
350 else if (cp
[0] == '-') {
357 if ((cp
[1] == 'x') || (cp
[1] == 'X')) {
366 } else if (base
== 16 && (cp
[0] == '0') && ((cp
[1] == 'x') || (cp
[1] == 'X'))) {
372 while (bcm_isxdigit(*cp
) &&
373 (value
= bcm_isdigit(*cp
) ? *cp
-'0' : bcm_toupper(*cp
)-'A'+10) < base
) {
374 result
= result
*base
+ value
;
375 /* Detected overflow */
376 if (result
< last_result
&& !minus
) {
378 /* Go to the end of current number */
379 while (bcm_isxdigit(*cp
)) {
382 *endp
= DISCARD_QUAL(cp
, char);
386 last_result
= result
;
391 result
= (ulong
)(-(long)result
);
394 *endp
= DISCARD_QUAL(cp
, char);
400 bcm_atoi(const char *s
)
402 return (int)bcm_strtoul(s
, NULL
, 10);
405 /* return pointer to location of substring 'needle' in 'haystack' */
407 bcmstrstr(const char *haystack
, const char *needle
)
412 if ((haystack
== NULL
) || (needle
== NULL
))
413 return DISCARD_QUAL(haystack
, char);
415 nlen
= (int)strlen(needle
);
416 len
= (int)strlen(haystack
) - nlen
+ 1;
418 for (i
= 0; i
< len
; i
++)
419 if (memcmp(needle
, &haystack
[i
], nlen
) == 0)
420 return DISCARD_QUAL(&haystack
[i
], char);
425 bcmstrnstr(const char *s
, uint s_len
, const char *substr
, uint substr_len
)
427 for (; s_len
>= substr_len
; s
++, s_len
--)
428 if (strncmp(s
, substr
, substr_len
) == 0)
429 return DISCARD_QUAL(s
, char);
435 bcmstrcat(char *dest
, const char *src
)
439 p
= dest
+ strlen(dest
);
441 while ((*p
++ = *src
++) != '\0')
448 bcmstrncat(char *dest
, const char *src
, uint size
)
453 p
= dest
+ strlen(dest
);
456 while (p
!= endp
&& (*p
++ = *src
++) != '\0')
463 /****************************************************************************
464 * Function: bcmstrtok
467 * Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
468 * but allows strToken() to be used by different strings or callers at the same
469 * time. Each call modifies '*string' by substituting a NULL character for the
470 * first delimiter that is encountered, and updates 'string' to point to the char
471 * after the delimiter. Leading delimiters are skipped.
474 * string (mod) Ptr to string ptr, updated by token.
475 * delimiters (in) Set of delimiter characters.
476 * tokdelim (out) Character that delimits the returned token. (May
477 * be set to NULL if token delimiter is not required).
479 * Returns: Pointer to the next token found. NULL when no more tokens are found.
480 *****************************************************************************
483 bcmstrtok(char **string
, const char *delimiters
, char *tokdelim
)
486 unsigned long map
[8];
490 if (tokdelim
!= NULL
) {
491 /* Prime the token delimiter */
495 /* Clear control map */
496 for (count
= 0; count
< 8; count
++) {
500 /* Set bits in delimiter table */
502 map
[*delimiters
>> 5] |= (1 << (*delimiters
& 31));
504 while (*delimiters
++);
506 str
= (unsigned char*)*string
;
508 /* Find beginning of token (skip over leading delimiters). Note that
509 * there is no token iff this loop sets str to point to the terminal
510 * null (*str == '\0')
512 while (((map
[*str
>> 5] & (1 << (*str
& 31))) && *str
) || (*str
== ' ')) {
516 nextoken
= (char*)str
;
518 /* Find the end of the token. If it is not the end of the string,
521 for (; *str
; str
++) {
522 if (map
[*str
>> 5] & (1 << (*str
& 31))) {
523 if (tokdelim
!= NULL
) {
532 *string
= (char*)str
;
534 /* Determine if a token has been found. */
535 if (nextoken
== (char *) str
) {
544 #define xToLower(C) \
545 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
548 /****************************************************************************
549 * Function: bcmstricmp
551 * Purpose: Compare to strings case insensitively.
553 * Parameters: s1 (in) First string to compare.
554 * s2 (in) Second string to compare.
556 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
557 * t1 > t2, when ignoring case sensitivity.
558 *****************************************************************************
561 bcmstricmp(const char *s1
, const char *s2
)
568 if (dc
< sc
) return -1;
569 if (dc
> sc
) return 1;
574 if (*s1
&& !*s2
) return 1;
575 if (!*s1
&& *s2
) return -1;
580 /****************************************************************************
581 * Function: bcmstrnicmp
583 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
586 * Parameters: s1 (in) First string to compare.
587 * s2 (in) Second string to compare.
588 * cnt (in) Max characters to compare.
590 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
591 * t1 > t2, when ignoring case sensitivity.
592 *****************************************************************************
595 bcmstrnicmp(const char* s1
, const char* s2
, int cnt
)
599 while (*s2
&& *s1
&& cnt
) {
602 if (dc
< sc
) return -1;
603 if (dc
> sc
) return 1;
610 if (*s1
&& !*s2
) return 1;
611 if (!*s1
&& *s2
) return -1;
615 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
617 bcm_ether_atoe(const char *p
, struct ether_addr
*ea
)
623 ea
->octet
[i
++] = (char) bcm_strtoul(p
, &ep
, 16);
633 bcm_atoipv4(const char *p
, struct ipv4_addr
*ip
)
639 ip
->addr
[i
++] = (uint8
)bcm_strtoul(p
, &c
, 0);
640 if (*c
++ != '.' || i
== IPV4_ADDR_LEN
)
644 return (i
== IPV4_ADDR_LEN
);
646 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
649 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
650 /* registry routine buffer preparation utility functions:
651 * parameter order is like strncpy, but returns count
652 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
655 wchar2ascii(char *abuf
, ushort
*wbuf
, ushort wbuflen
, ulong abuflen
)
663 /* wbuflen is in bytes */
664 wbuflen
/= sizeof(ushort
);
666 for (i
= 0; i
< wbuflen
; ++i
) {
669 *abuf
++ = (char) *wbuf
++;
676 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
679 bcm_ether_ntoa(const struct ether_addr
*ea
, char *buf
)
681 static const char hex
[] =
683 '0', '1', '2', '3', '4', '5', '6', '7',
684 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
686 const uint8
*octet
= ea
->octet
;
690 for (i
= 0; i
< 6; i
++, octet
++) {
691 *p
++ = hex
[(*octet
>> 4) & 0xf];
692 *p
++ = hex
[*octet
& 0xf];
702 bcm_ip_ntoa(struct ipv4_addr
*ia
, char *buf
)
704 snprintf(buf
, 16, "%d.%d.%d.%d",
705 ia
->addr
[0], ia
->addr
[1], ia
->addr
[2], ia
->addr
[3]);
710 bcm_ipv6_ntoa(void *ipv6
, char *buf
)
712 /* Implementing RFC 5952 Sections 4 + 5 */
713 /* Not thoroughly tested */
717 int i
, i_max
= -1, cnt
= 0, cnt_max
= 1;
719 memcpy((uint8
*)&tmp
[0], (uint8
*)ipv6
, IPV6_ADDR_LEN
);
721 for (i
= 0; i
< IPV6_ADDR_LEN
/2; i
++) {
736 /* IPv4-translated: ::ffff:0:a.b.c.d */
737 ((cnt_max
== 4 && a
[4] == 0xffff && a
[5] == 0) ||
738 /* IPv4-mapped: ::ffff:a.b.c.d */
739 (cnt_max
== 5 && a
[5] == 0xffff)))
740 a4
= (uint8
*) (a
+ 6);
742 for (i
= 0; i
< IPV6_ADDR_LEN
/2; i
++) {
743 if ((uint8
*) (a
+ i
) == a4
) {
744 snprintf(p
, 16, ":%u.%u.%u.%u", a4
[0], a4
[1], a4
[2], a4
[3]);
746 } else if (i
== i_max
) {
754 p
+= snprintf(p
, 8, "%x", ntoh16(a
[i
]));
767 for (i
= 0; i
< ms
; i
++) {
776 #if defined(DHD_DEBUG)
777 /* pretty hex print a pkt buffer chain */
779 prpkt(const char *msg
, osl_t
*osh
, void *p0
)
783 if (msg
&& (msg
[0] != '\0'))
784 printf("%s:\n", msg
);
786 for (p
= p0
; p
; p
= PKTNEXT(osh
, p
))
787 prhex(NULL
, PKTDATA(osh
, p
), PKTLEN(osh
, p
));
791 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
792 * Also updates the inplace vlan tag if requested.
793 * For debugging, it returns an indication of what it did.
796 pktsetprio(void *pkt
, bool update_vtag
)
798 struct ether_header
*eh
;
799 struct ethervlan_header
*evh
;
804 pktdata
= (uint8
*)PKTDATA(OSH_NULL
, pkt
);
805 ASSERT(ISALIGNED((uintptr
)pktdata
, sizeof(uint16
)));
807 eh
= (struct ether_header
*) pktdata
;
809 if (eh
->ether_type
== hton16(ETHER_TYPE_8021Q
)) {
811 int vlan_prio
, dscp_prio
= 0;
813 evh
= (struct ethervlan_header
*)eh
;
815 vlan_tag
= ntoh16(evh
->vlan_tag
);
816 vlan_prio
= (int) (vlan_tag
>> VLAN_PRI_SHIFT
) & VLAN_PRI_MASK
;
818 if ((evh
->ether_type
== hton16(ETHER_TYPE_IP
)) ||
819 (evh
->ether_type
== hton16(ETHER_TYPE_IPV6
))) {
820 uint8
*ip_body
= pktdata
+ sizeof(struct ethervlan_header
);
821 uint8 tos_tc
= IP_TOS46(ip_body
);
822 dscp_prio
= (int)(tos_tc
>> IPV4_TOS_PREC_SHIFT
);
825 /* DSCP priority gets precedence over 802.1P (vlan tag) */
826 if (dscp_prio
!= 0) {
827 priority
= dscp_prio
;
830 priority
= vlan_prio
;
834 * If the DSCP priority is not the same as the VLAN priority,
835 * then overwrite the priority field in the vlan tag, with the
836 * DSCP priority value. This is required for Linux APs because
837 * the VLAN driver on Linux, overwrites the skb->priority field
838 * with the priority value in the vlan tag
840 if (update_vtag
&& (priority
!= vlan_prio
)) {
841 vlan_tag
&= ~(VLAN_PRI_MASK
<< VLAN_PRI_SHIFT
);
842 vlan_tag
|= (uint16
)priority
<< VLAN_PRI_SHIFT
;
843 evh
->vlan_tag
= hton16(vlan_tag
);
846 #if defined(EAPOL_PKT_PRIO) || defined(DHD_LOSSLESS_ROAMING)
847 } else if (eh
->ether_type
== hton16(ETHER_TYPE_802_1X
)) {
848 priority
= PRIO_8021D_NC
;
850 #endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */
851 } else if ((eh
->ether_type
== hton16(ETHER_TYPE_IP
)) ||
852 (eh
->ether_type
== hton16(ETHER_TYPE_IPV6
))) {
853 uint8
*ip_body
= pktdata
+ sizeof(struct ether_header
);
854 uint8 tos_tc
= IP_TOS46(ip_body
);
855 uint8 dscp
= tos_tc
>> IPV4_TOS_DSCP_SHIFT
;
858 priority
= PRIO_8021D_VO
;
863 priority
= PRIO_8021D_CL
;
871 priority
= PRIO_8021D_EE
;
874 priority
= (int)(tos_tc
>> IPV4_TOS_PREC_SHIFT
);
881 ASSERT(priority
>= 0 && priority
<= MAXPRIO
);
882 PKTSETPRIO(pkt
, priority
);
883 return (rc
| priority
);
886 /* lookup user priority for specified DSCP */
888 dscp2up(uint8
*up_table
, uint8 dscp
)
890 uint8 user_priority
= 255;
892 /* lookup up from table if parameters valid */
893 if (up_table
!= NULL
&& dscp
< UP_TABLE_MAX
) {
894 user_priority
= up_table
[dscp
];
897 /* 255 is unused value so return up from dscp */
898 if (user_priority
== 255) {
899 user_priority
= dscp
>> (IPV4_TOS_PREC_SHIFT
- IPV4_TOS_DSCP_SHIFT
);
902 return user_priority
;
905 /* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */
907 pktsetprio_qms(void *pkt
, uint8
* up_table
, bool update_vtag
)
913 uint user_priority
= 0;
916 pktdata
= (uint8
*)PKTDATA(OSH_NULL
, pkt
);
917 pktlen
= PKTLEN(OSH_NULL
, pkt
);
919 if (pktgetdscp(pktdata
, pktlen
, &dscp
)) {
921 user_priority
= dscp2up(up_table
, dscp
);
922 PKTSETPRIO(pkt
, user_priority
);
925 return (rc
| user_priority
);
927 return pktsetprio(pkt
, update_vtag
);
931 /* Returns TRUE and DSCP if IP header found, FALSE otherwise.
934 pktgetdscp(uint8
*pktdata
, uint pktlen
, uint8
*dscp
)
936 struct ether_header
*eh
;
937 struct ethervlan_header
*evh
;
941 /* minimum length is ether header and IP header */
942 if (pktlen
< sizeof(struct ether_header
) + IPV4_MIN_HEADER_LEN
)
945 eh
= (struct ether_header
*) pktdata
;
947 if (eh
->ether_type
== HTON16(ETHER_TYPE_IP
)) {
948 ip_body
= pktdata
+ sizeof(struct ether_header
);
949 *dscp
= IP_DSCP46(ip_body
);
952 else if (eh
->ether_type
== HTON16(ETHER_TYPE_8021Q
)) {
953 evh
= (struct ethervlan_header
*)eh
;
955 /* minimum length is ethervlan header and IP header */
956 if (pktlen
>= sizeof(struct ethervlan_header
) + IPV4_MIN_HEADER_LEN
&&
957 evh
->ether_type
== HTON16(ETHER_TYPE_IP
)) {
958 ip_body
= pktdata
+ sizeof(struct ethervlan_header
);
959 *dscp
= IP_DSCP46(ip_body
);
967 /* Add to adjust the 802.1x priority */
969 pktset8021xprio(void *pkt
, int prio
)
971 struct ether_header
*eh
;
973 if(prio
== PKTPRIO(pkt
))
975 pktdata
= (uint8
*)PKTDATA(OSH_NULL
, pkt
);
976 ASSERT(ISALIGNED((uintptr
)pktdata
, sizeof(uint16
)));
977 eh
= (struct ether_header
*) pktdata
;
978 if (eh
->ether_type
== hton16(ETHER_TYPE_802_1X
)) {
979 ASSERT(prio
>= 0 && prio
<= MAXPRIO
);
980 PKTSETPRIO(pkt
, prio
);
984 /* usr_prio range from low to high with usr_prio value */
986 up_table_set(uint8
*up_table
, uint8 usr_prio
, uint8 low
, uint8 high
)
990 if (usr_prio
> 7 || low
> high
|| low
>= UP_TABLE_MAX
|| high
>= UP_TABLE_MAX
) {
994 for (i
= low
; i
<= high
; i
++) {
995 up_table
[i
] = usr_prio
;
1001 /* set user priority table */
1003 wl_set_up_table(uint8
*up_table
, bcm_tlv_t
*qos_map_ie
)
1007 if (up_table
== NULL
|| qos_map_ie
== NULL
) {
1011 /* clear table to check table was set or not */
1012 memset(up_table
, 0xff, UP_TABLE_MAX
);
1014 /* length of QoS Map IE must be 16+n*2, n is number of exceptions */
1015 if (qos_map_ie
!= NULL
&& qos_map_ie
->id
== DOT11_MNG_QOS_MAP_ID
&&
1016 (len
= qos_map_ie
->len
) >= QOS_MAP_FIXED_LENGTH
&&
1018 uint8
*except_ptr
= (uint8
*)qos_map_ie
->data
;
1019 uint8 except_len
= len
- QOS_MAP_FIXED_LENGTH
;
1020 uint8
*range_ptr
= except_ptr
+ except_len
;
1023 /* fill in ranges */
1024 for (i
= 0; i
< QOS_MAP_FIXED_LENGTH
; i
+= 2) {
1025 uint8 low
= range_ptr
[i
];
1026 uint8 high
= range_ptr
[i
+ 1];
1027 if (low
== 255 && high
== 255) {
1031 if (!up_table_set(up_table
, i
/ 2, low
, high
)) {
1032 /* clear the table on failure */
1033 memset(up_table
, 0xff, UP_TABLE_MAX
);
1038 /* update exceptions */
1039 for (i
= 0; i
< except_len
; i
+= 2) {
1040 uint8 dscp
= except_ptr
[i
];
1041 uint8 usr_prio
= except_ptr
[i
+1];
1043 /* exceptions with invalid dscp/usr_prio are ignored */
1044 up_table_set(up_table
, usr_prio
, dscp
, dscp
);
1051 /* The 0.5KB string table is not removed by compiler even though it's unused */
1053 static char bcm_undeferrstr
[32];
1054 static const char *bcmerrorstrtable
[] = BCMERRSTRINGTABLE
;
1056 /* Convert the error codes into related error strings */
1058 bcmerrorstr(int bcmerror
)
1060 /* check if someone added a bcmerror code but forgot to add errorstring */
1061 ASSERT(ABS(BCME_LAST
) == (ARRAYSIZE(bcmerrorstrtable
) - 1));
1063 if (bcmerror
> 0 || bcmerror
< BCME_LAST
) {
1064 snprintf(bcm_undeferrstr
, sizeof(bcm_undeferrstr
), "Undefined error %d", bcmerror
);
1065 return bcm_undeferrstr
;
1068 ASSERT(strlen(bcmerrorstrtable
[-bcmerror
]) < BCME_STRLEN
);
1070 return bcmerrorstrtable
[-bcmerror
];
1074 /* iovar table lookup */
1075 /* could mandate sorted tables and do a binary search */
1077 bcm_iovar_lookup(const bcm_iovar_t
*table
, const char *name
)
1079 const bcm_iovar_t
*vi
;
1080 const char *lookup_name
;
1082 /* skip any ':' delimited option prefixes */
1083 lookup_name
= strrchr(name
, ':');
1084 if (lookup_name
!= NULL
)
1089 ASSERT(table
!= NULL
);
1091 for (vi
= table
; vi
->name
; vi
++) {
1092 if (!strcmp(vi
->name
, lookup_name
))
1095 /* ran to end of table */
1097 return NULL
; /* var name not found */
1101 bcm_iovar_lencheck(const bcm_iovar_t
*vi
, void *arg
, int len
, bool set
)
1106 /* length check on io buf */
1115 /* all integers are int32 sized args at the ioctl interface */
1116 if (len
< (int)sizeof(int)) {
1117 bcmerror
= BCME_BUFTOOSHORT
;
1122 /* buffer must meet minimum length requirement */
1123 if (len
< vi
->minlen
) {
1124 bcmerror
= BCME_BUFTOOSHORT
;
1130 /* Cannot return nil... */
1131 bcmerror
= BCME_UNSUPPORTED
;
1133 /* Set is an action w/o parameters */
1134 bcmerror
= BCME_BUFTOOLONG
;
1139 /* unknown type for length check in iovar info */
1141 bcmerror
= BCME_UNSUPPORTED
;
1147 #endif /* BCMDRIVER */
1149 #ifdef BCM_OBJECT_TRACE
1151 #define BCM_OBJECT_MERGE_SAME_OBJ 0
1153 /* some place may add / remove the object to trace list for Linux: */
1154 /* add: osl_alloc_skb dev_alloc_skb skb_realloc_headroom dhd_start_xmit */
1155 /* remove: osl_pktfree dev_kfree_skb netif_rx */
1157 #define BCM_OBJDBG_COUNT (1024 * 100)
1158 static spinlock_t dbgobj_lock
;
1159 #define BCM_OBJDBG_LOCK_INIT() spin_lock_init(&dbgobj_lock)
1160 #define BCM_OBJDBG_LOCK_DESTROY()
1161 #define BCM_OBJDBG_LOCK spin_lock_irqsave
1162 #define BCM_OBJDBG_UNLOCK spin_unlock_irqrestore
1164 #define BCM_OBJDBG_ADDTOHEAD 0
1165 #define BCM_OBJDBG_ADDTOTAIL 1
1167 #define BCM_OBJDBG_CALLER_LEN 32
1169 struct bcm_dbgobj
*prior
;
1170 struct bcm_dbgobj
*next
;
1176 char caller
[BCM_OBJDBG_CALLER_LEN
];
1179 static struct bcm_dbgobj
*dbgobj_freehead
= NULL
;
1180 static struct bcm_dbgobj
*dbgobj_freetail
= NULL
;
1181 static struct bcm_dbgobj
*dbgobj_objhead
= NULL
;
1182 static struct bcm_dbgobj
*dbgobj_objtail
= NULL
;
1184 static uint32 dbgobj_sn
= 0;
1185 static int dbgobj_count
= 0;
1186 static struct bcm_dbgobj bcm_dbg_objs
[BCM_OBJDBG_COUNT
];
1189 bcm_object_trace_init(void)
1192 BCM_OBJDBG_LOCK_INIT();
1193 memset(&bcm_dbg_objs
, 0x00, sizeof(struct bcm_dbgobj
) * BCM_OBJDBG_COUNT
);
1194 dbgobj_freehead
= &bcm_dbg_objs
[0];
1195 dbgobj_freetail
= &bcm_dbg_objs
[BCM_OBJDBG_COUNT
- 1];
1197 for (i
= 0; i
< BCM_OBJDBG_COUNT
; ++i
) {
1198 bcm_dbg_objs
[i
].next
= (i
== (BCM_OBJDBG_COUNT
- 1)) ?
1199 dbgobj_freehead
: &bcm_dbg_objs
[i
+ 1];
1200 bcm_dbg_objs
[i
].prior
= (i
== 0) ?
1201 dbgobj_freetail
: &bcm_dbg_objs
[i
- 1];
1206 bcm_object_trace_deinit(void)
1208 if (dbgobj_objhead
|| dbgobj_objtail
) {
1209 printf("%s: not all objects are released\n", __FUNCTION__
);
1212 BCM_OBJDBG_LOCK_DESTROY();
1216 bcm_object_rm_list(struct bcm_dbgobj
**head
, struct bcm_dbgobj
**tail
,
1217 struct bcm_dbgobj
*dbgobj
)
1219 if ((dbgobj
== *head
) && (dbgobj
== *tail
)) {
1222 } else if (dbgobj
== *head
) {
1223 *head
= (*head
)->next
;
1224 } else if (dbgobj
== *tail
) {
1225 *tail
= (*tail
)->prior
;
1227 dbgobj
->next
->prior
= dbgobj
->prior
;
1228 dbgobj
->prior
->next
= dbgobj
->next
;
1232 bcm_object_add_list(struct bcm_dbgobj
**head
, struct bcm_dbgobj
**tail
,
1233 struct bcm_dbgobj
*dbgobj
, int addtotail
)
1235 if (!(*head
) && !(*tail
)) {
1238 dbgobj
->next
= dbgobj
;
1239 dbgobj
->prior
= dbgobj
;
1240 } else if ((*head
) && (*tail
)) {
1241 (*tail
)->next
= dbgobj
;
1242 (*head
)->prior
= dbgobj
;
1243 dbgobj
->next
= *head
;
1244 dbgobj
->prior
= *tail
;
1245 if (addtotail
== BCM_OBJDBG_ADDTOTAIL
)
1250 ASSERT(0); /* can't be this case */
1255 bcm_object_movetoend(struct bcm_dbgobj
**head
, struct bcm_dbgobj
**tail
,
1256 struct bcm_dbgobj
*dbgobj
, int movetotail
)
1258 if ((*head
) && (*tail
)) {
1259 if (movetotail
== BCM_OBJDBG_ADDTOTAIL
) {
1260 if (dbgobj
!= (*tail
)) {
1261 bcm_object_rm_list(head
, tail
, dbgobj
);
1262 bcm_object_add_list(head
, tail
, dbgobj
, movetotail
);
1265 if (dbgobj
!= (*head
)) {
1266 bcm_object_rm_list(head
, tail
, dbgobj
);
1267 bcm_object_add_list(head
, tail
, dbgobj
, movetotail
);
1271 ASSERT(0); /* can't be this case */
1276 bcm_object_trace_opr(void *obj
, uint32 opt
, const char *caller
, int line
)
1278 struct bcm_dbgobj
*dbgobj
;
1279 unsigned long flags
;
1281 BCM_REFERENCE(flags
);
1282 BCM_OBJDBG_LOCK(&dbgobj_lock
, flags
);
1284 if (opt
== BCM_OBJDBG_ADD_PKT
||
1285 opt
== BCM_OBJDBG_ADD
) {
1286 dbgobj
= dbgobj_objtail
;
1288 if (dbgobj
->obj
== obj
) {
1289 printf("%s: obj %p allocated from %s(%d),"
1290 " allocate again from %s(%d)\n",
1291 __FUNCTION__
, dbgobj
->obj
,
1292 dbgobj
->caller
, dbgobj
->line
,
1297 dbgobj
= dbgobj
->prior
;
1298 if (dbgobj
== dbgobj_objtail
)
1302 #if BCM_OBJECT_MERGE_SAME_OBJ
1303 dbgobj
= dbgobj_freetail
;
1305 if (dbgobj
->obj
== obj
) {
1306 goto FREED_ENTRY_FOUND
;
1308 dbgobj
= dbgobj
->prior
;
1309 if (dbgobj
== dbgobj_freetail
)
1312 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
1314 dbgobj
= dbgobj_freehead
;
1315 #if BCM_OBJECT_MERGE_SAME_OBJ
1317 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
1319 printf("%s: already got %d objects ?????????????????????\n",
1320 __FUNCTION__
, BCM_OBJDBG_COUNT
);
1325 bcm_object_rm_list(&dbgobj_freehead
, &dbgobj_freetail
, dbgobj
);
1327 strncpy(dbgobj
->caller
, caller
, BCM_OBJDBG_CALLER_LEN
);
1328 dbgobj
->caller
[BCM_OBJDBG_CALLER_LEN
-1] = '\0';
1329 dbgobj
->line
= line
;
1331 if (opt
== BCM_OBJDBG_ADD_PKT
) {
1332 dbgobj
->obj_sn
= dbgobj_sn
++;
1333 dbgobj
->obj_state
= 0;
1334 /* first 4 bytes is pkt sn */
1335 if (((unsigned long)PKTTAG(obj
)) & 0x3)
1336 printf("pkt tag address not aligned by 4: %p\n", PKTTAG(obj
));
1337 *(uint32
*)PKTTAG(obj
) = dbgobj
->obj_sn
;
1339 bcm_object_add_list(&dbgobj_objhead
, &dbgobj_objtail
, dbgobj
,
1340 BCM_OBJDBG_ADDTOTAIL
);
1344 } else if (opt
== BCM_OBJDBG_REMOVE
) {
1345 dbgobj
= dbgobj_objtail
;
1347 if (dbgobj
->obj
== obj
) {
1349 printf("%s: rm flagged obj %p flag 0x%08x from %s(%d)\n",
1350 __FUNCTION__
, obj
, dbgobj
->flag
, caller
, line
);
1352 bcm_object_rm_list(&dbgobj_objhead
, &dbgobj_objtail
, dbgobj
);
1353 memset(dbgobj
->caller
, 0x00, BCM_OBJDBG_CALLER_LEN
);
1354 strncpy(dbgobj
->caller
, caller
, BCM_OBJDBG_CALLER_LEN
);
1355 dbgobj
->caller
[BCM_OBJDBG_CALLER_LEN
-1] = '\0';
1356 dbgobj
->line
= line
;
1357 bcm_object_add_list(&dbgobj_freehead
, &dbgobj_freetail
, dbgobj
,
1358 BCM_OBJDBG_ADDTOTAIL
);
1362 dbgobj
= dbgobj
->prior
;
1363 if (dbgobj
== dbgobj_objtail
)
1367 dbgobj
= dbgobj_freetail
;
1368 while (dbgobj
&& dbgobj
->obj
) {
1369 if (dbgobj
->obj
== obj
) {
1370 printf("%s: obj %p already freed from from %s(%d),"
1371 " try free again from %s(%d)\n",
1373 dbgobj
->caller
, dbgobj
->line
,
1375 //ASSERT(0); /* release same obj more than one time? */
1378 dbgobj
= dbgobj
->prior
;
1379 if (dbgobj
== dbgobj_freetail
)
1383 printf("%s: ################### release none-existing obj %p from %s(%d)\n",
1384 __FUNCTION__
, obj
, caller
, line
);
1385 //ASSERT(0); /* release same obj more than one time? */
1390 BCM_OBJDBG_UNLOCK(&dbgobj_lock
, flags
);
1395 bcm_object_trace_upd(void *obj
, void *obj_new
)
1397 struct bcm_dbgobj
*dbgobj
;
1398 unsigned long flags
;
1400 BCM_REFERENCE(flags
);
1401 BCM_OBJDBG_LOCK(&dbgobj_lock
, flags
);
1403 dbgobj
= dbgobj_objtail
;
1405 if (dbgobj
->obj
== obj
) {
1406 dbgobj
->obj
= obj_new
;
1407 if (dbgobj
!= dbgobj_objtail
) {
1408 bcm_object_movetoend(&dbgobj_objhead
, &dbgobj_objtail
,
1409 dbgobj
, BCM_OBJDBG_ADDTOTAIL
);
1413 dbgobj
= dbgobj
->prior
;
1414 if (dbgobj
== dbgobj_objtail
)
1419 BCM_OBJDBG_UNLOCK(&dbgobj_lock
, flags
);
1424 bcm_object_trace_chk(void *obj
, uint32 chksn
, uint32 sn
,
1425 const char *caller
, int line
)
1427 struct bcm_dbgobj
*dbgobj
;
1428 unsigned long flags
;
1430 BCM_REFERENCE(flags
);
1431 BCM_OBJDBG_LOCK(&dbgobj_lock
, flags
);
1433 dbgobj
= dbgobj_objtail
;
1435 if ((dbgobj
->obj
== obj
) &&
1436 ((!chksn
) || (dbgobj
->obj_sn
== sn
))) {
1437 if (dbgobj
!= dbgobj_objtail
) {
1438 bcm_object_movetoend(&dbgobj_objhead
, &dbgobj_objtail
,
1439 dbgobj
, BCM_OBJDBG_ADDTOTAIL
);
1443 dbgobj
= dbgobj
->prior
;
1444 if (dbgobj
== dbgobj_objtail
)
1448 dbgobj
= dbgobj_freetail
;
1450 if ((dbgobj
->obj
== obj
) &&
1451 ((!chksn
) || (dbgobj
->obj_sn
== sn
))) {
1452 printf("%s: (%s:%d) obj %p (sn %d state %d) was freed from %s(%d)\n",
1453 __FUNCTION__
, caller
, line
,
1454 dbgobj
->obj
, dbgobj
->obj_sn
, dbgobj
->obj_state
,
1455 dbgobj
->caller
, dbgobj
->line
);
1458 else if (dbgobj
->obj
== NULL
) {
1461 dbgobj
= dbgobj
->prior
;
1462 if (dbgobj
== dbgobj_freetail
)
1466 printf("%s: obj %p not found, check from %s(%d), chksn %s, sn %d\n",
1467 __FUNCTION__
, obj
, caller
, line
, chksn
? "yes" : "no", sn
);
1468 dbgobj
= dbgobj_objtail
;
1470 printf("%s: (%s:%d) obj %p sn %d was allocated from %s(%d)\n",
1471 __FUNCTION__
, caller
, line
,
1472 dbgobj
->obj
, dbgobj
->obj_sn
, dbgobj
->caller
, dbgobj
->line
);
1473 dbgobj
= dbgobj
->prior
;
1474 if (dbgobj
== dbgobj_objtail
)
1479 BCM_OBJDBG_UNLOCK(&dbgobj_lock
, flags
);
1484 bcm_object_feature_set(void *obj
, uint32 type
, uint32 value
)
1486 struct bcm_dbgobj
*dbgobj
;
1487 unsigned long flags
;
1489 BCM_REFERENCE(flags
);
1490 BCM_OBJDBG_LOCK(&dbgobj_lock
, flags
);
1492 dbgobj
= dbgobj_objtail
;
1494 if (dbgobj
->obj
== obj
) {
1495 if (type
== BCM_OBJECT_FEATURE_FLAG
) {
1496 if (value
& BCM_OBJECT_FEATURE_CLEAR
)
1497 dbgobj
->flag
&= ~(value
);
1499 dbgobj
->flag
|= (value
);
1500 } else if (type
== BCM_OBJECT_FEATURE_PKT_STATE
) {
1501 dbgobj
->obj_state
= value
;
1503 if (dbgobj
!= dbgobj_objtail
) {
1504 bcm_object_movetoend(&dbgobj_objhead
, &dbgobj_objtail
,
1505 dbgobj
, BCM_OBJDBG_ADDTOTAIL
);
1509 dbgobj
= dbgobj
->prior
;
1510 if (dbgobj
== dbgobj_objtail
)
1514 printf("%s: obj %p not found in active list\n", __FUNCTION__
, obj
);
1518 BCM_OBJDBG_UNLOCK(&dbgobj_lock
, flags
);
1523 bcm_object_feature_get(void *obj
, uint32 type
, uint32 value
)
1526 struct bcm_dbgobj
*dbgobj
;
1527 unsigned long flags
;
1529 BCM_REFERENCE(flags
);
1530 BCM_OBJDBG_LOCK(&dbgobj_lock
, flags
);
1532 dbgobj
= dbgobj_objtail
;
1534 if (dbgobj
->obj
== obj
) {
1535 if (type
== BCM_OBJECT_FEATURE_FLAG
) {
1536 rtn
= (dbgobj
->flag
& value
) & (~BCM_OBJECT_FEATURE_CLEAR
);
1538 if (dbgobj
!= dbgobj_objtail
) {
1539 bcm_object_movetoend(&dbgobj_objhead
, &dbgobj_objtail
,
1540 dbgobj
, BCM_OBJDBG_ADDTOTAIL
);
1544 dbgobj
= dbgobj
->prior
;
1545 if (dbgobj
== dbgobj_objtail
)
1549 printf("%s: obj %p not found in active list\n", __FUNCTION__
, obj
);
1553 BCM_OBJDBG_UNLOCK(&dbgobj_lock
, flags
);
1557 #endif /* BCM_OBJECT_TRACE */
1560 bcm_write_tlv(int type
, const void *data
, int datalen
, uint8
*dst
)
1562 uint8
*new_dst
= dst
;
1563 bcm_tlv_t
*dst_tlv
= (bcm_tlv_t
*)dst
;
1565 /* dst buffer should always be valid */
1568 /* data len must be within valid range */
1569 ASSERT((datalen
>= 0) && (datalen
<= BCM_TLV_MAX_DATA_SIZE
));
1571 /* source data buffer pointer should be valid, unless datalen is 0
1572 * meaning no data with this TLV
1574 ASSERT((data
!= NULL
) || (datalen
== 0));
1576 /* only do work if the inputs are valid
1577 * - must have a dst to write to AND
1578 * - datalen must be within range AND
1579 * - the source data pointer must be non-NULL if datalen is non-zero
1580 * (this last condition detects datalen > 0 with a NULL data pointer)
1582 if ((dst
!= NULL
) &&
1583 ((datalen
>= 0) && (datalen
<= BCM_TLV_MAX_DATA_SIZE
)) &&
1584 ((data
!= NULL
) || (datalen
== 0))) {
1586 /* write type, len fields */
1587 dst_tlv
->id
= (uint8
)type
;
1588 dst_tlv
->len
= (uint8
)datalen
;
1590 /* if data is present, copy to the output buffer and update
1591 * pointer to output buffer
1595 memcpy(dst_tlv
->data
, data
, datalen
);
1598 /* update the output destination poitner to point past
1601 new_dst
= dst
+ BCM_TLV_HDR_SIZE
+ datalen
;
1608 bcm_write_tlv_safe(int type
, const void *data
, int datalen
, uint8
*dst
, int dst_maxlen
)
1610 uint8
*new_dst
= dst
;
1612 if ((datalen
>= 0) && (datalen
<= BCM_TLV_MAX_DATA_SIZE
)) {
1614 /* if len + tlv hdr len is more than destlen, don't do anything
1615 * just return the buffer untouched
1617 if ((int)(datalen
+ BCM_TLV_HDR_SIZE
) <= dst_maxlen
) {
1619 new_dst
= bcm_write_tlv(type
, data
, datalen
, dst
);
1627 bcm_copy_tlv(const void *src
, uint8
*dst
)
1629 uint8
*new_dst
= dst
;
1630 const bcm_tlv_t
*src_tlv
= (const bcm_tlv_t
*)src
;
1636 totlen
= BCM_TLV_HDR_SIZE
+ src_tlv
->len
;
1637 memcpy(dst
, src_tlv
, totlen
);
1638 new_dst
= dst
+ totlen
;
1645 uint8
*bcm_copy_tlv_safe(const void *src
, uint8
*dst
, int dst_maxlen
)
1647 uint8
*new_dst
= dst
;
1648 const bcm_tlv_t
*src_tlv
= (const bcm_tlv_t
*)src
;
1652 if (bcm_valid_tlv(src_tlv
, dst_maxlen
)) {
1653 new_dst
= bcm_copy_tlv(src
, dst
);
1661 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
1662 /*******************************************************************************
1665 * Computes a crc8 over the input data using the polynomial:
1667 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1669 * The caller provides the initial value (either CRC8_INIT_VALUE
1670 * or the previous returned value) to allow for processing of
1671 * discontiguous blocks of data. When generating the CRC the
1672 * caller is responsible for complementing the final return value
1673 * and inserting it into the byte stream. When checking, a final
1674 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1676 * Reference: Dallas Semiconductor Application Note 27
1677 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1678 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1679 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1681 * ****************************************************************************
1684 static const uint8 crc8_table
[256] = {
1685 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1686 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1687 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1688 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1689 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1690 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1691 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1692 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1693 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1694 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1695 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1696 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1697 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1698 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1699 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1700 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1701 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1702 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1703 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1704 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1705 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1706 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1707 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1708 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1709 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1710 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1711 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1712 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1713 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1714 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1715 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1716 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1719 #define CRC_INNER_LOOP(n, c, x) \
1720 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1724 uint8
*pdata
, /* pointer to array of data to process */
1725 uint nbytes
, /* number of input data bytes to process */
1726 uint8 crc
/* either CRC8_INIT_VALUE or previous return value */
1729 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1730 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1732 while (nbytes
-- > 0)
1733 crc
= crc8_table
[(crc
^ *pdata
++) & 0xff];
1738 /*******************************************************************************
1741 * Computes a crc16 over the input data using the polynomial:
1743 * x^16 + x^12 +x^5 + 1
1745 * The caller provides the initial value (either CRC16_INIT_VALUE
1746 * or the previous returned value) to allow for processing of
1747 * discontiguous blocks of data. When generating the CRC the
1748 * caller is responsible for complementing the final return value
1749 * and inserting it into the byte stream. When checking, a final
1750 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1752 * Reference: Dallas Semiconductor Application Note 27
1753 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1754 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1755 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1757 * ****************************************************************************
1760 static const uint16 crc16_table
[256] = {
1761 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1762 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1763 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1764 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1765 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1766 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1767 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1768 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1769 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1770 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1771 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1772 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1773 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1774 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1775 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1776 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1777 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1778 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1779 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1780 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1781 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1782 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1783 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1784 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1785 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1786 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1787 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1788 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1789 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1790 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1791 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1792 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1797 uint8
*pdata
, /* pointer to array of data to process */
1798 uint nbytes
, /* number of input data bytes to process */
1799 uint16 crc
/* either CRC16_INIT_VALUE or previous return value */
1802 while (nbytes
-- > 0)
1803 CRC_INNER_LOOP(16, crc
, *pdata
++);
1807 static const uint32 crc32_table
[256] = {
1808 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1809 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1810 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1811 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1812 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1813 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1814 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1815 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1816 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1817 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1818 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1819 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1820 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1821 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1822 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1823 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1824 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1825 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1826 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1827 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1828 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1829 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1830 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1831 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1832 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1833 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1834 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1835 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1836 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1837 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1838 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1839 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1840 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1841 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1842 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1843 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1844 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1845 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1846 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1847 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1848 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1849 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1850 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1851 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1852 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1853 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1854 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1855 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1856 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1857 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1858 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1859 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1860 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1861 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1862 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1863 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1864 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1865 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1866 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1867 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1868 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1869 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1870 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1871 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1875 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
1876 * accumulating over multiple pieces.
1879 hndcrc32(uint8
*pdata
, uint nbytes
, uint32 crc
)
1882 pend
= pdata
+ nbytes
;
1883 while (pdata
< pend
)
1884 CRC_INNER_LOOP(32, crc
, *pdata
++);
1890 #define CLEN 1499 /* CRC Length */
1891 #define CBUFSIZ (CLEN+4)
1892 #define CNBUFS 5 /* # of bufs */
1901 uint32 crc32tv
[CNBUFS
] =
1902 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1904 ASSERT((buf
= MALLOC(CBUFSIZ
*CNBUFS
)) != NULL
);
1906 /* step through all possible alignments */
1907 for (l
= 0; l
<= 4; l
++) {
1908 for (j
= 0; j
< CNBUFS
; j
++) {
1910 for (k
= 0; k
< len
[j
]; k
++)
1911 *(buf
+ j
*CBUFSIZ
+ (k
+l
)) = (j
+k
) & 0xff;
1914 for (j
= 0; j
< CNBUFS
; j
++) {
1915 crcr
= crc32(buf
+ j
*CBUFSIZ
+ l
, len
[j
], CRC32_INIT_VALUE
);
1916 ASSERT(crcr
== crc32tv
[j
]);
1920 MFREE(buf
, CBUFSIZ
*CNBUFS
);
1926 * Advance from the current 1-byte tag/1-byte length/variable-length value
1927 * triple, to the next, returning a pointer to the next.
1928 * If the current or next TLV is invalid (does not fit in given buffer length),
1930 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1931 * by the TLV parameter's length if it is valid.
1934 bcm_next_tlv(bcm_tlv_t
*elt
, int *buflen
)
1938 /* validate current elt */
1939 if (!bcm_valid_tlv(elt
, *buflen
)) {
1943 /* advance to next elt */
1945 elt
= (bcm_tlv_t
*)(elt
->data
+ len
);
1946 *buflen
-= (TLV_HDR_LEN
+ len
);
1948 /* validate next elt */
1949 if (!bcm_valid_tlv(elt
, *buflen
)) {
1957 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1958 * triples, returning a pointer to the substring whose first element
1962 bcm_parse_tlvs(void *buf
, int buflen
, uint key
)
1967 if ((elt
= (bcm_tlv_t
*)buf
) == NULL
) {
1972 /* find tagged parameter */
1973 while (totlen
>= TLV_HDR_LEN
) {
1976 /* validate remaining totlen */
1977 if ((elt
->id
== key
) && (totlen
>= (int)(len
+ TLV_HDR_LEN
))) {
1982 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ TLV_HDR_LEN
));
1983 totlen
-= (len
+ TLV_HDR_LEN
);
1990 bcm_parse_tlvs_dot11(void *buf
, int buflen
, uint key
, bool id_ext
)
1995 elt
= (bcm_tlv_t
*)buf
;
1998 /* find tagged parameter */
1999 while (totlen
>= TLV_HDR_LEN
) {
2003 /* validate remaining totlen */
2004 if (totlen
< (int)(len
+ TLV_HDR_LEN
))
2008 if (!DOT11_MNG_IE_ID_EXT_MATCH(elt
, key
))
2010 } else if (elt
->id
!= key
) {
2017 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ TLV_HDR_LEN
));
2018 totlen
-= (len
+ TLV_HDR_LEN
);
2025 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2026 * triples, returning a pointer to the substring whose first element
2028 * return NULL if not found or length field < min_varlen
2031 bcm_parse_tlvs_min_bodylen(void *buf
, int buflen
, uint key
, int min_bodylen
)
2034 ret
= bcm_parse_tlvs(buf
, buflen
, key
);
2035 if (ret
== NULL
|| ret
->len
< min_bodylen
) {
2042 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2043 * triples, returning a pointer to the substring whose first element
2044 * matches tag. Stop parsing when we see an element whose ID is greater
2045 * than the target key.
2048 bcm_parse_ordered_tlvs(void *buf
, int buflen
, uint key
)
2053 elt
= (bcm_tlv_t
*)buf
;
2056 /* find tagged parameter */
2057 while (totlen
>= TLV_HDR_LEN
) {
2061 /* Punt if we start seeing IDs > than target key */
2066 /* validate remaining totlen */
2067 if ((id
== key
) && (totlen
>= (int)(len
+ TLV_HDR_LEN
))) {
2071 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ TLV_HDR_LEN
));
2072 totlen
-= (len
+ TLV_HDR_LEN
);
2076 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
2078 #if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
2081 bcm_format_field(const bcm_bit_desc_ex_t
*bd
, uint32 flags
, char* buf
, int len
)
2087 if (len
< 2 || !buf
)
2092 for (i
= 0; (name
= bd
->bitfield
[i
].name
) != NULL
; i
++) {
2093 bit
= bd
->bitfield
[i
].bit
;
2094 if ((flags
& mask
) == bit
) {
2095 if (len
> (int)strlen(name
)) {
2096 slen
= strlen(name
);
2097 strncpy(buf
, name
, slen
+1);
2106 bcm_format_flags(const bcm_bit_desc_t
*bd
, uint32 flags
, char* buf
, int len
)
2111 int slen
= 0, nlen
= 0;
2115 if (len
< 2 || !buf
)
2120 for (i
= 0; flags
!= 0; i
++) {
2123 if (bit
== 0 && flags
!= 0) {
2124 /* print any unnamed bits */
2125 snprintf(hexstr
, 16, "0x%X", flags
);
2127 flags
= 0; /* exit loop */
2128 } else if ((flags
& bit
) == 0)
2131 nlen
= strlen(name
);
2133 /* count btwn flag space */
2136 /* need NULL char as well */
2139 /* copy NULL char but don't count it */
2140 strncpy(p
, name
, nlen
+ 1);
2142 /* copy btwn flag space and NULL char */
2144 p
+= snprintf(p
, 2, " ");
2147 /* indicate the str was too short */
2149 p
+= snprintf(p
, 2, ">");
2152 return (int)(p
- buf
);
2156 /* print bytes formatted as hex to a string. return the resulting string length */
2158 bcm_format_hex(char *str
, const void *bytes
, int len
)
2162 const uint8
*src
= (const uint8
*)bytes
;
2164 for (i
= 0; i
< len
; i
++) {
2165 p
+= snprintf(p
, 3, "%02X", *src
);
2168 return (int)(p
- str
);
2171 /* pretty hex print a contiguous buffer */
2173 prhex(const char *msg
, volatile uchar
*buf
, uint nbytes
)
2176 int len
= sizeof(line
);
2180 if (msg
&& (msg
[0] != '\0'))
2181 printf("%s:\n", msg
);
2184 for (i
= 0; i
< nbytes
; i
++) {
2186 nchar
= snprintf(p
, len
, " %04x: ", i
); /* line prefix */
2191 nchar
= snprintf(p
, len
, "%02x ", buf
[i
]);
2197 printf("%s\n", line
); /* flush line */
2203 /* flush last partial line */
2205 printf("%s\n", line
);
2208 static const char *crypto_algo_names
[] = {
2233 bcm_crypto_algo_name(uint algo
)
2235 return (algo
< ARRAYSIZE(crypto_algo_names
)) ? crypto_algo_names
[algo
] : "ERR";
2240 bcm_chipname(uint chipid
, char *buf
, uint len
)
2244 fmt
= ((chipid
> 0xa000) || (chipid
< 0x4000)) ? "%d" : "%x";
2245 snprintf(buf
, len
, fmt
, chipid
);
2249 /* Produce a human-readable string for boardrev */
2251 bcm_brev_str(uint32 brev
, char *buf
)
2254 snprintf(buf
, 8, "%d.%d", (brev
& 0xf0) >> 4, brev
& 0xf);
2256 snprintf(buf
, 8, "%c%03x", ((brev
& 0xf000) == 0x1000) ? 'P' : 'A', brev
& 0xfff);
2261 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
2263 /* dump large strings to console */
2270 len
= (uint
)strlen(buf
);
2272 max_len
= BUFSIZE_TODUMP_ATONCE
;
2274 while (len
> max_len
) {
2276 buf
[max_len
] = '\0';
2283 /* print the remaining string */
2284 printf("%s\n", buf
);
2288 /* routine to dump fields in a fileddesc structure */
2290 bcmdumpfields(bcmutl_rdreg_rtn read_rtn
, void *arg0
, uint arg1
, struct fielddesc
*fielddesc_array
,
2291 char *buf
, uint32 bufsize
)
2295 struct fielddesc
*cur_ptr
;
2298 cur_ptr
= fielddesc_array
;
2300 while (bufsize
> 1) {
2301 if (cur_ptr
->nameandfmt
== NULL
)
2303 len
= snprintf(buf
, bufsize
, cur_ptr
->nameandfmt
,
2304 read_rtn(arg0
, arg1
, cur_ptr
->offset
));
2305 /* check for snprintf overflow or error */
2306 if (len
< 0 || (uint32
)len
>= bufsize
)
2317 bcm_mkiovar(const char *name
, const char *data
, uint datalen
, char *buf
, uint buflen
)
2321 len
= (uint
)strlen(name
) + 1;
2323 if ((len
+ datalen
) > buflen
)
2326 strncpy(buf
, name
, buflen
);
2328 /* append data onto the end of the name string */
2329 if (data
&& datalen
!= 0) {
2330 memcpy(&buf
[len
], data
, datalen
);
2337 /* Quarter dBm units to mW
2338 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
2339 * Table is offset so the last entry is largest mW value that fits in
2343 #define QDBM_OFFSET 153 /* Offset for first entry */
2344 #define QDBM_TABLE_LEN 40 /* Table size */
2346 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
2347 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
2349 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
2351 /* Largest mW value that will round down to the last table entry,
2352 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
2353 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
2355 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
2357 static const uint16 nqdBm_to_mW_map
[QDBM_TABLE_LEN
] = {
2358 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
2359 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
2360 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
2361 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
2362 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
2363 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
2367 bcm_qdbm_to_mw(uint8 qdbm
)
2370 int idx
= qdbm
- QDBM_OFFSET
;
2372 if (idx
>= QDBM_TABLE_LEN
) {
2373 /* clamp to max uint16 mW value */
2377 /* scale the qdBm index up to the range of the table 0-40
2378 * where an offset of 40 qdBm equals a factor of 10 mW.
2385 /* return the mW value scaled down to the correct factor of 10,
2386 * adding in factor/2 to get proper rounding.
2388 return ((nqdBm_to_mW_map
[idx
] + factor
/2) / factor
);
2392 bcm_mw_to_qdbm(uint16 mw
)
2399 /* handle boundary case */
2403 offset
= QDBM_OFFSET
;
2405 /* move mw into the range of the table */
2406 while (mw_uint
< QDBM_TABLE_LOW_BOUND
) {
2411 for (qdbm
= 0; qdbm
< QDBM_TABLE_LEN
-1; qdbm
++) {
2412 boundary
= nqdBm_to_mW_map
[qdbm
] + (nqdBm_to_mW_map
[qdbm
+1] -
2413 nqdBm_to_mW_map
[qdbm
])/2;
2414 if (mw_uint
< boundary
) break;
2417 qdbm
+= (uint8
)offset
;
2424 bcm_bitcount(uint8
*bitmap
, uint length
)
2426 uint bitcount
= 0, i
;
2428 for (i
= 0; i
< length
; i
++) {
2438 #if defined(BCMDRIVER) || defined(WL_UNITTEST)
2440 /* triggers bcm_bprintf to print to kernel log */
2441 bool bcm_bprintf_bypass
= FALSE
;
2443 /* Initialization of bcmstrbuf structure */
2445 bcm_binit(struct bcmstrbuf
*b
, char *buf
, uint size
)
2447 b
->origsize
= b
->size
= size
;
2448 b
->origbuf
= b
->buf
= buf
;
2451 /* Buffer sprintf wrapper to guard against buffer overflow */
2453 bcm_bprintf(struct bcmstrbuf
*b
, const char *fmt
, ...)
2460 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
2461 if (bcm_bprintf_bypass
== TRUE
) {
2462 printf("%s", b
->buf
);
2466 /* Non Ansi C99 compliant returns -1,
2467 * Ansi compliant return r >= b->size,
2468 * bcmstdlib returns 0, handle all
2470 /* r == 0 is also the case when strlen(fmt) is zero.
2471 * typically the case when "" is passed as argument.
2473 if ((r
== -1) || (r
>= (int)b
->size
)) {
2487 bcm_bprhex(struct bcmstrbuf
*b
, const char *msg
, bool newline
, const uint8
*buf
, int len
)
2491 if (msg
!= NULL
&& msg
[0] != '\0')
2492 bcm_bprintf(b
, "%s", msg
);
2493 for (i
= 0; i
< len
; i
++)
2494 bcm_bprintf(b
, "%02X", buf
[i
]);
2496 bcm_bprintf(b
, "\n");
2500 bcm_inc_bytes(uchar
*num
, int num_bytes
, uint8 amount
)
2504 for (i
= 0; i
< num_bytes
; i
++) {
2506 if (num
[i
] >= amount
)
2513 bcm_cmp_bytes(const uchar
*arg1
, const uchar
*arg2
, uint8 nbytes
)
2517 for (i
= nbytes
- 1; i
>= 0; i
--) {
2518 if (arg1
[i
] != arg2
[i
])
2519 return (arg1
[i
] - arg2
[i
]);
2525 bcm_print_bytes(const char *name
, const uchar
*data
, int len
)
2530 printf("%s: %d \n", name
? name
: "", len
);
2531 for (i
= 0; i
< len
; i
++) {
2532 printf("%02x ", *data
++);
2534 if (per_line
== 16) {
2542 /* Look for vendor-specific IE with specified OUI and optional type */
2544 bcm_find_vendor_ie(void *tlvs
, int tlvs_len
, const char *voui
, uint8
*type
, int type_len
)
2549 ie
= (bcm_tlv_t
*)tlvs
;
2551 /* make sure we are looking at a valid IE */
2552 if (ie
== NULL
|| !bcm_valid_tlv(ie
, tlvs_len
)) {
2556 /* Walk through the IEs looking for an OUI match */
2559 if ((ie
->id
== DOT11_MNG_PROPR_ID
) &&
2560 (ie_len
>= (DOT11_OUI_LEN
+ type_len
)) &&
2561 !bcmp(ie
->data
, voui
, DOT11_OUI_LEN
))
2563 /* compare optional type */
2564 if (type_len
== 0 ||
2565 !bcmp(&ie
->data
[DOT11_OUI_LEN
], type
, type_len
)) {
2566 return (ie
); /* a match */
2569 } while ((ie
= bcm_next_tlv(ie
, &tlvs_len
)) != NULL
);
2574 #if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
2575 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
2576 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
2579 bcm_format_ssid(char* buf
, const uchar ssid
[], uint ssid_len
)
2583 char *endp
= buf
+ SSID_FMT_BUF_LEN
;
2585 if (ssid_len
> DOT11_MAX_SSID_LEN
) ssid_len
= DOT11_MAX_SSID_LEN
;
2587 for (i
= 0; i
< ssid_len
; i
++) {
2592 } else if (bcm_isprint((uchar
)c
)) {
2595 p
+= snprintf(p
, (endp
- p
), "\\x%02X", c
);
2601 return (int)(p
- buf
);
2605 #endif /* BCMDRIVER || WL_UNITTEST */
2608 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
2609 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
2610 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
2611 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
2615 process_nvram_vars(char *varbuf
, unsigned int len
)
2620 unsigned int buf_len
, n
;
2621 unsigned int pad
= 0;
2626 findNewline
= FALSE
;
2629 // terence 20130914: print out NVRAM version
2630 if (varbuf
[0] == '#') {
2631 memset(nv_ver
, 0x00, sizeof(nv_ver
));
2632 for (n
=1; n
<len
&& n
<(sizeof(nv_ver
)-1); n
++) {
2633 if (varbuf
[n
] == '\n')
2635 nv_ver
[n
-1] = varbuf
[n
];
2637 printk("NVRAM version: %s\n", nv_ver
);
2640 for (n
= 0; n
< len
; n
++) {
2641 if (varbuf
[n
] == '\r')
2643 if (findNewline
&& varbuf
[n
] != '\n')
2645 findNewline
= FALSE
;
2646 if (varbuf
[n
] == '#') {
2650 if (varbuf
[n
] == '\n') {
2660 buf_len
= (unsigned int)(dp
- varbuf
);
2662 pad
= 4 - buf_len
% 4;
2663 if (pad
&& (buf_len
+ pad
<= len
)) {
2668 while (dp
< varbuf
+ n
)
2674 /* calculate a * b + c */
2676 bcm_uint64_multiple_add(uint32
* r_high
, uint32
* r_low
, uint32 a
, uint32 b
, uint32 c
)
2678 #define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;}
2680 uint32 a1
, a0
, b1
, b0
, t
, cc
= 0;
2690 t
= (a1
* b0
) << 16;
2696 t
= (a0
* b1
) << 16;
2707 r0
|= (cc
% 2) ? 0x80000000 : 0;
2708 r1
= a1
* b1
+ ((a1
* b0
) >> 16) + ((b1
* a0
) >> 16) + (cc
/ 2);
2714 /* calculate a / b */
2716 bcm_uint64_divide(uint32
* r
, uint32 a_high
, uint32 a_low
, uint32 b
)
2718 uint32 a1
= a_high
, a0
= a_low
, r0
= 0;
2724 r0
+= (0xffffffff / b
) * a1
;
2725 bcm_uint64_multiple_add(&a1
, &a0
, ((0xffffffff % b
) + 1) % b
, a1
, a0
);
2732 #ifndef setbit /* As in the header file */
2733 #ifdef BCMUTILS_BIT_MACROS_USE_FUNCS
2734 /* Set bit in byte array. */
2736 setbit(void *array
, uint bit
)
2738 ((uint8
*)array
)[bit
/ NBBY
] |= 1 << (bit
% NBBY
);
2741 /* Clear bit in byte array. */
2743 clrbit(void *array
, uint bit
)
2745 ((uint8
*)array
)[bit
/ NBBY
] &= ~(1 << (bit
% NBBY
));
2748 /* Test if bit is set in byte array. */
2750 isset(const void *array
, uint bit
)
2752 return (((const uint8
*)array
)[bit
/ NBBY
] & (1 << (bit
% NBBY
)));
2755 /* Test if bit is clear in byte array. */
2757 isclr(const void *array
, uint bit
)
2759 return ((((const uint8
*)array
)[bit
/ NBBY
] & (1 << (bit
% NBBY
))) == 0);
2761 #endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */
2765 set_bitrange(void *array
, uint start
, uint end
, uint maxbit
)
2767 uint startbyte
= start
/NBBY
;
2768 uint endbyte
= end
/NBBY
;
2769 uint i
, startbytelastbit
, endbytestartbit
;
2772 if (endbyte
- startbyte
> 1)
2774 startbytelastbit
= (startbyte
+1)*NBBY
- 1;
2775 endbytestartbit
= endbyte
*NBBY
;
2776 for (i
= startbyte
+1; i
< endbyte
; i
++)
2777 ((uint8
*)array
)[i
] = 0xFF;
2778 for (i
= start
; i
<= startbytelastbit
; i
++)
2780 for (i
= endbytestartbit
; i
<= end
; i
++)
2783 for (i
= start
; i
<= end
; i
++)
2788 set_bitrange(array
, start
, maxbit
, maxbit
);
2789 set_bitrange(array
, 0, end
, maxbit
);
2794 bcm_bitprint32(const uint32 u32arg
)
2797 for (i
= NBITS(uint32
) - 1; i
>= 0; i
--) {
2798 if (isbitset(u32arg
, i
)) {
2804 if ((i
% NBBY
) == 0) printf(" ");
2809 /* calculate checksum for ip header, tcp / udp header / data */
2811 bcm_ip_cksum(uint8
*buf
, uint32 len
, uint32 sum
)
2814 sum
+= (buf
[0] << 8) | buf
[1];
2824 sum
= (sum
& 0xffff) + (sum
>> 16);
2827 return ((uint16
)~sum
);
2829 #if defined(BCMDRIVER) && !defined(_CFEZ_)
2831 * Hierarchical Multiword bitmap based small id allocator.
2833 * Multilevel hierarchy bitmap. (maximum 2 levels)
2834 * First hierarchy uses a multiword bitmap to identify 32bit words in the
2835 * second hierarchy that have at least a single bit set. Each bit in a word of
2836 * the second hierarchy represents a unique ID that may be allocated.
2838 * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed.
2839 * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word
2840 * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs.
2841 * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non
2842 * non-zero bitmap word carrying at least one free ID.
2843 * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations.
2844 * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID
2847 * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many
2848 * bits are computed each time on allocation and deallocation, requiring 4
2849 * array indexed access and 3 arithmetic operations. When not defined, a runtime
2850 * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed.
2851 * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation.
2852 * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may
2853 * be used by defining BCM_MWBMAP_USE_CNTSETBITS.
2855 * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array
2856 * size is fixed. No intention to support larger than 4K indice allocation. ID
2857 * allocators for ranges smaller than 4K will have a wastage of only 12Bytes
2858 * with savings in not having to use an indirect access, had it been dynamically
2861 #define BCM_MWBMAP_ITEMS_MAX (64 * 1024) /* May increase to 64K */
2863 #define BCM_MWBMAP_BITS_WORD (NBITS(uint32))
2864 #define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD)
2865 #define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD)
2866 #define BCM_MWBMAP_SHIFT_OP (5)
2867 #define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1))
2868 #define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP)
2869 #define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP)
2871 /* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */
2872 #define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl))
2873 #define BCM_MWBMAP_HDL(ptr) ((void *)(ptr))
2875 #if defined(BCM_MWBMAP_DEBUG)
2876 #define BCM_MWBMAP_AUDIT(mwb) \
2878 ASSERT((mwb != NULL) && \
2879 (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \
2880 bcm_mwbmap_audit(mwb); \
2882 #define MWBMAP_ASSERT(exp) ASSERT(exp)
2883 #define MWBMAP_DBG(x) printf x
2884 #else /* !BCM_MWBMAP_DEBUG */
2885 #define BCM_MWBMAP_AUDIT(mwb) do {} while (0)
2886 #define MWBMAP_ASSERT(exp) do {} while (0)
2887 #define MWBMAP_DBG(x)
2888 #endif /* !BCM_MWBMAP_DEBUG */
2891 typedef struct bcm_mwbmap
{ /* Hierarchical multiword bitmap allocator */
2892 uint16 wmaps
; /* Total number of words in free wd bitmap */
2893 uint16 imaps
; /* Total number of words in free id bitmap */
2894 int32 ifree
; /* Count of free indices. Used only in audits */
2895 uint16 total
; /* Total indices managed by multiword bitmap */
2897 void * magic
; /* Audit handle parameter from user */
2899 uint32 wd_bitmap
[BCM_MWBMAP_WDMAP_MAX
]; /* 1st level bitmap of */
2900 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2901 int8 wd_count
[BCM_MWBMAP_WORDS_MAX
]; /* free id running count, 1st lvl */
2902 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2904 uint32 id_bitmap
[0]; /* Second level bitmap */
2907 /* Incarnate a hierarchical multiword bitmap based small index allocator. */
2909 bcm_mwbmap_init(osl_t
*osh
, uint32 items_max
)
2911 struct bcm_mwbmap
* mwbmap_p
;
2912 uint32 wordix
, size
, words
, extra
;
2914 /* Implementation Constraint: Uses 32bit word bitmap */
2915 MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD
== 32U);
2916 MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP
== 5U);
2917 MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX
));
2918 MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX
% BCM_MWBMAP_BITS_WORD
) == 0U);
2920 ASSERT(items_max
<= BCM_MWBMAP_ITEMS_MAX
);
2922 /* Determine the number of words needed in the multiword bitmap */
2923 extra
= BCM_MWBMAP_MODOP(items_max
);
2924 words
= BCM_MWBMAP_DIVOP(items_max
) + ((extra
!= 0U) ? 1U : 0U);
2926 /* Allocate runtime state of multiword bitmap */
2927 /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */
2928 size
= sizeof(bcm_mwbmap_t
) + (sizeof(uint32
) * words
);
2929 mwbmap_p
= (bcm_mwbmap_t
*)MALLOC(osh
, size
);
2930 if (mwbmap_p
== (bcm_mwbmap_t
*)NULL
) {
2934 memset(mwbmap_p
, 0, size
);
2936 /* Initialize runtime multiword bitmap state */
2937 mwbmap_p
->imaps
= (uint16
)words
;
2938 mwbmap_p
->ifree
= (int32
)items_max
;
2939 mwbmap_p
->total
= (uint16
)items_max
;
2941 /* Setup magic, for use in audit of handle */
2942 mwbmap_p
->magic
= BCM_MWBMAP_HDL(mwbmap_p
);
2944 /* Setup the second level bitmap of free indices */
2945 /* Mark all indices as available */
2946 for (wordix
= 0U; wordix
< mwbmap_p
->imaps
; wordix
++) {
2947 mwbmap_p
->id_bitmap
[wordix
] = (uint32
)(~0U);
2948 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2949 mwbmap_p
->wd_count
[wordix
] = BCM_MWBMAP_BITS_WORD
;
2950 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2953 /* Ensure that extra indices are tagged as un-available */
2954 if (extra
) { /* fixup the free ids in last bitmap and wd_count */
2955 uint32
* bmap_p
= &mwbmap_p
->id_bitmap
[mwbmap_p
->imaps
- 1];
2956 *bmap_p
^= (uint32
)(~0U << extra
); /* fixup bitmap */
2957 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2958 mwbmap_p
->wd_count
[mwbmap_p
->imaps
- 1] = (int8
)extra
; /* fixup count */
2959 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2962 /* Setup the first level bitmap hierarchy */
2963 extra
= BCM_MWBMAP_MODOP(mwbmap_p
->imaps
);
2964 words
= BCM_MWBMAP_DIVOP(mwbmap_p
->imaps
) + ((extra
!= 0U) ? 1U : 0U);
2966 mwbmap_p
->wmaps
= (uint16
)words
;
2968 for (wordix
= 0U; wordix
< mwbmap_p
->wmaps
; wordix
++)
2969 mwbmap_p
->wd_bitmap
[wordix
] = (uint32
)(~0U);
2971 uint32
* bmap_p
= &mwbmap_p
->wd_bitmap
[mwbmap_p
->wmaps
- 1];
2972 *bmap_p
^= (uint32
)(~0U << extra
); /* fixup bitmap */
2978 return BCM_MWBMAP_INVALID_HDL
;
2981 /* Release resources used by multiword bitmap based small index allocator. */
2983 bcm_mwbmap_fini(osl_t
* osh
, struct bcm_mwbmap
* mwbmap_hdl
)
2985 bcm_mwbmap_t
* mwbmap_p
;
2987 BCM_MWBMAP_AUDIT(mwbmap_hdl
);
2988 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
2990 MFREE(osh
, mwbmap_p
, sizeof(struct bcm_mwbmap
)
2991 + (sizeof(uint32
) * mwbmap_p
->imaps
));
2995 /* Allocate a unique small index using a multiword bitmap index allocator. */
2997 bcm_mwbmap_alloc(struct bcm_mwbmap
* mwbmap_hdl
)
2999 bcm_mwbmap_t
* mwbmap_p
;
3000 uint32 wordix
, bitmap
;
3002 BCM_MWBMAP_AUDIT(mwbmap_hdl
);
3003 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
3005 /* Start with the first hierarchy */
3006 for (wordix
= 0; wordix
< mwbmap_p
->wmaps
; ++wordix
) {
3008 bitmap
= mwbmap_p
->wd_bitmap
[wordix
]; /* get the word bitmap */
3012 uint32 count
, bitix
, *bitmap_p
;
3014 bitmap_p
= &mwbmap_p
->wd_bitmap
[wordix
];
3016 /* clear all except trailing 1 */
3017 bitmap
= (uint32
)(((int)(bitmap
)) & (-((int)(bitmap
))));
3018 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap
) ==
3019 bcm_count_leading_zeros(bitmap
));
3020 bitix
= (BCM_MWBMAP_BITS_WORD
- 1)
3021 - bcm_count_leading_zeros(bitmap
); /* use asm clz */
3022 wordix
= BCM_MWBMAP_MULOP(wordix
) + bitix
;
3024 /* Clear bit if wd count is 0, without conditional branch */
3025 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3026 count
= bcm_cntsetbits(mwbmap_p
->id_bitmap
[wordix
]) - 1;
3027 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3028 mwbmap_p
->wd_count
[wordix
]--;
3029 count
= mwbmap_p
->wd_count
[wordix
];
3030 MWBMAP_ASSERT(count
==
3031 (bcm_cntsetbits(mwbmap_p
->id_bitmap
[wordix
]) - 1));
3032 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3033 MWBMAP_ASSERT(count
>= 0);
3035 /* clear wd_bitmap bit if id_map count is 0 */
3036 bitmap
= (count
== 0) << bitix
;
3039 "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
3040 bitix
, wordix
, *bitmap_p
, bitmap
, (*bitmap_p
) ^ bitmap
, count
));
3042 *bitmap_p
^= bitmap
;
3044 /* Use bitix in the second hierarchy */
3045 bitmap_p
= &mwbmap_p
->id_bitmap
[wordix
];
3047 bitmap
= mwbmap_p
->id_bitmap
[wordix
]; /* get the id bitmap */
3048 MWBMAP_ASSERT(bitmap
!= 0U);
3050 /* clear all except trailing 1 */
3051 bitmap
= (uint32
)(((int)(bitmap
)) & (-((int)(bitmap
))));
3052 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap
) ==
3053 bcm_count_leading_zeros(bitmap
));
3054 bitix
= BCM_MWBMAP_MULOP(wordix
)
3055 + (BCM_MWBMAP_BITS_WORD
- 1)
3056 - bcm_count_leading_zeros(bitmap
); /* use asm clz */
3058 mwbmap_p
->ifree
--; /* decrement system wide free count */
3059 MWBMAP_ASSERT(mwbmap_p
->ifree
>= 0);
3062 "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d",
3063 bitix
, wordix
, *bitmap_p
, bitmap
, (*bitmap_p
) ^ bitmap
,
3066 *bitmap_p
^= bitmap
; /* mark as allocated = 1b0 */
3072 ASSERT(mwbmap_p
->ifree
== 0);
3074 return BCM_MWBMAP_INVALID_IDX
;
3077 /* Force an index at a specified position to be in use */
3079 bcm_mwbmap_force(struct bcm_mwbmap
* mwbmap_hdl
, uint32 bitix
)
3081 bcm_mwbmap_t
* mwbmap_p
;
3082 uint32 count
, wordix
, bitmap
, *bitmap_p
;
3084 BCM_MWBMAP_AUDIT(mwbmap_hdl
);
3085 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
3087 ASSERT(bitix
< mwbmap_p
->total
);
3089 /* Start with second hierarchy */
3090 wordix
= BCM_MWBMAP_DIVOP(bitix
);
3091 bitmap
= (uint32
)(1U << BCM_MWBMAP_MODOP(bitix
));
3092 bitmap_p
= &mwbmap_p
->id_bitmap
[wordix
];
3094 ASSERT((*bitmap_p
& bitmap
) == bitmap
);
3096 mwbmap_p
->ifree
--; /* update free count */
3097 ASSERT(mwbmap_p
->ifree
>= 0);
3099 MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d",
3100 bitix
, wordix
, *bitmap_p
, bitmap
, (*bitmap_p
) ^ bitmap
,
3103 *bitmap_p
^= bitmap
; /* mark as in use */
3105 /* Update first hierarchy */
3108 wordix
= BCM_MWBMAP_DIVOP(bitix
);
3109 bitmap_p
= &mwbmap_p
->wd_bitmap
[wordix
];
3111 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3112 count
= bcm_cntsetbits(mwbmap_p
->id_bitmap
[bitix
]);
3113 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3114 mwbmap_p
->wd_count
[bitix
]--;
3115 count
= mwbmap_p
->wd_count
[bitix
];
3116 MWBMAP_ASSERT(count
== bcm_cntsetbits(mwbmap_p
->id_bitmap
[bitix
]));
3117 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3118 MWBMAP_ASSERT(count
>= 0);
3120 bitmap
= (count
== 0) << BCM_MWBMAP_MODOP(bitix
);
3122 MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
3123 BCM_MWBMAP_MODOP(bitix
), wordix
, *bitmap_p
, bitmap
,
3124 (*bitmap_p
) ^ bitmap
, count
));
3126 *bitmap_p
^= bitmap
; /* mark as in use */
3131 /* Free a previously allocated index back into the multiword bitmap allocator */
3133 bcm_mwbmap_free(struct bcm_mwbmap
* mwbmap_hdl
, uint32 bitix
)
3135 bcm_mwbmap_t
* mwbmap_p
;
3136 uint32 wordix
, bitmap
, *bitmap_p
;
3138 BCM_MWBMAP_AUDIT(mwbmap_hdl
);
3139 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
3141 ASSERT(bitix
< mwbmap_p
->total
);
3143 /* Start with second level hierarchy */
3144 wordix
= BCM_MWBMAP_DIVOP(bitix
);
3145 bitmap
= (1U << BCM_MWBMAP_MODOP(bitix
));
3146 bitmap_p
= &mwbmap_p
->id_bitmap
[wordix
];
3148 ASSERT((*bitmap_p
& bitmap
) == 0U); /* ASSERT not a double free */
3150 mwbmap_p
->ifree
++; /* update free count */
3151 ASSERT(mwbmap_p
->ifree
<= mwbmap_p
->total
);
3153 MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d",
3154 bitix
, wordix
, *bitmap_p
, bitmap
, (*bitmap_p
) | bitmap
,
3157 *bitmap_p
|= bitmap
; /* mark as available */
3159 /* Now update first level hierarchy */
3163 wordix
= BCM_MWBMAP_DIVOP(bitix
); /* first level's word index */
3164 bitmap
= (1U << BCM_MWBMAP_MODOP(bitix
));
3165 bitmap_p
= &mwbmap_p
->wd_bitmap
[wordix
];
3167 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
3168 mwbmap_p
->wd_count
[bitix
]++;
3171 #if defined(BCM_MWBMAP_DEBUG)
3174 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3175 count
= bcm_cntsetbits(mwbmap_p
->id_bitmap
[bitix
]);
3176 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3177 count
= mwbmap_p
->wd_count
[bitix
];
3178 MWBMAP_ASSERT(count
== bcm_cntsetbits(mwbmap_p
->id_bitmap
[bitix
]));
3179 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3181 MWBMAP_ASSERT(count
<= BCM_MWBMAP_BITS_WORD
);
3183 MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d",
3184 bitix
, wordix
, *bitmap_p
, bitmap
, (*bitmap_p
) | bitmap
, count
));
3186 #endif /* BCM_MWBMAP_DEBUG */
3188 *bitmap_p
|= bitmap
;
3193 /* Fetch the toal number of free indices in the multiword bitmap allocator */
3195 bcm_mwbmap_free_cnt(struct bcm_mwbmap
* mwbmap_hdl
)
3197 bcm_mwbmap_t
* mwbmap_p
;
3199 BCM_MWBMAP_AUDIT(mwbmap_hdl
);
3200 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
3202 ASSERT(mwbmap_p
->ifree
>= 0);
3204 return mwbmap_p
->ifree
;
3207 /* Determine whether an index is inuse or free */
3209 bcm_mwbmap_isfree(struct bcm_mwbmap
* mwbmap_hdl
, uint32 bitix
)
3211 bcm_mwbmap_t
* mwbmap_p
;
3212 uint32 wordix
, bitmap
;
3214 BCM_MWBMAP_AUDIT(mwbmap_hdl
);
3215 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
3217 ASSERT(bitix
< mwbmap_p
->total
);
3219 wordix
= BCM_MWBMAP_DIVOP(bitix
);
3220 bitmap
= (1U << BCM_MWBMAP_MODOP(bitix
));
3222 return ((mwbmap_p
->id_bitmap
[wordix
] & bitmap
) != 0U);
3225 /* Debug dump a multiword bitmap allocator */
3227 bcm_mwbmap_show(struct bcm_mwbmap
* mwbmap_hdl
)
3230 bcm_mwbmap_t
* mwbmap_p
;
3232 BCM_MWBMAP_AUDIT(mwbmap_hdl
);
3233 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
3235 printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p
,
3236 mwbmap_p
->wmaps
, mwbmap_p
->imaps
, mwbmap_p
->ifree
, mwbmap_p
->total
);
3237 for (ix
= 0U; ix
< mwbmap_p
->wmaps
; ix
++) {
3238 printf("\tWDMAP:%2u. 0x%08x\t", ix
, mwbmap_p
->wd_bitmap
[ix
]);
3239 bcm_bitprint32(mwbmap_p
->wd_bitmap
[ix
]);
3242 for (ix
= 0U; ix
< mwbmap_p
->imaps
; ix
++) {
3243 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3244 count
= bcm_cntsetbits(mwbmap_p
->id_bitmap
[ix
]);
3245 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3246 count
= mwbmap_p
->wd_count
[ix
];
3247 MWBMAP_ASSERT(count
== bcm_cntsetbits(mwbmap_p
->id_bitmap
[ix
]));
3248 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3249 printf("\tIDMAP:%2u. 0x%08x %02u\t", ix
, mwbmap_p
->id_bitmap
[ix
], count
);
3250 bcm_bitprint32(mwbmap_p
->id_bitmap
[ix
]);
3257 /* Audit a hierarchical multiword bitmap */
3259 bcm_mwbmap_audit(struct bcm_mwbmap
* mwbmap_hdl
)
3261 bcm_mwbmap_t
* mwbmap_p
;
3262 uint32 count
, free_cnt
= 0U, wordix
, idmap_ix
, bitix
, *bitmap_p
;
3264 mwbmap_p
= BCM_MWBMAP_PTR(mwbmap_hdl
);
3266 for (wordix
= 0U; wordix
< mwbmap_p
->wmaps
; ++wordix
) {
3268 bitmap_p
= &mwbmap_p
->wd_bitmap
[wordix
];
3270 for (bitix
= 0U; bitix
< BCM_MWBMAP_BITS_WORD
; bitix
++) {
3271 if ((*bitmap_p
) & (1 << bitix
)) {
3272 idmap_ix
= BCM_MWBMAP_MULOP(wordix
) + bitix
;
3273 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3274 count
= bcm_cntsetbits(mwbmap_p
->id_bitmap
[idmap_ix
]);
3275 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3276 count
= mwbmap_p
->wd_count
[idmap_ix
];
3277 ASSERT(count
== bcm_cntsetbits(mwbmap_p
->id_bitmap
[idmap_ix
]));
3278 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3279 ASSERT(count
!= 0U);
3285 ASSERT((int)free_cnt
== mwbmap_p
->ifree
);
3287 /* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
3289 /* Simple 16bit Id allocator using a stack implementation. */
3290 typedef struct id16_map
{
3291 uint32 failures
; /* count of failures */
3292 void *dbg
; /* debug placeholder */
3293 uint16 total
; /* total number of ids managed by allocator */
3294 uint16 start
; /* start value of 16bit ids to be managed */
3295 int stack_idx
; /* index into stack of available ids */
3296 uint16 stack
[0]; /* stack of 16 bit ids */
3299 #define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \
3300 (sizeof(uint16) * (items)))
3302 #if defined(BCM_DBG)
3304 /* Uncomment BCM_DBG_ID16 to debug double free */
3305 /* #define BCM_DBG_ID16 */
3307 typedef struct id16_map_dbg
{
3311 #define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \
3312 (sizeof(bool) * (items)))
3313 #define ID16_MAP_MSG(x) print x
3315 #define ID16_MAP_MSG(x)
3316 #endif /* BCM_DBG */
3318 void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */
3319 id16_map_init(osl_t
*osh
, uint16 total_ids
, uint16 start_val16
)
3322 id16_map_t
* id16_map
;
3324 ASSERT(total_ids
> 0);
3326 /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
3327 * with random values.
3329 ASSERT((start_val16
== ID16_UNDEFINED
) ||
3330 (start_val16
+ total_ids
) < ID16_INVALID
);
3332 id16_map
= (id16_map_t
*) MALLOC(osh
, ID16_MAP_SZ(total_ids
));
3333 if (id16_map
== NULL
) {
3337 id16_map
->total
= total_ids
;
3338 id16_map
->start
= start_val16
;
3339 id16_map
->failures
= 0;
3340 id16_map
->dbg
= NULL
;
3343 * Populate stack with 16bit id values, commencing with start_val16.
3344 * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map.
3346 id16_map
->stack_idx
= -1;
3348 if (id16_map
->start
!= ID16_UNDEFINED
) {
3349 val16
= start_val16
;
3351 for (idx
= 0; idx
< total_ids
; idx
++, val16
++) {
3352 id16_map
->stack_idx
= idx
;
3353 id16_map
->stack
[id16_map
->stack_idx
] = val16
;
3357 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3358 if (id16_map
->start
!= ID16_UNDEFINED
) {
3359 id16_map
->dbg
= MALLOC(osh
, ID16_MAP_DBG_SZ(total_ids
));
3361 if (id16_map
->dbg
) {
3362 id16_map_dbg_t
*id16_map_dbg
= (id16_map_dbg_t
*)id16_map
->dbg
;
3364 id16_map_dbg
->total
= total_ids
;
3365 for (idx
= 0; idx
< total_ids
; idx
++) {
3366 id16_map_dbg
->avail
[idx
] = TRUE
;
3370 #endif /* BCM_DBG && BCM_DBG_ID16 */
3372 return (void *)id16_map
;
3375 void * /* Destruct an id16 allocator instance */
3376 id16_map_fini(osl_t
*osh
, void * id16_map_hndl
)
3379 id16_map_t
* id16_map
;
3381 if (id16_map_hndl
== NULL
)
3384 id16_map
= (id16_map_t
*)id16_map_hndl
;
3386 total_ids
= id16_map
->total
;
3387 ASSERT(total_ids
> 0);
3389 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3390 if (id16_map
->dbg
) {
3391 MFREE(osh
, id16_map
->dbg
, ID16_MAP_DBG_SZ(total_ids
));
3392 id16_map
->dbg
= NULL
;
3394 #endif /* BCM_DBG && BCM_DBG_ID16 */
3396 id16_map
->total
= 0;
3397 MFREE(osh
, id16_map
, ID16_MAP_SZ(total_ids
));
3403 id16_map_clear(void * id16_map_hndl
, uint16 total_ids
, uint16 start_val16
)
3406 id16_map_t
* id16_map
;
3408 ASSERT(total_ids
> 0);
3409 /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
3410 * with random values.
3412 ASSERT((start_val16
== ID16_UNDEFINED
) ||
3413 (start_val16
+ total_ids
) < ID16_INVALID
);
3415 id16_map
= (id16_map_t
*)id16_map_hndl
;
3416 if (id16_map
== NULL
) {
3420 id16_map
->total
= total_ids
;
3421 id16_map
->start
= start_val16
;
3422 id16_map
->failures
= 0;
3424 /* Populate stack with 16bit id values, commencing with start_val16 */
3425 id16_map
->stack_idx
= -1;
3427 if (id16_map
->start
!= ID16_UNDEFINED
) {
3428 val16
= start_val16
;
3430 for (idx
= 0; idx
< total_ids
; idx
++, val16
++) {
3431 id16_map
->stack_idx
= idx
;
3432 id16_map
->stack
[id16_map
->stack_idx
] = val16
;
3436 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3437 if (id16_map
->start
!= ID16_UNDEFINED
) {
3438 if (id16_map
->dbg
) {
3439 id16_map_dbg_t
*id16_map_dbg
= (id16_map_dbg_t
*)id16_map
->dbg
;
3441 id16_map_dbg
->total
= total_ids
;
3442 for (idx
= 0; idx
< total_ids
; idx
++) {
3443 id16_map_dbg
->avail
[idx
] = TRUE
;
3447 #endif /* BCM_DBG && BCM_DBG_ID16 */
3450 uint16 BCMFASTPATH
/* Allocate a unique 16bit id */
3451 id16_map_alloc(void * id16_map_hndl
)
3454 id16_map_t
* id16_map
;
3456 ASSERT(id16_map_hndl
!= NULL
);
3458 id16_map
= (id16_map_t
*)id16_map_hndl
;
3460 ASSERT(id16_map
->total
> 0);
3462 if (id16_map
->stack_idx
< 0) {
3463 id16_map
->failures
++;
3464 return ID16_INVALID
;
3467 val16
= id16_map
->stack
[id16_map
->stack_idx
];
3468 id16_map
->stack_idx
--;
3470 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3471 ASSERT((id16_map
->start
== ID16_UNDEFINED
) ||
3472 (val16
< (id16_map
->start
+ id16_map
->total
)));
3474 if (id16_map
->dbg
) { /* Validate val16 */
3475 id16_map_dbg_t
*id16_map_dbg
= (id16_map_dbg_t
*)id16_map
->dbg
;
3477 ASSERT(id16_map_dbg
->avail
[val16
- id16_map
->start
] == TRUE
);
3478 id16_map_dbg
->avail
[val16
- id16_map
->start
] = FALSE
;
3480 #endif /* BCM_DBG && BCM_DBG_ID16 */
3486 void BCMFASTPATH
/* Free a 16bit id value into the id16 allocator */
3487 id16_map_free(void * id16_map_hndl
, uint16 val16
)
3489 id16_map_t
* id16_map
;
3491 ASSERT(id16_map_hndl
!= NULL
);
3493 id16_map
= (id16_map_t
*)id16_map_hndl
;
3495 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3496 ASSERT((id16_map
->start
== ID16_UNDEFINED
) ||
3497 (val16
< (id16_map
->start
+ id16_map
->total
)));
3499 if (id16_map
->dbg
) { /* Validate val16 */
3500 id16_map_dbg_t
*id16_map_dbg
= (id16_map_dbg_t
*)id16_map
->dbg
;
3502 ASSERT(id16_map_dbg
->avail
[val16
- id16_map
->start
] == FALSE
);
3503 id16_map_dbg
->avail
[val16
- id16_map
->start
] = TRUE
;
3505 #endif /* BCM_DBG && BCM_DBG_ID16 */
3507 id16_map
->stack_idx
++;
3508 id16_map
->stack
[id16_map
->stack_idx
] = val16
;
3511 uint32
/* Returns number of failures to allocate an unique id16 */
3512 id16_map_failures(void * id16_map_hndl
)
3514 ASSERT(id16_map_hndl
!= NULL
);
3515 return ((id16_map_t
*)id16_map_hndl
)->failures
;
3519 id16_map_audit(void * id16_map_hndl
)
3523 id16_map_t
* id16_map
;
3525 ASSERT(id16_map_hndl
!= NULL
);
3527 id16_map
= (id16_map_t
*)id16_map_hndl
;
3529 ASSERT(id16_map
->stack_idx
>= -1);
3530 ASSERT(id16_map
->stack_idx
< (int)id16_map
->total
);
3532 if (id16_map
->start
== ID16_UNDEFINED
)
3535 for (idx
= 0; idx
<= id16_map
->stack_idx
; idx
++) {
3536 ASSERT(id16_map
->stack
[idx
] >= id16_map
->start
);
3537 ASSERT(id16_map
->stack
[idx
] < (id16_map
->start
+ id16_map
->total
));
3539 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3540 if (id16_map
->dbg
) {
3541 uint16 val16
= id16_map
->stack
[idx
];
3542 if (((id16_map_dbg_t
*)(id16_map
->dbg
))->avail
[val16
] != TRUE
) {
3544 ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n",
3545 id16_map_hndl
, idx
, val16
));
3548 #endif /* BCM_DBG && BCM_DBG_ID16 */
3551 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3552 if (id16_map
->dbg
) {
3553 uint16 avail
= 0; /* Audit available ids counts */
3554 for (idx
= 0; idx
< id16_map_dbg
->total
; idx
++) {
3555 if (((id16_map_dbg_t
*)(id16_map
->dbg
))->avail
[idx16
] == TRUE
)
3558 if (avail
&& (avail
!= (id16_map
->stack_idx
+ 1))) {
3560 ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n",
3561 id16_map_hndl
, avail
, id16_map
->stack_idx
));
3564 #endif /* BCM_DBG && BCM_DBG_ID16 */
3567 /* invoke any other system audits */
3570 /* END: Simple id16 allocator */
3575 /* calculate a >> b; and returns only lower 32 bits */
3577 bcm_uint64_right_shift(uint32
* r
, uint32 a_high
, uint32 a_low
, uint32 b
)
3579 uint32 a1
= a_high
, a0
= a_low
, r0
= 0;
3589 a1
= a1
& ((1 << b
) - 1);
3590 a1
= a1
<< (32 - b
);
3595 r0
= a1
>> (b
- 32);
3602 /* calculate a + b where a is a 64 bit number and b is a 32 bit number */
3604 bcm_add_64(uint32
* r_hi
, uint32
* r_lo
, uint32 offset
)
3606 uint32 r1_lo
= *r_lo
;
3612 /* calculate a - b where a is a 64 bit number and b is a 32 bit number */
3614 bcm_sub_64(uint32
* r_hi
, uint32
* r_lo
, uint32 offset
)
3616 uint32 r1_lo
= *r_lo
;
3622 /* Does unsigned 64 bit fixed point multiplication */
3624 fp_mult_64(uint64 val1
, uint64 val2
, uint8 nf1
, uint8 nf2
, uint8 nf_res
)
3626 uint64 mult_out_tmp
, mult_out
, rnd_val
;
3629 shift_amt
= nf1
+ nf2
- nf_res
;
3630 /* 0.5 in 1.0.shift_amt */
3631 rnd_val
= bcm_shl_64(1, (shift_amt
- 1));
3632 rnd_val
= (shift_amt
== 0) ? 0 : rnd_val
;
3633 mult_out_tmp
= (uint64
)((uint64
)val1
* (uint64
)val2
) + (uint64
)rnd_val
;
3634 mult_out
= bcm_shr_64(mult_out_tmp
, shift_amt
);
3640 /* Does unsigned 64 bit by 32 bit fixed point division */
3642 fp_div_64(uint64 num
, uint32 den
, uint8 nf_num
, uint8 nf_den
, uint32
*div_out
)
3644 uint8 shift_amt1
, shift_amt2
, shift_amt
, nf_res
, hd_rm_nr
, hd_rm_dr
;
3645 uint32 num_hi
, num_lo
;
3648 /* Worst case shift possible */
3649 hd_rm_nr
= fp_calc_head_room_64(num
);
3650 hd_rm_dr
= fp_calc_head_room_32(den
);
3652 /* (Nr / Dr) <= 2^32 */
3653 shift_amt1
= hd_rm_nr
- hd_rm_dr
- 1;
3654 /* Shift <= 32 + N2 - N1 */
3655 shift_amt2
= 31 + nf_den
- nf_num
;
3656 shift_amt
= MINIMUM(shift_amt1
, shift_amt2
);
3658 /* Scale numerator */
3659 num_scale
= bcm_shl_64(num
, shift_amt
);
3662 num_hi
= (uint32
)((uint64
)num_scale
>> 32) & MASK_32_BITS
;
3663 num_lo
= (uint32
)(num_scale
& MASK_32_BITS
);
3664 bcm_uint64_divide(div_out
, num_hi
, num_lo
, den
);
3667 nf_res
= nf_num
- nf_den
+ shift_amt
;
3671 /* Finds the number of bits available for shifting in unsigned 64 bit number */
3673 fp_calc_head_room_64(uint64 num
)
3675 uint8 n_room_bits
= 0, msb_pos
;
3676 uint32 num_hi
, num_lo
, x
;
3678 num_hi
= (uint32
)((uint64
)num
>> 32) & MASK_32_BITS
;
3679 num_lo
= (uint32
)(num
& MASK_32_BITS
);
3689 msb_pos
= (x
>> 16) ? ((x
>> 24) ? (24 + msb_table
[(x
>> 24) & MASK_8_BITS
])
3690 : (16 + msb_table
[(x
>> 16) & MASK_8_BITS
]))
3691 : ((x
>> 8) ? (8 + msb_table
[(x
>> 8) & MASK_8_BITS
])
3692 : msb_table
[x
& MASK_8_BITS
]);
3694 return (n_room_bits
+ 32 - msb_pos
);
3697 /* Finds the number of bits available for shifting in unsigned 32 bit number */
3699 fp_calc_head_room_32(uint32 x
)
3703 msb_pos
= (x
>> 16) ? ((x
>> 24) ? (24 + msb_table
[(x
>> 24) & MASK_8_BITS
])
3704 : (16 + msb_table
[(x
>> 16) & MASK_8_BITS
]))
3705 : ((x
>> 8) ? (8 + msb_table
[(x
>> 8) & MASK_8_BITS
])
3706 : msb_table
[x
& MASK_8_BITS
]);
3708 return (32 - msb_pos
);
3711 /* Does unsigned 64 bit fixed point floor */
3713 fp_floor_64(uint64 num
, uint8 floor_pos
)
3717 floor_out
= (uint32
)bcm_shr_64(num
, floor_pos
);
3722 /* Does unsigned 32 bit fixed point floor */
3724 fp_floor_32(uint32 num
, uint8 floor_pos
)
3726 return num
>> floor_pos
;
3729 /* Does unsigned 64 bit fixed point rounding */
3731 fp_round_64(uint64 num
, uint8 rnd_pos
)
3733 uint64 rnd_val
, rnd_out_tmp
;
3736 /* 0.5 in 1.0.rnd_pos */
3737 rnd_val
= bcm_shl_64(1, (rnd_pos
- 1));
3738 rnd_val
= (rnd_pos
== 0) ? 0 : rnd_val
;
3739 rnd_out_tmp
= num
+ rnd_val
;
3740 rnd_out
= (uint32
)bcm_shr_64(rnd_out_tmp
, rnd_pos
);
3745 /* Does unsigned 32 bit fixed point rounding */
3747 fp_round_32(uint32 num
, uint8 rnd_pos
)
3749 uint32 rnd_val
, rnd_out_tmp
;
3751 /* 0.5 in 1.0.rnd_pos */
3752 rnd_val
= 1 << (rnd_pos
- 1);
3753 rnd_val
= (rnd_pos
== 0) ? 0 : rnd_val
;
3754 rnd_out_tmp
= num
+ rnd_val
;
3755 return (rnd_out_tmp
>> rnd_pos
);
3758 /* Does unsigned fixed point ceiling */
3760 fp_ceil_64(uint64 num
, uint8 ceil_pos
)
3762 uint64 ceil_val
, ceil_out_tmp
;
3765 /* 0.999 in 1.0.rnd_pos */
3766 ceil_val
= bcm_shl_64(1, ceil_pos
) - 1;
3767 ceil_out_tmp
= num
+ ceil_val
;
3768 ceil_out
= (uint32
)bcm_shr_64(ceil_out_tmp
, ceil_pos
);
3773 /* Does left shift of unsigned 64 bit number */
3775 bcm_shl_64(uint64 input
, uint8 shift_amt
)
3777 uint32 in_hi
, in_lo
;
3778 uint32 masked_lo
= 0;
3782 if (shift_amt
== 0) {
3786 /* Get hi and lo part */
3787 in_hi
= (uint32
)((uint64
)input
>> 32) & MASK_32_BITS
;
3788 in_lo
= (uint32
)(input
& MASK_32_BITS
);
3790 if (shift_amt
< 32) {
3791 /* Extract bit which belongs to hi part after shifting */
3792 mask
= ((uint32
)~0) << (32 - shift_amt
);
3793 masked_lo
= (in_lo
& mask
) >> (32 - shift_amt
);
3795 /* Shift hi and lo and prepare output */
3796 in_hi
= (in_hi
<< shift_amt
) | masked_lo
;
3797 in_lo
= in_lo
<< shift_amt
;
3799 /* Extract bit which belongs to hi part after shifting */
3800 shift_amt
= shift_amt
- 32;
3802 /* Shift hi and lo and prepare output */
3803 in_hi
= in_lo
<< shift_amt
;
3807 shl_out
= (((uint64
)in_hi
<< 32) | in_lo
);
3811 /* Does right shift of unsigned 64 bit number */
3813 bcm_shr_64(uint64 input
, uint8 shift_amt
)
3815 uint32 in_hi
, in_lo
;
3816 uint32 masked_hi
= 0;
3820 if (shift_amt
== 0) {
3824 /* Get hi and lo part */
3825 in_hi
= (uint32
)((uint64
)input
>> 32) & MASK_32_BITS
;
3826 in_lo
= (uint32
)(input
& MASK_32_BITS
);
3828 if (shift_amt
< 32) {
3829 /* Extract bit which belongs to lo part after shifting */
3830 mask
= (1 << shift_amt
) - 1;
3831 masked_hi
= in_hi
& mask
;
3833 /* Shift hi and lo and prepare output */
3834 in_hi
= (uint32
)in_hi
>> shift_amt
;
3835 in_lo
= ((uint32
)in_lo
>> shift_amt
) | (masked_hi
<< (32 - shift_amt
));
3837 shift_amt
= shift_amt
- 32;
3838 in_lo
= in_hi
>> shift_amt
;
3842 shr_out
= (((uint64
)in_hi
<< 32) | in_lo
);
3846 #ifdef DEBUG_COUNTER
3847 #if (OSL_SYSUPTIME_SUPPORT == TRUE)
3848 void counter_printlog(counter_tbl_t
*ctr_tbl
)
3852 if (!ctr_tbl
->enabled
)
3855 now
= OSL_SYSUPTIME();
3857 if (now
- ctr_tbl
->prev_log_print
> ctr_tbl
->log_print_interval
) {
3859 printf("counter_print(%s %d):", ctr_tbl
->name
, now
- ctr_tbl
->prev_log_print
);
3861 for (i
= 0; i
< ctr_tbl
->needed_cnt
; i
++) {
3862 printf(" %u", ctr_tbl
->cnt
[i
]);
3866 ctr_tbl
->prev_log_print
= now
;
3867 bzero(ctr_tbl
->cnt
, CNTR_TBL_MAX
* sizeof(uint
));
3871 /* OSL_SYSUPTIME is not supported so no way to get time */
3872 #define counter_printlog(a) do {} while (0)
3873 #endif /* OSL_SYSUPTIME_SUPPORT == TRUE */
3874 #endif /* DEBUG_COUNTER */
3876 #if defined(BCMDRIVER) && !defined(_CFEZ_)
3878 dll_pool_detach(void * osh
, dll_pool_t
* pool
, uint16 elems_max
, uint16 elem_size
)
3881 mem_size
= sizeof(dll_pool_t
) + (elems_max
* elem_size
);
3883 MFREE(osh
, pool
, mem_size
);
3886 dll_pool_init(void * osh
, uint16 elems_max
, uint16 elem_size
)
3889 dll_pool_t
* dll_pool_p
;
3892 ASSERT(elem_size
> sizeof(dll_t
));
3894 mem_size
= sizeof(dll_pool_t
) + (elems_max
* elem_size
);
3896 if ((dll_pool_p
= (dll_pool_t
*)MALLOCZ(osh
, mem_size
)) == NULL
) {
3897 printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n",
3898 elems_max
, elem_size
);
3903 dll_init(&dll_pool_p
->free_list
);
3904 dll_pool_p
->elems_max
= elems_max
;
3905 dll_pool_p
->elem_size
= elem_size
;
3907 elem_p
= dll_pool_p
->elements
;
3908 for (i
= 0; i
< elems_max
; i
++) {
3909 dll_append(&dll_pool_p
->free_list
, elem_p
);
3910 elem_p
= (dll_t
*)((uintptr
)elem_p
+ elem_size
);
3913 dll_pool_p
->free_count
= elems_max
;
3920 dll_pool_alloc(dll_pool_t
* dll_pool_p
)
3924 if (dll_pool_p
->free_count
== 0) {
3925 ASSERT(dll_empty(&dll_pool_p
->free_list
));
3929 elem_p
= dll_head_p(&dll_pool_p
->free_list
);
3931 dll_pool_p
->free_count
-= 1;
3933 return (void *)elem_p
;
3937 dll_pool_free(dll_pool_t
* dll_pool_p
, void * elem_p
)
3939 dll_t
* node_p
= (dll_t
*)elem_p
;
3940 dll_prepend(&dll_pool_p
->free_list
, node_p
);
3941 dll_pool_p
->free_count
+= 1;
3946 dll_pool_free_tail(dll_pool_t
* dll_pool_p
, void * elem_p
)
3948 dll_t
* node_p
= (dll_t
*)elem_p
;
3949 dll_append(&dll_pool_p
->free_list
, node_p
);
3950 dll_pool_p
->free_count
+= 1;
3955 /* calculate partial checksum */
3957 ip_cksum_partial(uint32 sum
, uint8
*val8
, uint32 count
)
3960 uint16
*val16
= (uint16
*)val8
;
3962 ASSERT(val8
!= NULL
);
3963 /* partial chksum calculated on 16-bit values */
3964 ASSERT((count
% 2) == 0);
3968 for (i
= 0; i
< count
; i
++) {
3974 /* calculate IP checksum */
3976 ip_cksum(uint32 sum
, uint8
*val8
, uint32 count
)
3978 uint16
*val16
= (uint16
*)val8
;
3980 ASSERT(val8
!= NULL
);
3986 /* add left-over byte, if any */
3988 sum
+= (*(uint8
*)val16
);
3991 /* fold 32-bit sum to 16 bits */
3992 sum
= (sum
>> 16) + (sum
& 0xffff);
3994 return ((uint16
)~sum
);
3997 /* calculate IPv4 header checksum
3998 * - input ip points to IP header in network order
3999 * - output cksum is in network order
4002 ipv4_hdr_cksum(uint8
*ip
, int ip_len
)
4008 ASSERT(ip_len
>= IPV4_MIN_HEADER_LEN
);
4010 /* partial cksum skipping the hdr_chksum field */
4011 sum
= ip_cksum_partial(sum
, ptr
, OFFSETOF(struct ipv4_hdr
, hdr_chksum
));
4012 ptr
+= OFFSETOF(struct ipv4_hdr
, hdr_chksum
) + 2;
4014 /* return calculated chksum */
4015 return ip_cksum(sum
, ptr
, ip_len
- OFFSETOF(struct ipv4_hdr
, src_ip
));
4018 /* calculate TCP header checksum using partial sum */
4020 tcp_hdr_chksum(uint32 sum
, uint8
*tcp_hdr
, uint16 tcp_len
)
4022 uint8
*ptr
= tcp_hdr
;
4024 ASSERT(tcp_hdr
!= NULL
);
4025 ASSERT(tcp_len
>= TCP_MIN_HEADER_LEN
);
4027 /* partial TCP cksum skipping the chksum field */
4028 sum
= ip_cksum_partial(sum
, ptr
, OFFSETOF(struct bcmtcp_hdr
, chksum
));
4029 ptr
+= OFFSETOF(struct bcmtcp_hdr
, chksum
) + 2;
4031 /* return calculated chksum */
4032 return ip_cksum(sum
, ptr
, tcp_len
- OFFSETOF(struct bcmtcp_hdr
, urg_ptr
));
4035 struct tcp_pseudo_hdr
{
4036 uint8 src_ip
[IPV4_ADDR_LEN
]; /* Source IP Address */
4037 uint8 dst_ip
[IPV4_ADDR_LEN
]; /* Destination IP Address */
4043 /* calculate IPv4 TCP header checksum
4044 * - input ip and tcp points to IP and TCP header in network order
4045 * - output cksum is in network order
4048 ipv4_tcp_hdr_cksum(uint8
*ip
, uint8
*tcp
, uint16 tcp_len
)
4050 struct ipv4_hdr
*ip_hdr
= (struct ipv4_hdr
*)ip
;
4051 struct tcp_pseudo_hdr tcp_ps
;
4055 ASSERT(tcp
!= NULL
);
4056 ASSERT(tcp_len
>= TCP_MIN_HEADER_LEN
);
4058 /* pseudo header cksum */
4059 memset(&tcp_ps
, 0, sizeof(tcp_ps
));
4060 memcpy(&tcp_ps
.dst_ip
, ip_hdr
->dst_ip
, IPV4_ADDR_LEN
);
4061 memcpy(&tcp_ps
.src_ip
, ip_hdr
->src_ip
, IPV4_ADDR_LEN
);
4063 tcp_ps
.prot
= ip_hdr
->prot
;
4064 tcp_ps
.tcp_size
= hton16(tcp_len
);
4065 sum
= ip_cksum_partial(sum
, (uint8
*)&tcp_ps
, sizeof(tcp_ps
));
4067 /* return calculated TCP header chksum */
4068 return tcp_hdr_chksum(sum
, tcp
, tcp_len
);
4071 struct ipv6_pseudo_hdr
{
4072 uint8 saddr
[IPV6_ADDR_LEN
];
4073 uint8 daddr
[IPV6_ADDR_LEN
];
4079 /* calculate IPv6 TCP header checksum
4080 * - input ipv6 and tcp points to IPv6 and TCP header in network order
4081 * - output cksum is in network order
4084 ipv6_tcp_hdr_cksum(uint8
*ipv6
, uint8
*tcp
, uint16 tcp_len
)
4086 struct ipv6_hdr
*ipv6_hdr
= (struct ipv6_hdr
*)ipv6
;
4087 struct ipv6_pseudo_hdr ipv6_pseudo
;
4090 ASSERT(ipv6
!= NULL
);
4091 ASSERT(tcp
!= NULL
);
4092 ASSERT(tcp_len
>= TCP_MIN_HEADER_LEN
);
4094 /* pseudo header cksum */
4095 memset((char *)&ipv6_pseudo
, 0, sizeof(ipv6_pseudo
));
4096 memcpy((char *)ipv6_pseudo
.saddr
, (char *)ipv6_hdr
->saddr
.addr
,
4097 sizeof(ipv6_pseudo
.saddr
));
4098 memcpy((char *)ipv6_pseudo
.daddr
, (char *)ipv6_hdr
->daddr
.addr
,
4099 sizeof(ipv6_pseudo
.daddr
));
4100 ipv6_pseudo
.payload_len
= ipv6_hdr
->payload_len
;
4101 ipv6_pseudo
.next_hdr
= ipv6_hdr
->nexthdr
;
4102 sum
= ip_cksum_partial(sum
, (uint8
*)&ipv6_pseudo
, sizeof(ipv6_pseudo
));
4104 /* return calculated TCP header chksum */
4105 return tcp_hdr_chksum(sum
, tcp
, tcp_len
);