nexmon – Blame information for rev 1

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