2 * Driver O/S-independent utility routines
4 * Copyright (C) 1999-2016, 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 591286 2015-10-07 11:59:26Z $
39 #else /* !BCMDRIVER */
45 #if defined(BCMEXTSUP)
53 #endif /* !BCMDRIVER */
55 #include <bcmendian.h>
57 #include <proto/ethernet.h>
58 #include <proto/vlan.h>
59 #include <proto/bcmip.h>
60 #include <proto/802.1d.h>
61 #include <proto/802.11.h>
64 void *_bcmutils_dummy_fn = NULL;
73 /* copy a pkt buffer chain into a buffer */
75 pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
80 len = 4096; /* "infinite" */
82 /* skip 'offset' bytes */
83 for (; p && offset; p = PKTNEXT(osh, p)) {
84 if (offset < (uint)PKTLEN(osh, p))
86 offset -= PKTLEN(osh, p);
93 for (; p && len; p = PKTNEXT(osh, p)) {
94 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
95 bcopy(PKTDATA(osh, p) + offset, buf, n);
105 /* copy a buffer into a pkt buffer chain */
107 pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
112 /* skip 'offset' bytes */
113 for (; p && offset; p = PKTNEXT(osh, p)) {
114 if (offset < (uint)PKTLEN(osh, p))
116 offset -= PKTLEN(osh, p);
123 for (; p && len; p = PKTNEXT(osh, p)) {
124 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
125 bcopy(buf, PKTDATA(osh, p) + offset, n);
137 /* return total length of buffer chain */
139 pkttotlen(osl_t *osh, void *p)
145 for (; p; p = PKTNEXT(osh, p)) {
146 len = PKTLEN(osh, p);
149 if (BCMLFRAG_ENAB()) {
150 if (PKTISFRAG(osh, p)) {
151 total += PKTFRAGTOTLEN(osh, p);
160 /* return the last buffer of chained pkt */
162 pktlast(osl_t *osh, void *p)
164 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
170 /* count segments of a chained packet */
172 pktsegcnt(osl_t *osh, void *p)
176 for (cnt = 0; p; p = PKTNEXT(osh, p)) {
179 if (BCMLFRAG_ENAB()) {
180 if (PKTISFRAG(osh, p)) {
181 cnt += PKTFRAGTOTNUM(osh, p);
191 /* count segments of a chained packet */
193 pktsegcnt_war(osl_t *osh, void *p)
197 uint len, remain, align64;
199 for (cnt = 0; p; p = PKTNEXT(osh, p)) {
201 len = PKTLEN(osh, p);
203 pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */
204 /* Check for page boundary straddle (2048B) */
205 if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff))
208 align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */
209 align64 = (64 - align64) & 0x3f;
210 len -= align64; /* bytes from aligned 64B to end */
211 /* if aligned to 128B, check for MOD 128 between 1 to 4B */
213 if (remain > 0 && remain <= 4)
214 cnt++; /* add extra seg */
222 pktdataoffset(osl_t *osh, void *p, uint offset)
224 uint total = pkttotlen(osh, p);
225 uint pkt_off = 0, len = 0;
226 uint8 *pdata = (uint8 *) PKTDATA(osh, p);
231 for (; p; p = PKTNEXT(osh, p)) {
232 pdata = (uint8 *) PKTDATA(osh, p);
233 pkt_off = offset - len;
234 len += PKTLEN(osh, p);
238 return (uint8*) (pdata+pkt_off);
242 /* given a offset in pdata, find the pkt seg hdr */
244 pktoffset(osl_t *osh, void *p, uint offset)
246 uint total = pkttotlen(osh, p);
252 for (; p; p = PKTNEXT(osh, p)) {
253 len += PKTLEN(osh, p);
260 #endif /* BCMDRIVER */
262 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
263 const unsigned char bcm_ctype[] = {
265 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
266 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
268 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
269 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
270 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
271 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
272 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
273 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
274 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
275 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
276 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
277 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
278 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
279 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
280 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
281 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
282 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
283 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
284 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
285 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
286 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
287 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
288 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
289 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
290 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
291 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
292 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
293 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
294 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
295 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
296 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
297 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
301 bcm_strtoul(const char *cp, char **endp, uint base)
303 ulong result, last_result = 0, value;
308 while (bcm_isspace(*cp))
313 else if (cp[0] == '-') {
320 if ((cp[1] == 'x') || (cp[1] == 'X')) {
329 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
335 while (bcm_isxdigit(*cp) &&
336 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
337 result = result*base + value;
338 /* Detected overflow */
339 if (result < last_result && !minus)
341 last_result = result;
346 result = (ulong)(-(long)result);
349 *endp = DISCARD_QUAL(cp, char);
355 bcm_atoi(const char *s)
357 return (int)bcm_strtoul(s, NULL, 10);
360 /* return pointer to location of substring 'needle' in 'haystack' */
362 bcmstrstr(const char *haystack, const char *needle)
367 if ((haystack == NULL) || (needle == NULL))
368 return DISCARD_QUAL(haystack, char);
370 nlen = (int)strlen(needle);
371 len = (int)strlen(haystack) - nlen + 1;
373 for (i = 0; i < len; i++)
374 if (memcmp(needle, &haystack[i], nlen) == 0)
375 return DISCARD_QUAL(&haystack[i], char);
380 bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len)
382 for (; s_len >= substr_len; s++, s_len--)
383 if (strncmp(s, substr, substr_len) == 0)
384 return DISCARD_QUAL(s, char);
390 bcmstrcat(char *dest, const char *src)
394 p = dest + strlen(dest);
396 while ((*p++ = *src++) != '\0')
403 bcmstrncat(char *dest, const char *src, uint size)
408 p = dest + strlen(dest);
411 while (p != endp && (*p++ = *src++) != '\0')
418 /****************************************************************************
419 * Function: bcmstrtok
422 * Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
423 * but allows strToken() to be used by different strings or callers at the same
424 * time. Each call modifies '*string' by substituting a NULL character for the
425 * first delimiter that is encountered, and updates 'string' to point to the char
426 * after the delimiter. Leading delimiters are skipped.
429 * string (mod) Ptr to string ptr, updated by token.
430 * delimiters (in) Set of delimiter characters.
431 * tokdelim (out) Character that delimits the returned token. (May
432 * be set to NULL if token delimiter is not required).
434 * Returns: Pointer to the next token found. NULL when no more tokens are found.
435 *****************************************************************************
438 bcmstrtok(char **string, const char *delimiters, char *tokdelim)
441 unsigned long map[8];
445 if (tokdelim != NULL) {
446 /* Prime the token delimiter */
450 /* Clear control map */
451 for (count = 0; count < 8; count++) {
455 /* Set bits in delimiter table */
457 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
459 while (*delimiters++);
461 str = (unsigned char*)*string;
463 /* Find beginning of token (skip over leading delimiters). Note that
464 * there is no token iff this loop sets str to point to the terminal
465 * null (*str == '\0')
467 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
471 nextoken = (char*)str;
473 /* Find the end of the token. If it is not the end of the string,
476 for (; *str; str++) {
477 if (map[*str >> 5] & (1 << (*str & 31))) {
478 if (tokdelim != NULL) {
487 *string = (char*)str;
489 /* Determine if a token has been found. */
490 if (nextoken == (char *) str) {
499 #define xToLower(C) \
500 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
503 /****************************************************************************
504 * Function: bcmstricmp
506 * Purpose: Compare to strings case insensitively.
508 * Parameters: s1 (in) First string to compare.
509 * s2 (in) Second string to compare.
511 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
512 * t1 > t2, when ignoring case sensitivity.
513 *****************************************************************************
516 bcmstricmp(const char *s1, const char *s2)
523 if (dc < sc) return -1;
524 if (dc > sc) return 1;
529 if (*s1 && !*s2) return 1;
530 if (!*s1 && *s2) return -1;
535 /****************************************************************************
536 * Function: bcmstrnicmp
538 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
541 * Parameters: s1 (in) First string to compare.
542 * s2 (in) Second string to compare.
543 * cnt (in) Max characters to compare.
545 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
546 * t1 > t2, when ignoring case sensitivity.
547 *****************************************************************************
550 bcmstrnicmp(const char* s1, const char* s2, int cnt)
554 while (*s2 && *s1 && cnt) {
557 if (dc < sc) return -1;
558 if (dc > sc) return 1;
565 if (*s1 && !*s2) return 1;
566 if (!*s1 && *s2) return -1;
570 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
572 bcm_ether_atoe(const char *p, struct ether_addr *ea)
578 ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16);
588 bcm_atoipv4(const char *p, struct ipv4_addr *ip)
594 ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0);
595 if (*c++ != '.' || i == IPV4_ADDR_LEN)
599 return (i == IPV4_ADDR_LEN);
601 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
604 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
605 /* registry routine buffer preparation utility functions:
606 * parameter order is like strncpy, but returns count
607 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
610 wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
618 /* wbuflen is in bytes */
619 wbuflen /= sizeof(ushort);
621 for (i = 0; i < wbuflen; ++i) {
624 *abuf++ = (char) *wbuf++;
631 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
634 bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
636 static const char hex[] =
638 '0', '1', '2', '3', '4', '5', '6', '7',
639 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
641 const uint8 *octet = ea->octet;
645 for (i = 0; i < 6; i++, octet++) {
646 *p++ = hex[(*octet >> 4) & 0xf];
647 *p++ = hex[*octet & 0xf];
657 bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
659 snprintf(buf, 16, "%d.%d.%d.%d",
660 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
665 bcm_ipv6_ntoa(void *ipv6, char *buf)
667 /* Implementing RFC 5952 Sections 4 + 5 */
668 /* Not thoroughly tested */
672 int i, i_max = -1, cnt = 0, cnt_max = 1;
674 memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN);
676 for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
691 /* IPv4-translated: ::ffff:0:a.b.c.d */
692 ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) ||
693 /* IPv4-mapped: ::ffff:a.b.c.d */
694 (cnt_max == 5 && a[5] == 0xffff)))
695 a4 = (uint8*) (a + 6);
697 for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
698 if ((uint8*) (a + i) == a4) {
699 snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]);
701 } else if (i == i_max) {
709 p += snprintf(p, 8, "%x", ntoh16(a[i]));
722 for (i = 0; i < ms; i++) {
731 #if defined(DHD_DEBUG)
732 /* pretty hex print a pkt buffer chain */
734 prpkt(const char *msg, osl_t *osh, void *p0)
738 if (msg && (msg[0] != '\0'))
739 printf("%s:\n", msg);
741 for (p = p0; p; p = PKTNEXT(osh, p))
742 prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
746 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
747 * Also updates the inplace vlan tag if requested.
748 * For debugging, it returns an indication of what it did.
751 pktsetprio(void *pkt, bool update_vtag)
753 struct ether_header *eh;
754 struct ethervlan_header *evh;
759 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
760 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
762 eh = (struct ether_header *) pktdata;
764 if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) {
766 int vlan_prio, dscp_prio = 0;
768 evh = (struct ethervlan_header *)eh;
770 vlan_tag = ntoh16(evh->vlan_tag);
771 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
773 if ((evh->ether_type == hton16(ETHER_TYPE_IP)) ||
774 (evh->ether_type == hton16(ETHER_TYPE_IPV6))) {
775 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
776 uint8 tos_tc = IP_TOS46(ip_body);
777 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
780 /* DSCP priority gets precedence over 802.1P (vlan tag) */
781 if (dscp_prio != 0) {
782 priority = dscp_prio;
785 priority = vlan_prio;
789 * If the DSCP priority is not the same as the VLAN priority,
790 * then overwrite the priority field in the vlan tag, with the
791 * DSCP priority value. This is required for Linux APs because
792 * the VLAN driver on Linux, overwrites the skb->priority field
793 * with the priority value in the vlan tag
795 if (update_vtag && (priority != vlan_prio)) {
796 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
797 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
798 evh->vlan_tag = hton16(vlan_tag);
801 #ifdef DHD_LOSSLESS_ROAMING
802 } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
803 priority = PRIO_8021D_NC;
805 #endif /* DHD_LOSSLESS_ROAMING */
806 } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) ||
807 (eh->ether_type == hton16(ETHER_TYPE_IPV6))) {
808 uint8 *ip_body = pktdata + sizeof(struct ether_header);
809 uint8 tos_tc = IP_TOS46(ip_body);
810 uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT;
813 priority = PRIO_8021D_VO;
818 priority = PRIO_8021D_CL;
826 priority = PRIO_8021D_EE;
829 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
836 ASSERT(priority >= 0 && priority <= MAXPRIO);
837 PKTSETPRIO(pkt, priority);
838 return (rc | priority);
841 /* lookup user priority for specified DSCP */
843 dscp2up(uint8 *up_table, uint8 dscp)
845 uint8 user_priority = 255;
847 /* lookup up from table if parameters valid */
848 if (up_table != NULL && dscp < UP_TABLE_MAX) {
849 user_priority = up_table[dscp];
852 /* 255 is unused value so return up from dscp */
853 if (user_priority == 255) {
854 user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT);
857 return user_priority;
860 /* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */
862 pktsetprio_qms(void *pkt, uint8* up_table, bool update_vtag)
868 uint user_priority = 0;
871 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
872 pktlen = PKTLEN(OSH_NULL, pkt);
874 if (pktgetdscp(pktdata, pktlen, &dscp)) {
876 user_priority = dscp2up(up_table, dscp);
877 PKTSETPRIO(pkt, user_priority);
880 return (rc | user_priority);
882 return pktsetprio(pkt, update_vtag);
886 /* Returns TRUE and DSCP if IP header found, FALSE otherwise.
889 pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp)
891 struct ether_header *eh;
892 struct ethervlan_header *evh;
896 /* minimum length is ether header and IP header */
897 if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN)
900 eh = (struct ether_header *) pktdata;
902 if (eh->ether_type == HTON16(ETHER_TYPE_IP)) {
903 ip_body = pktdata + sizeof(struct ether_header);
904 *dscp = IP_DSCP46(ip_body);
907 else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) {
908 evh = (struct ethervlan_header *)eh;
910 /* minimum length is ethervlan header and IP header */
911 if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN &&
912 evh->ether_type == HTON16(ETHER_TYPE_IP)) {
913 ip_body = pktdata + sizeof(struct ethervlan_header);
914 *dscp = IP_DSCP46(ip_body);
922 /* Add to adjust the 802.1x priority */
924 pktset8021xprio(void *pkt, int prio)
926 struct ether_header *eh;
928 if(prio == PKTPRIO(pkt))
930 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
931 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
932 eh = (struct ether_header *) pktdata;
933 if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
934 ASSERT(prio >= 0 && prio <= MAXPRIO);
935 PKTSETPRIO(pkt, prio);
939 /* The 0.5KB string table is not removed by compiler even though it's unused */
941 static char bcm_undeferrstr[32];
942 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
944 /* Convert the error codes into related error strings */
946 bcmerrorstr(int bcmerror)
948 /* check if someone added a bcmerror code but forgot to add errorstring */
949 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
951 if (bcmerror > 0 || bcmerror < BCME_LAST) {
952 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
953 return bcm_undeferrstr;
956 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
958 return bcmerrorstrtable[-bcmerror];
963 /* iovar table lookup */
964 /* could mandate sorted tables and do a binary search */
966 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
968 const bcm_iovar_t *vi;
969 const char *lookup_name;
971 /* skip any ':' delimited option prefixes */
972 lookup_name = strrchr(name, ':');
973 if (lookup_name != NULL)
978 ASSERT(table != NULL);
980 for (vi = table; vi->name; vi++) {
981 if (!strcmp(vi->name, lookup_name))
984 /* ran to end of table */
986 return NULL; /* var name not found */
990 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
994 /* length check on io buf */
1003 /* all integers are int32 sized args at the ioctl interface */
1004 if (len < (int)sizeof(int)) {
1005 bcmerror = BCME_BUFTOOSHORT;
1010 /* buffer must meet minimum length requirement */
1011 if (len < vi->minlen) {
1012 bcmerror = BCME_BUFTOOSHORT;
1018 /* Cannot return nil... */
1019 bcmerror = BCME_UNSUPPORTED;
1021 /* Set is an action w/o parameters */
1022 bcmerror = BCME_BUFTOOLONG;
1027 /* unknown type for length check in iovar info */
1029 bcmerror = BCME_UNSUPPORTED;
1035 #endif /* BCMDRIVER */
1037 #ifdef BCM_OBJECT_TRACE
1039 #define BCM_OBJECT_MERGE_SAME_OBJ 0
1041 /* some place may add / remove the object to trace list for Linux: */
1042 /* add: osl_alloc_skb dev_alloc_skb skb_realloc_headroom dhd_start_xmit */
1043 /* remove: osl_pktfree dev_kfree_skb netif_rx */
1045 #define BCM_OBJDBG_COUNT (1024 * 100)
1046 static spinlock_t dbgobj_lock;
1047 #define BCM_OBJDBG_LOCK_INIT() spin_lock_init(&dbgobj_lock)
1048 #define BCM_OBJDBG_LOCK_DESTROY()
1049 #define BCM_OBJDBG_LOCK spin_lock_irqsave
1050 #define BCM_OBJDBG_UNLOCK spin_unlock_irqrestore
1052 #define BCM_OBJDBG_ADDTOHEAD 0
1053 #define BCM_OBJDBG_ADDTOTAIL 1
1055 #define BCM_OBJDBG_CALLER_LEN 32
1057 struct bcm_dbgobj *prior;
1058 struct bcm_dbgobj *next;
1064 char caller[BCM_OBJDBG_CALLER_LEN];
1067 static struct bcm_dbgobj *dbgobj_freehead = NULL;
1068 static struct bcm_dbgobj *dbgobj_freetail = NULL;
1069 static struct bcm_dbgobj *dbgobj_objhead = NULL;
1070 static struct bcm_dbgobj *dbgobj_objtail = NULL;
1072 static uint32 dbgobj_sn = 0;
1073 static int dbgobj_count = 0;
1074 static struct bcm_dbgobj bcm_dbg_objs[BCM_OBJDBG_COUNT];
1077 bcm_object_trace_init(void)
1080 BCM_OBJDBG_LOCK_INIT();
1081 memset(&bcm_dbg_objs, 0x00, sizeof(struct bcm_dbgobj) * BCM_OBJDBG_COUNT);
1082 dbgobj_freehead = &bcm_dbg_objs[0];
1083 dbgobj_freetail = &bcm_dbg_objs[BCM_OBJDBG_COUNT - 1];
1085 for (i = 0; i < BCM_OBJDBG_COUNT; ++i) {
1086 bcm_dbg_objs[i].next = (i == (BCM_OBJDBG_COUNT - 1)) ?
1087 dbgobj_freehead : &bcm_dbg_objs[i + 1];
1088 bcm_dbg_objs[i].prior = (i == 0) ?
1089 dbgobj_freetail : &bcm_dbg_objs[i - 1];
1094 bcm_object_trace_deinit(void)
1096 if (dbgobj_objhead || dbgobj_objtail) {
1097 printf("%s: not all objects are released\n", __FUNCTION__);
1100 BCM_OBJDBG_LOCK_DESTROY();
1104 bcm_object_rm_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
1105 struct bcm_dbgobj *dbgobj)
1107 if ((dbgobj == *head) && (dbgobj == *tail)) {
1110 } else if (dbgobj == *head) {
1111 *head = (*head)->next;
1112 } else if (dbgobj == *tail) {
1113 *tail = (*tail)->prior;
1115 dbgobj->next->prior = dbgobj->prior;
1116 dbgobj->prior->next = dbgobj->next;
1120 bcm_object_add_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
1121 struct bcm_dbgobj *dbgobj, int addtotail)
1123 if (!(*head) && !(*tail)) {
1126 dbgobj->next = dbgobj;
1127 dbgobj->prior = dbgobj;
1128 } else if ((*head) && (*tail)) {
1129 (*tail)->next = dbgobj;
1130 (*head)->prior = dbgobj;
1131 dbgobj->next = *head;
1132 dbgobj->prior = *tail;
1133 if (addtotail == BCM_OBJDBG_ADDTOTAIL)
1138 ASSERT(0); /* can't be this case */
1143 bcm_object_movetoend(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
1144 struct bcm_dbgobj *dbgobj, int movetotail)
1146 if ((*head) && (*tail)) {
1147 if (movetotail == BCM_OBJDBG_ADDTOTAIL) {
1148 if (dbgobj != (*tail)) {
1149 bcm_object_rm_list(head, tail, dbgobj);
1150 bcm_object_add_list(head, tail, dbgobj, movetotail);
1153 if (dbgobj != (*head)) {
1154 bcm_object_rm_list(head, tail, dbgobj);
1155 bcm_object_add_list(head, tail, dbgobj, movetotail);
1159 ASSERT(0); /* can't be this case */
1164 bcm_object_trace_opr(void *obj, uint32 opt, const char *caller, int line)
1166 struct bcm_dbgobj *dbgobj;
1167 unsigned long flags;
1169 BCM_REFERENCE(flags);
1170 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1172 if (opt == BCM_OBJDBG_ADD_PKT ||
1173 opt == BCM_OBJDBG_ADD) {
1174 dbgobj = dbgobj_objtail;
1176 if (dbgobj->obj == obj) {
1177 printf("%s: obj %p allocated from %s(%d),"
1178 " allocate again from %s(%d)\n",
1179 __FUNCTION__, dbgobj->obj,
1180 dbgobj->caller, dbgobj->line,
1185 dbgobj = dbgobj->prior;
1186 if (dbgobj == dbgobj_objtail)
1190 #if BCM_OBJECT_MERGE_SAME_OBJ
1191 dbgobj = dbgobj_freetail;
1193 if (dbgobj->obj == obj) {
1194 goto FREED_ENTRY_FOUND;
1196 dbgobj = dbgobj->prior;
1197 if (dbgobj == dbgobj_freetail)
1200 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
1202 dbgobj = dbgobj_freehead;
1203 #if BCM_OBJECT_MERGE_SAME_OBJ
1205 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
1207 printf("%s: already got %d objects ?????????????????????\n",
1208 __FUNCTION__, BCM_OBJDBG_COUNT);
1213 bcm_object_rm_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj);
1215 strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN);
1216 dbgobj->caller[BCM_OBJDBG_CALLER_LEN-1] = '\0';
1217 dbgobj->line = line;
1219 if (opt == BCM_OBJDBG_ADD_PKT) {
1220 dbgobj->obj_sn = dbgobj_sn++;
1221 dbgobj->obj_state = 0;
1222 /* first 4 bytes is pkt sn */
1223 if (((unsigned long)PKTTAG(obj)) & 0x3)
1224 printf("pkt tag address not aligned by 4: %p\n", PKTTAG(obj));
1225 *(uint32*)PKTTAG(obj) = dbgobj->obj_sn;
1227 bcm_object_add_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj,
1228 BCM_OBJDBG_ADDTOTAIL);
1232 } else if (opt == BCM_OBJDBG_REMOVE) {
1233 dbgobj = dbgobj_objtail;
1235 if (dbgobj->obj == obj) {
1237 printf("%s: rm flagged obj %p flag 0x%08x from %s(%d)\n",
1238 __FUNCTION__, obj, dbgobj->flag, caller, line);
1240 bcm_object_rm_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj);
1241 memset(dbgobj->caller, 0x00, BCM_OBJDBG_CALLER_LEN);
1242 strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN);
1243 dbgobj->caller[BCM_OBJDBG_CALLER_LEN-1] = '\0';
1244 dbgobj->line = line;
1245 bcm_object_add_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj,
1246 BCM_OBJDBG_ADDTOTAIL);
1250 dbgobj = dbgobj->prior;
1251 if (dbgobj == dbgobj_objtail)
1255 dbgobj = dbgobj_freetail;
1256 while (dbgobj && dbgobj->obj) {
1257 if (dbgobj->obj == obj) {
1258 printf("%s: obj %p already freed from from %s(%d),"
1259 " try free again from %s(%d)\n",
1261 dbgobj->caller, dbgobj->line,
1263 //ASSERT(0); /* release same obj more than one time? */
1266 dbgobj = dbgobj->prior;
1267 if (dbgobj == dbgobj_freetail)
1271 printf("%s: ################### release none-existing obj %p from %s(%d)\n",
1272 __FUNCTION__, obj, caller, line);
1273 //ASSERT(0); /* release same obj more than one time? */
1278 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1283 bcm_object_trace_upd(void *obj, void *obj_new)
1285 struct bcm_dbgobj *dbgobj;
1286 unsigned long flags;
1288 BCM_REFERENCE(flags);
1289 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1291 dbgobj = dbgobj_objtail;
1293 if (dbgobj->obj == obj) {
1294 dbgobj->obj = obj_new;
1295 if (dbgobj != dbgobj_objtail) {
1296 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
1297 dbgobj, BCM_OBJDBG_ADDTOTAIL);
1301 dbgobj = dbgobj->prior;
1302 if (dbgobj == dbgobj_objtail)
1307 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1312 bcm_object_trace_chk(void *obj, uint32 chksn, uint32 sn,
1313 const char *caller, int line)
1315 struct bcm_dbgobj *dbgobj;
1316 unsigned long flags;
1318 BCM_REFERENCE(flags);
1319 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1321 dbgobj = dbgobj_objtail;
1323 if ((dbgobj->obj == obj) &&
1324 ((!chksn) || (dbgobj->obj_sn == sn))) {
1325 if (dbgobj != dbgobj_objtail) {
1326 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
1327 dbgobj, BCM_OBJDBG_ADDTOTAIL);
1331 dbgobj = dbgobj->prior;
1332 if (dbgobj == dbgobj_objtail)
1336 dbgobj = dbgobj_freetail;
1338 if ((dbgobj->obj == obj) &&
1339 ((!chksn) || (dbgobj->obj_sn == sn))) {
1340 printf("%s: (%s:%d) obj %p (sn %d state %d) was freed from %s(%d)\n",
1341 __FUNCTION__, caller, line,
1342 dbgobj->obj, dbgobj->obj_sn, dbgobj->obj_state,
1343 dbgobj->caller, dbgobj->line);
1346 else if (dbgobj->obj == NULL) {
1349 dbgobj = dbgobj->prior;
1350 if (dbgobj == dbgobj_freetail)
1354 printf("%s: obj %p not found, check from %s(%d), chksn %s, sn %d\n",
1355 __FUNCTION__, obj, caller, line, chksn ? "yes" : "no", sn);
1356 dbgobj = dbgobj_objtail;
1358 printf("%s: (%s:%d) obj %p sn %d was allocated from %s(%d)\n",
1359 __FUNCTION__, caller, line,
1360 dbgobj->obj, dbgobj->obj_sn, dbgobj->caller, dbgobj->line);
1361 dbgobj = dbgobj->prior;
1362 if (dbgobj == dbgobj_objtail)
1367 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1372 bcm_object_feature_set(void *obj, uint32 type, uint32 value)
1374 struct bcm_dbgobj *dbgobj;
1375 unsigned long flags;
1377 BCM_REFERENCE(flags);
1378 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1380 dbgobj = dbgobj_objtail;
1382 if (dbgobj->obj == obj) {
1383 if (type == BCM_OBJECT_FEATURE_FLAG) {
1384 if (value & BCM_OBJECT_FEATURE_CLEAR)
1385 dbgobj->flag &= ~(value);
1387 dbgobj->flag |= (value);
1388 } else if (type == BCM_OBJECT_FEATURE_PKT_STATE) {
1389 dbgobj->obj_state = value;
1391 if (dbgobj != dbgobj_objtail) {
1392 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
1393 dbgobj, BCM_OBJDBG_ADDTOTAIL);
1397 dbgobj = dbgobj->prior;
1398 if (dbgobj == dbgobj_objtail)
1402 printf("%s: obj %p not found in active list\n", __FUNCTION__, obj);
1406 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1411 bcm_object_feature_get(void *obj, uint32 type, uint32 value)
1414 struct bcm_dbgobj *dbgobj;
1415 unsigned long flags;
1417 BCM_REFERENCE(flags);
1418 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
1420 dbgobj = dbgobj_objtail;
1422 if (dbgobj->obj == obj) {
1423 if (type == BCM_OBJECT_FEATURE_FLAG) {
1424 rtn = (dbgobj->flag & value) & (~BCM_OBJECT_FEATURE_CLEAR);
1426 if (dbgobj != dbgobj_objtail) {
1427 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
1428 dbgobj, BCM_OBJDBG_ADDTOTAIL);
1432 dbgobj = dbgobj->prior;
1433 if (dbgobj == dbgobj_objtail)
1437 printf("%s: obj %p not found in active list\n", __FUNCTION__, obj);
1441 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
1445 #endif /* BCM_OBJECT_TRACE */
1448 bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst)
1450 uint8 *new_dst = dst;
1451 bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst;
1453 /* dst buffer should always be valid */
1456 /* data len must be within valid range */
1457 ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE));
1459 /* source data buffer pointer should be valid, unless datalen is 0
1460 * meaning no data with this TLV
1462 ASSERT((data != NULL) || (datalen == 0));
1464 /* only do work if the inputs are valid
1465 * - must have a dst to write to AND
1466 * - datalen must be within range AND
1467 * - the source data pointer must be non-NULL if datalen is non-zero
1468 * (this last condition detects datalen > 0 with a NULL data pointer)
1470 if ((dst != NULL) &&
1471 ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) &&
1472 ((data != NULL) || (datalen == 0))) {
1474 /* write type, len fields */
1475 dst_tlv->id = (uint8)type;
1476 dst_tlv->len = (uint8)datalen;
1478 /* if data is present, copy to the output buffer and update
1479 * pointer to output buffer
1483 memcpy(dst_tlv->data, data, datalen);
1486 /* update the output destination poitner to point past
1489 new_dst = dst + BCM_TLV_HDR_SIZE + datalen;
1496 bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, int dst_maxlen)
1498 uint8 *new_dst = dst;
1500 if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) {
1502 /* if len + tlv hdr len is more than destlen, don't do anything
1503 * just return the buffer untouched
1505 if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) {
1507 new_dst = bcm_write_tlv(type, data, datalen, dst);
1515 bcm_copy_tlv(const void *src, uint8 *dst)
1517 uint8 *new_dst = dst;
1518 const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
1524 totlen = BCM_TLV_HDR_SIZE + src_tlv->len;
1525 memcpy(dst, src_tlv, totlen);
1526 new_dst = dst + totlen;
1533 uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen)
1535 uint8 *new_dst = dst;
1536 const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
1540 if (bcm_valid_tlv(src_tlv, dst_maxlen)) {
1541 new_dst = bcm_copy_tlv(src, dst);
1549 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
1550 /*******************************************************************************
1553 * Computes a crc8 over the input data using the polynomial:
1555 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1557 * The caller provides the initial value (either CRC8_INIT_VALUE
1558 * or the previous returned value) to allow for processing of
1559 * discontiguous blocks of data. When generating the CRC the
1560 * caller is responsible for complementing the final return value
1561 * and inserting it into the byte stream. When checking, a final
1562 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1564 * Reference: Dallas Semiconductor Application Note 27
1565 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1566 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1567 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1569 * ****************************************************************************
1572 static const uint8 crc8_table[256] = {
1573 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1574 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1575 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1576 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1577 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1578 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1579 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1580 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1581 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1582 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1583 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1584 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1585 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1586 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1587 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1588 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1589 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1590 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1591 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1592 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1593 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1594 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1595 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1596 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1597 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1598 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1599 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1600 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1601 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1602 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1603 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1604 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1607 #define CRC_INNER_LOOP(n, c, x) \
1608 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1612 uint8 *pdata, /* pointer to array of data to process */
1613 uint nbytes, /* number of input data bytes to process */
1614 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1617 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1618 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1620 while (nbytes-- > 0)
1621 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1626 /*******************************************************************************
1629 * Computes a crc16 over the input data using the polynomial:
1631 * x^16 + x^12 +x^5 + 1
1633 * The caller provides the initial value (either CRC16_INIT_VALUE
1634 * or the previous returned value) to allow for processing of
1635 * discontiguous blocks of data. When generating the CRC the
1636 * caller is responsible for complementing the final return value
1637 * and inserting it into the byte stream. When checking, a final
1638 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1640 * Reference: Dallas Semiconductor Application Note 27
1641 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1642 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1643 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1645 * ****************************************************************************
1648 static const uint16 crc16_table[256] = {
1649 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1650 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1651 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1652 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1653 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1654 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1655 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1656 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1657 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1658 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1659 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1660 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1661 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1662 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1663 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1664 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1665 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1666 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1667 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1668 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1669 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1670 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1671 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1672 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1673 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1674 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1675 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1676 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1677 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1678 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1679 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1680 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1685 uint8 *pdata, /* pointer to array of data to process */
1686 uint nbytes, /* number of input data bytes to process */
1687 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1690 while (nbytes-- > 0)
1691 CRC_INNER_LOOP(16, crc, *pdata++);
1695 static const uint32 crc32_table[256] = {
1696 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1697 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1698 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1699 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1700 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1701 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1702 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1703 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1704 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1705 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1706 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1707 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1708 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1709 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1710 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1711 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1712 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1713 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1714 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1715 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1716 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1717 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1718 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1719 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1720 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1721 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1722 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1723 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1724 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1725 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1726 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1727 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1728 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1729 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1730 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1731 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1732 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1733 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1734 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1735 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1736 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1737 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1738 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1739 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1740 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1741 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1742 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1743 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1744 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1745 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1746 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1747 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1748 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1749 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1750 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1751 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1752 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1753 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1754 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1755 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1756 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1757 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1758 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1759 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1763 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
1764 * accumulating over multiple pieces.
1767 hndcrc32(uint8 *pdata, uint nbytes, uint32 crc)
1770 pend = pdata + nbytes;
1771 while (pdata < pend)
1772 CRC_INNER_LOOP(32, crc, *pdata++);
1778 #define CLEN 1499 /* CRC Length */
1779 #define CBUFSIZ (CLEN+4)
1780 #define CNBUFS 5 /* # of bufs */
1789 uint32 crc32tv[CNBUFS] =
1790 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1792 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
1794 /* step through all possible alignments */
1795 for (l = 0; l <= 4; l++) {
1796 for (j = 0; j < CNBUFS; j++) {
1798 for (k = 0; k < len[j]; k++)
1799 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
1802 for (j = 0; j < CNBUFS; j++) {
1803 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1804 ASSERT(crcr == crc32tv[j]);
1808 MFREE(buf, CBUFSIZ*CNBUFS);
1814 * Advance from the current 1-byte tag/1-byte length/variable-length value
1815 * triple, to the next, returning a pointer to the next.
1816 * If the current or next TLV is invalid (does not fit in given buffer length),
1818 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1819 * by the TLV parameter's length if it is valid.
1822 bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
1826 /* validate current elt */
1827 if (!bcm_valid_tlv(elt, *buflen)) {
1831 /* advance to next elt */
1833 elt = (bcm_tlv_t*)(elt->data + len);
1834 *buflen -= (TLV_HDR_LEN + len);
1836 /* validate next elt */
1837 if (!bcm_valid_tlv(elt, *buflen)) {
1845 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1846 * triples, returning a pointer to the substring whose first element
1850 bcm_parse_tlvs(void *buf, int buflen, uint key)
1855 if ((elt = (bcm_tlv_t*)buf) == NULL) {
1860 /* find tagged parameter */
1861 while (totlen >= TLV_HDR_LEN) {
1864 /* validate remaining totlen */
1865 if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
1870 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
1871 totlen -= (len + TLV_HDR_LEN);
1878 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1879 * triples, returning a pointer to the substring whose first element
1881 * return NULL if not found or length field < min_varlen
1884 bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen)
1886 bcm_tlv_t * ret = bcm_parse_tlvs(buf, buflen, key);
1887 if (ret == NULL || ret->len < min_bodylen) {
1894 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1895 * triples, returning a pointer to the substring whose first element
1896 * matches tag. Stop parsing when we see an element whose ID is greater
1897 * than the target key.
1900 bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
1905 elt = (bcm_tlv_t*)buf;
1908 /* find tagged parameter */
1909 while (totlen >= TLV_HDR_LEN) {
1913 /* Punt if we start seeing IDs > than target key */
1918 /* validate remaining totlen */
1919 if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
1923 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
1924 totlen -= (len + TLV_HDR_LEN);
1928 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
1930 #if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1933 bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len)
1939 if (len < 2 || !buf)
1944 for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) {
1945 bit = bd->bitfield[i].bit;
1946 if ((flags & mask) == bit) {
1947 if (len > (int)strlen(name)) {
1948 slen = strlen(name);
1949 strncpy(buf, name, slen+1);
1958 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
1963 int slen = 0, nlen = 0;
1967 if (len < 2 || !buf)
1972 for (i = 0; flags != 0; i++) {
1975 if (bit == 0 && flags != 0) {
1976 /* print any unnamed bits */
1977 snprintf(hexstr, 16, "0x%X", flags);
1979 flags = 0; /* exit loop */
1980 } else if ((flags & bit) == 0)
1983 nlen = strlen(name);
1985 /* count btwn flag space */
1988 /* need NULL char as well */
1991 /* copy NULL char but don't count it */
1992 strncpy(p, name, nlen + 1);
1994 /* copy btwn flag space and NULL char */
1996 p += snprintf(p, 2, " ");
1999 /* indicate the str was too short */
2001 p += snprintf(p, 2, ">");
2004 return (int)(p - buf);
2008 /* print bytes formatted as hex to a string. return the resulting string length */
2010 bcm_format_hex(char *str, const void *bytes, int len)
2014 const uint8 *src = (const uint8*)bytes;
2016 for (i = 0; i < len; i++) {
2017 p += snprintf(p, 3, "%02X", *src);
2020 return (int)(p - str);
2023 /* pretty hex print a contiguous buffer */
2025 prhex(const char *msg, uchar *buf, uint nbytes)
2028 int len = sizeof(line);
2032 if (msg && (msg[0] != '\0'))
2033 printf("%s:\n", msg);
2036 for (i = 0; i < nbytes; i++) {
2038 nchar = snprintf(p, len, " %04x: ", i); /* line prefix */
2043 nchar = snprintf(p, len, "%02x ", buf[i]);
2049 printf("%s\n", line); /* flush line */
2055 /* flush last partial line */
2057 printf("%s\n", line);
2060 static const char *crypto_algo_names[] = {
2085 bcm_crypto_algo_name(uint algo)
2087 return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
2092 bcm_chipname(uint chipid, char *buf, uint len)
2096 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
2097 snprintf(buf, len, fmt, chipid);
2101 /* Produce a human-readable string for boardrev */
2103 bcm_brev_str(uint32 brev, char *buf)
2106 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
2108 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
2113 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
2115 /* dump large strings to console */
2122 len = (uint)strlen(buf);
2124 max_len = BUFSIZE_TODUMP_ATONCE;
2126 while (len > max_len) {
2128 buf[max_len] = '\0';
2135 /* print the remaining string */
2136 printf("%s\n", buf);
2140 /* routine to dump fields in a fileddesc structure */
2142 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
2143 char *buf, uint32 bufsize)
2147 struct fielddesc *cur_ptr;
2150 cur_ptr = fielddesc_array;
2152 while (bufsize > 1) {
2153 if (cur_ptr->nameandfmt == NULL)
2155 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
2156 read_rtn(arg0, arg1, cur_ptr->offset));
2157 /* check for snprintf overflow or error */
2158 if (len < 0 || (uint32)len >= bufsize)
2169 bcm_mkiovar(const char *name, char *data, uint datalen, char *buf, uint buflen)
2173 len = (uint)strlen(name) + 1;
2175 if ((len + datalen) > buflen)
2178 strncpy(buf, name, buflen);
2180 /* append data onto the end of the name string */
2181 memcpy(&buf[len], data, datalen);
2187 /* Quarter dBm units to mW
2188 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
2189 * Table is offset so the last entry is largest mW value that fits in
2193 #define QDBM_OFFSET 153 /* Offset for first entry */
2194 #define QDBM_TABLE_LEN 40 /* Table size */
2196 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
2197 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
2199 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
2201 /* Largest mW value that will round down to the last table entry,
2202 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
2203 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
2205 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
2207 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
2208 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
2209 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
2210 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
2211 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
2212 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
2213 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
2217 bcm_qdbm_to_mw(uint8 qdbm)
2220 int idx = qdbm - QDBM_OFFSET;
2222 if (idx >= QDBM_TABLE_LEN) {
2223 /* clamp to max uint16 mW value */
2227 /* scale the qdBm index up to the range of the table 0-40
2228 * where an offset of 40 qdBm equals a factor of 10 mW.
2235 /* return the mW value scaled down to the correct factor of 10,
2236 * adding in factor/2 to get proper rounding.
2238 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
2242 bcm_mw_to_qdbm(uint16 mw)
2249 /* handle boundary case */
2253 offset = QDBM_OFFSET;
2255 /* move mw into the range of the table */
2256 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
2261 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
2262 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
2263 nqdBm_to_mW_map[qdbm])/2;
2264 if (mw_uint < boundary) break;
2267 qdbm += (uint8)offset;
2274 bcm_bitcount(uint8 *bitmap, uint length)
2276 uint bitcount = 0, i;
2278 for (i = 0; i < length; i++) {
2288 #if defined(BCMDRIVER) || defined(WL_UNITTEST)
2290 /* triggers bcm_bprintf to print to kernel log */
2291 bool bcm_bprintf_bypass = FALSE;
2293 /* Initialization of bcmstrbuf structure */
2295 bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
2297 b->origsize = b->size = size;
2298 b->origbuf = b->buf = buf;
2301 /* Buffer sprintf wrapper to guard against buffer overflow */
2303 bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
2310 r = vsnprintf(b->buf, b->size, fmt, ap);
2311 if (bcm_bprintf_bypass == TRUE) {
2316 /* Non Ansi C99 compliant returns -1,
2317 * Ansi compliant return r >= b->size,
2318 * bcmstdlib returns 0, handle all
2320 /* r == 0 is also the case when strlen(fmt) is zero.
2321 * typically the case when "" is passed as argument.
2323 if ((r == -1) || (r >= (int)b->size)) {
2337 bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, const uint8 *buf, int len)
2341 if (msg != NULL && msg[0] != '\0')
2342 bcm_bprintf(b, "%s", msg);
2343 for (i = 0; i < len; i ++)
2344 bcm_bprintf(b, "%02X", buf[i]);
2346 bcm_bprintf(b, "\n");
2350 bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
2354 for (i = 0; i < num_bytes; i++) {
2356 if (num[i] >= amount)
2363 bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes)
2367 for (i = nbytes - 1; i >= 0; i--) {
2368 if (arg1[i] != arg2[i])
2369 return (arg1[i] - arg2[i]);
2375 bcm_print_bytes(const char *name, const uchar *data, int len)
2380 printf("%s: %d \n", name ? name : "", len);
2381 for (i = 0; i < len; i++) {
2382 printf("%02x ", *data++);
2384 if (per_line == 16) {
2392 /* Look for vendor-specific IE with specified OUI and optional type */
2394 bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len)
2399 ie = (bcm_tlv_t*)tlvs;
2401 /* make sure we are looking at a valid IE */
2402 if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) {
2406 /* Walk through the IEs looking for an OUI match */
2409 if ((ie->id == DOT11_MNG_PROPR_ID) &&
2410 (ie_len >= (DOT11_OUI_LEN + type_len)) &&
2411 !bcmp(ie->data, voui, DOT11_OUI_LEN))
2413 /* compare optional type */
2414 if (type_len == 0 ||
2415 !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) {
2416 return (ie); /* a match */
2419 } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL);
2424 #if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
2425 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
2426 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
2429 bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
2433 char *endp = buf + SSID_FMT_BUF_LEN;
2435 if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
2437 for (i = 0; i < ssid_len; i++) {
2442 } else if (bcm_isprint((uchar)c)) {
2445 p += snprintf(p, (endp - p), "\\x%02X", c);
2451 return (int)(p - buf);
2455 #endif /* BCMDRIVER || WL_UNITTEST */
2458 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
2459 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
2460 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
2461 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
2465 process_nvram_vars(char *varbuf, unsigned int len)
2470 unsigned int buf_len, n;
2471 unsigned int pad = 0;
2475 findNewline = FALSE;
2478 // terence 20130914: print out NVRAM version
2479 if (varbuf[0] == '#') {
2480 printf("NVRAM version: ");
2481 for (n=1; n<len; n++) {
2482 if (varbuf[n] == '\n')
2484 printk("%c", varbuf[n]);
2489 for (n = 0; n < len; n++) {
2490 if (varbuf[n] == '\r')
2492 if (findNewline && varbuf[n] != '\n')
2494 findNewline = FALSE;
2495 if (varbuf[n] == '#') {
2499 if (varbuf[n] == '\n') {
2509 buf_len = (unsigned int)(dp - varbuf);
2511 pad = 4 - buf_len % 4;
2512 if (pad && (buf_len + pad <= len)) {
2517 while (dp < varbuf + n)
2523 /* calculate a * b + c */
2525 bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c)
2527 #define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;}
2529 uint32 a1, a0, b1, b0, t, cc = 0;
2539 t = (a1 * b0) << 16;
2545 t = (a0 * b1) << 16;
2556 r0 |= (cc % 2) ? 0x80000000 : 0;
2557 r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2);
2563 /* calculate a / b */
2565 bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
2567 uint32 a1 = a_high, a0 = a_low, r0 = 0;
2573 r0 += (0xffffffff / b) * a1;
2574 bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0);
2581 #ifndef setbit /* As in the header file */
2582 #ifdef BCMUTILS_BIT_MACROS_USE_FUNCS
2583 /* Set bit in byte array. */
2585 setbit(void *array, uint bit)
2587 ((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY);
2590 /* Clear bit in byte array. */
2592 clrbit(void *array, uint bit)
2594 ((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY));
2597 /* Test if bit is set in byte array. */
2599 isset(const void *array, uint bit)
2601 return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY)));
2604 /* Test if bit is clear in byte array. */
2606 isclr(const void *array, uint bit)
2608 return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0);
2610 #endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */
2614 set_bitrange(void *array, uint start, uint end, uint maxbit)
2616 uint startbyte = start/NBBY;
2617 uint endbyte = end/NBBY;
2618 uint i, startbytelastbit, endbytestartbit;
2621 if (endbyte - startbyte > 1)
2623 startbytelastbit = (startbyte+1)*NBBY - 1;
2624 endbytestartbit = endbyte*NBBY;
2625 for (i = startbyte+1; i < endbyte; i++)
2626 ((uint8 *)array)[i] = 0xFF;
2627 for (i = start; i <= startbytelastbit; i++)
2629 for (i = endbytestartbit; i <= end; i++)
2632 for (i = start; i <= end; i++)
2637 set_bitrange(array, start, maxbit, maxbit);
2638 set_bitrange(array, 0, end, maxbit);
2643 bcm_bitprint32(const uint32 u32arg)
2646 for (i = NBITS(uint32) - 1; i >= 0; i--) {
2647 isbitset(u32arg, i) ? printf("1") : printf("0");
2648 if ((i % NBBY) == 0) printf(" ");
2653 /* calculate checksum for ip header, tcp / udp header / data */
2655 bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum)
2658 sum += (buf[0] << 8) | buf[1];
2668 sum = (sum & 0xffff) + (sum >> 16);
2671 return ((uint16)~sum);
2673 #if defined(BCMDRIVER) && !defined(_CFEZ_)
2675 * Hierarchical Multiword bitmap based small id allocator.
2677 * Multilevel hierarchy bitmap. (maximum 2 levels)
2678 * First hierarchy uses a multiword bitmap to identify 32bit words in the
2679 * second hierarchy that have at least a single bit set. Each bit in a word of
2680 * the second hierarchy represents a unique ID that may be allocated.
2682 * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed.
2683 * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word
2684 * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs.
2685 * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non
2686 * non-zero bitmap word carrying at least one free ID.
2687 * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations.
2688 * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID
2691 * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many
2692 * bits are computed each time on allocation and deallocation, requiring 4
2693 * array indexed access and 3 arithmetic operations. When not defined, a runtime
2694 * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed.
2695 * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation.
2696 * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may
2697 * be used by defining BCM_MWBMAP_USE_CNTSETBITS.
2699 * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array
2700 * size is fixed. No intention to support larger than 4K indice allocation. ID
2701 * allocators for ranges smaller than 4K will have a wastage of only 12Bytes
2702 * with savings in not having to use an indirect access, had it been dynamically
2705 #define BCM_MWBMAP_ITEMS_MAX (64 * 1024) /* May increase to 64K */
2707 #define BCM_MWBMAP_BITS_WORD (NBITS(uint32))
2708 #define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD)
2709 #define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD)
2710 #define BCM_MWBMAP_SHIFT_OP (5)
2711 #define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1))
2712 #define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP)
2713 #define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP)
2715 /* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */
2716 #define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl))
2717 #define BCM_MWBMAP_HDL(ptr) ((void *)(ptr))
2719 #if defined(BCM_MWBMAP_DEBUG)
2720 #define BCM_MWBMAP_AUDIT(mwb) \
2722 ASSERT((mwb != NULL) && \
2723 (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \
2724 bcm_mwbmap_audit(mwb); \
2726 #define MWBMAP_ASSERT(exp) ASSERT(exp)
2727 #define MWBMAP_DBG(x) printf x
2728 #else /* !BCM_MWBMAP_DEBUG */
2729 #define BCM_MWBMAP_AUDIT(mwb) do {} while (0)
2730 #define MWBMAP_ASSERT(exp) do {} while (0)
2731 #define MWBMAP_DBG(x)
2732 #endif /* !BCM_MWBMAP_DEBUG */
2735 typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */
2736 uint16 wmaps; /* Total number of words in free wd bitmap */
2737 uint16 imaps; /* Total number of words in free id bitmap */
2738 int32 ifree; /* Count of free indices. Used only in audits */
2739 uint16 total; /* Total indices managed by multiword bitmap */
2741 void * magic; /* Audit handle parameter from user */
2743 uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */
2744 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2745 int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */
2746 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2748 uint32 id_bitmap[0]; /* Second level bitmap */
2751 /* Incarnate a hierarchical multiword bitmap based small index allocator. */
2753 bcm_mwbmap_init(osl_t *osh, uint32 items_max)
2755 struct bcm_mwbmap * mwbmap_p;
2756 uint32 wordix, size, words, extra;
2758 /* Implementation Constraint: Uses 32bit word bitmap */
2759 MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U);
2760 MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U);
2761 MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX));
2762 MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U);
2764 ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX);
2766 /* Determine the number of words needed in the multiword bitmap */
2767 extra = BCM_MWBMAP_MODOP(items_max);
2768 words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U);
2770 /* Allocate runtime state of multiword bitmap */
2771 /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */
2772 size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words);
2773 mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size);
2774 if (mwbmap_p == (bcm_mwbmap_t *)NULL) {
2778 memset(mwbmap_p, 0, size);
2780 /* Initialize runtime multiword bitmap state */
2781 mwbmap_p->imaps = (uint16)words;
2782 mwbmap_p->ifree = (int32)items_max;
2783 mwbmap_p->total = (uint16)items_max;
2785 /* Setup magic, for use in audit of handle */
2786 mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p);
2788 /* Setup the second level bitmap of free indices */
2789 /* Mark all indices as available */
2790 for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) {
2791 mwbmap_p->id_bitmap[wordix] = (uint32)(~0U);
2792 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2793 mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD;
2794 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2797 /* Ensure that extra indices are tagged as un-available */
2798 if (extra) { /* fixup the free ids in last bitmap and wd_count */
2799 uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1];
2800 *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
2801 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
2802 mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */
2803 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2806 /* Setup the first level bitmap hierarchy */
2807 extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps);
2808 words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U);
2810 mwbmap_p->wmaps = (uint16)words;
2812 for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++)
2813 mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U);
2815 uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1];
2816 *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
2822 return BCM_MWBMAP_INVALID_HDL;
2825 /* Release resources used by multiword bitmap based small index allocator. */
2827 bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl)
2829 bcm_mwbmap_t * mwbmap_p;
2831 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2832 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2834 MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap)
2835 + (sizeof(uint32) * mwbmap_p->imaps));
2839 /* Allocate a unique small index using a multiword bitmap index allocator. */
2841 bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl)
2843 bcm_mwbmap_t * mwbmap_p;
2844 uint32 wordix, bitmap;
2846 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2847 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2849 /* Start with the first hierarchy */
2850 for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) {
2852 bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */
2856 uint32 count, bitix, *bitmap_p;
2858 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
2860 /* clear all except trailing 1 */
2861 bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
2862 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
2863 bcm_count_leading_zeros(bitmap));
2864 bitix = (BCM_MWBMAP_BITS_WORD - 1)
2865 - bcm_count_leading_zeros(bitmap); /* use asm clz */
2866 wordix = BCM_MWBMAP_MULOP(wordix) + bitix;
2868 /* Clear bit if wd count is 0, without conditional branch */
2869 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
2870 count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1;
2871 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
2872 mwbmap_p->wd_count[wordix]--;
2873 count = mwbmap_p->wd_count[wordix];
2874 MWBMAP_ASSERT(count ==
2875 (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1));
2876 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2877 MWBMAP_ASSERT(count >= 0);
2879 /* clear wd_bitmap bit if id_map count is 0 */
2880 bitmap = (count == 0) << bitix;
2883 "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
2884 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count));
2886 *bitmap_p ^= bitmap;
2888 /* Use bitix in the second hierarchy */
2889 bitmap_p = &mwbmap_p->id_bitmap[wordix];
2891 bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */
2892 MWBMAP_ASSERT(bitmap != 0U);
2894 /* clear all except trailing 1 */
2895 bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
2896 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
2897 bcm_count_leading_zeros(bitmap));
2898 bitix = BCM_MWBMAP_MULOP(wordix)
2899 + (BCM_MWBMAP_BITS_WORD - 1)
2900 - bcm_count_leading_zeros(bitmap); /* use asm clz */
2902 mwbmap_p->ifree--; /* decrement system wide free count */
2903 MWBMAP_ASSERT(mwbmap_p->ifree >= 0);
2906 "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d",
2907 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
2910 *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */
2916 ASSERT(mwbmap_p->ifree == 0);
2918 return BCM_MWBMAP_INVALID_IDX;
2921 /* Force an index at a specified position to be in use */
2923 bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
2925 bcm_mwbmap_t * mwbmap_p;
2926 uint32 count, wordix, bitmap, *bitmap_p;
2928 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2929 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2931 ASSERT(bitix < mwbmap_p->total);
2933 /* Start with second hierarchy */
2934 wordix = BCM_MWBMAP_DIVOP(bitix);
2935 bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix));
2936 bitmap_p = &mwbmap_p->id_bitmap[wordix];
2938 ASSERT((*bitmap_p & bitmap) == bitmap);
2940 mwbmap_p->ifree--; /* update free count */
2941 ASSERT(mwbmap_p->ifree >= 0);
2943 MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d",
2944 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
2947 *bitmap_p ^= bitmap; /* mark as in use */
2949 /* Update first hierarchy */
2952 wordix = BCM_MWBMAP_DIVOP(bitix);
2953 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
2955 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
2956 count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
2957 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
2958 mwbmap_p->wd_count[bitix]--;
2959 count = mwbmap_p->wd_count[bitix];
2960 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
2961 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2962 MWBMAP_ASSERT(count >= 0);
2964 bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix);
2966 MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
2967 BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap,
2968 (*bitmap_p) ^ bitmap, count));
2970 *bitmap_p ^= bitmap; /* mark as in use */
2975 /* Free a previously allocated index back into the multiword bitmap allocator */
2977 bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
2979 bcm_mwbmap_t * mwbmap_p;
2980 uint32 wordix, bitmap, *bitmap_p;
2982 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2983 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2985 ASSERT(bitix < mwbmap_p->total);
2987 /* Start with second level hierarchy */
2988 wordix = BCM_MWBMAP_DIVOP(bitix);
2989 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
2990 bitmap_p = &mwbmap_p->id_bitmap[wordix];
2992 ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */
2994 mwbmap_p->ifree++; /* update free count */
2995 ASSERT(mwbmap_p->ifree <= mwbmap_p->total);
2997 MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d",
2998 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap,
3001 *bitmap_p |= bitmap; /* mark as available */
3003 /* Now update first level hierarchy */
3007 wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */
3008 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
3009 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
3011 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
3012 mwbmap_p->wd_count[bitix]++;
3015 #if defined(BCM_MWBMAP_DEBUG)
3018 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3019 count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
3020 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3021 count = mwbmap_p->wd_count[bitix];
3022 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
3023 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3025 MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD);
3027 MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d",
3028 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count));
3030 #endif /* BCM_MWBMAP_DEBUG */
3032 *bitmap_p |= bitmap;
3037 /* Fetch the toal number of free indices in the multiword bitmap allocator */
3039 bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl)
3041 bcm_mwbmap_t * mwbmap_p;
3043 BCM_MWBMAP_AUDIT(mwbmap_hdl);
3044 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3046 ASSERT(mwbmap_p->ifree >= 0);
3048 return mwbmap_p->ifree;
3051 /* Determine whether an index is inuse or free */
3053 bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
3055 bcm_mwbmap_t * mwbmap_p;
3056 uint32 wordix, bitmap;
3058 BCM_MWBMAP_AUDIT(mwbmap_hdl);
3059 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3061 ASSERT(bitix < mwbmap_p->total);
3063 wordix = BCM_MWBMAP_DIVOP(bitix);
3064 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
3066 return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U);
3069 /* Debug dump a multiword bitmap allocator */
3071 bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl)
3074 bcm_mwbmap_t * mwbmap_p;
3076 BCM_MWBMAP_AUDIT(mwbmap_hdl);
3077 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3079 printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p,
3080 mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total);
3081 for (ix = 0U; ix < mwbmap_p->wmaps; ix++) {
3082 printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]);
3083 bcm_bitprint32(mwbmap_p->wd_bitmap[ix]);
3086 for (ix = 0U; ix < mwbmap_p->imaps; ix++) {
3087 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3088 count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]);
3089 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3090 count = mwbmap_p->wd_count[ix];
3091 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix]));
3092 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3093 printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count);
3094 bcm_bitprint32(mwbmap_p->id_bitmap[ix]);
3101 /* Audit a hierarchical multiword bitmap */
3103 bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)
3105 bcm_mwbmap_t * mwbmap_p;
3106 uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p;
3108 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
3110 for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) {
3112 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
3114 for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) {
3115 if ((*bitmap_p) & (1 << bitix)) {
3116 idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix;
3117 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
3118 count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]);
3119 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
3120 count = mwbmap_p->wd_count[idmap_ix];
3121 ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]));
3122 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
3123 ASSERT(count != 0U);
3129 ASSERT((int)free_cnt == mwbmap_p->ifree);
3131 /* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
3133 /* Simple 16bit Id allocator using a stack implementation. */
3134 typedef struct id16_map {
3135 uint32 failures; /* count of failures */
3136 void *dbg; /* debug placeholder */
3137 uint16 total; /* total number of ids managed by allocator */
3138 uint16 start; /* start value of 16bit ids to be managed */
3139 int stack_idx; /* index into stack of available ids */
3140 uint16 stack[0]; /* stack of 16 bit ids */
3143 #define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \
3144 (sizeof(uint16) * (items)))
3146 #if defined(BCM_DBG)
3148 /* Uncomment BCM_DBG_ID16 to debug double free */
3149 /* #define BCM_DBG_ID16 */
3151 typedef struct id16_map_dbg {
3155 #define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \
3156 (sizeof(bool) * (items)))
3157 #define ID16_MAP_MSG(x) print x
3159 #define ID16_MAP_MSG(x)
3160 #endif /* BCM_DBG */
3162 void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */
3163 id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16)
3166 id16_map_t * id16_map;
3168 ASSERT(total_ids > 0);
3170 /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
3171 * with random values.
3173 ASSERT((start_val16 == ID16_UNDEFINED) ||
3174 (start_val16 + total_ids) < ID16_INVALID);
3176 id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids));
3177 if (id16_map == NULL) {
3181 id16_map->total = total_ids;
3182 id16_map->start = start_val16;
3183 id16_map->failures = 0;
3184 id16_map->dbg = NULL;
3187 * Populate stack with 16bit id values, commencing with start_val16.
3188 * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map.
3190 id16_map->stack_idx = -1;
3192 if (id16_map->start != ID16_UNDEFINED) {
3193 val16 = start_val16;
3195 for (idx = 0; idx < total_ids; idx++, val16++) {
3196 id16_map->stack_idx = idx;
3197 id16_map->stack[id16_map->stack_idx] = val16;
3201 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3202 if (id16_map->start != ID16_UNDEFINED) {
3203 id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids));
3205 if (id16_map->dbg) {
3206 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
3208 id16_map_dbg->total = total_ids;
3209 for (idx = 0; idx < total_ids; idx++) {
3210 id16_map_dbg->avail[idx] = TRUE;
3214 #endif /* BCM_DBG && BCM_DBG_ID16 */
3216 return (void *)id16_map;
3219 void * /* Destruct an id16 allocator instance */
3220 id16_map_fini(osl_t *osh, void * id16_map_hndl)
3223 id16_map_t * id16_map;
3225 if (id16_map_hndl == NULL)
3228 id16_map = (id16_map_t *)id16_map_hndl;
3230 total_ids = id16_map->total;
3231 ASSERT(total_ids > 0);
3233 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3234 if (id16_map->dbg) {
3235 MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids));
3236 id16_map->dbg = NULL;
3238 #endif /* BCM_DBG && BCM_DBG_ID16 */
3240 id16_map->total = 0;
3241 MFREE(osh, id16_map, ID16_MAP_SZ(total_ids));
3247 id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16)
3250 id16_map_t * id16_map;
3252 ASSERT(total_ids > 0);
3253 /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
3254 * with random values.
3256 ASSERT((start_val16 == ID16_UNDEFINED) ||
3257 (start_val16 + total_ids) < ID16_INVALID);
3259 id16_map = (id16_map_t *)id16_map_hndl;
3260 if (id16_map == NULL) {
3264 id16_map->total = total_ids;
3265 id16_map->start = start_val16;
3266 id16_map->failures = 0;
3268 /* Populate stack with 16bit id values, commencing with start_val16 */
3269 id16_map->stack_idx = -1;
3271 if (id16_map->start != ID16_UNDEFINED) {
3272 val16 = start_val16;
3274 for (idx = 0; idx < total_ids; idx++, val16++) {
3275 id16_map->stack_idx = idx;
3276 id16_map->stack[id16_map->stack_idx] = val16;
3280 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3281 if (id16_map->start != ID16_UNDEFINED) {
3282 if (id16_map->dbg) {
3283 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
3285 id16_map_dbg->total = total_ids;
3286 for (idx = 0; idx < total_ids; idx++) {
3287 id16_map_dbg->avail[idx] = TRUE;
3291 #endif /* BCM_DBG && BCM_DBG_ID16 */
3294 uint16 BCMFASTPATH /* Allocate a unique 16bit id */
3295 id16_map_alloc(void * id16_map_hndl)
3298 id16_map_t * id16_map;
3300 ASSERT(id16_map_hndl != NULL);
3302 id16_map = (id16_map_t *)id16_map_hndl;
3304 ASSERT(id16_map->total > 0);
3306 if (id16_map->stack_idx < 0) {
3307 id16_map->failures++;
3308 return ID16_INVALID;
3311 val16 = id16_map->stack[id16_map->stack_idx];
3312 id16_map->stack_idx--;
3314 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3315 ASSERT((id16_map->start == ID16_UNDEFINED) ||
3316 (val16 < (id16_map->start + id16_map->total)));
3318 if (id16_map->dbg) { /* Validate val16 */
3319 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
3321 ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE);
3322 id16_map_dbg->avail[val16 - id16_map->start] = FALSE;
3324 #endif /* BCM_DBG && BCM_DBG_ID16 */
3330 void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */
3331 id16_map_free(void * id16_map_hndl, uint16 val16)
3333 id16_map_t * id16_map;
3335 ASSERT(id16_map_hndl != NULL);
3337 id16_map = (id16_map_t *)id16_map_hndl;
3339 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3340 ASSERT((id16_map->start == ID16_UNDEFINED) ||
3341 (val16 < (id16_map->start + id16_map->total)));
3343 if (id16_map->dbg) { /* Validate val16 */
3344 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
3346 ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE);
3347 id16_map_dbg->avail[val16 - id16_map->start] = TRUE;
3349 #endif /* BCM_DBG && BCM_DBG_ID16 */
3351 id16_map->stack_idx++;
3352 id16_map->stack[id16_map->stack_idx] = val16;
3355 uint32 /* Returns number of failures to allocate an unique id16 */
3356 id16_map_failures(void * id16_map_hndl)
3358 ASSERT(id16_map_hndl != NULL);
3359 return ((id16_map_t *)id16_map_hndl)->failures;
3363 id16_map_audit(void * id16_map_hndl)
3367 id16_map_t * id16_map;
3369 ASSERT(id16_map_hndl != NULL);
3371 id16_map = (id16_map_t *)id16_map_hndl;
3373 ASSERT(id16_map->stack_idx >= -1);
3374 ASSERT(id16_map->stack_idx < (int)id16_map->total);
3376 if (id16_map->start == ID16_UNDEFINED)
3379 for (idx = 0; idx <= id16_map->stack_idx; idx++) {
3380 ASSERT(id16_map->stack[idx] >= id16_map->start);
3381 ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total));
3383 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3384 if (id16_map->dbg) {
3385 uint16 val16 = id16_map->stack[idx];
3386 if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) {
3388 ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n",
3389 id16_map_hndl, idx, val16));
3392 #endif /* BCM_DBG && BCM_DBG_ID16 */
3395 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
3396 if (id16_map->dbg) {
3397 uint16 avail = 0; /* Audit available ids counts */
3398 for (idx = 0; idx < id16_map_dbg->total; idx++) {
3399 if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE)
3402 if (avail && (avail != (id16_map->stack_idx + 1))) {
3404 ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n",
3405 id16_map_hndl, avail, id16_map->stack_idx));
3408 #endif /* BCM_DBG && BCM_DBG_ID16 */
3411 /* invoke any other system audits */
3414 /* END: Simple id16 allocator */
3419 /* calculate a >> b; and returns only lower 32 bits */
3421 bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
3423 uint32 a1 = a_high, a0 = a_low, r0 = 0;
3433 a1 = a1 & ((1 << b) - 1);
3434 a1 = a1 << (32 - b);
3439 r0 = a1 >> (b - 32);
3446 /* calculate a + b where a is a 64 bit number and b is a 32 bit number */
3448 bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset)
3450 uint32 r1_lo = *r_lo;
3456 /* calculate a - b where a is a 64 bit number and b is a 32 bit number */
3458 bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset)
3460 uint32 r1_lo = *r_lo;
3466 #ifdef DEBUG_COUNTER
3467 #if (OSL_SYSUPTIME_SUPPORT == TRUE)
3468 void counter_printlog(counter_tbl_t *ctr_tbl)
3472 if (!ctr_tbl->enabled)
3475 now = OSL_SYSUPTIME();
3477 if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) {
3479 printf("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print);
3481 for (i = 0; i < ctr_tbl->needed_cnt; i++) {
3482 printf(" %u", ctr_tbl->cnt[i]);
3486 ctr_tbl->prev_log_print = now;
3487 bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint));
3491 /* OSL_SYSUPTIME is not supported so no way to get time */
3492 #define counter_printlog(a) do {} while (0)
3493 #endif /* OSL_SYSUPTIME_SUPPORT == TRUE */
3494 #endif /* DEBUG_COUNTER */
3496 #if defined(BCMDRIVER) && !defined(_CFEZ_)
3498 dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size)
3501 mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
3503 MFREE(osh, pool, mem_size);
3506 dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size)
3509 dll_pool_t * dll_pool_p;
3512 ASSERT(elem_size > sizeof(dll_t));
3514 mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
3516 if ((dll_pool_p = (dll_pool_t *)MALLOCZ(osh, mem_size)) == NULL) {
3517 printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n",
3518 elems_max, elem_size);
3523 dll_init(&dll_pool_p->free_list);
3524 dll_pool_p->elems_max = elems_max;
3525 dll_pool_p->elem_size = elem_size;
3527 elem_p = dll_pool_p->elements;
3528 for (i = 0; i < elems_max; i++) {
3529 dll_append(&dll_pool_p->free_list, elem_p);
3530 elem_p = (dll_t *)((uintptr)elem_p + elem_size);
3533 dll_pool_p->free_count = elems_max;
3540 dll_pool_alloc(dll_pool_t * dll_pool_p)
3544 if (dll_pool_p->free_count == 0) {
3545 ASSERT(dll_empty(&dll_pool_p->free_list));
3549 elem_p = dll_head_p(&dll_pool_p->free_list);
3551 dll_pool_p->free_count -= 1;
3553 return (void *)elem_p;
3557 dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p)
3559 dll_t * node_p = (dll_t *)elem_p;
3560 dll_prepend(&dll_pool_p->free_list, node_p);
3561 dll_pool_p->free_count += 1;
3566 dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p)
3568 dll_t * node_p = (dll_t *)elem_p;
3569 dll_append(&dll_pool_p->free_list, node_p);
3570 dll_pool_p->free_count += 1;