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