2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27 /* This case for external supplicant use */
28 #if defined(BCMEXTSUP)
32 #endif /* BCMDRIVER */
33 #include <bcmendian.h>
35 #include <proto/ethernet.h>
36 #include <proto/vlan.h>
37 #include <proto/bcmip.h>
38 #include <proto/802.1d.h>
39 #include <proto/802.11.h>
43 /* copy a pkt buffer chain into a buffer */
44 uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar * buf)
49 len = 4096; /* "infinite" */
51 /* skip 'offset' bytes */
52 for (; p && offset; p = PKTNEXT(p)) {
53 if (offset < (uint) PKTLEN(p))
62 for (; p && len; p = PKTNEXT(p)) {
63 n = MIN((uint) PKTLEN(p) - offset, (uint) len);
64 bcopy(PKTDATA(p) + offset, buf, n);
74 /* copy a buffer into a pkt buffer chain */
75 uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
79 /* skip 'offset' bytes */
80 for (; p && offset; p = PKTNEXT(p)) {
81 if (offset < (uint) PKTLEN(p))
90 for (; p && len; p = PKTNEXT(p)) {
91 n = MIN((uint) PKTLEN(p) - offset, (uint) len);
92 bcopy(buf, PKTDATA(p) + offset, n);
102 /* return total length of buffer chain */
103 uint pkttotlen(osl_t *osh, void *p)
108 for (; p; p = PKTNEXT(p))
113 /* return the last buffer of chained pkt */
114 void *pktlast(osl_t *osh, void *p)
116 for (; PKTNEXT(p); p = PKTNEXT(p))
122 /* count segments of a chained packet */
123 uint pktsegcnt(osl_t *osh, void *p)
127 for (cnt = 0; p; p = PKTNEXT(p))
134 * osl multiple-precedence packet queue
135 * hi_prec is always >= the number of the highest non-empty precedence
137 void *pktq_penq(struct pktq *pq, int prec, void *p)
141 ASSERT(prec >= 0 && prec < pq->num_prec);
142 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
144 ASSERT(!pktq_full(pq));
145 ASSERT(!pktq_pfull(pq, prec));
150 PKTSETLINK(q->tail, p);
159 if (pq->hi_prec < prec)
160 pq->hi_prec = (uint8) prec;
165 void *pktq_penq_head(struct pktq *pq, int prec, void *p)
169 ASSERT(prec >= 0 && prec < pq->num_prec);
170 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
172 ASSERT(!pktq_full(pq));
173 ASSERT(!pktq_pfull(pq, prec));
180 PKTSETLINK(p, q->head);
186 if (pq->hi_prec < prec)
187 pq->hi_prec = (uint8) prec;
192 void *pktq_pdeq(struct pktq *pq, int prec)
197 ASSERT(prec >= 0 && prec < pq->num_prec);
201 if ((p = q->head) == NULL)
204 if ((q->head = PKTLINK(p)) == NULL)
216 void *pktq_pdeq_tail(struct pktq *pq, int prec)
221 ASSERT(prec >= 0 && prec < pq->num_prec);
225 if ((p = q->head) == NULL)
228 for (prev = NULL; p != q->tail; p = PKTLINK(p))
232 PKTSETLINK(prev, NULL);
244 void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
252 q->head = PKTLINK(p);
254 PKTFREE(osh, p, dir);
263 bool pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
268 ASSERT(prec >= 0 && prec < pq->num_prec);
275 if (q->head == pktbuf) {
276 if ((q->head = PKTLINK(pktbuf)) == NULL)
279 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
284 PKTSETLINK(p, PKTLINK(pktbuf));
285 if (q->tail == pktbuf)
291 PKTSETLINK(pktbuf, NULL);
295 void pktq_init(struct pktq *pq, int num_prec, int max_len)
299 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
301 /* pq is variable size; only zero out what's requested */
303 OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
305 pq->num_prec = (uint16) num_prec;
307 pq->max = (uint16) max_len;
309 for (prec = 0; prec < num_prec; prec++)
310 pq->q[prec].max = pq->max;
313 void *pktq_deq(struct pktq *pq, int *prec_out)
322 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
327 if ((p = q->head) == NULL)
330 if ((q->head = PKTLINK(p)) == NULL)
345 void *pktq_deq_tail(struct pktq *pq, int *prec_out)
354 for (prec = 0; prec < pq->hi_prec; prec++)
355 if (pq->q[prec].head)
360 if ((p = q->head) == NULL)
363 for (prev = NULL; p != q->tail; p = PKTLINK(p))
367 PKTSETLINK(prev, NULL);
384 void *pktq_peek(struct pktq *pq, int *prec_out)
391 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
397 return pq->q[prec].head;
400 void *pktq_peek_tail(struct pktq *pq, int *prec_out)
407 for (prec = 0; prec < pq->hi_prec; prec++)
408 if (pq->q[prec].head)
414 return pq->q[prec].tail;
417 void pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
420 for (prec = 0; prec < pq->num_prec; prec++)
421 pktq_pflush(osh, pq, prec, dir);
422 ASSERT(pq->len == 0);
425 /* Return sum of lengths of a specific set of precedences */
426 int pktq_mlen(struct pktq *pq, uint prec_bmp)
432 for (prec = 0; prec <= pq->hi_prec; prec++)
433 if (prec_bmp & (1 << prec))
434 len += pq->q[prec].len;
439 /* Priority dequeue from a specific set of precedences */
440 void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
449 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
452 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
458 if ((p = q->head) == NULL)
461 if ((q->head = PKTLINK(p)) == NULL)
475 #endif /* BCMDRIVER */
477 const unsigned char bcm_ctype[] = {
478 _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C,
479 _BCM_C, _BCM_C | _BCM_S, _BCM_C | _BCM_S, _BCM_C | _BCM_S,
480 _BCM_C | _BCM_S, _BCM_C | _BCM_S, _BCM_C,
482 _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C,
483 _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C,
484 _BCM_S | _BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
486 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
487 _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D,
488 _BCM_D, _BCM_D, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
489 _BCM_P, _BCM_U | _BCM_X, _BCM_U | _BCM_X, _BCM_U | _BCM_X,
490 _BCM_U | _BCM_X, _BCM_U | _BCM_X,
491 _BCM_U | _BCM_X, _BCM_U,
492 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
493 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
494 _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
495 _BCM_P, _BCM_L | _BCM_X, _BCM_L | _BCM_X, _BCM_L | _BCM_X,
496 _BCM_L | _BCM_X, _BCM_L | _BCM_X,
497 _BCM_L | _BCM_X, _BCM_L,
498 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
499 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
500 _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_C,
501 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
502 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
503 _BCM_S | _BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
504 _BCM_P, _BCM_P, _BCM_P,
505 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
506 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
508 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
509 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
511 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
512 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U,
514 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
515 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
517 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
518 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L,
520 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
523 ulong bcm_strtoul(char *cp, char **endp, uint base)
525 ulong result, last_result = 0, value;
530 while (bcm_isspace(*cp))
535 else if (cp[0] == '-') {
542 if ((cp[1] == 'x') || (cp[1] == 'X')) {
551 } else if (base == 16 && (cp[0] == '0')
552 && ((cp[1] == 'x') || (cp[1] == 'X'))) {
558 while (bcm_isxdigit(*cp) &&
560 bcm_isdigit(*cp) ? *cp - '0' : bcm_toupper(*cp) - 'A' + 10) <
562 result = result * base + value;
563 /* Detected overflow */
564 if (result < last_result && !minus)
566 last_result = result;
571 result = (ulong) (-(long)result);
579 int bcm_atoi(char *s)
581 return (int)bcm_strtoul(s, NULL, 10);
584 /* return pointer to location of substring 'needle' in 'haystack' */
585 char *bcmstrstr(char *haystack, char *needle)
590 if ((haystack == NULL) || (needle == NULL))
593 nlen = strlen(needle);
594 len = strlen(haystack) - nlen + 1;
596 for (i = 0; i < len; i++)
597 if (memcmp(needle, &haystack[i], nlen) == 0)
602 char *bcmstrcat(char *dest, const char *src)
606 p = dest + strlen(dest);
608 while ((*p++ = *src++) != '\0')
614 char *bcmstrncat(char *dest, const char *src, uint size)
619 p = dest + strlen(dest);
622 while (p != endp && (*p++ = *src++) != '\0')
628 /****************************************************************************
629 * Function: bcmstrtok
632 * Tokenizes a string. This function is conceptually similiar
633 * to ANSI C strtok(),
634 * but allows strToken() to be used by different strings or callers at the same
635 * time. Each call modifies '*string' by substituting a NULL character for the
636 * first delimiter that is encountered, and updates 'string' to point to
638 * after the delimiter. Leading delimiters are skipped.
641 * string (mod) Ptr to string ptr, updated by token.
642 * delimiters (in) Set of delimiter characters.
643 * tokdelim (out) Character that delimits the returned token. (May
644 * be set to NULL if token delimiter is not required).
646 * Returns: Pointer to the next token found. NULL when no more tokens are found.
647 *****************************************************************************
649 char *bcmstrtok(char **string, const char *delimiters, char *tokdelim)
652 unsigned long map[8];
656 if (tokdelim != NULL) {
657 /* Prime the token delimiter */
661 /* Clear control map */
662 for (count = 0; count < 8; count++)
665 /* Set bits in delimiter table */
667 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
669 while (*delimiters++)
672 str = (unsigned char *)*string;
674 /* Find beginning of token (skip over leading delimiters). Note that
675 * there is no token iff this loop sets str to point to the terminal
676 * null (*str == '\0')
678 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' '))
681 nextoken = (char *)str;
683 /* Find the end of the token. If it is not the end of the string,
686 for (; *str; str++) {
687 if (map[*str >> 5] & (1 << (*str & 31))) {
688 if (tokdelim != NULL)
696 *string = (char *)str;
698 /* Determine if a token has been found. */
699 if (nextoken == (char *)str)
705 #define xToLower(C) \
706 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
708 /****************************************************************************
709 * Function: bcmstricmp
711 * Purpose: Compare to strings case insensitively.
713 * Parameters: s1 (in) First string to compare.
714 * s2 (in) Second string to compare.
716 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
717 * t1 > t2, when ignoring case sensitivity.
718 *****************************************************************************
720 int bcmstricmp(const char *s1, const char *s2)
742 /****************************************************************************
743 * Function: bcmstrnicmp
745 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
748 * Parameters: s1 (in) First string to compare.
749 * s2 (in) Second string to compare.
750 * cnt (in) Max characters to compare.
752 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
753 * t1 > t2, when ignoring case sensitivity.
754 *****************************************************************************
756 int bcmstrnicmp(const char *s1, const char *s2, int cnt)
760 while (*s2 && *s1 && cnt) {
781 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
782 int bcm_ether_atoe(char *p, struct ether_addr *ea)
787 ea->octet[i++] = (char)bcm_strtoul(p, &p, 16);
795 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
796 /* registry routine buffer preparation utility functions:
797 * parameter order is like strncpy, but returns count
798 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
800 ulong wchar2ascii(char *abuf, ushort * wbuf, ushort wbuflen, ulong abuflen)
808 /* wbuflen is in bytes */
809 wbuflen /= sizeof(ushort);
811 for (i = 0; i < wbuflen; ++i) {
814 *abuf++ = (char)*wbuf++;
821 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
823 char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
825 static const char template[] = "%02x:%02x:%02x:%02x:%02x:%02x";
826 snprintf(buf, 18, template,
827 ea->octet[0] & 0xff, ea->octet[1] & 0xff, ea->octet[2] & 0xff,
828 ea->octet[3] & 0xff, ea->octet[4] & 0xff, ea->octet[5] & 0xff);
832 char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
834 snprintf(buf, 16, "%d.%d.%d.%d",
835 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
841 void bcm_mdelay(uint ms)
845 for (i = 0; i < ms; i++)
849 #if defined(DHD_DEBUG)
850 /* pretty hex print a pkt buffer chain */
851 void prpkt(const char *msg, osl_t *osh, void *p0)
855 if (msg && (msg[0] != '\0'))
856 printf("%s:\n", msg);
858 for (p = p0; p; p = PKTNEXT(p))
859 prhex(NULL, PKTDATA(p), PKTLEN(p));
863 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
864 * Also updates the inplace vlan tag if requested.
865 * For debugging, it returns an indication of what it did.
867 uint pktsetprio(void *pkt, bool update_vtag)
869 struct ether_header *eh;
870 struct ethervlan_header *evh;
875 pktdata = (uint8 *) PKTDATA(pkt);
876 ASSERT(ISALIGNED((uintptr) pktdata, sizeof(uint16)));
878 eh = (struct ether_header *)pktdata;
880 if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
882 int vlan_prio, dscp_prio = 0;
884 evh = (struct ethervlan_header *)eh;
886 vlan_tag = ntoh16(evh->vlan_tag);
887 vlan_prio = (int)(vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
889 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
891 pktdata + sizeof(struct ethervlan_header);
892 uint8 tos_tc = IP_TOS(ip_body);
893 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
896 /* DSCP priority gets precedence over 802.1P (vlan tag) */
897 if (dscp_prio != 0) {
898 priority = dscp_prio;
901 priority = vlan_prio;
905 * If the DSCP priority is not the same as the VLAN priority,
906 * then overwrite the priority field in the vlan tag, with the
907 * DSCP priority value. This is required for Linux APs because
908 * the VLAN driver on Linux, overwrites the skb->priority field
909 * with the priority value in the vlan tag
911 if (update_vtag && (priority != vlan_prio)) {
912 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
913 vlan_tag |= (uint16) priority << VLAN_PRI_SHIFT;
914 evh->vlan_tag = hton16(vlan_tag);
917 } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
918 uint8 *ip_body = pktdata + sizeof(struct ether_header);
919 uint8 tos_tc = IP_TOS(ip_body);
920 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
924 ASSERT(priority >= 0 && priority <= MAXPRIO);
925 PKTSETPRIO(pkt, priority);
926 return rc | priority;
929 static char bcm_undeferrstr[BCME_STRLEN];
931 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
933 /* Convert the error codes into related error strings */
934 const char *bcmerrorstr(int bcmerror)
936 /* check if someone added a bcmerror code but
937 forgot to add errorstring */
938 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
940 if (bcmerror > 0 || bcmerror < BCME_LAST) {
941 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d",
943 return bcm_undeferrstr;
946 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
948 return bcmerrorstrtable[-bcmerror];
951 /* iovar table lookup */
952 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
954 const bcm_iovar_t *vi;
955 const char *lookup_name;
957 /* skip any ':' delimited option prefixes */
958 lookup_name = strrchr(name, ':');
959 if (lookup_name != NULL)
964 ASSERT(table != NULL);
966 for (vi = table; vi->name; vi++) {
967 if (!strcmp(vi->name, lookup_name))
970 /* ran to end of table */
972 return NULL; /* var name not found */
975 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
979 /* length check on io buf */
988 /* all integers are int32 sized args at the ioctl interface */
989 if (len < (int)sizeof(int))
990 bcmerror = BCME_BUFTOOSHORT;
994 /* buffer must meet minimum length requirement */
995 if (len < vi->minlen)
996 bcmerror = BCME_BUFTOOSHORT;
1001 /* Cannot return nil... */
1002 bcmerror = BCME_UNSUPPORTED;
1004 /* Set is an action w/o parameters */
1005 bcmerror = BCME_BUFTOOLONG;
1010 /* unknown type for length check in iovar info */
1012 bcmerror = BCME_UNSUPPORTED;
1018 #endif /* BCMDRIVER */
1020 /****************************************************************************
1023 * Computes a crc8 over the input data using the polynomial:
1025 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1027 * The caller provides the initial value (either CRC8_INIT_VALUE
1028 * or the previous returned value) to allow for processing of
1029 * discontiguous blocks of data. When generating the CRC the
1030 * caller is responsible for complementing the final return value
1031 * and inserting it into the byte stream. When checking, a final
1032 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1034 * Reference: Dallas Semiconductor Application Note 27
1035 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1036 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1037 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1039 * ****************************************************************************
1042 STATIC const uint8 crc8_table[256] = {
1043 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1044 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1045 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1046 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1047 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1048 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1049 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1050 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1051 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1052 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1053 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1054 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1055 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1056 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1057 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1058 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1059 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1060 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1061 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1062 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1063 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1064 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1065 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1066 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1067 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1068 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1069 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1070 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1071 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1072 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1073 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1074 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1077 #define CRC_INNER_LOOP(n, c, x) \
1078 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1080 uint8 hndcrc8(uint8 *pdata, /* pointer to array of data to process */
1081 uint nbytes, /* number of input data bytes to process */
1082 uint8 crc /* either CRC8_INIT_VALUE or previous
1086 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1087 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1089 while (nbytes-- > 0)
1090 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1095 /*****************************************************************************
1098 * Computes a crc16 over the input data using the polynomial:
1100 * x^16 + x^12 +x^5 + 1
1102 * The caller provides the initial value (either CRC16_INIT_VALUE
1103 * or the previous returned value) to allow for processing of
1104 * discontiguous blocks of data. When generating the CRC the
1105 * caller is responsible for complementing the final return value
1106 * and inserting it into the byte stream. When checking, a final
1107 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1109 * Reference: Dallas Semiconductor Application Note 27
1110 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1111 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1112 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1114 * ****************************************************************************
1117 static const uint16 crc16_table[256] = {
1118 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1119 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1120 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1121 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1122 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1123 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1124 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1125 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1126 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1127 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1128 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1129 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1130 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1131 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1132 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1133 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1134 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1135 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1136 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1137 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1138 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1139 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1140 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1141 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1142 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1143 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1144 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1145 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1146 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1147 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1148 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1149 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1152 uint16 hndcrc16(uint8 *pdata, /* pointer to array of data to process */
1153 uint nbytes, /* number of input data bytes to process */
1154 uint16 crc /* either CRC16_INIT_VALUE or previous
1158 while (nbytes-- > 0)
1159 CRC_INNER_LOOP(16, crc, *pdata++);
1163 STATIC const uint32 crc32_table[256] = {
1164 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1165 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1166 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1167 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1168 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1169 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1170 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1171 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1172 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1173 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1174 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1175 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1176 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1177 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1178 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1179 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1180 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1181 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1182 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1183 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1184 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1185 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1186 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1187 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1188 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1189 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1190 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1191 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1192 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1193 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1194 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1195 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1196 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1197 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1198 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1199 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1200 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1201 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1202 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1203 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1204 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1205 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1206 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1207 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1208 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1209 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1210 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1211 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1212 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1213 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1214 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1215 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1216 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1217 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1218 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1219 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1220 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1221 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1222 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1223 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1224 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1225 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1226 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1227 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1230 uint32 hndcrc32(uint8 *pdata, /* pointer to array of data to process */
1231 uint nbytes, /* number of input data bytes to process */
1232 uint32 crc /* either CRC32_INIT_VALUE or previous
1239 ulong *tptr = (ulong *) tmp;
1241 /* in case the beginning of the buffer isn't aligned */
1242 pend = (uint8 *) ((uint) (pdata + 3) & 0xfffffffc);
1243 nbytes -= (pend - pdata);
1244 while (pdata < pend)
1245 CRC_INNER_LOOP(32, crc, *pdata++);
1247 /* handle bulk of data as 32-bit words */
1248 pend = pdata + (nbytes & 0xfffffffc);
1249 while (pdata < pend) {
1250 *tptr = *(ulong *) pdata;
1251 pdata += sizeof(ulong *);
1252 CRC_INNER_LOOP(32, crc, tmp[0]);
1253 CRC_INNER_LOOP(32, crc, tmp[1]);
1254 CRC_INNER_LOOP(32, crc, tmp[2]);
1255 CRC_INNER_LOOP(32, crc, tmp[3]);
1258 /* 1-3 bytes at end of buffer */
1259 pend = pdata + (nbytes & 0x03);
1260 while (pdata < pend)
1261 CRC_INNER_LOOP(32, crc, *pdata++);
1263 pend = pdata + nbytes;
1264 while (pdata < pend)
1265 CRC_INNER_LOOP(32, crc, *pdata++);
1266 #endif /* __mips__ */
1272 #define CLEN 1499 /* CRC Length */
1273 #define CBUFSIZ (CLEN+4)
1274 #define CNBUFS 5 /* # of bufs */
1276 void testcrc32(void)
1282 uint32 crc32tv[CNBUFS] = {
1283 0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1285 ASSERT((buf = MALLOC(CBUFSIZ * CNBUFS)) != NULL);
1287 /* step through all possible alignments */
1288 for (l = 0; l <= 4; l++) {
1289 for (j = 0; j < CNBUFS; j++) {
1291 for (k = 0; k < len[j]; k++)
1292 *(buf + j * CBUFSIZ + (k + l)) = (j + k) & 0xff;
1295 for (j = 0; j < CNBUFS; j++) {
1297 crc32(buf + j * CBUFSIZ + l, len[j],
1299 ASSERT(crcr == crc32tv[j]);
1303 MFREE(buf, CBUFSIZ * CNBUFS);
1309 * Advance from the current 1-byte tag/1-byte length/variable-length value
1310 * triple, to the next, returning a pointer to the next.
1311 * If the current or next TLV is invalid (does not fit in given buffer length),
1313 * *buflen is not modified if the TLV elt parameter is invalid,
1315 * by the TLV parameter's length if it is valid.
1317 bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
1321 /* validate current elt */
1322 if (!bcm_valid_tlv(elt, *buflen))
1325 /* advance to next elt */
1327 elt = (bcm_tlv_t *) (elt->data + len);
1328 *buflen -= (2 + len);
1330 /* validate next elt */
1331 if (!bcm_valid_tlv(elt, *buflen))
1338 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1339 * triples, returning a pointer to the substring whose first element
1342 bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key)
1347 elt = (bcm_tlv_t *) buf;
1350 /* find tagged parameter */
1351 while (totlen >= 2) {
1354 /* validate remaining totlen */
1355 if ((elt->id == key) && (totlen >= (len + 2)))
1358 elt = (bcm_tlv_t *) ((uint8 *) elt + (len + 2));
1359 totlen -= (len + 2);
1366 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1367 * triples, returning a pointer to the substring whose first element
1368 * matches tag. Stop parsing when we see an element whose ID is greater
1369 * than the target key.
1371 bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
1376 elt = (bcm_tlv_t *) buf;
1379 /* find tagged parameter */
1380 while (totlen >= 2) {
1384 /* Punt if we start seeing IDs > than target key */
1388 /* validate remaining totlen */
1389 if ((id == key) && (totlen >= (len + 2)))
1392 elt = (bcm_tlv_t *) ((uint8 *) elt + (len + 2));
1393 totlen -= (len + 2);
1398 #if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1401 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char *buf, int len)
1410 if (len < 2 || !buf)
1416 for (i = 0; flags != 0; i++) {
1419 if (bit == 0 && flags) {
1420 /* print any unnamed bits */
1421 sprintf(hexstr, "0x%X", flags);
1423 flags = 0; /* exit loop */
1424 } else if ((flags & bit) == 0)
1426 slen += strlen(name);
1430 p += sprintf(p, " "); /* btwn flag space */
1435 slen = 1; /* account for btwn flag space */
1438 /* indicate the str was too short */
1441 p--; /* overwrite last char */
1442 p += sprintf(p, ">");
1445 return (int)(p - buf);
1449 * print bytes formatted as hex to a string. return the resulting
1452 int bcm_format_hex(char *str, const void *bytes, int len)
1456 const uint8 *src = (const uint8 *)bytes;
1458 for (i = 0; i < len; i++) {
1459 p += sprintf(p, "%02X", *src);
1462 return (int)(p - str);
1465 /* pretty hex print a contiguous buffer */
1466 void prhex(const char *msg, uchar *buf, uint nbytes)
1471 if (msg && (msg[0] != '\0'))
1472 printf("%s:\n", msg);
1475 for (i = 0; i < nbytes; i++) {
1477 p += sprintf(p, " %04d: ", i); /* line prefix */
1479 p += sprintf(p, "%02x ", buf[i]);
1481 printf("%s\n", line); /* flush line */
1486 /* flush last partial line */
1488 printf("%s\n", line);
1490 #endif /* defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) */
1492 /* Produce a human-readable string for boardrev */
1493 char *bcm_brev_str(uint32 brev, char *buf)
1496 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1498 snprintf(buf, 8, "%c%03x",
1499 ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
1504 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1506 /* dump large strings to console */
1507 void printbig(char *buf)
1514 max_len = BUFSIZE_TODUMP_ATONCE;
1516 while (len > max_len) {
1518 buf[max_len] = '\0';
1525 /* print the remaining string */
1526 printf("%s\n", buf);
1530 /* routine to dump fields in a fileddesc structure */
1532 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1,
1533 struct fielddesc *fielddesc_array, char *buf, uint32 bufsize)
1537 struct fielddesc *cur_ptr;
1540 cur_ptr = fielddesc_array;
1542 while (bufsize > 1) {
1543 if (cur_ptr->nameandfmt == NULL)
1545 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
1546 read_rtn(arg0, arg1, cur_ptr->offset));
1547 /* check for snprintf overflow or error */
1548 if (len < 0 || (uint32) len >= bufsize)
1558 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1562 len = strlen(name) + 1;
1564 if ((len + datalen) > buflen)
1567 strncpy(buf, name, buflen);
1569 /* append data onto the end of the name string */
1570 memcpy(&buf[len], data, datalen);
1576 /* Quarter dBm units to mW
1577 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1578 * Table is offset so the last entry is largest mW value that fits in
1582 #define QDBM_OFFSET 153 /* Offset for first entry */
1583 #define QDBM_TABLE_LEN 40 /* Table size */
1585 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1586 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1588 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1590 /* Largest mW value that will round down to the last table entry,
1591 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1592 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
1593 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1595 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1597 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1598 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1599 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1600 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1601 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1602 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1603 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1606 uint16 bcm_qdbm_to_mw(uint8 qdbm)
1609 int idx = qdbm - QDBM_OFFSET;
1611 if (idx >= QDBM_TABLE_LEN) {
1612 /* clamp to max uint16 mW value */
1616 /* scale the qdBm index up to the range of the table 0-40
1617 * where an offset of 40 qdBm equals a factor of 10 mW.
1624 /* return the mW value scaled down to the correct factor of 10,
1625 * adding in factor/2 to get proper rounding.
1627 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
1630 uint8 bcm_mw_to_qdbm(uint16 mw)
1637 /* handle boundary case */
1641 offset = QDBM_OFFSET;
1643 /* move mw into the range of the table */
1644 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1649 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
1650 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
1651 nqdBm_to_mW_map[qdbm]) / 2;
1652 if (mw_uint < boundary)
1656 qdbm += (uint8) offset;
1661 uint bcm_bitcount(uint8 *bitmap, uint length)
1663 uint bitcount = 0, i;
1665 for (i = 0; i < length; i++) {
1677 /* Initialization of bcmstrbuf structure */
1678 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1680 b->origsize = b->size = size;
1681 b->origbuf = b->buf = buf;
1684 /* Buffer sprintf wrapper to guard against buffer overflow */
1685 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1691 r = vsnprintf(b->buf, b->size, fmt, ap);
1693 /* Non Ansi C99 compliant returns -1,
1694 * Ansi compliant return r >= b->size,
1695 * bcmstdlib returns 0, handle all
1697 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1709 void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
1713 for (i = 0; i < num_bytes; i++) {
1715 if (num[i] >= amount)
1721 int bcm_cmp_bytes(uchar *arg1, uchar *arg2, uint8 nbytes)
1725 for (i = nbytes - 1; i >= 0; i--) {
1726 if (arg1[i] != arg2[i])
1727 return arg1[i] - arg2[i];
1732 void bcm_print_bytes(char *name, const uchar *data, int len)
1737 printf("%s: %d \n", name ? name : "", len);
1738 for (i = 0; i < len; i++) {
1739 printf("%02x ", *data++);
1741 if (per_line == 16) {
1750 * buffer length needed for wlc_format_ssid
1751 * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
1754 #if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
1755 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
1756 int bcm_format_ssid(char *buf, const uchar ssid[], uint ssid_len)
1760 char *endp = buf + SSID_FMT_BUF_LEN;
1762 if (ssid_len > DOT11_MAX_SSID_LEN)
1763 ssid_len = DOT11_MAX_SSID_LEN;
1765 for (i = 0; i < ssid_len; i++) {
1770 } else if (bcm_isprint((uchar) c)) {
1773 p += snprintf(p, (endp - p), "\\x%02X", c);
1779 return (int)(p - buf);
1781 #endif /* defined(WLTINYDUMP) ||
1782 defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) */
1784 #endif /* BCMDRIVER */