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.
24 #include <bcmendian.h>
26 #include <proto/ethernet.h>
27 #include <proto/802.1d.h>
28 #include <proto/802.11.h>
31 /* nvram vars cache */
32 static char *nvram_vars = NULL;
33 static int vars_len = -1;
36 /* copy a pkt buffer chain into a buffer */
37 uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
42 len = 4096; /* "infinite" */
44 /* skip 'offset' bytes */
45 for (; p && offset; p = PKTNEXT(p)) {
46 if (offset < (uint) PKTLEN(p))
55 for (; p && len; p = PKTNEXT(p)) {
56 n = MIN((uint) PKTLEN(p) - offset, (uint) len);
57 bcopy(PKTDATA(p) + offset, buf, n);
67 /* copy a buffer into a pkt buffer chain */
68 uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
72 /* skip 'offset' bytes */
73 for (; p && offset; p = PKTNEXT(p)) {
74 if (offset < (uint) PKTLEN(p))
83 for (; p && len; p = PKTNEXT(p)) {
84 n = MIN((uint) PKTLEN(p) - offset, (uint) len);
85 bcopy(buf, PKTDATA(p) + offset, n);
95 /* return total length of buffer chain */
96 uint BCMFASTPATH pkttotlen(osl_t *osh, void *p)
101 for (; p; p = PKTNEXT(p))
106 /* return the last buffer of chained pkt */
107 void *pktlast(osl_t *osh, void *p)
109 for (; PKTNEXT(p); p = PKTNEXT(p)) ;
114 /* count segments of a chained packet */
115 uint BCMFASTPATH pktsegcnt(osl_t *osh, void *p)
119 for (cnt = 0; p; p = PKTNEXT(p))
126 * osl multiple-precedence packet queue
127 * hi_prec is always >= the number of the highest non-empty precedence
129 void *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, void *p)
133 ASSERT(prec >= 0 && prec < pq->num_prec);
134 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
136 ASSERT(!pktq_full(pq));
137 ASSERT(!pktq_pfull(pq, prec));
142 PKTSETLINK(q->tail, p);
151 if (pq->hi_prec < prec)
152 pq->hi_prec = (uint8) prec;
157 void *BCMFASTPATH pktq_penq_head(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));
172 PKTSETLINK(p, q->head);
178 if (pq->hi_prec < prec)
179 pq->hi_prec = (uint8) prec;
184 void *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
189 ASSERT(prec >= 0 && prec < pq->num_prec);
193 if ((p = q->head) == NULL)
196 if ((q->head = PKTLINK(p)) == NULL)
208 void *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
213 ASSERT(prec >= 0 && prec < pq->num_prec);
217 if ((p = q->head) == NULL)
220 for (prev = NULL; p != q->tail; p = PKTLINK(p))
224 PKTSETLINK(prev, NULL);
237 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn,
241 void *p, *prev = NULL;
246 if (fn == NULL || (*fn) (p, arg)) {
247 bool head = (p == q->head);
249 q->head = PKTLINK(p);
251 PKTSETLINK(prev, PKTLINK(p));
253 PKTFREE(osh, p, dir);
256 p = (head ? q->head : PKTLINK(prev));
263 if (q->head == NULL) {
269 bool BCMFASTPATH pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
274 ASSERT(prec >= 0 && prec < pq->num_prec);
281 if (q->head == pktbuf) {
282 if ((q->head = PKTLINK(pktbuf)) == NULL)
285 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p)) ;
289 PKTSETLINK(p, PKTLINK(pktbuf));
290 if (q->tail == pktbuf)
296 PKTSETLINK(pktbuf, NULL);
300 void pktq_init(struct pktq *pq, int num_prec, int max_len)
304 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
306 /* pq is variable size; only zero out what's requested */
308 OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
310 pq->num_prec = (uint16) num_prec;
312 pq->max = (uint16) max_len;
314 for (prec = 0; prec < num_prec; prec++)
315 pq->q[prec].max = pq->max;
318 void *BCMFASTPATH pktq_deq(struct pktq *pq, int *prec_out)
327 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
332 if ((p = q->head) == NULL)
335 if ((q->head = PKTLINK(p)) == NULL)
350 void *BCMFASTPATH pktq_deq_tail(struct pktq *pq, int *prec_out)
359 for (prec = 0; prec < pq->hi_prec; prec++)
360 if (pq->q[prec].head)
365 if ((p = q->head) == NULL)
368 for (prev = NULL; p != q->tail; p = PKTLINK(p))
372 PKTSETLINK(prev, NULL);
389 void *pktq_peek(struct pktq *pq, int *prec_out)
396 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
402 return (pq->q[prec].head);
405 void *pktq_peek_tail(struct pktq *pq, int *prec_out)
412 for (prec = 0; prec < pq->hi_prec; prec++)
413 if (pq->q[prec].head)
419 return (pq->q[prec].tail);
422 void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
425 for (prec = 0; prec < pq->num_prec; prec++)
426 pktq_pflush(osh, pq, prec, dir, fn, arg);
428 ASSERT(pq->len == 0);
431 /* Return sum of lengths of a specific set of precedences */
432 int pktq_mlen(struct pktq *pq, uint prec_bmp)
438 for (prec = 0; prec <= pq->hi_prec; prec++)
439 if (prec_bmp & (1 << prec))
440 len += pq->q[prec].len;
445 /* Priority dequeue from a specific set of precedences */
446 void *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
455 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
458 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
464 if ((p = q->head) == NULL)
467 if ((q->head = PKTLINK(p)) == NULL)
482 const unsigned char bcm_ctype[] = {
484 _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, /* 0-7 */
485 _BCM_C, _BCM_C | _BCM_S, _BCM_C | _BCM_S, _BCM_C | _BCM_S,
486 _BCM_C | _BCM_S, _BCM_C | _BCM_S, _BCM_C,
488 _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, /* 16-23 */
489 _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, /* 24-31 */
490 _BCM_S | _BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 32-39 */
491 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 40-47 */
492 _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, /* 48-55 */
493 _BCM_D, _BCM_D, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 56-63 */
494 _BCM_P, _BCM_U | _BCM_X, _BCM_U | _BCM_X, _BCM_U | _BCM_X,
495 _BCM_U | _BCM_X, _BCM_U | _BCM_X,
496 _BCM_U | _BCM_X, _BCM_U, /* 64-71 */
497 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 72-79 */
498 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 80-87 */
499 _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 88-95 */
500 _BCM_P, _BCM_L | _BCM_X, _BCM_L | _BCM_X, _BCM_L | _BCM_X,
501 _BCM_L | _BCM_X, _BCM_L | _BCM_X,
502 _BCM_L | _BCM_X, _BCM_L, /* 96-103 */
503 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 104-111 */
504 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 112-119 */
505 _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_C, /* 120-127 */
506 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
507 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
508 _BCM_S | _BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
509 _BCM_P, _BCM_P, _BCM_P,
510 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
511 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
513 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
514 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
516 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
517 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U,
519 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
520 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
522 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
523 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L,
525 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
528 ulong BCMROMFN(bcm_strtoul) (char *cp, char **endp, uint base)
530 ulong result, last_result = 0, value;
535 while (bcm_isspace(*cp))
540 else if (cp[0] == '-') {
547 if ((cp[1] == 'x') || (cp[1] == 'X')) {
556 } else if (base == 16 && (cp[0] == '0')
557 && ((cp[1] == 'x') || (cp[1] == 'X'))) {
563 while (bcm_isxdigit(*cp) &&
565 bcm_isdigit(*cp) ? *cp - '0' : bcm_toupper(*cp) - 'A' + 10) <
567 result = result * base + value;
568 /* Detected overflow */
569 if (result < last_result && !minus)
571 last_result = result;
576 result = (ulong) (-(long)result);
584 int BCMROMFN(bcm_atoi) (char *s)
586 return (int)bcm_strtoul(s, NULL, 10);
589 /* return pointer to location of substring 'needle' in 'haystack' */
590 char *BCMROMFN(bcmstrstr) (char *haystack, char *needle)
595 if ((haystack == NULL) || (needle == NULL))
598 nlen = strlen(needle);
599 len = strlen(haystack) - nlen + 1;
601 for (i = 0; i < len; i++)
602 if (memcmp(needle, &haystack[i], nlen) == 0)
603 return (&haystack[i]);
607 char *BCMROMFN(bcmstrcat) (char *dest, const char *src)
611 p = dest + strlen(dest);
613 while ((*p++ = *src++) != '\0') ;
618 char *BCMROMFN(bcmstrncat) (char *dest, const char *src, uint size)
623 p = dest + strlen(dest);
626 while (p != endp && (*p++ = *src++) != '\0') ;
631 /****************************************************************************
632 * Function: bcmstrtok
635 * Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
636 * but allows strToken() to be used by different strings or callers at the same
637 * time. Each call modifies '*string' by substituting a NULL character for the
638 * first delimiter that is encountered, and updates 'string' to point to the char
639 * after the delimiter. Leading delimiters are skipped.
642 * string (mod) Ptr to string ptr, updated by token.
643 * delimiters (in) Set of delimiter characters.
644 * tokdelim (out) Character that delimits the returned token. (May
645 * be set to NULL if token delimiter is not required).
647 * Returns: Pointer to the next token found. NULL when no more tokens are found.
648 *****************************************************************************
650 char *bcmstrtok(char **string, const char *delimiters, char *tokdelim)
653 unsigned long map[8];
657 if (tokdelim != NULL) {
658 /* Prime the token delimiter */
662 /* Clear control map */
663 for (count = 0; count < 8; count++) {
667 /* Set bits in delimiter table */
669 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
671 while (*delimiters++);
673 str = (unsigned char *)*string;
675 /* Find beginning of token (skip over leading delimiters). Note that
676 * there is no token iff this loop sets str to point to the terminal
677 * null (*str == '\0')
679 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
683 nextoken = (char *)str;
685 /* Find the end of the token. If it is not the end of the string,
688 for (; *str; str++) {
689 if (map[*str >> 5] & (1 << (*str & 31))) {
690 if (tokdelim != NULL) {
699 *string = (char *)str;
701 /* Determine if a token has been found. */
702 if (nextoken == (char *)str) {
709 #define xToLower(C) \
710 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
712 /****************************************************************************
713 * Function: bcmstricmp
715 * Purpose: Compare to strings case insensitively.
717 * Parameters: s1 (in) First string to compare.
718 * s2 (in) Second string to compare.
720 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
721 * t1 > t2, when ignoring case sensitivity.
722 *****************************************************************************
724 int bcmstricmp(const char *s1, const char *s2)
746 /****************************************************************************
747 * Function: bcmstrnicmp
749 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
752 * Parameters: s1 (in) First string to compare.
753 * s2 (in) Second string to compare.
754 * cnt (in) Max characters to compare.
756 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
757 * t1 > t2, when ignoring case sensitivity.
758 *****************************************************************************
760 int bcmstrnicmp(const char *s1, const char *s2, int cnt)
764 while (*s2 && *s1 && cnt) {
785 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
786 int BCMROMFN(bcm_ether_atoe) (char *p, struct ether_addr *ea)
791 ea->octet[i++] = (char)bcm_strtoul(p, &p, 16);
799 char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
801 snprintf(buf, 18, "%pM", ea->octet);
805 void bcm_mdelay(uint ms)
809 for (i = 0; i < ms; i++) {
815 * Search the name=value vars for a specific one and return its value.
816 * Returns NULL if not found.
818 char *getvar(char *vars, const char *name)
830 /* first look in vars[] */
831 for (s = vars; s && *s;) {
832 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
833 return (&s[len + 1]);
838 /* then query nvram */
839 return (nvram_get(name));
843 * Search the vars for a specific one and return its value as
844 * an integer. Returns 0 if not found.
846 int getintvar(char *vars, const char *name)
850 if ((val = getvar(vars, name)) == NULL)
853 return (bcm_strtoul(val, NULL, 0));
856 int getintvararray(char *vars, const char *name, uint8 index)
862 if ((buf = getvar(vars, name)) == NULL) {
866 /* table values are always separated by "," or " " */
867 while (*buf != '\0') {
868 val = bcm_strtoul(buf, &endp, 0);
873 /* delimiter is ',' */
881 /* Search for token in comma separated token-string */
882 static int findmatch(char *string, char *name)
888 while ((c = strchr(string, ',')) != NULL) {
889 if (len == (uint) (c - string) && !strncmp(string, name, len))
894 return (!strcmp(string, name));
897 /* Return gpio pin number assigned to the named pin
899 * Variable should be in format:
901 * gpio<N>=pin_name,pin_name
903 * This format allows multiple features to share the gpio with mutual
906 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
907 * and if def_pin is not used by others.
909 uint getgpiopin(char *vars, char *pin_name, uint def_pin)
911 char name[] = "gpioXXXX";
915 /* Go thru all possibilities till a match in pin name */
916 for (pin = 0; pin < GPIO_NUMPINS; pin++) {
917 snprintf(name, sizeof(name), "gpio%d", pin);
918 val = getvar(vars, name);
919 if (val && findmatch(val, pin_name))
923 if (def_pin != GPIO_PIN_NOTDEFINED) {
924 /* make sure the default pin is not used by someone else */
925 snprintf(name, sizeof(name), "gpio%d", def_pin);
926 if (getvar(vars, name)) {
927 def_pin = GPIO_PIN_NOTDEFINED;
934 /* pretty hex print a pkt buffer chain */
935 void prpkt(const char *msg, osl_t *osh, void *p0)
939 if (msg && (msg[0] != '\0'))
940 printf("%s:\n", msg);
942 for (p = p0; p; p = PKTNEXT(p))
943 prhex(NULL, PKTDATA(p), PKTLEN(p));
945 #endif /* defined(BCMDBG) */
947 static char bcm_undeferrstr[32];
948 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
950 /* Convert the error codes into related error strings */
951 const char *bcmerrorstr(int bcmerror)
953 /* check if someone added a bcmerror code but forgot to add errorstring */
954 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
956 if (bcmerror > 0 || bcmerror < BCME_LAST) {
957 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr),
958 "Undefined error %d", bcmerror);
959 return bcm_undeferrstr;
962 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
964 return bcmerrorstrtable[-bcmerror];
968 static void BCMINITFN(bcm_nvram_refresh) (char *flash)
973 ASSERT(flash != NULL);
975 /* default "empty" vars cache */
978 if ((ret = nvram_getall(flash, NVRAM_SPACE)))
981 /* determine nvram length */
982 for (i = 0; i < NVRAM_SPACE; i++) {
983 if (flash[i] == '\0' && flash[i + 1] == '\0')
993 char *bcm_nvram_vars(uint *length)
996 /* cache may be stale if nvram is read/write */
998 ASSERT(!bcmreclaimed);
999 bcm_nvram_refresh(nvram_vars);
1007 /* copy nvram vars into locally-allocated multi-string array */
1008 int BCMINITFN(bcm_nvram_cache) (void *sih)
1014 if (vars_len >= 0) {
1016 bcm_nvram_refresh(nvram_vars);
1021 osh = si_osh((si_t *) sih);
1023 /* allocate memory and read in flash */
1024 if (!(flash = MALLOC(osh, NVRAM_SPACE))) {
1029 bcm_nvram_refresh(flash);
1032 /* copy into a properly-sized buffer */
1033 if (!(nvram_vars = MALLOC(osh, vars_len))) {
1036 bcopy(flash, nvram_vars, vars_len);
1038 MFREE(osh, flash, NVRAM_SPACE);
1040 /* cache must be full size of nvram if read/write */
1042 #endif /* BCMNVRAMR */
1047 #endif /* WLC_LOW */
1049 /* iovar table lookup */
1050 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
1052 const bcm_iovar_t *vi;
1053 const char *lookup_name;
1055 /* skip any ':' delimited option prefixes */
1056 lookup_name = strrchr(name, ':');
1057 if (lookup_name != NULL)
1062 ASSERT(table != NULL);
1064 for (vi = table; vi->name; vi++) {
1065 if (!strcmp(vi->name, lookup_name))
1068 /* ran to end of table */
1070 return NULL; /* var name not found */
1073 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
1077 /* length check on io buf */
1086 /* all integers are int32 sized args at the ioctl interface */
1087 if (len < (int)sizeof(int)) {
1088 bcmerror = BCME_BUFTOOSHORT;
1093 /* buffer must meet minimum length requirement */
1094 if (len < vi->minlen) {
1095 bcmerror = BCME_BUFTOOSHORT;
1101 /* Cannot return nil... */
1102 bcmerror = BCME_UNSUPPORTED;
1104 /* Set is an action w/o parameters */
1105 bcmerror = BCME_BUFTOOLONG;
1110 /* unknown type for length check in iovar info */
1112 bcmerror = BCME_UNSUPPORTED;
1118 /*******************************************************************************
1121 * Computes a crc8 over the input data using the polynomial:
1123 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1125 * The caller provides the initial value (either CRC8_INIT_VALUE
1126 * or the previous returned value) to allow for processing of
1127 * discontiguous blocks of data. When generating the CRC the
1128 * caller is responsible for complementing the final return value
1129 * and inserting it into the byte stream. When checking, a final
1130 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1132 * Reference: Dallas Semiconductor Application Note 27
1133 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1134 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1135 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1137 * ****************************************************************************
1140 static const uint8 crc8_table[256] = {
1141 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1142 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1143 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1144 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1145 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1146 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1147 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1148 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1149 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1150 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1151 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1152 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1153 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1154 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1155 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1156 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1157 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1158 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1159 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1160 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1161 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1162 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1163 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1164 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1165 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1166 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1167 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1168 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1169 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1170 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1171 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1172 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1175 #define CRC_INNER_LOOP(n, c, x) \
1176 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1178 uint8 BCMROMFN(hndcrc8) (uint8 *pdata, /* pointer to array of data to process */
1179 uint nbytes, /* number of input data bytes to process */
1180 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1182 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1183 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1185 while (nbytes-- > 0)
1186 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1191 /*******************************************************************************
1194 * Computes a crc16 over the input data using the polynomial:
1196 * x^16 + x^12 +x^5 + 1
1198 * The caller provides the initial value (either CRC16_INIT_VALUE
1199 * or the previous returned value) to allow for processing of
1200 * discontiguous blocks of data. When generating the CRC the
1201 * caller is responsible for complementing the final return value
1202 * and inserting it into the byte stream. When checking, a final
1203 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1205 * Reference: Dallas Semiconductor Application Note 27
1206 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1207 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1208 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1210 * ****************************************************************************
1213 static const uint16 crc16_table[256] = {
1214 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1215 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1216 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1217 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1218 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1219 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1220 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1221 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1222 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1223 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1224 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1225 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1226 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1227 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1228 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1229 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1230 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1231 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1232 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1233 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1234 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1235 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1236 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1237 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1238 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1239 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1240 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1241 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1242 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1243 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1244 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1245 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1248 uint16 BCMROMFN(hndcrc16) (uint8 *pdata, /* pointer to array of data to process */
1249 uint nbytes, /* number of input data bytes to process */
1250 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1252 while (nbytes-- > 0)
1253 CRC_INNER_LOOP(16, crc, *pdata++);
1258 * Advance from the current 1-byte tag/1-byte length/variable-length value
1259 * triple, to the next, returning a pointer to the next.
1260 * If the current or next TLV is invalid (does not fit in given buffer length),
1262 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1263 * by the TLV parameter's length if it is valid.
1265 bcm_tlv_t *BCMROMFN(bcm_next_tlv) (bcm_tlv_t *elt, int *buflen)
1269 /* validate current elt */
1270 if (!bcm_valid_tlv(elt, *buflen))
1273 /* advance to next elt */
1275 elt = (bcm_tlv_t *) (elt->data + len);
1276 *buflen -= (2 + len);
1278 /* validate next elt */
1279 if (!bcm_valid_tlv(elt, *buflen))
1286 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1287 * triples, returning a pointer to the substring whose first element
1290 bcm_tlv_t *BCMROMFN(bcm_parse_tlvs) (void *buf, int buflen, uint key)
1295 elt = (bcm_tlv_t *) buf;
1298 /* find tagged parameter */
1299 while (totlen >= 2) {
1302 /* validate remaining totlen */
1303 if ((elt->id == key) && (totlen >= (len + 2)))
1306 elt = (bcm_tlv_t *) ((uint8 *) elt + (len + 2));
1307 totlen -= (len + 2);
1314 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1315 * triples, returning a pointer to the substring whose first element
1316 * matches tag. Stop parsing when we see an element whose ID is greater
1317 * than the target key.
1319 bcm_tlv_t *BCMROMFN(bcm_parse_ordered_tlvs) (void *buf, int buflen, uint key)
1324 elt = (bcm_tlv_t *) buf;
1327 /* find tagged parameter */
1328 while (totlen >= 2) {
1332 /* Punt if we start seeing IDs > than target key */
1336 /* validate remaining totlen */
1337 if ((id == key) && (totlen >= (len + 2)))
1340 elt = (bcm_tlv_t *) ((uint8 *) elt + (len + 2));
1341 totlen -= (len + 2);
1348 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char *buf, int len)
1353 int slen = 0, nlen = 0;
1357 if (len < 2 || !buf)
1362 for (i = 0; flags != 0; i++) {
1365 if (bit == 0 && flags != 0) {
1366 /* print any unnamed bits */
1367 snprintf(hexstr, 16, "0x%X", flags);
1369 flags = 0; /* exit loop */
1370 } else if ((flags & bit) == 0)
1373 nlen = strlen(name);
1375 /* count btwn flag space */
1378 /* need NULL char as well */
1381 /* copy NULL char but don't count it */
1382 strncpy(p, name, nlen + 1);
1384 /* copy btwn flag space and NULL char */
1386 p += snprintf(p, 2, " ");
1390 /* indicate the str was too short */
1393 p -= 2 - len; /* overwrite last char */
1394 p += snprintf(p, 2, ">");
1397 return (int)(p - buf);
1400 /* print bytes formatted as hex to a string. return the resulting string length */
1401 int bcm_format_hex(char *str, const void *bytes, int len)
1405 const uint8 *src = (const uint8 *)bytes;
1407 for (i = 0; i < len; i++) {
1408 p += snprintf(p, 3, "%02X", *src);
1411 return (int)(p - str);
1413 #endif /* defined(BCMDBG) */
1415 /* pretty hex print a contiguous buffer */
1416 void prhex(const char *msg, uchar *buf, uint nbytes)
1419 int len = sizeof(line);
1423 if (msg && (msg[0] != '\0'))
1424 printf("%s:\n", msg);
1427 for (i = 0; i < nbytes; i++) {
1429 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
1434 nchar = snprintf(p, len, "%02x ", buf[i]);
1440 printf("%s\n", line); /* flush line */
1446 /* flush last partial line */
1448 printf("%s\n", line);
1451 static const char *crypto_algo_names[] = {
1463 const char *bcm_crypto_algo_name(uint algo)
1466 ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
1470 void deadbeef(void *p, uint len)
1472 static uint8 meat[] = { 0xde, 0xad, 0xbe, 0xef };
1475 *(uint8 *) p = meat[((uintptr) p) & 3];
1476 p = (uint8 *) p + 1;
1481 char *bcm_chipname(uint chipid, char *buf, uint len)
1485 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
1486 snprintf(buf, len, fmt, chipid);
1490 /* Produce a human-readable string for boardrev */
1491 char *bcm_brev_str(uint32 brev, char *buf)
1494 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1496 snprintf(buf, 8, "%c%03x",
1497 ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
1502 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1504 /* dump large strings to console */
1505 void printbig(char *buf)
1512 max_len = BUFSIZE_TODUMP_ATONCE;
1514 while (len > max_len) {
1516 buf[max_len] = '\0';
1523 /* print the remaining string */
1524 printf("%s\n", buf);
1528 /* routine to dump fields in a fileddesc structure */
1530 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1,
1531 struct fielddesc *fielddesc_array, char *buf, uint32 bufsize)
1535 struct fielddesc *cur_ptr;
1538 cur_ptr = fielddesc_array;
1540 while (bufsize > 1) {
1541 if (cur_ptr->nameandfmt == NULL)
1543 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
1544 read_rtn(arg0, arg1, cur_ptr->offset));
1545 /* check for snprintf overflow or error */
1546 if (len < 0 || (uint32) len >= bufsize)
1556 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1560 len = strlen(name) + 1;
1562 if ((len + datalen) > buflen)
1565 strncpy(buf, name, buflen);
1567 /* append data onto the end of the name string */
1568 memcpy(&buf[len], data, datalen);
1574 /* Quarter dBm units to mW
1575 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1576 * Table is offset so the last entry is largest mW value that fits in
1580 #define QDBM_OFFSET 153 /* Offset for first entry */
1581 #define QDBM_TABLE_LEN 40 /* Table size */
1583 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1584 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1586 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1588 /* Largest mW value that will round down to the last table entry,
1589 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1590 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1592 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1594 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1595 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1596 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1597 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1598 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1599 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1600 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1603 uint16 BCMROMFN(bcm_qdbm_to_mw) (uint8 qdbm)
1606 int idx = qdbm - QDBM_OFFSET;
1608 if (idx >= QDBM_TABLE_LEN) {
1609 /* clamp to max uint16 mW value */
1613 /* scale the qdBm index up to the range of the table 0-40
1614 * where an offset of 40 qdBm equals a factor of 10 mW.
1621 /* return the mW value scaled down to the correct factor of 10,
1622 * adding in factor/2 to get proper rounding.
1624 return ((nqdBm_to_mW_map[idx] + factor / 2) / factor);
1627 uint8 BCMROMFN(bcm_mw_to_qdbm) (uint16 mw)
1634 /* handle boundary case */
1638 offset = QDBM_OFFSET;
1640 /* move mw into the range of the table */
1641 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1646 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
1647 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
1648 nqdBm_to_mW_map[qdbm]) / 2;
1649 if (mw_uint < boundary)
1653 qdbm += (uint8) offset;
1658 uint BCMROMFN(bcm_bitcount) (uint8 *bitmap, uint length)
1660 uint bitcount = 0, i;
1662 for (i = 0; i < length; i++) {
1672 /* Initialization of bcmstrbuf structure */
1673 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1675 b->origsize = b->size = size;
1676 b->origbuf = b->buf = buf;
1679 /* Buffer sprintf wrapper to guard against buffer overflow */
1680 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1686 r = vsnprintf(b->buf, b->size, fmt, ap);
1688 /* Non Ansi C99 compliant returns -1,
1689 * Ansi compliant return r >= b->size,
1690 * bcmstdlib returns 0, handle all
1692 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1704 void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
1708 for (i = 0; i < num_bytes; i++) {
1710 if (num[i] >= amount)
1716 int bcm_cmp_bytes(uchar *arg1, uchar *arg2, uint8 nbytes)
1720 for (i = nbytes - 1; i >= 0; i--) {
1721 if (arg1[i] != arg2[i])
1722 return (arg1[i] - arg2[i]);
1727 void bcm_print_bytes(char *name, const uchar *data, int len)
1732 printf("%s: %d\n", name ? name : "", len);
1733 for (i = 0; i < len; i++) {
1734 printf("%02x ", *data++);
1736 if (per_line == 16) {
1745 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
1746 int bcm_format_ssid(char *buf, const uchar ssid[], uint ssid_len)
1750 char *endp = buf + SSID_FMT_BUF_LEN;
1752 if (ssid_len > DOT11_MAX_SSID_LEN)
1753 ssid_len = DOT11_MAX_SSID_LEN;
1755 for (i = 0; i < ssid_len; i++) {
1760 } else if (bcm_isprint((uchar) c)) {
1763 p += snprintf(p, (endp - p), "\\x%02X", c);
1769 return (int)(p - buf);
1771 #endif /* defined(BCMDBG) */