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