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) {
529 ulong result, last_result = 0, value;
534 while (bcm_isspace(*cp))
539 else if (cp[0] == '-') {
546 if ((cp[1] == 'x') || (cp[1] == 'X')) {
555 } else if (base == 16 && (cp[0] == '0')
556 && ((cp[1] == 'x') || (cp[1] == 'X'))) {
562 while (bcm_isxdigit(*cp) &&
564 bcm_isdigit(*cp) ? *cp - '0' : bcm_toupper(*cp) - 'A' + 10) <
566 result = result * base + value;
567 /* Detected overflow */
568 if (result < last_result && !minus)
570 last_result = result;
575 result = (ulong) (-(long)result);
583 int BCMROMFN(bcm_atoi) (char *s) {
584 return (int)bcm_strtoul(s, NULL, 10);
587 /* return pointer to location of substring 'needle' in 'haystack' */
588 char *BCMROMFN(bcmstrstr) (char *haystack, char *needle) {
592 if ((haystack == NULL) || (needle == NULL))
595 nlen = strlen(needle);
596 len = strlen(haystack) - nlen + 1;
598 for (i = 0; i < len; i++)
599 if (memcmp(needle, &haystack[i], nlen) == 0)
600 return (&haystack[i]);
604 char *BCMROMFN(bcmstrcat) (char *dest, const char *src) {
607 p = dest + strlen(dest);
609 while ((*p++ = *src++) != '\0') ;
614 char *BCMROMFN(bcmstrncat) (char *dest, const char *src, uint size) {
618 p = dest + strlen(dest);
621 while (p != endp && (*p++ = *src++) != '\0') ;
626 /****************************************************************************
627 * Function: bcmstrtok
630 * Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
631 * but allows strToken() to be used by different strings or callers at the same
632 * time. Each call modifies '*string' by substituting a NULL character for the
633 * first delimiter that is encountered, and updates 'string' to point to the char
634 * after the delimiter. Leading delimiters are skipped.
637 * string (mod) Ptr to string ptr, updated by token.
638 * delimiters (in) Set of delimiter characters.
639 * tokdelim (out) Character that delimits the returned token. (May
640 * be set to NULL if token delimiter is not required).
642 * Returns: Pointer to the next token found. NULL when no more tokens are found.
643 *****************************************************************************
645 char *bcmstrtok(char **string, const char *delimiters, char *tokdelim)
648 unsigned long map[8];
652 if (tokdelim != NULL) {
653 /* Prime the token delimiter */
657 /* Clear control map */
658 for (count = 0; count < 8; count++) {
662 /* Set bits in delimiter table */
664 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
666 while (*delimiters++);
668 str = (unsigned char *)*string;
670 /* Find beginning of token (skip over leading delimiters). Note that
671 * there is no token iff this loop sets str to point to the terminal
672 * null (*str == '\0')
674 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
678 nextoken = (char *)str;
680 /* Find the end of the token. If it is not the end of the string,
683 for (; *str; str++) {
684 if (map[*str >> 5] & (1 << (*str & 31))) {
685 if (tokdelim != NULL) {
694 *string = (char *)str;
696 /* Determine if a token has been found. */
697 if (nextoken == (char *)str) {
704 #define xToLower(C) \
705 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
707 /****************************************************************************
708 * Function: bcmstricmp
710 * Purpose: Compare to strings case insensitively.
712 * Parameters: s1 (in) First string to compare.
713 * s2 (in) Second string to compare.
715 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
716 * t1 > t2, when ignoring case sensitivity.
717 *****************************************************************************
719 int bcmstricmp(const char *s1, const char *s2)
741 /****************************************************************************
742 * Function: bcmstrnicmp
744 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
747 * Parameters: s1 (in) First string to compare.
748 * s2 (in) Second string to compare.
749 * cnt (in) Max characters to compare.
751 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
752 * t1 > t2, when ignoring case sensitivity.
753 *****************************************************************************
755 int bcmstrnicmp(const char *s1, const char *s2, int cnt)
759 while (*s2 && *s1 && cnt) {
780 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
781 int BCMROMFN(bcm_ether_atoe) (char *p, struct ether_addr * ea) {
785 ea->octet[i++] = (char)bcm_strtoul(p, &p, 16);
793 char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
795 static const char template[] = "%02x:%02x:%02x:%02x:%02x:%02x";
796 snprintf(buf, 18, template,
797 ea->octet[0] & 0xff, ea->octet[1] & 0xff, ea->octet[2] & 0xff,
798 ea->octet[3] & 0xff, ea->octet[4] & 0xff, ea->octet[5] & 0xff);
802 void bcm_mdelay(uint ms)
806 for (i = 0; i < ms; i++) {
812 * Search the name=value vars for a specific one and return its value.
813 * Returns NULL if not found.
815 char *getvar(char *vars, const char *name)
827 /* first look in vars[] */
828 for (s = vars; s && *s;) {
829 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
830 return (&s[len + 1]);
835 /* then query nvram */
836 return (nvram_get(name));
840 * Search the vars for a specific one and return its value as
841 * an integer. Returns 0 if not found.
843 int getintvar(char *vars, const char *name)
847 if ((val = getvar(vars, name)) == NULL)
850 return (bcm_strtoul(val, NULL, 0));
853 int getintvararray(char *vars, const char *name, uint8 index)
859 if ((buf = getvar(vars, name)) == NULL) {
863 /* table values are always separated by "," or " " */
864 while (*buf != '\0') {
865 val = bcm_strtoul(buf, &endp, 0);
870 /* delimiter is ',' */
878 /* Search for token in comma separated token-string */
879 static int findmatch(char *string, char *name)
885 while ((c = strchr(string, ',')) != NULL) {
886 if (len == (uint) (c - string) && !strncmp(string, name, len))
891 return (!strcmp(string, name));
894 /* Return gpio pin number assigned to the named pin
896 * Variable should be in format:
898 * gpio<N>=pin_name,pin_name
900 * This format allows multiple features to share the gpio with mutual
903 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
904 * and if def_pin is not used by others.
906 uint getgpiopin(char *vars, char *pin_name, uint def_pin)
908 char name[] = "gpioXXXX";
912 /* Go thru all possibilities till a match in pin name */
913 for (pin = 0; pin < GPIO_NUMPINS; pin++) {
914 snprintf(name, sizeof(name), "gpio%d", pin);
915 val = getvar(vars, name);
916 if (val && findmatch(val, pin_name))
920 if (def_pin != GPIO_PIN_NOTDEFINED) {
921 /* make sure the default pin is not used by someone else */
922 snprintf(name, sizeof(name), "gpio%d", def_pin);
923 if (getvar(vars, name)) {
924 def_pin = GPIO_PIN_NOTDEFINED;
931 /* pretty hex print a pkt buffer chain */
932 void prpkt(const char *msg, osl_t * osh, void *p0)
936 if (msg && (msg[0] != '\0'))
937 printf("%s:\n", msg);
939 for (p = p0; p; p = PKTNEXT(p))
940 prhex(NULL, PKTDATA(p), PKTLEN(p));
942 #endif /* defined(BCMDBG) */
944 static char bcm_undeferrstr[32];
945 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
947 /* Convert the error codes into related error strings */
948 const char *bcmerrorstr(int bcmerror)
950 /* check if someone added a bcmerror code but forgot to add errorstring */
951 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
953 if (bcmerror > 0 || bcmerror < BCME_LAST) {
954 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr),
955 "Undefined error %d", bcmerror);
956 return bcm_undeferrstr;
959 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
961 return bcmerrorstrtable[-bcmerror];
965 static void BCMINITFN(bcm_nvram_refresh) (char *flash) {
969 ASSERT(flash != NULL);
971 /* default "empty" vars cache */
974 if ((ret = nvram_getall(flash, NVRAM_SPACE)))
977 /* determine nvram length */
978 for (i = 0; i < NVRAM_SPACE; i++) {
979 if (flash[i] == '\0' && flash[i + 1] == '\0')
989 char *bcm_nvram_vars(uint * length)
992 /* cache may be stale if nvram is read/write */
994 ASSERT(!bcmreclaimed);
995 bcm_nvram_refresh(nvram_vars);
1003 /* copy nvram vars into locally-allocated multi-string array */
1004 int BCMINITFN(bcm_nvram_cache) (void *sih) {
1009 if (vars_len >= 0) {
1011 bcm_nvram_refresh(nvram_vars);
1016 osh = si_osh((si_t *) sih);
1018 /* allocate memory and read in flash */
1019 if (!(flash = MALLOC(osh, NVRAM_SPACE))) {
1024 bcm_nvram_refresh(flash);
1027 /* copy into a properly-sized buffer */
1028 if (!(nvram_vars = MALLOC(osh, vars_len))) {
1031 bcopy(flash, nvram_vars, vars_len);
1033 MFREE(osh, flash, NVRAM_SPACE);
1035 /* cache must be full size of nvram if read/write */
1037 #endif /* BCMNVRAMR */
1042 #endif /* WLC_LOW */
1044 /* iovar table lookup */
1045 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t * table, const char *name)
1047 const bcm_iovar_t *vi;
1048 const char *lookup_name;
1050 /* skip any ':' delimited option prefixes */
1051 lookup_name = strrchr(name, ':');
1052 if (lookup_name != NULL)
1057 ASSERT(table != NULL);
1059 for (vi = table; vi->name; vi++) {
1060 if (!strcmp(vi->name, lookup_name))
1063 /* ran to end of table */
1065 return NULL; /* var name not found */
1068 int bcm_iovar_lencheck(const bcm_iovar_t * vi, void *arg, int len, bool set)
1072 /* length check on io buf */
1081 /* all integers are int32 sized args at the ioctl interface */
1082 if (len < (int)sizeof(int)) {
1083 bcmerror = BCME_BUFTOOSHORT;
1088 /* buffer must meet minimum length requirement */
1089 if (len < vi->minlen) {
1090 bcmerror = BCME_BUFTOOSHORT;
1096 /* Cannot return nil... */
1097 bcmerror = BCME_UNSUPPORTED;
1099 /* Set is an action w/o parameters */
1100 bcmerror = BCME_BUFTOOLONG;
1105 /* unknown type for length check in iovar info */
1107 bcmerror = BCME_UNSUPPORTED;
1113 /*******************************************************************************
1116 * Computes a crc8 over the input data using the polynomial:
1118 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1120 * The caller provides the initial value (either CRC8_INIT_VALUE
1121 * or the previous returned value) to allow for processing of
1122 * discontiguous blocks of data. When generating the CRC the
1123 * caller is responsible for complementing the final return value
1124 * and inserting it into the byte stream. When checking, a final
1125 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1127 * Reference: Dallas Semiconductor Application Note 27
1128 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1129 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1130 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1132 * ****************************************************************************
1135 static const uint8 crc8_table[256] = {
1136 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1137 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1138 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1139 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1140 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1141 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1142 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1143 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1144 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1145 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1146 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1147 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1148 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1149 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1150 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1151 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1152 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1153 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1154 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1155 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1156 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1157 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1158 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1159 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1160 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1161 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1162 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1163 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1164 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1165 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1166 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1167 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1170 #define CRC_INNER_LOOP(n, c, x) \
1171 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1173 uint8 BCMROMFN(hndcrc8) (uint8 * pdata, /* pointer to array of data to process */
1174 uint nbytes, /* number of input data bytes to process */
1175 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1177 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1178 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1180 while (nbytes-- > 0)
1181 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1186 /*******************************************************************************
1189 * Computes a crc16 over the input data using the polynomial:
1191 * x^16 + x^12 +x^5 + 1
1193 * The caller provides the initial value (either CRC16_INIT_VALUE
1194 * or the previous returned value) to allow for processing of
1195 * discontiguous blocks of data. When generating the CRC the
1196 * caller is responsible for complementing the final return value
1197 * and inserting it into the byte stream. When checking, a final
1198 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1200 * Reference: Dallas Semiconductor Application Note 27
1201 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1202 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1203 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1205 * ****************************************************************************
1208 static const uint16 crc16_table[256] = {
1209 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1210 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1211 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1212 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1213 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1214 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1215 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1216 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1217 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1218 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1219 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1220 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1221 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1222 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1223 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1224 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1225 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1226 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1227 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1228 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1229 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1230 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1231 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1232 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1233 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1234 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1235 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1236 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1237 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1238 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1239 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1240 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1243 uint16 BCMROMFN(hndcrc16) (uint8 * pdata, /* pointer to array of data to process */
1244 uint nbytes, /* number of input data bytes to process */
1245 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1247 while (nbytes-- > 0)
1248 CRC_INNER_LOOP(16, crc, *pdata++);
1253 * Advance from the current 1-byte tag/1-byte length/variable-length value
1254 * triple, to the next, returning a pointer to the next.
1255 * If the current or next TLV is invalid (does not fit in given buffer length),
1257 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1258 * by the TLV parameter's length if it is valid.
1260 bcm_tlv_t *BCMROMFN(bcm_next_tlv) (bcm_tlv_t * elt, int *buflen) {
1263 /* validate current elt */
1264 if (!bcm_valid_tlv(elt, *buflen))
1267 /* advance to next elt */
1269 elt = (bcm_tlv_t *) (elt->data + len);
1270 *buflen -= (2 + len);
1272 /* validate next elt */
1273 if (!bcm_valid_tlv(elt, *buflen))
1280 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1281 * triples, returning a pointer to the substring whose first element
1284 bcm_tlv_t *BCMROMFN(bcm_parse_tlvs) (void *buf, int buflen, uint key) {
1288 elt = (bcm_tlv_t *) buf;
1291 /* find tagged parameter */
1292 while (totlen >= 2) {
1295 /* validate remaining totlen */
1296 if ((elt->id == key) && (totlen >= (len + 2)))
1299 elt = (bcm_tlv_t *) ((uint8 *) elt + (len + 2));
1300 totlen -= (len + 2);
1307 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1308 * triples, returning a pointer to the substring whose first element
1309 * matches tag. Stop parsing when we see an element whose ID is greater
1310 * than the target key.
1312 bcm_tlv_t *BCMROMFN(bcm_parse_ordered_tlvs) (void *buf, int buflen, uint key) {
1316 elt = (bcm_tlv_t *) buf;
1319 /* find tagged parameter */
1320 while (totlen >= 2) {
1324 /* Punt if we start seeing IDs > than target key */
1328 /* validate remaining totlen */
1329 if ((id == key) && (totlen >= (len + 2)))
1332 elt = (bcm_tlv_t *) ((uint8 *) elt + (len + 2));
1333 totlen -= (len + 2);
1340 bcm_format_flags(const bcm_bit_desc_t * bd, uint32 flags, char *buf, int len)
1345 int slen = 0, nlen = 0;
1349 if (len < 2 || !buf)
1354 for (i = 0; flags != 0; i++) {
1357 if (bit == 0 && flags != 0) {
1358 /* print any unnamed bits */
1359 snprintf(hexstr, 16, "0x%X", flags);
1361 flags = 0; /* exit loop */
1362 } else if ((flags & bit) == 0)
1365 nlen = strlen(name);
1367 /* count btwn flag space */
1370 /* need NULL char as well */
1373 /* copy NULL char but don't count it */
1374 strncpy(p, name, nlen + 1);
1376 /* copy btwn flag space and NULL char */
1378 p += snprintf(p, 2, " ");
1382 /* indicate the str was too short */
1385 p -= 2 - len; /* overwrite last char */
1386 p += snprintf(p, 2, ">");
1389 return (int)(p - buf);
1392 /* print bytes formatted as hex to a string. return the resulting string length */
1393 int bcm_format_hex(char *str, const void *bytes, int len)
1397 const uint8 *src = (const uint8 *)bytes;
1399 for (i = 0; i < len; i++) {
1400 p += snprintf(p, 3, "%02X", *src);
1403 return (int)(p - str);
1405 #endif /* defined(BCMDBG) */
1407 /* pretty hex print a contiguous buffer */
1408 void prhex(const char *msg, uchar * buf, uint nbytes)
1411 int len = sizeof(line);
1415 if (msg && (msg[0] != '\0'))
1416 printf("%s:\n", msg);
1419 for (i = 0; i < nbytes; i++) {
1421 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
1426 nchar = snprintf(p, len, "%02x ", buf[i]);
1432 printf("%s\n", line); /* flush line */
1438 /* flush last partial line */
1440 printf("%s\n", line);
1443 static const char *crypto_algo_names[] = {
1455 const char *bcm_crypto_algo_name(uint algo)
1458 ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
1462 void deadbeef(void *p, uint len)
1464 static uint8 meat[] = { 0xde, 0xad, 0xbe, 0xef };
1467 *(uint8 *) p = meat[((uintptr) p) & 3];
1468 p = (uint8 *) p + 1;
1473 char *bcm_chipname(uint chipid, char *buf, uint len)
1477 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
1478 snprintf(buf, len, fmt, chipid);
1482 /* Produce a human-readable string for boardrev */
1483 char *bcm_brev_str(uint32 brev, char *buf)
1486 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1488 snprintf(buf, 8, "%c%03x",
1489 ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
1494 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1496 /* dump large strings to console */
1497 void printbig(char *buf)
1504 max_len = BUFSIZE_TODUMP_ATONCE;
1506 while (len > max_len) {
1508 buf[max_len] = '\0';
1515 /* print the remaining string */
1516 printf("%s\n", buf);
1520 /* routine to dump fields in a fileddesc structure */
1522 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1,
1523 struct fielddesc * fielddesc_array, char *buf, uint32 bufsize)
1527 struct fielddesc *cur_ptr;
1530 cur_ptr = fielddesc_array;
1532 while (bufsize > 1) {
1533 if (cur_ptr->nameandfmt == NULL)
1535 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
1536 read_rtn(arg0, arg1, cur_ptr->offset));
1537 /* check for snprintf overflow or error */
1538 if (len < 0 || (uint32) len >= bufsize)
1548 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1552 len = strlen(name) + 1;
1554 if ((len + datalen) > buflen)
1557 strncpy(buf, name, buflen);
1559 /* append data onto the end of the name string */
1560 memcpy(&buf[len], data, datalen);
1566 /* Quarter dBm units to mW
1567 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1568 * Table is offset so the last entry is largest mW value that fits in
1572 #define QDBM_OFFSET 153 /* Offset for first entry */
1573 #define QDBM_TABLE_LEN 40 /* Table size */
1575 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1576 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1578 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1580 /* Largest mW value that will round down to the last table entry,
1581 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1582 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1584 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1586 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1587 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1588 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1589 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1590 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1591 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1592 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1595 uint16 BCMROMFN(bcm_qdbm_to_mw) (uint8 qdbm) {
1597 int idx = qdbm - QDBM_OFFSET;
1599 if (idx >= QDBM_TABLE_LEN) {
1600 /* clamp to max uint16 mW value */
1604 /* scale the qdBm index up to the range of the table 0-40
1605 * where an offset of 40 qdBm equals a factor of 10 mW.
1612 /* return the mW value scaled down to the correct factor of 10,
1613 * adding in factor/2 to get proper rounding.
1615 return ((nqdBm_to_mW_map[idx] + factor / 2) / factor);
1618 uint8 BCMROMFN(bcm_mw_to_qdbm) (uint16 mw) {
1624 /* handle boundary case */
1628 offset = QDBM_OFFSET;
1630 /* move mw into the range of the table */
1631 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1636 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
1637 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
1638 nqdBm_to_mW_map[qdbm]) / 2;
1639 if (mw_uint < boundary)
1643 qdbm += (uint8) offset;
1648 uint BCMROMFN(bcm_bitcount) (uint8 * bitmap, uint length) {
1649 uint bitcount = 0, i;
1651 for (i = 0; i < length; i++) {
1661 /* Initialization of bcmstrbuf structure */
1662 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1664 b->origsize = b->size = size;
1665 b->origbuf = b->buf = buf;
1668 /* Buffer sprintf wrapper to guard against buffer overflow */
1669 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1675 r = vsnprintf(b->buf, b->size, fmt, ap);
1677 /* Non Ansi C99 compliant returns -1,
1678 * Ansi compliant return r >= b->size,
1679 * bcmstdlib returns 0, handle all
1681 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1693 void bcm_inc_bytes(uchar * num, int num_bytes, uint8 amount)
1697 for (i = 0; i < num_bytes; i++) {
1699 if (num[i] >= amount)
1705 int bcm_cmp_bytes(uchar * arg1, uchar * arg2, uint8 nbytes)
1709 for (i = nbytes - 1; i >= 0; i--) {
1710 if (arg1[i] != arg2[i])
1711 return (arg1[i] - arg2[i]);
1716 void bcm_print_bytes(char *name, const uchar * data, int len)
1721 printf("%s: %d\n", name ? name : "", len);
1722 for (i = 0; i < len; i++) {
1723 printf("%02x ", *data++);
1725 if (per_line == 16) {
1734 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
1735 int bcm_format_ssid(char *buf, const uchar ssid[], uint ssid_len)
1739 char *endp = buf + SSID_FMT_BUF_LEN;
1741 if (ssid_len > DOT11_MAX_SSID_LEN)
1742 ssid_len = DOT11_MAX_SSID_LEN;
1744 for (i = 0; i < ssid_len; i++) {
1749 } else if (bcm_isprint((uchar) c)) {
1752 p += snprintf(p, (endp - p), "\\x%02X", c);
1758 return (int)(p - buf);
1760 #endif /* defined(BCMDBG) */