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