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