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