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