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