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