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