staging: brcm80211: use string native library
[linux-2.6/btrfs-unstable.git] / drivers / staging / brcm80211 / util / bcmutils.c
blobcc548e030179d8a961f23e0cacd8d28bb967017f
1 /*
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.
17 #include <typedefs.h>
18 #include <bcmdefs.h>
19 #include <stdarg.h>
20 #include <osl.h>
21 #include <linux/ctype.h>
22 #include <linux/kernel.h>
23 #include <bcmutils.h>
24 #include <siutils.h>
25 #include <bcmnvram.h>
26 #include <bcmendian.h>
27 #include <bcmdevs.h>
28 #include <proto/ethernet.h>
29 #include <proto/802.1d.h>
30 #include <proto/802.11.h>
32 #ifdef WLC_LOW
33 /* nvram vars cache */
34 static char *nvram_vars;
35 static int vars_len = -1;
36 #endif /* WLC_LOW */
38 /* copy a pkt buffer chain into a buffer */
39 uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
41 uint n, ret = 0;
43 if (len < 0)
44 len = 4096; /* "infinite" */
46 /* skip 'offset' bytes */
47 for (; p && offset; p = PKTNEXT(p)) {
48 if (offset < (uint) PKTLEN(p))
49 break;
50 offset -= PKTLEN(p);
53 if (!p)
54 return 0;
56 /* copy the data */
57 for (; p && len; p = PKTNEXT(p)) {
58 n = MIN((uint) PKTLEN(p) - offset, (uint) len);
59 bcopy(PKTDATA(p) + offset, buf, n);
60 buf += n;
61 len -= n;
62 ret += n;
63 offset = 0;
66 return ret;
69 /* copy a buffer into a pkt buffer chain */
70 uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
72 uint n, ret = 0;
74 /* skip 'offset' bytes */
75 for (; p && offset; p = PKTNEXT(p)) {
76 if (offset < (uint) PKTLEN(p))
77 break;
78 offset -= PKTLEN(p);
81 if (!p)
82 return 0;
84 /* copy the data */
85 for (; p && len; p = PKTNEXT(p)) {
86 n = MIN((uint) PKTLEN(p) - offset, (uint) len);
87 bcopy(buf, PKTDATA(p) + offset, n);
88 buf += n;
89 len -= n;
90 ret += n;
91 offset = 0;
94 return ret;
97 /* return total length of buffer chain */
98 uint BCMFASTPATH pkttotlen(osl_t *osh, void *p)
100 uint total;
102 total = 0;
103 for (; p; p = PKTNEXT(p))
104 total += PKTLEN(p);
105 return total;
108 /* return the last buffer of chained pkt */
109 void *pktlast(osl_t *osh, void *p)
111 for (; PKTNEXT(p); p = PKTNEXT(p))
114 return p;
117 /* count segments of a chained packet */
118 uint BCMFASTPATH pktsegcnt(osl_t *osh, void *p)
120 uint cnt;
122 for (cnt = 0; p; p = PKTNEXT(p))
123 cnt++;
125 return cnt;
129 * osl multiple-precedence packet queue
130 * hi_prec is always >= the number of the highest non-empty precedence
132 void *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, void *p)
134 struct pktq_prec *q;
136 ASSERT(prec >= 0 && prec < pq->num_prec);
137 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
139 ASSERT(!pktq_full(pq));
140 ASSERT(!pktq_pfull(pq, prec));
142 q = &pq->q[prec];
144 if (q->head)
145 PKTSETLINK(q->tail, p);
146 else
147 q->head = p;
149 q->tail = p;
150 q->len++;
152 pq->len++;
154 if (pq->hi_prec < prec)
155 pq->hi_prec = (uint8) prec;
157 return p;
160 void *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, void *p)
162 struct pktq_prec *q;
164 ASSERT(prec >= 0 && prec < pq->num_prec);
165 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
167 ASSERT(!pktq_full(pq));
168 ASSERT(!pktq_pfull(pq, prec));
170 q = &pq->q[prec];
172 if (q->head == NULL)
173 q->tail = p;
175 PKTSETLINK(p, q->head);
176 q->head = p;
177 q->len++;
179 pq->len++;
181 if (pq->hi_prec < prec)
182 pq->hi_prec = (uint8) prec;
184 return p;
187 void *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
189 struct pktq_prec *q;
190 void *p;
192 ASSERT(prec >= 0 && prec < pq->num_prec);
194 q = &pq->q[prec];
196 p = q->head;
197 if (p == NULL)
198 return NULL;
200 q->head = PKTLINK(p);
201 if (q->head == NULL)
202 q->tail = NULL;
204 q->len--;
206 pq->len--;
208 PKTSETLINK(p, NULL);
210 return p;
213 void *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
215 struct pktq_prec *q;
216 void *p, *prev;
218 ASSERT(prec >= 0 && prec < pq->num_prec);
220 q = &pq->q[prec];
222 p = q->head;
223 if (p == NULL)
224 return NULL;
226 for (prev = NULL; p != q->tail; p = PKTLINK(p))
227 prev = p;
229 if (prev)
230 PKTSETLINK(prev, NULL);
231 else
232 q->head = NULL;
234 q->tail = prev;
235 q->len--;
237 pq->len--;
239 return p;
242 void
243 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn,
244 int arg)
246 struct pktq_prec *q;
247 void *p, *prev = NULL;
249 q = &pq->q[prec];
250 p = q->head;
251 while (p) {
252 if (fn == NULL || (*fn) (p, arg)) {
253 bool head = (p == q->head);
254 if (head)
255 q->head = PKTLINK(p);
256 else
257 PKTSETLINK(prev, PKTLINK(p));
258 PKTSETLINK(p, NULL);
259 PKTFREE(osh, p, dir);
260 q->len--;
261 pq->len--;
262 p = (head ? q->head : PKTLINK(prev));
263 } else {
264 prev = p;
265 p = PKTLINK(p);
269 if (q->head == NULL) {
270 ASSERT(q->len == 0);
271 q->tail = NULL;
275 bool BCMFASTPATH pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
277 struct pktq_prec *q;
278 void *p;
280 ASSERT(prec >= 0 && prec < pq->num_prec);
282 if (!pktbuf)
283 return FALSE;
285 q = &pq->q[prec];
287 if (q->head == pktbuf) {
288 q->head = PKTLINK(pktbuf);
289 if (q->head == NULL)
290 q->tail = NULL;
291 } else {
292 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
294 if (p == NULL)
295 return FALSE;
297 PKTSETLINK(p, PKTLINK(pktbuf));
298 if (q->tail == pktbuf)
299 q->tail = p;
302 q->len--;
303 pq->len--;
304 PKTSETLINK(pktbuf, NULL);
305 return TRUE;
308 void pktq_init(struct pktq *pq, int num_prec, int max_len)
310 int prec;
312 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
314 /* pq is variable size; only zero out what's requested */
315 bzero(pq,
316 OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
318 pq->num_prec = (uint16) num_prec;
320 pq->max = (uint16) max_len;
322 for (prec = 0; prec < num_prec; prec++)
323 pq->q[prec].max = pq->max;
326 void *BCMFASTPATH pktq_deq(struct pktq *pq, int *prec_out)
328 struct pktq_prec *q;
329 void *p;
330 int prec;
332 if (pq->len == 0)
333 return NULL;
335 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
336 pq->hi_prec--;
338 q = &pq->q[prec];
340 p = q->head;
341 if (p == NULL)
342 return NULL;
344 q->head = PKTLINK(p);
345 if (q->head == NULL)
346 q->tail = NULL;
348 q->len--;
350 pq->len--;
352 if (prec_out)
353 *prec_out = prec;
355 PKTSETLINK(p, NULL);
357 return p;
360 void *BCMFASTPATH pktq_deq_tail(struct pktq *pq, int *prec_out)
362 struct pktq_prec *q;
363 void *p, *prev;
364 int prec;
366 if (pq->len == 0)
367 return NULL;
369 for (prec = 0; prec < pq->hi_prec; prec++)
370 if (pq->q[prec].head)
371 break;
373 q = &pq->q[prec];
375 p = q->head;
376 if (p == NULL)
377 return NULL;
379 for (prev = NULL; p != q->tail; p = PKTLINK(p))
380 prev = p;
382 if (prev)
383 PKTSETLINK(prev, NULL);
384 else
385 q->head = NULL;
387 q->tail = prev;
388 q->len--;
390 pq->len--;
392 if (prec_out)
393 *prec_out = prec;
395 PKTSETLINK(p, NULL);
397 return p;
400 void *pktq_peek(struct pktq *pq, int *prec_out)
402 int prec;
404 if (pq->len == 0)
405 return NULL;
407 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
408 pq->hi_prec--;
410 if (prec_out)
411 *prec_out = prec;
413 return pq->q[prec].head;
416 void *pktq_peek_tail(struct pktq *pq, int *prec_out)
418 int prec;
420 if (pq->len == 0)
421 return NULL;
423 for (prec = 0; prec < pq->hi_prec; prec++)
424 if (pq->q[prec].head)
425 break;
427 if (prec_out)
428 *prec_out = prec;
430 return pq->q[prec].tail;
433 void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
435 int prec;
436 for (prec = 0; prec < pq->num_prec; prec++)
437 pktq_pflush(osh, pq, prec, dir, fn, arg);
438 if (fn == NULL)
439 ASSERT(pq->len == 0);
442 /* Return sum of lengths of a specific set of precedences */
443 int pktq_mlen(struct pktq *pq, uint prec_bmp)
445 int prec, len;
447 len = 0;
449 for (prec = 0; prec <= pq->hi_prec; prec++)
450 if (prec_bmp & (1 << prec))
451 len += pq->q[prec].len;
453 return len;
456 /* Priority dequeue from a specific set of precedences */
457 void *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
459 struct pktq_prec *q;
460 void *p;
461 int prec;
463 if (pq->len == 0)
464 return NULL;
466 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
467 pq->hi_prec--;
469 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
470 if (prec-- == 0)
471 return NULL;
473 q = &pq->q[prec];
475 p = q->head;
476 if (p == NULL)
477 return NULL;
479 q->head = PKTLINK(p);
480 if (q->head == NULL)
481 q->tail = NULL;
483 q->len--;
485 if (prec_out)
486 *prec_out = prec;
488 pq->len--;
490 PKTSETLINK(p, NULL);
492 return p;
495 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
496 int BCMROMFN(bcm_ether_atoe) (char *p, struct ether_addr *ea)
498 int i = 0;
500 for (;;) {
501 ea->octet[i++] = (char)simple_strtoul(p, &p, 16);
502 if (!*p++ || i == 6)
503 break;
506 return i == 6;
509 char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
511 snprintf(buf, 18, "%pM", ea->octet);
512 return buf;
515 void bcm_mdelay(uint ms)
517 uint i;
519 for (i = 0; i < ms; i++) {
520 OSL_DELAY(1000);
525 * Search the name=value vars for a specific one and return its value.
526 * Returns NULL if not found.
528 char *getvar(char *vars, const char *name)
530 char *s;
531 int len;
533 if (!name)
534 return NULL;
536 len = strlen(name);
537 if (len == 0)
538 return NULL;
540 /* first look in vars[] */
541 for (s = vars; s && *s;) {
542 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
543 return &s[len + 1];
545 while (*s++)
549 /* then query nvram */
550 return nvram_get(name);
554 * Search the vars for a specific one and return its value as
555 * an integer. Returns 0 if not found.
557 int getintvar(char *vars, const char *name)
559 char *val;
561 val = getvar(vars, name);
562 if (val == NULL)
563 return 0;
565 return simple_strtoul(val, NULL, 0);
568 int getintvararray(char *vars, const char *name, uint8 index)
570 char *buf, *endp;
571 int i = 0;
572 int val = 0;
574 buf = getvar(vars, name);
575 if (buf == NULL) {
576 return 0;
579 /* table values are always separated by "," or " " */
580 while (*buf != '\0') {
581 val = simple_strtoul(buf, &endp, 0);
582 if (i == index) {
583 return val;
585 buf = endp;
586 /* delimiter is ',' */
587 if (*buf == ',')
588 buf++;
589 i++;
591 return 0;
594 /* Search for token in comma separated token-string */
595 static int findmatch(char *string, char *name)
597 uint len;
598 char *c;
600 len = strlen(name);
601 while ((c = strchr(string, ',')) != NULL) {
602 if (len == (uint) (c - string) && !strncmp(string, name, len))
603 return 1;
604 string = c + 1;
607 return !strcmp(string, name);
610 /* Return gpio pin number assigned to the named pin
612 * Variable should be in format:
614 * gpio<N>=pin_name,pin_name
616 * This format allows multiple features to share the gpio with mutual
617 * understanding.
619 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
620 * and if def_pin is not used by others.
622 uint getgpiopin(char *vars, char *pin_name, uint def_pin)
624 char name[] = "gpioXXXX";
625 char *val;
626 uint pin;
628 /* Go thru all possibilities till a match in pin name */
629 for (pin = 0; pin < GPIO_NUMPINS; pin++) {
630 snprintf(name, sizeof(name), "gpio%d", pin);
631 val = getvar(vars, name);
632 if (val && findmatch(val, pin_name))
633 return pin;
636 if (def_pin != GPIO_PIN_NOTDEFINED) {
637 /* make sure the default pin is not used by someone else */
638 snprintf(name, sizeof(name), "gpio%d", def_pin);
639 if (getvar(vars, name)) {
640 def_pin = GPIO_PIN_NOTDEFINED;
643 return def_pin;
646 #if defined(BCMDBG)
647 /* pretty hex print a pkt buffer chain */
648 void prpkt(const char *msg, osl_t *osh, void *p0)
650 void *p;
652 if (msg && (msg[0] != '\0'))
653 printf("%s:\n", msg);
655 for (p = p0; p; p = PKTNEXT(p))
656 prhex(NULL, PKTDATA(p), PKTLEN(p));
658 #endif /* defined(BCMDBG) */
660 static char bcm_undeferrstr[32];
661 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
663 /* Convert the error codes into related error strings */
664 const char *bcmerrorstr(int bcmerror)
666 /* check if someone added a bcmerror code but forgot to add errorstring */
667 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
669 if (bcmerror > 0 || bcmerror < BCME_LAST) {
670 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr),
671 "Undefined error %d", bcmerror);
672 return bcm_undeferrstr;
675 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
677 return bcmerrorstrtable[-bcmerror];
680 #ifdef WLC_LOW
681 static void BCMINITFN(bcm_nvram_refresh) (char *flash)
683 int i;
684 int ret = 0;
686 ASSERT(flash != NULL);
688 /* default "empty" vars cache */
689 bzero(flash, 2);
691 ret = nvram_getall(flash, NVRAM_SPACE);
692 if (ret)
693 return;
695 /* determine nvram length */
696 for (i = 0; i < NVRAM_SPACE; i++) {
697 if (flash[i] == '\0' && flash[i + 1] == '\0')
698 break;
701 if (i > 1)
702 vars_len = i + 2;
703 else
704 vars_len = 0;
707 char *bcm_nvram_vars(uint *length)
709 #ifndef BCMNVRAMR
710 /* cache may be stale if nvram is read/write */
711 if (nvram_vars) {
712 ASSERT(!bcmreclaimed);
713 bcm_nvram_refresh(nvram_vars);
715 #endif
716 if (length)
717 *length = vars_len;
718 return nvram_vars;
721 /* copy nvram vars into locally-allocated multi-string array */
722 int BCMINITFN(bcm_nvram_cache) (void *sih)
724 int ret = 0;
725 void *osh;
726 char *flash = NULL;
728 if (vars_len >= 0) {
729 #ifndef BCMNVRAMR
730 bcm_nvram_refresh(nvram_vars);
731 #endif
732 return 0;
735 osh = si_osh((si_t *) sih);
737 /* allocate memory and read in flash */
738 flash = MALLOC(osh, NVRAM_SPACE);
739 if (!flash) {
740 ret = BCME_NOMEM;
741 goto exit;
744 bcm_nvram_refresh(flash);
745 #ifdef BCMNVRAMR
746 if (vars_len > 3) {
747 /* copy into a properly-sized buffer */
748 nvram_vars = MALLOC(osh, vars_len);
749 if (!nvram_vars) {
750 ret = BCME_NOMEM;
751 } else
752 bcopy(flash, nvram_vars, vars_len);
754 MFREE(osh, flash, NVRAM_SPACE);
755 #else
756 /* cache must be full size of nvram if read/write */
757 nvram_vars = flash;
758 #endif /* BCMNVRAMR */
760 exit:
761 return ret;
763 #endif /* WLC_LOW */
765 /* iovar table lookup */
766 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
768 const bcm_iovar_t *vi;
769 const char *lookup_name;
771 /* skip any ':' delimited option prefixes */
772 lookup_name = strrchr(name, ':');
773 if (lookup_name != NULL)
774 lookup_name++;
775 else
776 lookup_name = name;
778 ASSERT(table != NULL);
780 for (vi = table; vi->name; vi++) {
781 if (!strcmp(vi->name, lookup_name))
782 return vi;
784 /* ran to end of table */
786 return NULL; /* var name not found */
789 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
791 int bcmerror = 0;
793 /* length check on io buf */
794 switch (vi->type) {
795 case IOVT_BOOL:
796 case IOVT_INT8:
797 case IOVT_INT16:
798 case IOVT_INT32:
799 case IOVT_UINT8:
800 case IOVT_UINT16:
801 case IOVT_UINT32:
802 /* all integers are int32 sized args at the ioctl interface */
803 if (len < (int)sizeof(int)) {
804 bcmerror = BCME_BUFTOOSHORT;
806 break;
808 case IOVT_BUFFER:
809 /* buffer must meet minimum length requirement */
810 if (len < vi->minlen) {
811 bcmerror = BCME_BUFTOOSHORT;
813 break;
815 case IOVT_VOID:
816 if (!set) {
817 /* Cannot return nil... */
818 bcmerror = BCME_UNSUPPORTED;
819 } else if (len) {
820 /* Set is an action w/o parameters */
821 bcmerror = BCME_BUFTOOLONG;
823 break;
825 default:
826 /* unknown type for length check in iovar info */
827 ASSERT(0);
828 bcmerror = BCME_UNSUPPORTED;
831 return bcmerror;
834 /*******************************************************************************
835 * crc8
837 * Computes a crc8 over the input data using the polynomial:
839 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
841 * The caller provides the initial value (either CRC8_INIT_VALUE
842 * or the previous returned value) to allow for processing of
843 * discontiguous blocks of data. When generating the CRC the
844 * caller is responsible for complementing the final return value
845 * and inserting it into the byte stream. When checking, a final
846 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
848 * Reference: Dallas Semiconductor Application Note 27
849 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
850 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
851 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
853 * ****************************************************************************
856 static const uint8 crc8_table[256] = {
857 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
858 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
859 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
860 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
861 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
862 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
863 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
864 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
865 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
866 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
867 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
868 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
869 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
870 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
871 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
872 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
873 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
874 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
875 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
876 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
877 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
878 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
879 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
880 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
881 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
882 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
883 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
884 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
885 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
886 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
887 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
888 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
891 #define CRC_INNER_LOOP(n, c, x) \
892 ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
894 uint8 BCMROMFN(hndcrc8) (uint8 *pdata, /* pointer to array of data to process */
895 uint nbytes, /* number of input data bytes to process */
896 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
898 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
899 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
901 while (nbytes-- > 0)
902 crc = crc8_table[(crc ^ *pdata++) & 0xff];
904 return crc;
907 /*******************************************************************************
908 * crc16
910 * Computes a crc16 over the input data using the polynomial:
912 * x^16 + x^12 +x^5 + 1
914 * The caller provides the initial value (either CRC16_INIT_VALUE
915 * or the previous returned value) to allow for processing of
916 * discontiguous blocks of data. When generating the CRC the
917 * caller is responsible for complementing the final return value
918 * and inserting it into the byte stream. When checking, a final
919 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
921 * Reference: Dallas Semiconductor Application Note 27
922 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
923 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
924 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
926 * ****************************************************************************
929 static const uint16 crc16_table[256] = {
930 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
931 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
932 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
933 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
934 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
935 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
936 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
937 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
938 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
939 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
940 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
941 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
942 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
943 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
944 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
945 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
946 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
947 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
948 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
949 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
950 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
951 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
952 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
953 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
954 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
955 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
956 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
957 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
958 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
959 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
960 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
961 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
964 uint16 BCMROMFN(hndcrc16) (uint8 *pdata, /* pointer to array of data to process */
965 uint nbytes, /* number of input data bytes to process */
966 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
968 while (nbytes-- > 0)
969 CRC_INNER_LOOP(16, crc, *pdata++);
970 return crc;
974 * Advance from the current 1-byte tag/1-byte length/variable-length value
975 * triple, to the next, returning a pointer to the next.
976 * If the current or next TLV is invalid (does not fit in given buffer length),
977 * NULL is returned.
978 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
979 * by the TLV parameter's length if it is valid.
981 bcm_tlv_t *BCMROMFN(bcm_next_tlv) (bcm_tlv_t *elt, int *buflen)
983 int len;
985 /* validate current elt */
986 if (!bcm_valid_tlv(elt, *buflen))
987 return NULL;
989 /* advance to next elt */
990 len = elt->len;
991 elt = (bcm_tlv_t *) (elt->data + len);
992 *buflen -= (2 + len);
994 /* validate next elt */
995 if (!bcm_valid_tlv(elt, *buflen))
996 return NULL;
998 return elt;
1002 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1003 * triples, returning a pointer to the substring whose first element
1004 * matches tag
1006 bcm_tlv_t *BCMROMFN(bcm_parse_tlvs) (void *buf, int buflen, uint key)
1008 bcm_tlv_t *elt;
1009 int totlen;
1011 elt = (bcm_tlv_t *) buf;
1012 totlen = buflen;
1014 /* find tagged parameter */
1015 while (totlen >= 2) {
1016 int len = elt->len;
1018 /* validate remaining totlen */
1019 if ((elt->id == key) && (totlen >= (len + 2)))
1020 return elt;
1022 elt = (bcm_tlv_t *) ((uint8 *) elt + (len + 2));
1023 totlen -= (len + 2);
1026 return NULL;
1030 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1031 * triples, returning a pointer to the substring whose first element
1032 * matches tag. Stop parsing when we see an element whose ID is greater
1033 * than the target key.
1035 bcm_tlv_t *BCMROMFN(bcm_parse_ordered_tlvs) (void *buf, int buflen, uint key)
1037 bcm_tlv_t *elt;
1038 int totlen;
1040 elt = (bcm_tlv_t *) buf;
1041 totlen = buflen;
1043 /* find tagged parameter */
1044 while (totlen >= 2) {
1045 uint id = elt->id;
1046 int len = elt->len;
1048 /* Punt if we start seeing IDs > than target key */
1049 if (id > key)
1050 return NULL;
1052 /* validate remaining totlen */
1053 if ((id == key) && (totlen >= (len + 2)))
1054 return elt;
1056 elt = (bcm_tlv_t *) ((uint8 *) elt + (len + 2));
1057 totlen -= (len + 2);
1059 return NULL;
1062 #if defined(BCMDBG)
1064 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char *buf, int len)
1066 int i;
1067 char *p = buf;
1068 char hexstr[16];
1069 int slen = 0, nlen = 0;
1070 uint32 bit;
1071 const char *name;
1073 if (len < 2 || !buf)
1074 return 0;
1076 buf[0] = '\0';
1078 for (i = 0; flags != 0; i++) {
1079 bit = bd[i].bit;
1080 name = bd[i].name;
1081 if (bit == 0 && flags != 0) {
1082 /* print any unnamed bits */
1083 snprintf(hexstr, 16, "0x%X", flags);
1084 name = hexstr;
1085 flags = 0; /* exit loop */
1086 } else if ((flags & bit) == 0)
1087 continue;
1088 flags &= ~bit;
1089 nlen = strlen(name);
1090 slen += nlen;
1091 /* count btwn flag space */
1092 if (flags != 0)
1093 slen += 1;
1094 /* need NULL char as well */
1095 if (len <= slen)
1096 break;
1097 /* copy NULL char but don't count it */
1098 strncpy(p, name, nlen + 1);
1099 p += nlen;
1100 /* copy btwn flag space and NULL char */
1101 if (flags != 0)
1102 p += snprintf(p, 2, " ");
1103 len -= slen;
1106 /* indicate the str was too short */
1107 if (flags != 0) {
1108 if (len < 2)
1109 p -= 2 - len; /* overwrite last char */
1110 p += snprintf(p, 2, ">");
1113 return (int)(p - buf);
1116 /* print bytes formatted as hex to a string. return the resulting string length */
1117 int bcm_format_hex(char *str, const void *bytes, int len)
1119 int i;
1120 char *p = str;
1121 const uint8 *src = (const uint8 *)bytes;
1123 for (i = 0; i < len; i++) {
1124 p += snprintf(p, 3, "%02X", *src);
1125 src++;
1127 return (int)(p - str);
1129 #endif /* defined(BCMDBG) */
1131 /* pretty hex print a contiguous buffer */
1132 void prhex(const char *msg, uchar *buf, uint nbytes)
1134 char line[128], *p;
1135 int len = sizeof(line);
1136 int nchar;
1137 uint i;
1139 if (msg && (msg[0] != '\0'))
1140 printf("%s:\n", msg);
1142 p = line;
1143 for (i = 0; i < nbytes; i++) {
1144 if (i % 16 == 0) {
1145 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
1146 p += nchar;
1147 len -= nchar;
1149 if (len > 0) {
1150 nchar = snprintf(p, len, "%02x ", buf[i]);
1151 p += nchar;
1152 len -= nchar;
1155 if (i % 16 == 15) {
1156 printf("%s\n", line); /* flush line */
1157 p = line;
1158 len = sizeof(line);
1162 /* flush last partial line */
1163 if (p != line)
1164 printf("%s\n", line);
1167 static const char *crypto_algo_names[] = {
1168 "NONE",
1169 "WEP1",
1170 "TKIP",
1171 "WEP128",
1172 "AES_CCM",
1173 "NALG" "UNDEF",
1174 "UNDEF",
1175 "UNDEF",
1176 "UNDEF"
1179 const char *bcm_crypto_algo_name(uint algo)
1181 return (algo <
1182 ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
1185 #ifdef BCMDBG
1186 void deadbeef(void *p, uint len)
1188 static uint8 meat[] = { 0xde, 0xad, 0xbe, 0xef };
1190 while (len-- > 0) {
1191 *(uint8 *) p = meat[((uintptr) p) & 3];
1192 p = (uint8 *) p + 1;
1195 #endif /* BCMDBG */
1197 char *bcm_chipname(uint chipid, char *buf, uint len)
1199 const char *fmt;
1201 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
1202 snprintf(buf, len, fmt, chipid);
1203 return buf;
1206 /* Produce a human-readable string for boardrev */
1207 char *bcm_brev_str(uint32 brev, char *buf)
1209 if (brev < 0x100)
1210 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1211 else
1212 snprintf(buf, 8, "%c%03x",
1213 ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
1215 return buf;
1218 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1220 /* dump large strings to console */
1221 void printbig(char *buf)
1223 uint len, max_len;
1224 char c;
1226 len = strlen(buf);
1228 max_len = BUFSIZE_TODUMP_ATONCE;
1230 while (len > max_len) {
1231 c = buf[max_len];
1232 buf[max_len] = '\0';
1233 printf("%s", buf);
1234 buf[max_len] = c;
1236 buf += max_len;
1237 len -= max_len;
1239 /* print the remaining string */
1240 printf("%s\n", buf);
1241 return;
1244 /* routine to dump fields in a fileddesc structure */
1245 uint
1246 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1,
1247 struct fielddesc *fielddesc_array, char *buf, uint32 bufsize)
1249 uint filled_len;
1250 int len;
1251 struct fielddesc *cur_ptr;
1253 filled_len = 0;
1254 cur_ptr = fielddesc_array;
1256 while (bufsize > 1) {
1257 if (cur_ptr->nameandfmt == NULL)
1258 break;
1259 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
1260 read_rtn(arg0, arg1, cur_ptr->offset));
1261 /* check for snprintf overflow or error */
1262 if (len < 0 || (uint32) len >= bufsize)
1263 len = bufsize - 1;
1264 buf += len;
1265 bufsize -= len;
1266 filled_len += len;
1267 cur_ptr++;
1269 return filled_len;
1272 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1274 uint len;
1276 len = strlen(name) + 1;
1278 if ((len + datalen) > buflen)
1279 return 0;
1281 strncpy(buf, name, buflen);
1283 /* append data onto the end of the name string */
1284 memcpy(&buf[len], data, datalen);
1285 len += datalen;
1287 return len;
1290 /* Quarter dBm units to mW
1291 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1292 * Table is offset so the last entry is largest mW value that fits in
1293 * a uint16.
1296 #define QDBM_OFFSET 153 /* Offset for first entry */
1297 #define QDBM_TABLE_LEN 40 /* Table size */
1299 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1300 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1302 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1304 /* Largest mW value that will round down to the last table entry,
1305 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1306 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1308 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1310 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1311 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1312 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1313 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1314 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1315 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1316 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1319 uint16 BCMROMFN(bcm_qdbm_to_mw) (uint8 qdbm)
1321 uint factor = 1;
1322 int idx = qdbm - QDBM_OFFSET;
1324 if (idx >= QDBM_TABLE_LEN) {
1325 /* clamp to max uint16 mW value */
1326 return 0xFFFF;
1329 /* scale the qdBm index up to the range of the table 0-40
1330 * where an offset of 40 qdBm equals a factor of 10 mW.
1332 while (idx < 0) {
1333 idx += 40;
1334 factor *= 10;
1337 /* return the mW value scaled down to the correct factor of 10,
1338 * adding in factor/2 to get proper rounding.
1340 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
1343 uint8 BCMROMFN(bcm_mw_to_qdbm) (uint16 mw)
1345 uint8 qdbm;
1346 int offset;
1347 uint mw_uint = mw;
1348 uint boundary;
1350 /* handle boundary case */
1351 if (mw_uint <= 1)
1352 return 0;
1354 offset = QDBM_OFFSET;
1356 /* move mw into the range of the table */
1357 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1358 mw_uint *= 10;
1359 offset -= 40;
1362 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
1363 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
1364 nqdBm_to_mW_map[qdbm]) / 2;
1365 if (mw_uint < boundary)
1366 break;
1369 qdbm += (uint8) offset;
1371 return qdbm;
1374 uint BCMROMFN(bcm_bitcount) (uint8 *bitmap, uint length)
1376 uint bitcount = 0, i;
1377 uint8 tmp;
1378 for (i = 0; i < length; i++) {
1379 tmp = bitmap[i];
1380 while (tmp) {
1381 bitcount++;
1382 tmp &= (tmp - 1);
1385 return bitcount;
1388 /* Initialization of bcmstrbuf structure */
1389 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1391 b->origsize = b->size = size;
1392 b->origbuf = b->buf = buf;
1395 /* Buffer sprintf wrapper to guard against buffer overflow */
1396 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1398 va_list ap;
1399 int r;
1401 va_start(ap, fmt);
1402 r = vsnprintf(b->buf, b->size, fmt, ap);
1404 /* Non Ansi C99 compliant returns -1,
1405 * Ansi compliant return r >= b->size,
1406 * bcmstdlib returns 0, handle all
1408 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1409 b->size = 0;
1410 } else {
1411 b->size -= r;
1412 b->buf += r;
1415 va_end(ap);
1417 return r;
1420 void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
1422 int i;
1424 for (i = 0; i < num_bytes; i++) {
1425 num[i] += amount;
1426 if (num[i] >= amount)
1427 break;
1428 amount = 1;
1432 int bcm_cmp_bytes(uchar *arg1, uchar *arg2, uint8 nbytes)
1434 int i;
1436 for (i = nbytes - 1; i >= 0; i--) {
1437 if (arg1[i] != arg2[i])
1438 return arg1[i] - arg2[i];
1440 return 0;
1443 void bcm_print_bytes(char *name, const uchar *data, int len)
1445 int i;
1446 int per_line = 0;
1448 printf("%s: %d\n", name ? name : "", len);
1449 for (i = 0; i < len; i++) {
1450 printf("%02x ", *data++);
1451 per_line++;
1452 if (per_line == 16) {
1453 per_line = 0;
1454 printf("\n");
1457 printf("\n");
1460 #if defined(BCMDBG)
1461 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
1462 int bcm_format_ssid(char *buf, const uchar ssid[], uint ssid_len)
1464 uint i, c;
1465 char *p = buf;
1466 char *endp = buf + SSID_FMT_BUF_LEN;
1468 if (ssid_len > DOT11_MAX_SSID_LEN)
1469 ssid_len = DOT11_MAX_SSID_LEN;
1471 for (i = 0; i < ssid_len; i++) {
1472 c = (uint) ssid[i];
1473 if (c == '\\') {
1474 *p++ = '\\';
1475 *p++ = '\\';
1476 } else if (isprint((uchar) c)) {
1477 *p++ = (char)c;
1478 } else {
1479 p += snprintf(p, (endp - p), "\\x%02X", c);
1482 *p = '\0';
1483 ASSERT(p < endp);
1485 return (int)(p - buf);
1487 #endif /* defined(BCMDBG) */