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