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
pktcopy(osl_t * osh,void * p,uint offset,int len,uchar * buf)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
pktfrombuf(osl_t * osh,void * p,uint offset,int len,uchar * buf)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
pkttotlen(osl_t * osh,void * p)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 *
pktlast(osl_t * osh,void * p)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
pktsegcnt(osl_t * osh,void * p)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
pktsegcnt_war(osl_t * osh,void * p)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
pktdataoffset(osl_t * osh,void * p,uint offset)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 *
pktoffset(osl_t * osh,void * p,uint offset)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
pktq_penq(struct pktq * pq,int prec,void * p)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
pktq_penq_head(struct pktq * pq,int prec,void * p)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
pktq_pdeq(struct pktq * pq,int prec)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
pktq_pdeq_prev(struct pktq * pq,int prec,void * prev_p)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
pktq_pdeq_with_fn(struct pktq * pq,int prec,ifpkt_cb_t fn,int arg)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
pktq_pdeq_tail(struct pktq * pq,int prec)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
pktq_pflush(osl_t * osh,struct pktq * pq,int prec,bool dir,ifpkt_cb_t fn,int arg)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
pktq_pdel(struct pktq * pq,void * pktbuf,int prec)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
pktq_init(struct pktq * pq,int num_prec,int max_len)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
pktq_set_max_plen(struct pktq * pq,int prec,int max_len)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
pktq_deq(struct pktq * pq,int * prec_out)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
pktq_deq_tail(struct pktq * pq,int * prec_out)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 *
pktq_peek(struct pktq * pq,int * prec_out)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 *
pktq_peek_tail(struct pktq * pq,int * prec_out)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
pktq_flush(osl_t * osh,struct pktq * pq,bool dir,ifpkt_cb_t fn,int arg)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
pktq_mlen(struct pktq * pq,uint prec_bmp)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
pktq_mpeek(struct pktq * pq,uint prec_bmp,int * prec_out)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
pktq_mdeq(struct pktq * pq,uint prec_bmp,int * prec_out)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
bcm_strtoul(const char * cp,char ** endp,uint base)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
bcm_atoi(const char * s)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 *
bcmstrstr(const char * haystack,const char * needle)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 *
bcmstrcat(char * dest,const char * src)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 *
bcmstrncat(char * dest,const char * src,uint size)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 *
bcmstrtok(char ** string,const char * delimiters,char * tokdelim)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
bcmstricmp(const char * s1,const char * s2)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
bcmstrnicmp(const char * s1,const char * s2,int cnt)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
bcm_ether_atoe(const char * p,struct ether_addr * ea)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
wchar2ascii(char * abuf,ushort * wbuf,ushort wbuflen,ulong abuflen)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 *
bcm_ether_ntoa(const struct ether_addr * ea,char * buf)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 *
bcm_ip_ntoa(struct ipv4_addr * ia,char * buf)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
bcm_mdelay(uint ms)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
prpkt(const char * msg,osl_t * osh,void * p0)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
pktsetprio(void * pkt,bool update_vtag)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 *
bcmerrorstr(int bcmerror)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*
bcm_iovar_lookup(const bcm_iovar_t * table,const char * name)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
bcm_iovar_lencheck(const bcm_iovar_t * vi,void * arg,int len,bool set)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
hndcrc8(uint8 * pdata,uint nbytes,uint8 crc)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
hndcrc16(uint8 * pdata,uint nbytes,uint16 crc)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
hndcrc32(uint8 * pdata,uint nbytes,uint32 crc)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
testcrc32(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 *
bcm_next_tlv(bcm_tlv_t * elt,int * buflen)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 *
bcm_parse_tlvs(void * buf,int buflen,uint key)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 *
bcm_parse_ordered_tlvs(void * buf,int buflen,uint key)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
bcm_format_field(const bcm_bit_desc_ex_t * bd,uint32 flags,char * buf,int len)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
bcm_format_flags(const bcm_bit_desc_t * bd,uint32 flags,char * buf,int len)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
bcm_format_hex(char * str,const void * bytes,int len)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
prhex(const char * msg,uchar * buf,uint nbytes)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 *
bcm_crypto_algo_name(uint algo)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 *
bcm_chipname(uint chipid,char * buf,uint len)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 *
bcm_brev_str(uint32 brev,char * buf)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
printbig(char * buf)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
bcmdumpfields(bcmutl_rdreg_rtn read_rtn,void * arg0,uint arg1,struct fielddesc * fielddesc_array,char * buf,uint32 bufsize)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
bcm_mkiovar(char * name,char * data,uint datalen,char * buf,uint buflen)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
bcm_qdbm_to_mw(uint8 qdbm)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
bcm_mw_to_qdbm(uint16 mw)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
bcm_bitcount(uint8 * bitmap,uint length)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
bcm_binit(struct bcmstrbuf * b,char * buf,uint size)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
bcm_bprintf(struct bcmstrbuf * b,const char * fmt,...)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
bcm_bprhex(struct bcmstrbuf * b,const char * msg,bool newline,uint8 * buf,int len)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
bcm_inc_bytes(uchar * num,int num_bytes,uint8 amount)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
bcm_cmp_bytes(const uchar * arg1,const uchar * arg2,uint8 nbytes)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
bcm_print_bytes(const char * name,const uchar * data,int len)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 *
find_vendor_ie(void * tlvs,int tlvs_len,const char * voui,uint8 * type,int type_len)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
bcm_format_ssid(char * buf,const uchar ssid[],uint ssid_len)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
process_nvram_vars(char * varbuf,unsigned int len)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
bcm_uint64_multiple_add(uint32 * r_high,uint32 * r_low,uint32 a,uint32 b,uint32 c)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
bcm_uint64_divide(uint32 * r,uint32 a_high,uint32 a_low,uint32 b)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
setbit(void * array,uint bit)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
clrbit(void * array,uint bit)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
isset(const void * array,uint bit)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
isclr(const void * array,uint bit)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 */
2295