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