2 * Driver O/S-independent utility routines
4 * Copyright (C) 1999-2010, 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.
23 * $Id: bcmutils.c,v 1.210.4.5.2.4.6.19 2010/04/26 06:05:25 Exp $
36 /* This case for external supplicant use */
37 #if defined(BCMEXTSUP)
41 #endif /* BCMDRIVER */
42 #include <bcmendian.h>
44 #include <proto/ethernet.h>
45 #include <proto/vlan.h>
46 #include <proto/bcmip.h>
47 #include <proto/802.1d.h>
48 #include <proto/802.11.h>
54 /* copy a pkt buffer chain into a buffer */
56 pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
61 len = 4096; /* "infinite" */
63 /* skip 'offset' bytes */
64 for (; p && offset; p = PKTNEXT(osh, p)) {
65 if (offset < (uint)PKTLEN(osh, p))
67 offset -= PKTLEN(osh, p);
74 for (; p && len; p = PKTNEXT(osh, p)) {
75 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
76 bcopy(PKTDATA(osh, p) + offset, buf, n);
86 /* copy a buffer into a pkt buffer chain */
88 pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
92 /* skip 'offset' bytes */
93 for (; p && offset; p = PKTNEXT(osh, p)) {
94 if (offset < (uint)PKTLEN(osh, p))
96 offset -= PKTLEN(osh, p);
103 for (; p && len; p = PKTNEXT(osh, p)) {
104 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
105 bcopy(buf, PKTDATA(osh, p) + offset, n);
117 /* return total length of buffer chain */
119 pkttotlen(osl_t *osh, void *p)
124 for (; p; p = PKTNEXT(osh, p))
125 total += PKTLEN(osh, p);
129 /* return the last buffer of chained pkt */
131 pktlast(osl_t *osh, void *p)
133 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
139 /* count segments of a chained packet */
141 pktsegcnt(osl_t *osh, void *p)
145 for (cnt = 0; p; p = PKTNEXT(osh, p))
153 * osl multiple-precedence packet queue
154 * hi_prec is always >= the number of the highest non-empty precedence
157 pktq_penq(struct pktq *pq, int prec, void *p)
161 ASSERT(prec >= 0 && prec < pq->num_prec);
162 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
164 ASSERT(!pktq_full(pq));
165 ASSERT(!pktq_pfull(pq, prec));
170 PKTSETLINK(q->tail, p);
179 if (pq->hi_prec < prec)
180 pq->hi_prec = (uint8)prec;
186 pktq_penq_head(struct pktq *pq, int prec, void *p)
190 ASSERT(prec >= 0 && prec < pq->num_prec);
191 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
193 ASSERT(!pktq_full(pq));
194 ASSERT(!pktq_pfull(pq, prec));
201 PKTSETLINK(p, q->head);
207 if (pq->hi_prec < prec)
208 pq->hi_prec = (uint8)prec;
214 pktq_pdeq(struct pktq *pq, int prec)
219 ASSERT(prec >= 0 && prec < pq->num_prec);
223 if ((p = q->head) == NULL)
226 if ((q->head = PKTLINK(p)) == NULL)
239 pktq_pdeq_tail(struct pktq *pq, int prec)
244 ASSERT(prec >= 0 && prec < pq->num_prec);
248 if ((p = q->head) == NULL)
251 for (prev = NULL; p != q->tail; p = PKTLINK(p))
255 PKTSETLINK(prev, NULL);
268 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
276 q->head = PKTLINK(p);
278 PKTFREE(osh, p, dir);
288 pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
293 ASSERT(prec >= 0 && prec < pq->num_prec);
300 if (q->head == pktbuf) {
301 if ((q->head = PKTLINK(pktbuf)) == NULL)
304 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
309 PKTSETLINK(p, PKTLINK(pktbuf));
310 if (q->tail == pktbuf)
316 PKTSETLINK(pktbuf, NULL);
321 pktq_init(struct pktq *pq, int num_prec, int max_len)
325 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
327 /* pq is variable size; only zero out what's requested */
328 bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
330 pq->num_prec = (uint16)num_prec;
332 pq->max = (uint16)max_len;
334 for (prec = 0; prec < num_prec; prec++)
335 pq->q[prec].max = pq->max;
339 pktq_deq(struct pktq *pq, int *prec_out)
348 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
353 if ((p = q->head) == NULL)
356 if ((q->head = PKTLINK(p)) == NULL)
372 pktq_deq_tail(struct pktq *pq, int *prec_out)
381 for (prec = 0; prec < pq->hi_prec; prec++)
382 if (pq->q[prec].head)
387 if ((p = q->head) == NULL)
390 for (prev = NULL; p != q->tail; p = PKTLINK(p))
394 PKTSETLINK(prev, NULL);
412 pktq_peek(struct pktq *pq, int *prec_out)
419 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
425 return (pq->q[prec].head);
429 pktq_peek_tail(struct pktq *pq, int *prec_out)
436 for (prec = 0; prec < pq->hi_prec; prec++)
437 if (pq->q[prec].head)
443 return (pq->q[prec].tail);
447 pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
450 for (prec = 0; prec < pq->num_prec; prec++)
451 pktq_pflush(osh, pq, prec, dir);
452 ASSERT(pq->len == 0);
455 /* Return sum of lengths of a specific set of precedences */
457 pktq_mlen(struct pktq *pq, uint prec_bmp)
463 for (prec = 0; prec <= pq->hi_prec; prec++)
464 if (prec_bmp & (1 << prec))
465 len += pq->q[prec].len;
470 /* Priority dequeue from a specific set of precedences */
472 pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
481 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
484 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
490 if ((p = q->head) == NULL)
493 if ((q->head = PKTLINK(p)) == NULL)
507 #endif /* BCMDRIVER */
511 const unsigned char bcm_ctype[] = {
512 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
513 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
515 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
516 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
517 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
518 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
519 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
520 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
521 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
522 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
523 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
524 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
525 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
526 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
527 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
528 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
529 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
530 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
531 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
532 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
533 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
534 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
535 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
536 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
537 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
538 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
539 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
540 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
541 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
542 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
543 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
544 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
548 bcm_strtoul(char *cp, char **endp, uint base)
550 ulong result, last_result = 0, value;
555 while (bcm_isspace(*cp))
560 else if (cp[0] == '-') {
567 if ((cp[1] == 'x') || (cp[1] == 'X')) {
576 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
582 while (bcm_isxdigit(*cp) &&
583 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
584 result = result*base + value;
585 /* Detected overflow */
586 if (result < last_result && !minus)
588 last_result = result;
593 result = (ulong)(-(long)result);
604 return (int)bcm_strtoul(s, NULL, 10);
607 /* return pointer to location of substring 'needle' in 'haystack' */
609 bcmstrstr(char *haystack, char *needle)
614 if ((haystack == NULL) || (needle == NULL))
617 nlen = strlen(needle);
618 len = strlen(haystack) - nlen + 1;
620 for (i = 0; i < len; i++)
621 if (memcmp(needle, &haystack[i], nlen) == 0)
622 return (&haystack[i]);
627 bcmstrcat(char *dest, const char *src)
631 p = dest + strlen(dest);
633 while ((*p++ = *src++) != '\0')
640 bcmstrncat(char *dest, const char *src, uint size)
645 p = dest + strlen(dest);
648 while (p != endp && (*p++ = *src++) != '\0')
655 /****************************************************************************
656 * Function: bcmstrtok
659 * Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
660 * but allows strToken() to be used by different strings or callers at the same
661 * time. Each call modifies '*string' by substituting a NULL character for the
662 * first delimiter that is encountered, and updates 'string' to point to the char
663 * after the delimiter. Leading delimiters are skipped.
666 * string (mod) Ptr to string ptr, updated by token.
667 * delimiters (in) Set of delimiter characters.
668 * tokdelim (out) Character that delimits the returned token. (May
669 * be set to NULL if token delimiter is not required).
671 * Returns: Pointer to the next token found. NULL when no more tokens are found.
672 *****************************************************************************
675 bcmstrtok(char **string, const char *delimiters, char *tokdelim)
678 unsigned long map[8];
682 if (tokdelim != NULL) {
683 /* Prime the token delimiter */
687 /* Clear control map */
688 for (count = 0; count < 8; count++) {
692 /* Set bits in delimiter table */
694 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
696 while (*delimiters++);
698 str = (unsigned char*)*string;
700 /* Find beginning of token (skip over leading delimiters). Note that
701 * there is no token iff this loop sets str to point to the terminal
702 * null (*str == '\0')
704 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
708 nextoken = (char*)str;
710 /* Find the end of the token. If it is not the end of the string,
713 for (; *str; str++) {
714 if (map[*str >> 5] & (1 << (*str & 31))) {
715 if (tokdelim != NULL) {
724 *string = (char*)str;
726 /* Determine if a token has been found. */
727 if (nextoken == (char *) str) {
736 #define xToLower(C) \
737 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
740 /****************************************************************************
741 * Function: bcmstricmp
743 * Purpose: Compare to strings case insensitively.
745 * Parameters: s1 (in) First string to compare.
746 * s2 (in) Second string to compare.
748 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
749 * t1 > t2, when ignoring case sensitivity.
750 *****************************************************************************
753 bcmstricmp(const char *s1, const char *s2)
760 if (dc < sc) return -1;
761 if (dc > sc) return 1;
766 if (*s1 && !*s2) return 1;
767 if (!*s1 && *s2) return -1;
772 /****************************************************************************
773 * Function: bcmstrnicmp
775 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
778 * Parameters: s1 (in) First string to compare.
779 * s2 (in) Second string to compare.
780 * cnt (in) Max characters to compare.
782 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
783 * t1 > t2, when ignoring case sensitivity.
784 *****************************************************************************
787 bcmstrnicmp(const char* s1, const char* s2, int cnt)
791 while (*s2 && *s1 && cnt) {
794 if (dc < sc) return -1;
795 if (dc > sc) return 1;
802 if (*s1 && !*s2) return 1;
803 if (!*s1 && *s2) return -1;
807 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
809 bcm_ether_atoe(char *p, struct ether_addr *ea)
814 ea->octet[i++] = (char) bcm_strtoul(p, &p, 16);
823 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
824 /* registry routine buffer preparation utility functions:
825 * parameter order is like strncpy, but returns count
826 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
829 wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
837 /* wbuflen is in bytes */
838 wbuflen /= sizeof(ushort);
840 for (i = 0; i < wbuflen; ++i) {
843 *abuf++ = (char) *wbuf++;
850 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
853 bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
855 static const char template[] = "%02x:%02x:%02x:%02x:%02x:%02x";
856 snprintf(buf, 18, template,
857 ea->octet[0]&0xff, ea->octet[1]&0xff, ea->octet[2]&0xff,
858 ea->octet[3]&0xff, ea->octet[4]&0xff, ea->octet[5]&0xff);
863 bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
865 snprintf(buf, 16, "%d.%d.%d.%d",
866 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
877 for (i = 0; i < ms; i++) {
887 #if defined(DHD_DEBUG)
888 /* pretty hex print a pkt buffer chain */
890 prpkt(const char *msg, osl_t *osh, void *p0)
894 if (msg && (msg[0] != '\0'))
895 printf("%s:\n", msg);
897 for (p = p0; p; p = PKTNEXT(osh, p))
898 prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
902 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
903 * Also updates the inplace vlan tag if requested.
904 * For debugging, it returns an indication of what it did.
907 pktsetprio(void *pkt, bool update_vtag)
909 struct ether_header *eh;
910 struct ethervlan_header *evh;
915 pktdata = (uint8 *) PKTDATA(NULL, pkt);
916 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
918 eh = (struct ether_header *) pktdata;
920 if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
922 int vlan_prio, dscp_prio = 0;
924 evh = (struct ethervlan_header *)eh;
926 vlan_tag = ntoh16(evh->vlan_tag);
927 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
929 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
930 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
931 uint8 tos_tc = IP_TOS(ip_body);
932 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
935 /* DSCP priority gets precedence over 802.1P (vlan tag) */
936 if (dscp_prio != 0) {
937 priority = dscp_prio;
940 priority = vlan_prio;
944 * If the DSCP priority is not the same as the VLAN priority,
945 * then overwrite the priority field in the vlan tag, with the
946 * DSCP priority value. This is required for Linux APs because
947 * the VLAN driver on Linux, overwrites the skb->priority field
948 * with the priority value in the vlan tag
950 if (update_vtag && (priority != vlan_prio)) {
951 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
952 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
953 evh->vlan_tag = hton16(vlan_tag);
956 } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
957 uint8 *ip_body = pktdata + sizeof(struct ether_header);
958 uint8 tos_tc = IP_TOS(ip_body);
959 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
963 ASSERT(priority >= 0 && priority <= MAXPRIO);
964 PKTSETPRIO(pkt, priority);
965 return (rc | priority);
968 static char bcm_undeferrstr[BCME_STRLEN];
970 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
972 /* Convert the error codes into related error strings */
974 bcmerrorstr(int bcmerror)
976 /* check if someone added a bcmerror code but forgot to add errorstring */
977 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
979 if (bcmerror > 0 || bcmerror < BCME_LAST) {
980 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d", bcmerror);
981 return bcm_undeferrstr;
984 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
986 return bcmerrorstrtable[-bcmerror];
991 /* iovar table lookup */
993 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
995 const bcm_iovar_t *vi;
996 const char *lookup_name;
998 /* skip any ':' delimited option prefixes */
999 lookup_name = strrchr(name, ':');
1000 if (lookup_name != NULL)
1005 ASSERT(table != NULL);
1007 for (vi = table; vi->name; vi++) {
1008 if (!strcmp(vi->name, lookup_name))
1011 /* ran to end of table */
1013 return NULL; /* var name not found */
1017 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
1021 /* length check on io buf */
1030 /* all integers are int32 sized args at the ioctl interface */
1031 if (len < (int)sizeof(int)) {
1032 bcmerror = BCME_BUFTOOSHORT;
1037 /* buffer must meet minimum length requirement */
1038 if (len < vi->minlen) {
1039 bcmerror = BCME_BUFTOOSHORT;
1045 /* Cannot return nil... */
1046 bcmerror = BCME_UNSUPPORTED;
1048 /* Set is an action w/o parameters */
1049 bcmerror = BCME_BUFTOOLONG;
1054 /* unknown type for length check in iovar info */
1056 bcmerror = BCME_UNSUPPORTED;
1062 #endif /* BCMDRIVER */
1064 /*******************************************************************************
1067 * Computes a crc8 over the input data using the polynomial:
1069 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1071 * The caller provides the initial value (either CRC8_INIT_VALUE
1072 * or the previous returned value) to allow for processing of
1073 * discontiguous blocks of data. When generating the CRC the
1074 * caller is responsible for complementing the final return value
1075 * and inserting it into the byte stream. When checking, a final
1076 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1078 * Reference: Dallas Semiconductor Application Note 27
1079 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1080 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1081 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1083 * ****************************************************************************
1086 STATIC const uint8 crc8_table[256] = {
1087 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1088 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1089 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1090 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1091 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1092 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1093 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1094 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1095 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1096 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1097 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1098 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1099 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1100 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1101 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1102 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1103 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1104 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1105 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1106 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1107 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1108 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1109 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1110 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1111 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1112 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1113 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1114 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1115 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1116 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1117 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1118 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1121 #define CRC_INNER_LOOP(n, c, x) \
1122 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1126 uint8 *pdata, /* pointer to array of data to process */
1127 uint nbytes, /* number of input data bytes to process */
1128 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1131 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1132 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1134 while (nbytes-- > 0)
1135 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1140 /*******************************************************************************
1143 * Computes a crc16 over the input data using the polynomial:
1145 * x^16 + x^12 +x^5 + 1
1147 * The caller provides the initial value (either CRC16_INIT_VALUE
1148 * or the previous returned value) to allow for processing of
1149 * discontiguous blocks of data. When generating the CRC the
1150 * caller is responsible for complementing the final return value
1151 * and inserting it into the byte stream. When checking, a final
1152 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1154 * Reference: Dallas Semiconductor Application Note 27
1155 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1156 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1157 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1159 * ****************************************************************************
1162 static const uint16 crc16_table[256] = {
1163 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1164 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1165 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1166 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1167 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1168 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1169 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1170 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1171 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1172 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1173 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1174 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1175 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1176 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1177 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1178 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1179 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1180 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1181 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1182 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1183 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1184 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1185 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1186 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1187 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1188 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1189 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1190 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1191 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1192 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1193 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1194 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1199 uint8 *pdata, /* pointer to array of data to process */
1200 uint nbytes, /* number of input data bytes to process */
1201 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1204 while (nbytes-- > 0)
1205 CRC_INNER_LOOP(16, crc, *pdata++);
1209 STATIC const uint32 crc32_table[256] = {
1210 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1211 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1212 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1213 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1214 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1215 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1216 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1217 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1218 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1219 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1220 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1221 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1222 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1223 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1224 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1225 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1226 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1227 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1228 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1229 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1230 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1231 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1232 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1233 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1234 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1235 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1236 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1237 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1238 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1239 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1240 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1241 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1242 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1243 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1244 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1245 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1246 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1247 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1248 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1249 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1250 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1251 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1252 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1253 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1254 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1255 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1256 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1257 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1258 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1259 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1260 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1261 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1262 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1263 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1264 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1265 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1266 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1267 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1268 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1269 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1270 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1271 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1272 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1273 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1278 uint8 *pdata, /* pointer to array of data to process */
1279 uint nbytes, /* number of input data bytes to process */
1280 uint32 crc /* either CRC32_INIT_VALUE or previous return value */
1286 ulong *tptr = (ulong *)tmp;
1288 /* in case the beginning of the buffer isn't aligned */
1289 pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
1290 nbytes -= (pend - pdata);
1291 while (pdata < pend)
1292 CRC_INNER_LOOP(32, crc, *pdata++);
1294 /* handle bulk of data as 32-bit words */
1295 pend = pdata + (nbytes & 0xfffffffc);
1296 while (pdata < pend) {
1297 *tptr = *(ulong *)pdata;
1298 pdata += sizeof(ulong *);
1299 CRC_INNER_LOOP(32, crc, tmp[0]);
1300 CRC_INNER_LOOP(32, crc, tmp[1]);
1301 CRC_INNER_LOOP(32, crc, tmp[2]);
1302 CRC_INNER_LOOP(32, crc, tmp[3]);
1305 /* 1-3 bytes at end of buffer */
1306 pend = pdata + (nbytes & 0x03);
1307 while (pdata < pend)
1308 CRC_INNER_LOOP(32, crc, *pdata++);
1310 pend = pdata + nbytes;
1311 while (pdata < pend)
1312 CRC_INNER_LOOP(32, crc, *pdata++);
1313 #endif /* __mips__ */
1319 #define CLEN 1499 /* CRC Length */
1320 #define CBUFSIZ (CLEN+4)
1321 #define CNBUFS 5 /* # of bufs */
1323 void testcrc32(void)
1329 uint32 crc32tv[CNBUFS] =
1330 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1332 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
1334 /* step through all possible alignments */
1335 for (l = 0; l <= 4; l++) {
1336 for (j = 0; j < CNBUFS; j++) {
1338 for (k = 0; k < len[j]; k++)
1339 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
1342 for (j = 0; j < CNBUFS; j++) {
1343 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1344 ASSERT(crcr == crc32tv[j]);
1348 MFREE(buf, CBUFSIZ*CNBUFS);
1354 * Advance from the current 1-byte tag/1-byte length/variable-length value
1355 * triple, to the next, returning a pointer to the next.
1356 * If the current or next TLV is invalid (does not fit in given buffer length),
1358 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1359 * by the TLV parameter's length if it is valid.
1362 bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
1366 /* validate current elt */
1367 if (!bcm_valid_tlv(elt, *buflen))
1370 /* advance to next elt */
1372 elt = (bcm_tlv_t*)(elt->data + len);
1373 *buflen -= (2 + len);
1375 /* validate next elt */
1376 if (!bcm_valid_tlv(elt, *buflen))
1383 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1384 * triples, returning a pointer to the substring whose first element
1388 bcm_parse_tlvs(void *buf, int buflen, uint key)
1393 elt = (bcm_tlv_t*)buf;
1396 /* find tagged parameter */
1397 while (totlen >= 2) {
1400 /* validate remaining totlen */
1401 if ((elt->id == key) && (totlen >= (len + 2)))
1404 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1405 totlen -= (len + 2);
1412 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1413 * triples, returning a pointer to the substring whose first element
1414 * matches tag. Stop parsing when we see an element whose ID is greater
1415 * than the target key.
1418 bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
1423 elt = (bcm_tlv_t*)buf;
1426 /* find tagged parameter */
1427 while (totlen >= 2) {
1431 /* Punt if we start seeing IDs > than target key */
1435 /* validate remaining totlen */
1436 if ((id == key) && (totlen >= (len + 2)))
1439 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1440 totlen -= (len + 2);
1445 #if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1448 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
1457 if (len < 2 || !buf)
1463 for (i = 0; flags != 0; i++) {
1466 if (bit == 0 && flags) {
1467 /* print any unnamed bits */
1468 sprintf(hexstr, "0x%X", flags);
1470 flags = 0; /* exit loop */
1471 } else if ((flags & bit) == 0)
1473 slen += strlen(name);
1476 if (p != buf) p += sprintf(p, " "); /* btwn flag space */
1481 slen = 1; /* account for btwn flag space */
1484 /* indicate the str was too short */
1487 p--; /* overwrite last char */
1488 p += sprintf(p, ">");
1491 return (int)(p - buf);
1494 /* print bytes formatted as hex to a string. return the resulting string length */
1496 bcm_format_hex(char *str, const void *bytes, int len)
1500 const uint8 *src = (const uint8*)bytes;
1502 for (i = 0; i < len; i++) {
1503 p += sprintf(p, "%02X", *src);
1506 return (int)(p - str);
1509 /* pretty hex print a contiguous buffer */
1511 prhex(const char *msg, uchar *buf, uint nbytes)
1516 if (msg && (msg[0] != '\0'))
1517 printf("%s:\n", msg);
1520 for (i = 0; i < nbytes; i++) {
1522 p += sprintf(p, " %04d: ", i); /* line prefix */
1524 p += sprintf(p, "%02x ", buf[i]);
1526 printf("%s\n", line); /* flush line */
1531 /* flush last partial line */
1533 printf("%s\n", line);
1538 /* Produce a human-readable string for boardrev */
1540 bcm_brev_str(uint32 brev, char *buf)
1543 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1545 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
1550 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1552 /* dump large strings to console */
1561 max_len = BUFSIZE_TODUMP_ATONCE;
1563 while (len > max_len) {
1565 buf[max_len] = '\0';
1572 /* print the remaining string */
1573 printf("%s\n", buf);
1577 /* routine to dump fields in a fileddesc structure */
1579 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
1580 char *buf, uint32 bufsize)
1584 struct fielddesc *cur_ptr;
1587 cur_ptr = fielddesc_array;
1589 while (bufsize > 1) {
1590 if (cur_ptr->nameandfmt == NULL)
1592 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
1593 read_rtn(arg0, arg1, cur_ptr->offset));
1594 /* check for snprintf overflow or error */
1595 if (len < 0 || (uint32)len >= bufsize)
1606 bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1610 len = strlen(name) + 1;
1612 if ((len + datalen) > buflen)
1615 strncpy(buf, name, buflen);
1617 /* append data onto the end of the name string */
1618 memcpy(&buf[len], data, datalen);
1624 /* Quarter dBm units to mW
1625 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1626 * Table is offset so the last entry is largest mW value that fits in
1630 #define QDBM_OFFSET 153 /* Offset for first entry */
1631 #define QDBM_TABLE_LEN 40 /* Table size */
1633 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1634 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1636 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1638 /* Largest mW value that will round down to the last table entry,
1639 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1640 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1642 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1644 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1645 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1646 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1647 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1648 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1649 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1650 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1654 bcm_qdbm_to_mw(uint8 qdbm)
1657 int idx = qdbm - QDBM_OFFSET;
1659 if (idx >= QDBM_TABLE_LEN) {
1660 /* clamp to max uint16 mW value */
1664 /* scale the qdBm index up to the range of the table 0-40
1665 * where an offset of 40 qdBm equals a factor of 10 mW.
1672 /* return the mW value scaled down to the correct factor of 10,
1673 * adding in factor/2 to get proper rounding.
1675 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
1679 bcm_mw_to_qdbm(uint16 mw)
1686 /* handle boundary case */
1690 offset = QDBM_OFFSET;
1692 /* move mw into the range of the table */
1693 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1698 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
1699 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
1700 nqdBm_to_mW_map[qdbm])/2;
1701 if (mw_uint < boundary) break;
1704 qdbm += (uint8)offset;
1711 bcm_bitcount(uint8 *bitmap, uint length)
1713 uint bitcount = 0, i;
1715 for (i = 0; i < length; i++) {
1727 /* Initialization of bcmstrbuf structure */
1729 bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1731 b->origsize = b->size = size;
1732 b->origbuf = b->buf = buf;
1735 /* Buffer sprintf wrapper to guard against buffer overflow */
1737 bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1743 r = vsnprintf(b->buf, b->size, fmt, ap);
1745 /* Non Ansi C99 compliant returns -1,
1746 * Ansi compliant return r >= b->size,
1747 * bcmstdlib returns 0, handle all
1749 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1762 bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
1766 for (i = 0; i < num_bytes; i++) {
1768 if (num[i] >= amount)
1775 bcm_cmp_bytes(uchar *arg1, uchar *arg2, uint8 nbytes)
1779 for (i = nbytes - 1; i >= 0; i--) {
1780 if (arg1[i] != arg2[i])
1781 return (arg1[i] - arg2[i]);
1787 bcm_print_bytes(char *name, const uchar *data, int len)
1792 printf("%s: %d \n", name ? name : "", len);
1793 for (i = 0; i < len; i++) {
1794 printf("%02x ", *data++);
1796 if (per_line == 16) {
1805 * buffer length needed for wlc_format_ssid
1806 * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
1809 #if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
1810 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
1812 bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
1816 char *endp = buf + SSID_FMT_BUF_LEN;
1818 if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
1820 for (i = 0; i < ssid_len; i++) {
1825 } else if (bcm_isprint((uchar)c)) {
1828 p += snprintf(p, (endp - p), "\\x%02X", c);
1834 return (int)(p - buf);
1838 #endif /* BCMDRIVER */