Staging: brcm80211: s/ulong/unsigned long/
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / brcm80211 / brcmfmac / bcmutils.c
blob73eb086862236b42ade3530aa62e6ea06927e83f
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 <bcmutils.h>
21 #ifdef BCMDRIVER
22 #include <osl.h>
23 #include <siutils.h>
24 #else
25 #include <stdio.h>
26 #include <string.h>
27 /* This case for external supplicant use */
28 #if defined(BCMEXTSUP)
29 #include <bcm_osl.h>
30 #endif
32 #endif /* BCMDRIVER */
33 #include <bcmendian.h>
34 #include <bcmdevs.h>
35 #include <bcmnvram.h>
36 #include <proto/ethernet.h>
37 #include <proto/vlan.h>
38 #include <proto/bcmip.h>
39 #include <proto/802.1d.h>
40 #include <proto/802.11.h>
42 #ifdef BCMDRIVER
44 /* copy a pkt buffer chain into a buffer */
45 uint pktcopy(osl_t *osh, void *p, uint offset, int len, unsigned char * buf)
47 uint n, ret = 0;
49 if (len < 0)
50 len = 4096; /* "infinite" */
52 /* skip 'offset' bytes */
53 for (; p && offset; p = PKTNEXT(p)) {
54 if (offset < (uint) PKTLEN(p))
55 break;
56 offset -= PKTLEN(p);
59 if (!p)
60 return 0;
62 /* copy the data */
63 for (; p && len; p = PKTNEXT(p)) {
64 n = MIN((uint) PKTLEN(p) - offset, (uint) len);
65 bcopy(PKTDATA(p) + offset, buf, n);
66 buf += n;
67 len -= n;
68 ret += n;
69 offset = 0;
72 return ret;
75 /* copy a buffer into a pkt buffer chain */
76 uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, unsigned char *buf)
78 uint n, ret = 0;
80 /* skip 'offset' bytes */
81 for (; p && offset; p = PKTNEXT(p)) {
82 if (offset < (uint) PKTLEN(p))
83 break;
84 offset -= PKTLEN(p);
87 if (!p)
88 return 0;
90 /* copy the data */
91 for (; p && len; p = PKTNEXT(p)) {
92 n = MIN((uint) PKTLEN(p) - offset, (uint) len);
93 bcopy(buf, PKTDATA(p) + offset, n);
94 buf += n;
95 len -= n;
96 ret += n;
97 offset = 0;
100 return ret;
103 /* return total length of buffer chain */
104 uint pkttotlen(osl_t *osh, void *p)
106 uint total;
108 total = 0;
109 for (; p; p = PKTNEXT(p))
110 total += PKTLEN(p);
111 return total;
114 /* return the last buffer of chained pkt */
115 void *pktlast(osl_t *osh, void *p)
117 for (; PKTNEXT(p); p = PKTNEXT(p))
120 return p;
123 /* count segments of a chained packet */
124 uint pktsegcnt(osl_t *osh, void *p)
126 uint cnt;
128 for (cnt = 0; p; p = PKTNEXT(p))
129 cnt++;
131 return cnt;
135 * osl multiple-precedence packet queue
136 * hi_prec is always >= the number of the highest non-empty precedence
138 void *pktq_penq(struct pktq *pq, int prec, void *p)
140 struct pktq_prec *q;
142 ASSERT(prec >= 0 && prec < pq->num_prec);
143 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
145 ASSERT(!pktq_full(pq));
146 ASSERT(!pktq_pfull(pq, prec));
148 q = &pq->q[prec];
150 if (q->head)
151 PKTSETLINK(q->tail, p);
152 else
153 q->head = p;
155 q->tail = p;
156 q->len++;
158 pq->len++;
160 if (pq->hi_prec < prec)
161 pq->hi_prec = (u8) prec;
163 return p;
166 void *pktq_penq_head(struct pktq *pq, int prec, void *p)
168 struct pktq_prec *q;
170 ASSERT(prec >= 0 && prec < pq->num_prec);
171 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
173 ASSERT(!pktq_full(pq));
174 ASSERT(!pktq_pfull(pq, prec));
176 q = &pq->q[prec];
178 if (q->head == NULL)
179 q->tail = p;
181 PKTSETLINK(p, q->head);
182 q->head = p;
183 q->len++;
185 pq->len++;
187 if (pq->hi_prec < prec)
188 pq->hi_prec = (u8) prec;
190 return p;
193 void *pktq_pdeq(struct pktq *pq, int prec)
195 struct pktq_prec *q;
196 void *p;
198 ASSERT(prec >= 0 && prec < pq->num_prec);
200 q = &pq->q[prec];
202 p = q->head;
203 if (p == NULL)
204 return NULL;
206 q->head = PKTLINK(p);
207 if (q->head == NULL)
208 q->tail = NULL;
210 q->len--;
212 pq->len--;
214 PKTSETLINK(p, NULL);
216 return p;
219 void *pktq_pdeq_tail(struct pktq *pq, int prec)
221 struct pktq_prec *q;
222 void *p, *prev;
224 ASSERT(prec >= 0 && prec < pq->num_prec);
226 q = &pq->q[prec];
228 p = q->head;
229 if (p == NULL)
230 return NULL;
232 for (prev = NULL; p != q->tail; p = PKTLINK(p))
233 prev = p;
235 if (prev)
236 PKTSETLINK(prev, NULL);
237 else
238 q->head = NULL;
240 q->tail = prev;
241 q->len--;
243 pq->len--;
245 return p;
248 void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
250 struct pktq_prec *q;
251 void *p;
253 q = &pq->q[prec];
254 p = q->head;
255 while (p) {
256 q->head = PKTLINK(p);
257 PKTSETLINK(p, NULL);
258 PKTFREE(osh, p, dir);
259 q->len--;
260 pq->len--;
261 p = q->head;
263 ASSERT(q->len == 0);
264 q->tail = NULL;
267 bool pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
269 struct pktq_prec *q;
270 void *p;
272 ASSERT(prec >= 0 && prec < pq->num_prec);
274 if (!pktbuf)
275 return FALSE;
277 q = &pq->q[prec];
279 if (q->head == pktbuf) {
280 q->head = PKTLINK(pktbuf);
281 if (q->head == NULL)
282 q->tail = NULL;
283 } else {
284 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
286 if (p == NULL)
287 return FALSE;
289 PKTSETLINK(p, PKTLINK(pktbuf));
290 if (q->tail == pktbuf)
291 q->tail = p;
294 q->len--;
295 pq->len--;
296 PKTSETLINK(pktbuf, NULL);
297 return TRUE;
300 void pktq_init(struct pktq *pq, int num_prec, int max_len)
302 int prec;
304 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
306 /* pq is variable size; only zero out what's requested */
307 bzero(pq,
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 *pktq_deq(struct pktq *pq, int *prec_out)
320 struct pktq_prec *q;
321 void *p;
322 int prec;
324 if (pq->len == 0)
325 return NULL;
327 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
328 pq->hi_prec--;
330 q = &pq->q[prec];
332 p = q->head;
333 if (p == NULL)
334 return NULL;
336 q->head = PKTLINK(p);
337 if (q->head == NULL)
338 q->tail = NULL;
340 q->len--;
342 pq->len--;
344 if (prec_out)
345 *prec_out = prec;
347 PKTSETLINK(p, NULL);
349 return p;
352 void *pktq_deq_tail(struct pktq *pq, int *prec_out)
354 struct pktq_prec *q;
355 void *p, *prev;
356 int prec;
358 if (pq->len == 0)
359 return NULL;
361 for (prec = 0; prec < pq->hi_prec; prec++)
362 if (pq->q[prec].head)
363 break;
365 q = &pq->q[prec];
367 p = q->head;
368 if (p == NULL)
369 return NULL;
371 for (prev = NULL; p != q->tail; p = PKTLINK(p))
372 prev = p;
374 if (prev)
375 PKTSETLINK(prev, NULL);
376 else
377 q->head = NULL;
379 q->tail = prev;
380 q->len--;
382 pq->len--;
384 if (prec_out)
385 *prec_out = prec;
387 PKTSETLINK(p, NULL);
389 return p;
392 void *pktq_peek(struct pktq *pq, int *prec_out)
394 int prec;
396 if (pq->len == 0)
397 return NULL;
399 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
400 pq->hi_prec--;
402 if (prec_out)
403 *prec_out = prec;
405 return pq->q[prec].head;
408 void *pktq_peek_tail(struct pktq *pq, int *prec_out)
410 int prec;
412 if (pq->len == 0)
413 return NULL;
415 for (prec = 0; prec < pq->hi_prec; prec++)
416 if (pq->q[prec].head)
417 break;
419 if (prec_out)
420 *prec_out = prec;
422 return pq->q[prec].tail;
425 void pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
427 int prec;
428 for (prec = 0; prec < pq->num_prec; prec++)
429 pktq_pflush(osh, pq, prec, dir);
430 ASSERT(pq->len == 0);
433 /* Return sum of lengths of a specific set of precedences */
434 int pktq_mlen(struct pktq *pq, uint prec_bmp)
436 int prec, len;
438 len = 0;
440 for (prec = 0; prec <= pq->hi_prec; prec++)
441 if (prec_bmp & (1 << prec))
442 len += pq->q[prec].len;
444 return len;
447 /* Priority dequeue from a specific set of precedences */
448 void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
450 struct pktq_prec *q;
451 void *p;
452 int prec;
454 if (pq->len == 0)
455 return NULL;
457 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
458 pq->hi_prec--;
460 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
461 if (prec-- == 0)
462 return NULL;
464 q = &pq->q[prec];
466 p = q->head;
467 if (p == NULL)
468 return NULL;
470 q->head = PKTLINK(p);
471 if (q->head == NULL)
472 q->tail = NULL;
474 q->len--;
476 if (prec_out)
477 *prec_out = prec;
479 pq->len--;
481 PKTSETLINK(p, NULL);
483 return p;
485 #endif /* BCMDRIVER */
487 const unsigned char bcm_ctype[] = {
488 _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C,
489 _BCM_C, _BCM_C | _BCM_S, _BCM_C | _BCM_S, _BCM_C | _BCM_S,
490 _BCM_C | _BCM_S, _BCM_C | _BCM_S, _BCM_C,
491 _BCM_C, /* 8-15 */
492 _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C,
493 _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C,
494 _BCM_S | _BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
495 _BCM_P,
496 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
497 _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D,
498 _BCM_D, _BCM_D, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
499 _BCM_P, _BCM_U | _BCM_X, _BCM_U | _BCM_X, _BCM_U | _BCM_X,
500 _BCM_U | _BCM_X, _BCM_U | _BCM_X,
501 _BCM_U | _BCM_X, _BCM_U,
502 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
503 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
504 _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
505 _BCM_P, _BCM_L | _BCM_X, _BCM_L | _BCM_X, _BCM_L | _BCM_X,
506 _BCM_L | _BCM_X, _BCM_L | _BCM_X,
507 _BCM_L | _BCM_X, _BCM_L,
508 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
509 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
510 _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_C,
511 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
512 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
513 _BCM_S | _BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
514 _BCM_P, _BCM_P, _BCM_P,
515 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
516 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
517 _BCM_P, _BCM_P,
518 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
519 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
520 _BCM_U, _BCM_U,
521 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
522 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U,
523 _BCM_U, _BCM_U,
524 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
525 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
526 _BCM_L, _BCM_L,
527 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
528 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L,
529 _BCM_L, _BCM_L,
530 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
533 unsigned long bcm_strtoul(char *cp, char **endp, uint base)
535 unsigned long result, last_result = 0, value;
536 bool minus;
538 minus = FALSE;
540 while (bcm_isspace(*cp))
541 cp++;
543 if (cp[0] == '+')
544 cp++;
545 else if (cp[0] == '-') {
546 minus = TRUE;
547 cp++;
550 if (base == 0) {
551 if (cp[0] == '0') {
552 if ((cp[1] == 'x') || (cp[1] == 'X')) {
553 base = 16;
554 cp = &cp[2];
555 } else {
556 base = 8;
557 cp = &cp[1];
559 } else
560 base = 10;
561 } else if (base == 16 && (cp[0] == '0')
562 && ((cp[1] == 'x') || (cp[1] == 'X'))) {
563 cp = &cp[2];
566 result = 0;
568 while (bcm_isxdigit(*cp) &&
569 (value =
570 bcm_isdigit(*cp) ? *cp - '0' : bcm_toupper(*cp) - 'A' + 10) <
571 base) {
572 result = result * base + value;
573 /* Detected overflow */
574 if (result < last_result && !minus)
575 return (unsigned long)-1;
576 last_result = result;
577 cp++;
580 if (minus)
581 result = (unsigned long) (-(long)result);
583 if (endp)
584 *endp = (char *)cp;
586 return result;
589 int bcm_atoi(char *s)
591 return (int)bcm_strtoul(s, NULL, 10);
594 /* return pointer to location of substring 'needle' in 'haystack' */
595 char *bcmstrstr(char *haystack, char *needle)
597 int len, nlen;
598 int i;
600 if ((haystack == NULL) || (needle == NULL))
601 return haystack;
603 nlen = strlen(needle);
604 len = strlen(haystack) - nlen + 1;
606 for (i = 0; i < len; i++)
607 if (memcmp(needle, &haystack[i], nlen) == 0)
608 return &haystack[i];
609 return NULL;
612 char *bcmstrcat(char *dest, const char *src)
614 char *p;
616 p = dest + strlen(dest);
618 while ((*p++ = *src++) != '\0')
621 return dest;
624 char *bcmstrncat(char *dest, const char *src, uint size)
626 char *endp;
627 char *p;
629 p = dest + strlen(dest);
630 endp = p + size;
632 while (p != endp && (*p++ = *src++) != '\0')
635 return dest;
638 /****************************************************************************
639 * Function: bcmstrtok
641 * Purpose:
642 * Tokenizes a string. This function is conceptually similiar
643 * to ANSI C strtok(),
644 * but allows strToken() to be used by different strings or callers at the same
645 * time. Each call modifies '*string' by substituting a NULL character for the
646 * first delimiter that is encountered, and updates 'string' to point to
647 * the char
648 * after the delimiter. Leading delimiters are skipped.
650 * Parameters:
651 * string (mod) Ptr to string ptr, updated by token.
652 * delimiters (in) Set of delimiter characters.
653 * tokdelim (out) Character that delimits the returned token. (May
654 * be set to NULL if token delimiter is not required).
656 * Returns: Pointer to the next token found. NULL when no more tokens are found.
657 *****************************************************************************
659 char *bcmstrtok(char **string, const char *delimiters, char *tokdelim)
661 unsigned char *str;
662 unsigned long map[8];
663 int count;
664 char *nextoken;
666 if (tokdelim != NULL) {
667 /* Prime the token delimiter */
668 *tokdelim = '\0';
671 /* Clear control map */
672 for (count = 0; count < 8; count++)
673 map[count] = 0;
675 /* Set bits in delimiter table */
676 do {
677 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
679 while (*delimiters++)
682 str = (unsigned char *)*string;
684 /* Find beginning of token (skip over leading delimiters). Note that
685 * there is no token iff this loop sets str to point to the terminal
686 * null (*str == '\0')
688 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' '))
689 str++;
691 nextoken = (char *)str;
693 /* Find the end of the token. If it is not the end of the string,
694 * put a null there.
696 for (; *str; str++) {
697 if (map[*str >> 5] & (1 << (*str & 31))) {
698 if (tokdelim != NULL)
699 *tokdelim = *str;
701 *str++ = '\0';
702 break;
706 *string = (char *)str;
708 /* Determine if a token has been found. */
709 if (nextoken == (char *)str)
710 return NULL;
711 else
712 return nextoken;
715 #define xToLower(C) \
716 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
718 /****************************************************************************
719 * Function: bcmstricmp
721 * Purpose: Compare to strings case insensitively.
723 * Parameters: s1 (in) First string to compare.
724 * s2 (in) Second string to compare.
726 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
727 * t1 > t2, when ignoring case sensitivity.
728 *****************************************************************************
730 int bcmstricmp(const char *s1, const char *s2)
732 char dc, sc;
734 while (*s2 && *s1) {
735 dc = xToLower(*s1);
736 sc = xToLower(*s2);
737 if (dc < sc)
738 return -1;
739 if (dc > sc)
740 return 1;
741 s1++;
742 s2++;
745 if (*s1 && !*s2)
746 return 1;
747 if (!*s1 && *s2)
748 return -1;
749 return 0;
752 /****************************************************************************
753 * Function: bcmstrnicmp
755 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
756 * characters.
758 * Parameters: s1 (in) First string to compare.
759 * s2 (in) Second string to compare.
760 * cnt (in) Max characters to compare.
762 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
763 * t1 > t2, when ignoring case sensitivity.
764 *****************************************************************************
766 int bcmstrnicmp(const char *s1, const char *s2, int cnt)
768 char dc, sc;
770 while (*s2 && *s1 && cnt) {
771 dc = xToLower(*s1);
772 sc = xToLower(*s2);
773 if (dc < sc)
774 return -1;
775 if (dc > sc)
776 return 1;
777 s1++;
778 s2++;
779 cnt--;
782 if (!cnt)
783 return 0;
784 if (*s1 && !*s2)
785 return 1;
786 if (!*s1 && *s2)
787 return -1;
788 return 0;
791 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
792 int bcm_ether_atoe(char *p, struct ether_addr *ea)
794 int i = 0;
796 for (;;) {
797 ea->octet[i++] = (char)bcm_strtoul(p, &p, 16);
798 if (!*p++ || i == 6)
799 break;
802 return i == 6;
805 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
806 /* registry routine buffer preparation utility functions:
807 * parameter order is like strncpy, but returns count
808 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
810 unsigned long wchar2ascii(char *abuf, unsigned short * wbuf, unsigned short wbuflen, unsigned long abuflen)
812 unsigned long copyct = 1;
813 unsigned short i;
815 if (abuflen == 0)
816 return 0;
818 /* wbuflen is in bytes */
819 wbuflen /= sizeof(unsigned short);
821 for (i = 0; i < wbuflen; ++i) {
822 if (--abuflen == 0)
823 break;
824 *abuf++ = (char)*wbuf++;
825 ++copyct;
827 *abuf = '\0';
829 return copyct;
831 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
833 char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
835 static const char template[] = "%02x:%02x:%02x:%02x:%02x:%02x";
836 snprintf(buf, 18, template,
837 ea->octet[0] & 0xff, ea->octet[1] & 0xff, ea->octet[2] & 0xff,
838 ea->octet[3] & 0xff, ea->octet[4] & 0xff, ea->octet[5] & 0xff);
839 return buf;
842 char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
844 snprintf(buf, 16, "%d.%d.%d.%d",
845 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
846 return buf;
849 #ifdef BCMDRIVER
851 void bcm_mdelay(uint ms)
853 uint i;
855 for (i = 0; i < ms; i++)
856 OSL_DELAY(1000);
859 #if defined(DHD_DEBUG)
860 /* pretty hex print a pkt buffer chain */
861 void prpkt(const char *msg, osl_t *osh, void *p0)
863 void *p;
865 if (msg && (msg[0] != '\0'))
866 printf("%s:\n", msg);
868 for (p = p0; p; p = PKTNEXT(p))
869 prhex(NULL, PKTDATA(p), PKTLEN(p));
871 #endif
873 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
874 * Also updates the inplace vlan tag if requested.
875 * For debugging, it returns an indication of what it did.
877 uint pktsetprio(void *pkt, bool update_vtag)
879 struct ether_header *eh;
880 struct ethervlan_header *evh;
881 u8 *pktdata;
882 int priority = 0;
883 int rc = 0;
885 pktdata = (u8 *) PKTDATA(pkt);
886 ASSERT(ISALIGNED((uintptr) pktdata, sizeof(uint16)));
888 eh = (struct ether_header *)pktdata;
890 if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
891 uint16 vlan_tag;
892 int vlan_prio, dscp_prio = 0;
894 evh = (struct ethervlan_header *)eh;
896 vlan_tag = ntoh16(evh->vlan_tag);
897 vlan_prio = (int)(vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
899 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
900 u8 *ip_body =
901 pktdata + sizeof(struct ethervlan_header);
902 u8 tos_tc = IP_TOS(ip_body);
903 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
906 /* DSCP priority gets precedence over 802.1P (vlan tag) */
907 if (dscp_prio != 0) {
908 priority = dscp_prio;
909 rc |= PKTPRIO_VDSCP;
910 } else {
911 priority = vlan_prio;
912 rc |= PKTPRIO_VLAN;
915 * If the DSCP priority is not the same as the VLAN priority,
916 * then overwrite the priority field in the vlan tag, with the
917 * DSCP priority value. This is required for Linux APs because
918 * the VLAN driver on Linux, overwrites the skb->priority field
919 * with the priority value in the vlan tag
921 if (update_vtag && (priority != vlan_prio)) {
922 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
923 vlan_tag |= (uint16) priority << VLAN_PRI_SHIFT;
924 evh->vlan_tag = hton16(vlan_tag);
925 rc |= PKTPRIO_UPD;
927 } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
928 u8 *ip_body = pktdata + sizeof(struct ether_header);
929 u8 tos_tc = IP_TOS(ip_body);
930 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
931 rc |= PKTPRIO_DSCP;
934 ASSERT(priority >= 0 && priority <= MAXPRIO);
935 PKTSETPRIO(pkt, priority);
936 return rc | priority;
939 static char bcm_undeferrstr[BCME_STRLEN];
941 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
943 /* Convert the error codes into related error strings */
944 const char *bcmerrorstr(int bcmerror)
946 /* check if someone added a bcmerror code but
947 forgot to add errorstring */
948 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
950 if (bcmerror > 0 || bcmerror < BCME_LAST) {
951 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d",
952 bcmerror);
953 return bcm_undeferrstr;
956 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
958 return bcmerrorstrtable[-bcmerror];
961 /* iovar table lookup */
962 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
964 const bcm_iovar_t *vi;
965 const char *lookup_name;
967 /* skip any ':' delimited option prefixes */
968 lookup_name = strrchr(name, ':');
969 if (lookup_name != NULL)
970 lookup_name++;
971 else
972 lookup_name = name;
974 ASSERT(table != NULL);
976 for (vi = table; vi->name; vi++) {
977 if (!strcmp(vi->name, lookup_name))
978 return vi;
980 /* ran to end of table */
982 return NULL; /* var name not found */
985 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
987 int bcmerror = 0;
989 /* length check on io buf */
990 switch (vi->type) {
991 case IOVT_BOOL:
992 case IOVT_INT8:
993 case IOVT_INT16:
994 case IOVT_INT32:
995 case IOVT_UINT8:
996 case IOVT_UINT16:
997 case IOVT_UINT32:
998 /* all integers are int32 sized args at the ioctl interface */
999 if (len < (int)sizeof(int))
1000 bcmerror = BCME_BUFTOOSHORT;
1001 break;
1003 case IOVT_BUFFER:
1004 /* buffer must meet minimum length requirement */
1005 if (len < vi->minlen)
1006 bcmerror = BCME_BUFTOOSHORT;
1007 break;
1009 case IOVT_VOID:
1010 if (!set) {
1011 /* Cannot return nil... */
1012 bcmerror = BCME_UNSUPPORTED;
1013 } else if (len) {
1014 /* Set is an action w/o parameters */
1015 bcmerror = BCME_BUFTOOLONG;
1017 break;
1019 default:
1020 /* unknown type for length check in iovar info */
1021 ASSERT(0);
1022 bcmerror = BCME_UNSUPPORTED;
1025 return bcmerror;
1028 #endif /* BCMDRIVER */
1030 /****************************************************************************
1031 * crc8
1033 * Computes a crc8 over the input data using the polynomial:
1035 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1037 * The caller provides the initial value (either CRC8_INIT_VALUE
1038 * or the previous returned value) to allow for processing of
1039 * discontiguous blocks of data. When generating the CRC the
1040 * caller is responsible for complementing the final return value
1041 * and inserting it into the byte stream. When checking, a final
1042 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1044 * Reference: Dallas Semiconductor Application Note 27
1045 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1046 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1047 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1049 * ****************************************************************************
1052 STATIC const u8 crc8_table[256] = {
1053 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1054 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1055 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1056 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1057 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1058 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1059 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1060 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1061 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1062 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1063 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1064 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1065 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1066 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1067 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1068 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1069 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1070 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1071 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1072 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1073 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1074 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1075 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1076 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1077 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1078 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1079 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1080 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1081 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1082 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1083 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1084 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1087 #define CRC_INNER_LOOP(n, c, x) \
1088 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1090 u8 hndcrc8(u8 *pdata, /* pointer to array of data to process */
1091 uint nbytes, /* number of input data bytes to process */
1092 u8 crc /* either CRC8_INIT_VALUE or previous
1093 return value */
1096 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1097 * to avoid the undefined and unnecessary (u8 >> 8) operation.
1099 while (nbytes-- > 0)
1100 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1102 return crc;
1105 /*****************************************************************************
1106 * crc16
1108 * Computes a crc16 over the input data using the polynomial:
1110 * x^16 + x^12 +x^5 + 1
1112 * The caller provides the initial value (either CRC16_INIT_VALUE
1113 * or the previous returned value) to allow for processing of
1114 * discontiguous blocks of data. When generating the CRC the
1115 * caller is responsible for complementing the final return value
1116 * and inserting it into the byte stream. When checking, a final
1117 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1119 * Reference: Dallas Semiconductor Application Note 27
1120 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1121 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1122 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1124 * ****************************************************************************
1127 static const uint16 crc16_table[256] = {
1128 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1129 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1130 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1131 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1132 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1133 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1134 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1135 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1136 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1137 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1138 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1139 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1140 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1141 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1142 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1143 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1144 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1145 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1146 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1147 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1148 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1149 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1150 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1151 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1152 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1153 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1154 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1155 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1156 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1157 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1158 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1159 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1162 uint16 hndcrc16(u8 *pdata, /* pointer to array of data to process */
1163 uint nbytes, /* number of input data bytes to process */
1164 uint16 crc /* either CRC16_INIT_VALUE or previous
1165 return value */
1168 while (nbytes-- > 0)
1169 CRC_INNER_LOOP(16, crc, *pdata++);
1170 return crc;
1173 STATIC const uint32 crc32_table[256] = {
1174 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1175 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1176 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1177 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1178 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1179 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1180 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1181 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1182 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1183 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1184 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1185 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1186 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1187 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1188 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1189 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1190 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1191 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1192 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1193 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1194 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1195 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1196 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1197 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1198 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1199 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1200 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1201 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1202 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1203 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1204 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1205 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1206 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1207 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1208 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1209 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1210 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1211 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1212 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1213 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1214 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1215 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1216 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1217 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1218 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1219 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1220 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1221 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1222 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1223 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1224 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1225 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1226 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1227 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1228 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1229 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1230 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1231 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1232 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1233 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1234 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1235 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1236 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1237 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1240 uint32 hndcrc32(u8 *pdata, /* pointer to array of data to process */
1241 uint nbytes, /* number of input data bytes to process */
1242 uint32 crc /* either CRC32_INIT_VALUE or previous
1243 return value */
1246 u8 *pend;
1247 #ifdef __mips__
1248 u8 tmp[4];
1249 unsigned long *tptr = (unsigned long *) tmp;
1251 /* in case the beginning of the buffer isn't aligned */
1252 pend = (u8 *) ((uint) (pdata + 3) & 0xfffffffc);
1253 nbytes -= (pend - pdata);
1254 while (pdata < pend)
1255 CRC_INNER_LOOP(32, crc, *pdata++);
1257 /* handle bulk of data as 32-bit words */
1258 pend = pdata + (nbytes & 0xfffffffc);
1259 while (pdata < pend) {
1260 *tptr = *(unsigned long *) pdata;
1261 pdata += sizeof(unsigned long *);
1262 CRC_INNER_LOOP(32, crc, tmp[0]);
1263 CRC_INNER_LOOP(32, crc, tmp[1]);
1264 CRC_INNER_LOOP(32, crc, tmp[2]);
1265 CRC_INNER_LOOP(32, crc, tmp[3]);
1268 /* 1-3 bytes at end of buffer */
1269 pend = pdata + (nbytes & 0x03);
1270 while (pdata < pend)
1271 CRC_INNER_LOOP(32, crc, *pdata++);
1272 #else
1273 pend = pdata + nbytes;
1274 while (pdata < pend)
1275 CRC_INNER_LOOP(32, crc, *pdata++);
1276 #endif /* __mips__ */
1278 return crc;
1281 #ifdef notdef
1282 #define CLEN 1499 /* CRC Length */
1283 #define CBUFSIZ (CLEN+4)
1284 #define CNBUFS 5 /* # of bufs */
1286 void testcrc32(void)
1288 uint j, k, l;
1289 u8 *buf;
1290 uint len[CNBUFS];
1291 uint32 crcr;
1292 uint32 crc32tv[CNBUFS] = {
1293 0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1295 ASSERT((buf = MALLOC(CBUFSIZ * CNBUFS)) != NULL);
1297 /* step through all possible alignments */
1298 for (l = 0; l <= 4; l++) {
1299 for (j = 0; j < CNBUFS; j++) {
1300 len[j] = CLEN;
1301 for (k = 0; k < len[j]; k++)
1302 *(buf + j * CBUFSIZ + (k + l)) = (j + k) & 0xff;
1305 for (j = 0; j < CNBUFS; j++) {
1306 crcr =
1307 crc32(buf + j * CBUFSIZ + l, len[j],
1308 CRC32_INIT_VALUE);
1309 ASSERT(crcr == crc32tv[j]);
1313 MFREE(buf, CBUFSIZ * CNBUFS);
1314 return;
1316 #endif /* notdef */
1319 * Advance from the current 1-byte tag/1-byte length/variable-length value
1320 * triple, to the next, returning a pointer to the next.
1321 * If the current or next TLV is invalid (does not fit in given buffer length),
1322 * NULL is returned.
1323 * *buflen is not modified if the TLV elt parameter is invalid,
1324 * or is decremented
1325 * by the TLV parameter's length if it is valid.
1327 bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
1329 int len;
1331 /* validate current elt */
1332 if (!bcm_valid_tlv(elt, *buflen))
1333 return NULL;
1335 /* advance to next elt */
1336 len = elt->len;
1337 elt = (bcm_tlv_t *) (elt->data + len);
1338 *buflen -= (2 + len);
1340 /* validate next elt */
1341 if (!bcm_valid_tlv(elt, *buflen))
1342 return NULL;
1344 return elt;
1348 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1349 * triples, returning a pointer to the substring whose first element
1350 * matches tag
1352 bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key)
1354 bcm_tlv_t *elt;
1355 int totlen;
1357 elt = (bcm_tlv_t *) buf;
1358 totlen = buflen;
1360 /* find tagged parameter */
1361 while (totlen >= 2) {
1362 int len = elt->len;
1364 /* validate remaining totlen */
1365 if ((elt->id == key) && (totlen >= (len + 2)))
1366 return elt;
1368 elt = (bcm_tlv_t *) ((u8 *) elt + (len + 2));
1369 totlen -= (len + 2);
1372 return NULL;
1376 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1377 * triples, returning a pointer to the substring whose first element
1378 * matches tag. Stop parsing when we see an element whose ID is greater
1379 * than the target key.
1381 bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
1383 bcm_tlv_t *elt;
1384 int totlen;
1386 elt = (bcm_tlv_t *) buf;
1387 totlen = buflen;
1389 /* find tagged parameter */
1390 while (totlen >= 2) {
1391 uint id = elt->id;
1392 int len = elt->len;
1394 /* Punt if we start seeing IDs > than target key */
1395 if (id > key)
1396 return NULL;
1398 /* validate remaining totlen */
1399 if ((id == key) && (totlen >= (len + 2)))
1400 return elt;
1402 elt = (bcm_tlv_t *) ((u8 *) elt + (len + 2));
1403 totlen -= (len + 2);
1405 return NULL;
1408 #if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1409 defined(DHD_DEBUG)
1411 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char *buf, int len)
1413 int i;
1414 char *p = buf;
1415 char hexstr[16];
1416 int slen = 0;
1417 uint32 bit;
1418 const char *name;
1420 if (len < 2 || !buf)
1421 return 0;
1423 buf[0] = '\0';
1424 len -= 1;
1426 for (i = 0; flags != 0; i++) {
1427 bit = bd[i].bit;
1428 name = bd[i].name;
1429 if (bit == 0 && flags) {
1430 /* print any unnamed bits */
1431 sprintf(hexstr, "0x%X", flags);
1432 name = hexstr;
1433 flags = 0; /* exit loop */
1434 } else if ((flags & bit) == 0)
1435 continue;
1436 slen += strlen(name);
1437 if (len < slen)
1438 break;
1439 if (p != buf)
1440 p += sprintf(p, " "); /* btwn flag space */
1441 strcat(p, name);
1442 p += strlen(name);
1443 flags &= ~bit;
1444 len -= slen;
1445 slen = 1; /* account for btwn flag space */
1448 /* indicate the str was too short */
1449 if (flags != 0) {
1450 if (len == 0)
1451 p--; /* overwrite last char */
1452 p += sprintf(p, ">");
1455 return (int)(p - buf);
1459 * print bytes formatted as hex to a string. return the resulting
1460 * string length
1462 int bcm_format_hex(char *str, const void *bytes, int len)
1464 int i;
1465 char *p = str;
1466 const u8 *src = (const u8 *)bytes;
1468 for (i = 0; i < len; i++) {
1469 p += sprintf(p, "%02X", *src);
1470 src++;
1472 return (int)(p - str);
1475 /* pretty hex print a contiguous buffer */
1476 void prhex(const char *msg, unsigned char *buf, uint nbytes)
1478 char line[128], *p;
1479 uint i;
1481 if (msg && (msg[0] != '\0'))
1482 printf("%s:\n", msg);
1484 p = line;
1485 for (i = 0; i < nbytes; i++) {
1486 if (i % 16 == 0)
1487 p += sprintf(p, " %04d: ", i); /* line prefix */
1489 p += sprintf(p, "%02x ", buf[i]);
1490 if (i % 16 == 15) {
1491 printf("%s\n", line); /* flush line */
1492 p = line;
1496 /* flush last partial line */
1497 if (p != line)
1498 printf("%s\n", line);
1500 #endif /* defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) */
1502 /* Produce a human-readable string for boardrev */
1503 char *bcm_brev_str(uint32 brev, char *buf)
1505 if (brev < 0x100)
1506 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1507 else
1508 snprintf(buf, 8, "%c%03x",
1509 ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
1511 return buf;
1514 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1516 /* dump large strings to console */
1517 void printbig(char *buf)
1519 uint len, max_len;
1520 char c;
1522 len = strlen(buf);
1524 max_len = BUFSIZE_TODUMP_ATONCE;
1526 while (len > max_len) {
1527 c = buf[max_len];
1528 buf[max_len] = '\0';
1529 printf("%s", buf);
1530 buf[max_len] = c;
1532 buf += max_len;
1533 len -= max_len;
1535 /* print the remaining string */
1536 printf("%s\n", buf);
1537 return;
1540 /* routine to dump fields in a fileddesc structure */
1541 uint
1542 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1,
1543 struct fielddesc *fielddesc_array, char *buf, uint32 bufsize)
1545 uint filled_len;
1546 int len;
1547 struct fielddesc *cur_ptr;
1549 filled_len = 0;
1550 cur_ptr = fielddesc_array;
1552 while (bufsize > 1) {
1553 if (cur_ptr->nameandfmt == NULL)
1554 break;
1555 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
1556 read_rtn(arg0, arg1, cur_ptr->offset));
1557 /* check for snprintf overflow or error */
1558 if (len < 0 || (uint32) len >= bufsize)
1559 len = bufsize - 1;
1560 buf += len;
1561 bufsize -= len;
1562 filled_len += len;
1563 cur_ptr++;
1565 return filled_len;
1568 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1570 uint len;
1572 len = strlen(name) + 1;
1574 if ((len + datalen) > buflen)
1575 return 0;
1577 strncpy(buf, name, buflen);
1579 /* append data onto the end of the name string */
1580 memcpy(&buf[len], data, datalen);
1581 len += datalen;
1583 return len;
1586 /* Quarter dBm units to mW
1587 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1588 * Table is offset so the last entry is largest mW value that fits in
1589 * a uint16.
1592 #define QDBM_OFFSET 153 /* Offset for first entry */
1593 #define QDBM_TABLE_LEN 40 /* Table size */
1595 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1596 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1598 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1600 /* Largest mW value that will round down to the last table entry,
1601 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1602 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
1603 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1605 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1607 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1608 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1609 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1610 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1611 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1612 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1613 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1616 uint16 bcm_qdbm_to_mw(u8 qdbm)
1618 uint factor = 1;
1619 int idx = qdbm - QDBM_OFFSET;
1621 if (idx >= QDBM_TABLE_LEN) {
1622 /* clamp to max uint16 mW value */
1623 return 0xFFFF;
1626 /* scale the qdBm index up to the range of the table 0-40
1627 * where an offset of 40 qdBm equals a factor of 10 mW.
1629 while (idx < 0) {
1630 idx += 40;
1631 factor *= 10;
1634 /* return the mW value scaled down to the correct factor of 10,
1635 * adding in factor/2 to get proper rounding.
1637 return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
1640 u8 bcm_mw_to_qdbm(uint16 mw)
1642 u8 qdbm;
1643 int offset;
1644 uint mw_uint = mw;
1645 uint boundary;
1647 /* handle boundary case */
1648 if (mw_uint <= 1)
1649 return 0;
1651 offset = QDBM_OFFSET;
1653 /* move mw into the range of the table */
1654 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1655 mw_uint *= 10;
1656 offset -= 40;
1659 for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
1660 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
1661 nqdBm_to_mW_map[qdbm]) / 2;
1662 if (mw_uint < boundary)
1663 break;
1666 qdbm += (u8) offset;
1668 return qdbm;
1671 uint bcm_bitcount(u8 *bitmap, uint length)
1673 uint bitcount = 0, i;
1674 u8 tmp;
1675 for (i = 0; i < length; i++) {
1676 tmp = bitmap[i];
1677 while (tmp) {
1678 bitcount++;
1679 tmp &= (tmp - 1);
1682 return bitcount;
1685 #ifdef BCMDRIVER
1687 /* Initialization of bcmstrbuf structure */
1688 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1690 b->origsize = b->size = size;
1691 b->origbuf = b->buf = buf;
1694 /* Buffer sprintf wrapper to guard against buffer overflow */
1695 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1697 va_list ap;
1698 int r;
1700 va_start(ap, fmt);
1701 r = vsnprintf(b->buf, b->size, fmt, ap);
1703 /* Non Ansi C99 compliant returns -1,
1704 * Ansi compliant return r >= b->size,
1705 * bcmstdlib returns 0, handle all
1707 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1708 b->size = 0;
1709 } else {
1710 b->size -= r;
1711 b->buf += r;
1714 va_end(ap);
1716 return r;
1719 void bcm_inc_bytes(unsigned char *num, int num_bytes, u8 amount)
1721 int i;
1723 for (i = 0; i < num_bytes; i++) {
1724 num[i] += amount;
1725 if (num[i] >= amount)
1726 break;
1727 amount = 1;
1731 int bcm_cmp_bytes(unsigned char *arg1, unsigned char *arg2, u8 nbytes)
1733 int i;
1735 for (i = nbytes - 1; i >= 0; i--) {
1736 if (arg1[i] != arg2[i])
1737 return arg1[i] - arg2[i];
1739 return 0;
1742 void bcm_print_bytes(char *name, const unsigned char *data, int len)
1744 int i;
1745 int per_line = 0;
1747 printf("%s: %d \n", name ? name : "", len);
1748 for (i = 0; i < len; i++) {
1749 printf("%02x ", *data++);
1750 per_line++;
1751 if (per_line == 16) {
1752 per_line = 0;
1753 printf("\n");
1756 printf("\n");
1759 int getintvar(char *vars, const char *name)
1761 return 0;
1764 char *bcm_chipname(uint chipid, char *buf, uint len)
1766 const char *fmt;
1768 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
1769 snprintf(buf, len, fmt, chipid);
1770 return buf;
1773 char *getvar(char *vars, const char *name)
1775 return NULL;
1779 * buffer length needed for wlc_format_ssid
1780 * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
1783 #if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
1784 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
1785 int bcm_format_ssid(char *buf, const unsigned char ssid[], uint ssid_len)
1787 uint i, c;
1788 char *p = buf;
1789 char *endp = buf + SSID_FMT_BUF_LEN;
1791 if (ssid_len > DOT11_MAX_SSID_LEN)
1792 ssid_len = DOT11_MAX_SSID_LEN;
1794 for (i = 0; i < ssid_len; i++) {
1795 c = (uint) ssid[i];
1796 if (c == '\\') {
1797 *p++ = '\\';
1798 *p++ = '\\';
1799 } else if (bcm_isprint((unsigned char) c)) {
1800 *p++ = (char)c;
1801 } else {
1802 p += snprintf(p, (endp - p), "\\x%02X", c);
1805 *p = '\0';
1806 ASSERT(p < endp);
1808 return (int)(p - buf);
1810 #endif /* defined(WLTINYDUMP) ||
1811 defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) */
1813 #endif /* BCMDRIVER */