BCM WL 6.30.102.9 (r366174)
[tomato.git] / release / src-rt / shared / bcmutils.c
blobf0caa5d893a560cf097ee3e32c35e7dee08945bd
1 /*
2 * Driver O/S-independent utility routines
4 * Copyright (C) 2011, Broadcom Corporation. All Rights Reserved.
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 * $Id: bcmutils.c 329066 2012-04-23 22:56:34Z $
20 #include <bcm_cfg.h>
21 #include <typedefs.h>
22 #include <bcmdefs.h>
23 #if defined(__FreeBSD__) || defined(__NetBSD__)
24 #include <machine/stdarg.h>
25 #else
26 #include <stdarg.h>
27 #endif
28 #ifdef BCMDRIVER
30 #include <osl.h>
31 #include <bcmutils.h>
32 #include <siutils.h>
33 #include <bcmnvram.h>
35 #else /* !BCMDRIVER */
37 #include <stdio.h>
38 #include <string.h>
39 #include <bcmutils.h>
41 #if defined(BCMEXTSUP)
42 #include <bcm_osl.h>
43 #endif
46 #endif /* !BCMDRIVER */
48 #if defined(_WIN32) || defined(NDIS) || defined(__vxworks) || defined(_CFE_)
49 #include <bcmstdlib.h>
50 #endif
51 #include <bcmendian.h>
52 #include <bcmdevs.h>
53 #include <proto/ethernet.h>
54 #include <proto/vlan.h>
55 #include <proto/bcmip.h>
56 #include <proto/802.1d.h>
57 #include <proto/802.11.h>
58 #ifdef BCMPERFSTATS
59 #include <bcmperf.h>
60 #endif
61 #include <proto/bcmipv6.h>
62 void *_bcmutils_dummy_fn = NULL;
64 #ifdef BCMDRIVER
66 #ifdef WLC_LOW
67 /* nvram vars cache */
68 static char *nvram_vars = NULL;
69 static int vars_len = -1;
70 #endif /* WLC_LOW */
72 int
73 pktpool_init(osl_t *osh, pktpool_t *pktp, int *pplen, int plen, bool istx)
75 int i, err = BCME_OK;
76 void *p;
77 int pktplen;
79 ASSERT(pktp != NULL);
80 ASSERT(osh != NULL);
81 ASSERT(pplen != NULL);
83 pktplen = *pplen;
85 bzero(pktp, sizeof(pktpool_t));
86 pktp->inited = TRUE;
87 pktp->istx = istx ? TRUE : FALSE;
88 pktp->plen = (uint16)plen;
89 *pplen = 0;
91 pktp->maxlen = PKTPOOL_LEN_MAX;
92 if (pktplen > pktp->maxlen)
93 pktplen = pktp->maxlen;
95 for (i = 0; i < pktplen; i++) {
96 p = PKTGET(osh, plen, pktp->istx);
97 if (p == NULL) {
98 /* Not able to allocate all requested pkts
99 * so just return what was actually allocated
100 * We can add to the pool later
102 if (pktp->w == 0)
103 err = BCME_NOMEM;
105 goto exit;
108 PKTSETPOOL(osh, p, TRUE, pktp);
109 pktp->q[i] = p;
110 pktp->w++;
111 pktp->len++;
112 #ifdef BCMDBG_POOL
113 pktp->dbg_q[pktp->dbg_qlen++].p = p;
114 #endif
117 exit:
118 *pplen = pktp->w;
119 pktp->len++; /* Add one for end */
120 return err;
124 pktpool_deinit(osl_t *osh, pktpool_t *pktp)
126 int i;
127 int cnt;
129 ASSERT(osh != NULL);
130 ASSERT(pktp != NULL);
132 cnt = pktp->len;
133 for (i = 0; i < cnt; i++) {
134 if (pktp->q[i] != NULL) {
135 PKTSETPOOL(osh, pktp->q[i], FALSE, NULL);
136 PKTFREE(osh, pktp->q[i], pktp->istx);
137 pktp->q[i] = NULL;
138 pktp->len--;
140 #ifdef BCMDBG_POOL
141 if (pktp->dbg_q[i].p != NULL)
142 pktp->dbg_q[i].p = NULL;
143 #endif
145 pktp->inited = FALSE;
147 /* Are there still pending pkts? */
148 ASSERT(pktpool_len(pktp) == 0);
150 return 0;
154 pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal)
156 void *p;
157 int err = 0;
158 int len, psize, maxlen;
160 ASSERT(pktpool_plen(pktp) != 0);
162 maxlen = pktpool_maxlen(pktp);
163 psize = minimal ? (maxlen >> 2) : maxlen;
164 len = pktpool_len(pktp);
165 for (; len < psize; len++) {
166 p = PKTGET(osh, pktpool_plen(pktp), FALSE);
167 if (p == NULL) {
168 err = BCME_NOMEM;
169 break;
172 if (pktpool_add(pktp, p) != BCME_OK) {
173 PKTFREE(osh, p, FALSE);
174 err = BCME_ERROR;
175 break;
179 return err;
182 uint16
183 pktpool_avail(pktpool_t *pktp)
185 if (pktp->w == pktp->r)
186 return 0;
188 return (pktp->w > pktp->r) ? (pktp->w - pktp->r) : ((pktp->len) - (pktp->r - pktp->w));
191 static void *
192 pktpool_deq(pktpool_t *pktp)
194 void *p;
196 if (pktp->r == pktp->w)
197 return NULL;
199 p = pktp->q[pktp->r];
200 ASSERT(p != NULL);
202 pktp->q[pktp->r++] = NULL;
203 pktp->r %= (pktp->len);
205 return p;
208 static void
209 pktpool_enq(pktpool_t *pktp, void *p)
211 uint16 next;
213 ASSERT(p != NULL);
215 next = (pktp->w + 1) % (pktp->len);
216 if (next == pktp->r) {
217 /* Should not happen; otherwise pkt leak */
218 ASSERT(0);
219 return;
222 ASSERT(pktp->q[pktp->w] == NULL);
224 pktp->q[pktp->w] = p;
225 pktp->w = next;
229 pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
231 int i;
233 ASSERT(cb != NULL);
235 i = pktp->cbcnt;
236 if (i == PKTPOOL_CB_MAX)
237 return BCME_ERROR;
239 ASSERT(pktp->cbs[i].cb == NULL);
240 pktp->cbs[i].cb = cb;
241 pktp->cbs[i].arg = arg;
242 pktp->cbcnt++;
244 return 0;
248 pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
250 int i;
252 ASSERT(cb != NULL);
254 i = pktp->ecbcnt;
255 if (i == PKTPOOL_CB_MAX)
256 return BCME_ERROR;
258 ASSERT(pktp->ecbs[i].cb == NULL);
259 pktp->ecbs[i].cb = cb;
260 pktp->ecbs[i].arg = arg;
261 pktp->ecbcnt++;
263 return 0;
266 static int
267 pktpool_empty_notify(pktpool_t *pktp)
269 int i;
271 pktp->empty = TRUE;
272 for (i = 0; i < pktp->ecbcnt; i++) {
273 ASSERT(pktp->ecbs[i].cb != NULL);
274 pktp->ecbs[i].cb(pktp, pktp->ecbs[i].arg);
276 pktp->empty = FALSE;
278 return 0;
281 #ifdef BCMDBG_POOL
283 pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
285 int i;
287 ASSERT(cb);
289 i = pktp->dbg_cbcnt;
290 if (i == PKTPOOL_CB_MAX)
291 return BCME_ERROR;
293 ASSERT(pktp->dbg_cbs[i].cb == NULL);
294 pktp->dbg_cbs[i].cb = cb;
295 pktp->dbg_cbs[i].arg = arg;
296 pktp->dbg_cbcnt++;
298 return 0;
301 int pktpool_dbg_notify(pktpool_t *pktp);
304 pktpool_dbg_notify(pktpool_t *pktp)
306 int i;
308 for (i = 0; i < pktp->dbg_cbcnt; i++) {
309 ASSERT(pktp->dbg_cbs[i].cb);
310 pktp->dbg_cbs[i].cb(pktp, pktp->dbg_cbs[i].arg);
313 return 0;
317 pktpool_dbg_dump(pktpool_t *pktp)
319 int i;
321 printf("pool len=%d maxlen=%d\n", pktp->dbg_qlen, pktp->maxlen);
322 for (i = 0; i < pktp->dbg_qlen; i++) {
323 ASSERT(pktp->dbg_q[i].p);
324 printf("%d, p: 0x%x dur:%lu us state:%d\n", i,
325 pktp->dbg_q[i].p, pktp->dbg_q[i].dur/100, PKTPOOLSTATE(pktp->dbg_q[i].p));
328 return 0;
332 pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats)
334 int i;
335 int state;
337 bzero(stats, sizeof(pktpool_stats_t));
338 for (i = 0; i < pktp->dbg_qlen; i++) {
339 ASSERT(pktp->dbg_q[i].p != NULL);
341 state = PKTPOOLSTATE(pktp->dbg_q[i].p);
342 switch (state) {
343 case POOL_TXENQ:
344 stats->enq++; break;
345 case POOL_TXDH:
346 stats->txdh++; break;
347 case POOL_TXD11:
348 stats->txd11++; break;
349 case POOL_RXDH:
350 stats->rxdh++; break;
351 case POOL_RXD11:
352 stats->rxd11++; break;
353 case POOL_RXFILL:
354 stats->rxfill++; break;
355 case POOL_IDLE:
356 stats->idle++; break;
360 return 0;
364 pktpool_start_trigger(pktpool_t *pktp, void *p)
366 uint32 cycles, i;
368 if (!PKTPOOL(NULL, p))
369 return 0;
371 OSL_GETCYCLES(cycles);
373 for (i = 0; i < pktp->dbg_qlen; i++) {
374 ASSERT(pktp->dbg_q[i].p != NULL);
376 if (pktp->dbg_q[i].p == p) {
377 pktp->dbg_q[i].cycles = cycles;
378 break;
382 return 0;
385 int pktpool_stop_trigger(pktpool_t *pktp, void *p);
387 pktpool_stop_trigger(pktpool_t *pktp, void *p)
389 uint32 cycles, i;
391 if (!PKTPOOL(NULL, p))
392 return 0;
394 OSL_GETCYCLES(cycles);
396 for (i = 0; i < pktp->dbg_qlen; i++) {
397 ASSERT(pktp->dbg_q[i].p != NULL);
399 if (pktp->dbg_q[i].p == p) {
400 if (pktp->dbg_q[i].cycles == 0)
401 break;
403 if (cycles >= pktp->dbg_q[i].cycles)
404 pktp->dbg_q[i].dur = cycles - pktp->dbg_q[i].cycles;
405 else
406 pktp->dbg_q[i].dur =
407 (((uint32)-1) - pktp->dbg_q[i].cycles) + cycles + 1;
409 pktp->dbg_q[i].cycles = 0;
410 break;
414 return 0;
416 #endif /* BCMDBG_POOL */
419 pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp)
421 ASSERT(pktp);
422 pktp->availcb_excl = NULL;
423 return 0;
427 pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb)
429 int i;
431 ASSERT(pktp);
432 ASSERT(pktp->availcb_excl == NULL);
433 for (i = 0; i < pktp->cbcnt; i++) {
434 if (cb == pktp->cbs[i].cb) {
435 pktp->availcb_excl = &pktp->cbs[i];
436 break;
440 if (pktp->availcb_excl == NULL)
441 return BCME_ERROR;
442 else
443 return 0;
446 static int
447 pktpool_avail_notify(pktpool_t *pktp)
449 int i, k, idx;
450 int avail;
452 ASSERT(pktp);
453 if (pktp->availcb_excl != NULL) {
454 pktp->availcb_excl->cb(pktp, pktp->availcb_excl->arg);
455 return 0;
458 k = pktp->cbcnt - 1;
459 for (i = 0; i < pktp->cbcnt; i++) {
460 avail = pktpool_avail(pktp);
462 if (avail) {
463 if (pktp->cbtoggle)
464 idx = i;
465 else
466 idx = k--;
468 ASSERT(pktp->cbs[idx].cb != NULL);
469 pktp->cbs[idx].cb(pktp, pktp->cbs[idx].arg);
473 /* Alternate between filling from head or tail
475 pktp->cbtoggle ^= 1;
477 return 0;
480 void *
481 pktpool_get(pktpool_t *pktp)
483 void *p;
485 p = pktpool_deq(pktp);
487 if (p == NULL) {
488 /* Notify and try to reclaim tx pkts */
489 if (pktp->ecbcnt)
490 pktpool_empty_notify(pktp);
492 p = pktpool_deq(pktp);
495 return p;
498 void
499 pktpool_free(pktpool_t *pktp, void *p)
501 ASSERT(p != NULL);
503 #ifdef BCMDBG_POOL
504 /* pktpool_stop_trigger(pktp, p); */
505 #endif
507 pktpool_enq(pktp, p);
509 if (pktp->emptycb_disable)
510 return;
512 if (pktp->cbcnt) {
513 if (pktp->empty == FALSE)
514 pktpool_avail_notify(pktp);
519 pktpool_add(pktpool_t *pktp, void *p)
521 ASSERT(p != NULL);
523 if (pktpool_len(pktp) == pktp->maxlen)
524 return BCME_RANGE;
526 ASSERT(pktpool_plen(pktp) == PKTLEN(NULL, p)); /* pkts in pool have same length */
527 PKTSETPOOL(NULL, p, TRUE, pktp);
529 pktp->len++;
530 if (pktp->r > pktp->w) {
531 /* Add to tail */
532 ASSERT(pktp->q[pktp->len - 1] == NULL);
533 pktp->q[pktp->len - 1] = p;
534 } else
535 pktpool_enq(pktp, p);
537 #ifdef BCMDBG_POOL
538 pktp->dbg_q[pktp->dbg_qlen++].p = p;
539 #endif
541 return 0;
545 pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen)
547 if (maxlen > PKTPOOL_LEN_MAX)
548 maxlen = PKTPOOL_LEN_MAX;
550 /* if pool is already beyond maxlen, then just cap it
551 * since we currently do not reduce the pool len
552 * already allocated
554 pktp->maxlen = (pktpool_len(pktp) > maxlen) ? pktpool_len(pktp) : maxlen;
556 return pktp->maxlen;
559 void
560 pktpool_emptycb_disable(pktpool_t *pktp, bool disable)
562 ASSERT(pktp);
564 pktp->emptycb_disable = disable;
567 bool
568 pktpool_emptycb_disabled(pktpool_t *pktp)
570 ASSERT(pktp);
571 return pktp->emptycb_disable;
574 /* copy a pkt buffer chain into a buffer */
575 uint
576 pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
578 uint n, ret = 0;
580 if (len < 0)
581 len = 4096; /* "infinite" */
583 /* skip 'offset' bytes */
584 for (; p && offset; p = PKTNEXT(osh, p)) {
585 if (offset < (uint)PKTLEN(osh, p))
586 break;
587 offset -= PKTLEN(osh, p);
590 if (!p)
591 return 0;
593 /* copy the data */
594 for (; p && len; p = PKTNEXT(osh, p)) {
595 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
596 bcopy(PKTDATA(osh, p) + offset, buf, n);
597 buf += n;
598 len -= n;
599 ret += n;
600 offset = 0;
603 return ret;
606 /* copy a buffer into a pkt buffer chain */
607 uint
608 pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
610 uint n, ret = 0;
612 /* skip 'offset' bytes */
613 for (; p && offset; p = PKTNEXT(osh, p)) {
614 if (offset < (uint)PKTLEN(osh, p))
615 break;
616 offset -= PKTLEN(osh, p);
619 if (!p)
620 return 0;
622 /* copy the data */
623 for (; p && len; p = PKTNEXT(osh, p)) {
624 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
625 bcopy(buf, PKTDATA(osh, p) + offset, n);
626 buf += n;
627 len -= n;
628 ret += n;
629 offset = 0;
632 return ret;
635 #ifdef NOTYET
636 /* copy data from one pkt buffer (chain) to another */
637 uint
638 pkt2pktcopy(osl_t *osh, void *p1, uint offs1, void *p2, uint offs2, int maxlen)
640 uint8 *dp1, *dp2;
641 uint len1, len2, copylen, totallen;
643 for (; p1 && offs; p1 = PKTNEXT(osh, p1)) {
644 if (offs1 < (uint)PKTLEN(osh, p1))
645 break;
646 offs1 -= PKTLEN(osh, p1);
648 for (; p2 && offs; p2 = PKTNEXT(osh, p2)) {
649 if (offs2 < (uint)PKTLEN(osh, p2))
650 break;
651 offs2 -= PKTLEN(osh, p2);
654 /* Heck w/it, only need the above for now */
656 #endif /* NOTYET */
659 /* return total length of buffer chain */
660 uint BCMFASTPATH
661 pkttotlen(osl_t *osh, void *p)
663 uint total;
664 int len;
666 total = 0;
667 for (; p; p = PKTNEXT(osh, p)) {
668 len = PKTLEN(osh, p);
669 #ifdef MACOSX
670 if (len < 0) {
671 /* Bad packet length, just drop and exit */
672 printf("wl: pkttotlen bad (%p,%d)\n", p, len);
673 break;
675 #endif /* MACOSX */
676 total += len;
679 return (total);
682 /* return the last buffer of chained pkt */
683 void *
684 pktlast(osl_t *osh, void *p)
686 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
689 return (p);
692 /* count segments of a chained packet */
693 uint BCMFASTPATH
694 pktsegcnt(osl_t *osh, void *p)
696 uint cnt;
698 for (cnt = 0; p; p = PKTNEXT(osh, p))
699 cnt++;
701 return cnt;
705 /* count segments of a chained packet */
706 uint BCMFASTPATH
707 pktsegcnt_war(osl_t *osh, void *p)
709 uint cnt;
710 uint8 *pktdata;
711 uint len, remain, align64;
713 for (cnt = 0; p; p = PKTNEXT(osh, p)) {
714 cnt++;
715 len = PKTLEN(osh, p);
716 if (len > 128) {
717 pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */
718 /* Check for page boundary straddle (2048B) */
719 if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff))
720 cnt++;
722 align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */
723 align64 = (64 - align64) & 0x3f;
724 len -= align64; /* bytes from aligned 64B to end */
725 /* if aligned to 128B, check for MOD 128 between 1 to 4B */
726 remain = len % 128;
727 if (remain > 0 && remain <= 4)
728 cnt++; /* add extra seg */
732 return cnt;
735 uint8 * BCMFASTPATH
736 pktdataoffset(osl_t *osh, void *p, uint offset)
738 uint total = pkttotlen(osh, p);
739 uint pkt_off = 0, len = 0;
740 uint8 *pdata = (uint8 *) PKTDATA(osh, p);
742 if (offset > total)
743 return NULL;
745 for (; p; p = PKTNEXT(osh, p)) {
746 pdata = (uint8 *) PKTDATA(osh, p);
747 pkt_off = offset - len;
748 len += PKTLEN(osh, p);
749 if (len > offset)
750 break;
752 return (uint8*) (pdata+pkt_off);
756 /* given a offset in pdata, find the pkt seg hdr */
757 void *
758 pktoffset(osl_t *osh, void *p, uint offset)
760 uint total = pkttotlen(osh, p);
761 uint len = 0;
763 if (offset > total)
764 return NULL;
766 for (; p; p = PKTNEXT(osh, p)) {
767 len += PKTLEN(osh, p);
768 if (len > offset)
769 break;
771 return p;
775 * osl multiple-precedence packet queue
776 * hi_prec is always >= the number of the highest non-empty precedence
778 void * BCMFASTPATH
779 pktq_penq(struct pktq *pq, int prec, void *p)
781 struct pktq_prec *q;
783 ASSERT(prec >= 0 && prec < pq->num_prec);
784 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
786 ASSERT(!pktq_full(pq));
787 ASSERT(!pktq_pfull(pq, prec));
789 q = &pq->q[prec];
791 if (q->head)
792 PKTSETLINK(q->tail, p);
793 else
794 q->head = p;
796 q->tail = p;
797 q->len++;
799 pq->len++;
801 if (pq->hi_prec < prec)
802 pq->hi_prec = (uint8)prec;
804 return p;
807 void * BCMFASTPATH
808 pktq_penq_head(struct pktq *pq, int prec, void *p)
810 struct pktq_prec *q;
812 ASSERT(prec >= 0 && prec < pq->num_prec);
813 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
815 ASSERT(!pktq_full(pq));
816 ASSERT(!pktq_pfull(pq, prec));
818 q = &pq->q[prec];
820 if (q->head == NULL)
821 q->tail = p;
823 PKTSETLINK(p, q->head);
824 q->head = p;
825 q->len++;
827 pq->len++;
829 if (pq->hi_prec < prec)
830 pq->hi_prec = (uint8)prec;
832 return p;
835 void * BCMFASTPATH
836 pktq_pdeq(struct pktq *pq, int prec)
838 struct pktq_prec *q;
839 void *p;
841 ASSERT(prec >= 0 && prec < pq->num_prec);
843 q = &pq->q[prec];
845 if ((p = q->head) == NULL)
846 return NULL;
848 if ((q->head = PKTLINK(p)) == NULL)
849 q->tail = NULL;
851 q->len--;
853 pq->len--;
855 PKTSETLINK(p, NULL);
857 return p;
860 void * BCMFASTPATH
861 pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p)
863 struct pktq_prec *q;
864 void *p;
866 ASSERT(prec >= 0 && prec < pq->num_prec);
868 q = &pq->q[prec];
870 if (prev_p == NULL)
871 return NULL;
873 if ((p = PKTLINK(prev_p)) == NULL)
874 return NULL;
876 if (q->tail == p)
877 q->tail = prev_p;
879 q->len--;
881 pq->len--;
883 PKTSETLINK(prev_p, PKTLINK(p));
884 PKTSETLINK(p, NULL);
886 return p;
889 void * BCMFASTPATH
890 pktq_pdeq_tail(struct pktq *pq, int prec)
892 struct pktq_prec *q;
893 void *p, *prev;
895 ASSERT(prec >= 0 && prec < pq->num_prec);
897 q = &pq->q[prec];
899 if ((p = q->head) == NULL)
900 return NULL;
902 for (prev = NULL; p != q->tail; p = PKTLINK(p))
903 prev = p;
905 if (prev)
906 PKTSETLINK(prev, NULL);
907 else
908 q->head = NULL;
910 q->tail = prev;
911 q->len--;
913 pq->len--;
915 return p;
918 void
919 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg)
921 struct pktq_prec *q;
922 void *p, *prev = NULL;
924 q = &pq->q[prec];
925 p = q->head;
926 while (p) {
927 if (fn == NULL || (*fn)(p, arg)) {
928 bool head = (p == q->head);
929 if (head)
930 q->head = PKTLINK(p);
931 else
932 PKTSETLINK(prev, PKTLINK(p));
933 PKTSETLINK(p, NULL);
934 PKTFREE(osh, p, dir);
935 q->len--;
936 pq->len--;
937 p = (head ? q->head : PKTLINK(prev));
938 } else {
939 prev = p;
940 p = PKTLINK(p);
944 if (q->head == NULL) {
945 ASSERT(q->len == 0);
946 q->tail = NULL;
950 bool BCMFASTPATH
951 pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
953 struct pktq_prec *q;
954 void *p;
956 ASSERT(prec >= 0 && prec < pq->num_prec);
958 if (!pktbuf)
959 return FALSE;
961 q = &pq->q[prec];
963 if (q->head == pktbuf) {
964 if ((q->head = PKTLINK(pktbuf)) == NULL)
965 q->tail = NULL;
966 } else {
967 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
969 if (p == NULL)
970 return FALSE;
972 PKTSETLINK(p, PKTLINK(pktbuf));
973 if (q->tail == pktbuf)
974 q->tail = p;
977 q->len--;
978 pq->len--;
979 PKTSETLINK(pktbuf, NULL);
980 return TRUE;
983 void
984 pktq_init(struct pktq *pq, int num_prec, int max_len)
986 int prec;
988 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
990 /* pq is variable size; only zero out what's requested */
991 bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
993 pq->num_prec = (uint16)num_prec;
995 pq->max = (uint16)max_len;
997 for (prec = 0; prec < num_prec; prec++)
998 pq->q[prec].max = pq->max;
1001 void
1002 pktq_set_max_plen(struct pktq *pq, int prec, int max_len)
1004 ASSERT(prec >= 0 && prec < pq->num_prec);
1006 if (prec < pq->num_prec)
1007 pq->q[prec].max = (uint16)max_len;
1010 void * BCMFASTPATH
1011 pktq_deq(struct pktq *pq, int *prec_out)
1013 struct pktq_prec *q;
1014 void *p;
1015 int prec;
1017 if (pq->len == 0)
1018 return NULL;
1020 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1021 pq->hi_prec--;
1023 q = &pq->q[prec];
1025 if ((p = q->head) == NULL)
1026 return NULL;
1028 if ((q->head = PKTLINK(p)) == NULL)
1029 q->tail = NULL;
1031 q->len--;
1033 pq->len--;
1035 if (prec_out)
1036 *prec_out = prec;
1038 PKTSETLINK(p, NULL);
1040 return p;
1043 void * BCMFASTPATH
1044 pktq_deq_tail(struct pktq *pq, int *prec_out)
1046 struct pktq_prec *q;
1047 void *p, *prev;
1048 int prec;
1050 if (pq->len == 0)
1051 return NULL;
1053 for (prec = 0; prec < pq->hi_prec; prec++)
1054 if (pq->q[prec].head)
1055 break;
1057 q = &pq->q[prec];
1059 if ((p = q->head) == NULL)
1060 return NULL;
1062 for (prev = NULL; p != q->tail; p = PKTLINK(p))
1063 prev = p;
1065 if (prev)
1066 PKTSETLINK(prev, NULL);
1067 else
1068 q->head = NULL;
1070 q->tail = prev;
1071 q->len--;
1073 pq->len--;
1075 if (prec_out)
1076 *prec_out = prec;
1078 PKTSETLINK(p, NULL);
1080 return p;
1083 void *
1084 pktq_peek(struct pktq *pq, int *prec_out)
1086 int prec;
1088 if (pq->len == 0)
1089 return NULL;
1091 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1092 pq->hi_prec--;
1094 if (prec_out)
1095 *prec_out = prec;
1097 return (pq->q[prec].head);
1100 void *
1101 pktq_peek_tail(struct pktq *pq, int *prec_out)
1103 int prec;
1105 if (pq->len == 0)
1106 return NULL;
1108 for (prec = 0; prec < pq->hi_prec; prec++)
1109 if (pq->q[prec].head)
1110 break;
1112 if (prec_out)
1113 *prec_out = prec;
1115 return (pq->q[prec].tail);
1118 void
1119 pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
1121 int prec;
1123 /* Optimize flush, if pktq len = 0, just return.
1124 * pktq len of 0 means pktq's prec q's are all empty.
1126 if (pq->len == 0) {
1127 return;
1130 for (prec = 0; prec < pq->num_prec; prec++)
1131 pktq_pflush(osh, pq, prec, dir, fn, arg);
1132 if (fn == NULL)
1133 ASSERT(pq->len == 0);
1136 /* Return sum of lengths of a specific set of precedences */
1138 pktq_mlen(struct pktq *pq, uint prec_bmp)
1140 int prec, len;
1142 len = 0;
1144 for (prec = 0; prec <= pq->hi_prec; prec++)
1145 if (prec_bmp & (1 << prec))
1146 len += pq->q[prec].len;
1148 return len;
1151 /* Priority peek from a specific set of precedences */
1152 void * BCMFASTPATH
1153 pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out)
1155 struct pktq_prec *q;
1156 void *p;
1157 int prec;
1159 if (pq->len == 0)
1161 return NULL;
1163 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1164 pq->hi_prec--;
1166 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
1167 if (prec-- == 0)
1168 return NULL;
1170 q = &pq->q[prec];
1172 if ((p = q->head) == NULL)
1173 return NULL;
1175 if (prec_out)
1176 *prec_out = prec;
1178 return p;
1180 /* Priority dequeue from a specific set of precedences */
1181 void * BCMFASTPATH
1182 pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
1184 struct pktq_prec *q;
1185 void *p;
1186 int prec;
1188 if (pq->len == 0)
1189 return NULL;
1191 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1192 pq->hi_prec--;
1194 while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0))
1195 if (prec-- == 0)
1196 return NULL;
1198 q = &pq->q[prec];
1200 if ((p = q->head) == NULL)
1201 return NULL;
1203 if ((q->head = PKTLINK(p)) == NULL)
1204 q->tail = NULL;
1206 q->len--;
1208 if (prec_out)
1209 *prec_out = prec;
1211 pq->len--;
1213 PKTSETLINK(p, NULL);
1215 return p;
1218 #endif /* BCMDRIVER */
1220 #if defined(BCMROMBUILD)
1221 const unsigned char BCMROMDATA(bcm_ctype)[] = {
1222 #else
1223 const unsigned char bcm_ctype[] = {
1224 #endif
1226 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
1227 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
1228 _BCM_C, /* 8-15 */
1229 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
1230 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
1231 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
1232 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
1233 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
1234 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
1235 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
1236 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
1237 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
1238 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
1239 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
1240 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
1241 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
1242 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
1243 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
1244 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
1245 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
1246 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
1247 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
1248 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
1249 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
1250 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
1251 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
1252 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
1253 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
1254 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
1255 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
1256 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
1257 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
1258 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
1261 ulong
1262 BCMROMFN(bcm_strtoul)(const char *cp, char **endp, uint base)
1264 ulong result, last_result = 0, value;
1265 bool minus;
1267 minus = FALSE;
1269 while (bcm_isspace(*cp))
1270 cp++;
1272 if (cp[0] == '+')
1273 cp++;
1274 else if (cp[0] == '-') {
1275 minus = TRUE;
1276 cp++;
1279 if (base == 0) {
1280 if (cp[0] == '0') {
1281 if ((cp[1] == 'x') || (cp[1] == 'X')) {
1282 base = 16;
1283 cp = &cp[2];
1284 } else {
1285 base = 8;
1286 cp = &cp[1];
1288 } else
1289 base = 10;
1290 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
1291 cp = &cp[2];
1294 result = 0;
1296 while (bcm_isxdigit(*cp) &&
1297 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
1298 result = result*base + value;
1299 /* Detected overflow */
1300 if (result < last_result && !minus)
1301 return (ulong)-1;
1302 last_result = result;
1303 cp++;
1306 if (minus)
1307 result = (ulong)(-(long)result);
1309 if (endp)
1310 *endp = DISCARD_QUAL(cp, char);
1312 return (result);
1316 BCMROMFN(bcm_atoi)(const char *s)
1318 return (int)bcm_strtoul(s, NULL, 10);
1321 /* return pointer to location of substring 'needle' in 'haystack' */
1322 char *
1323 BCMROMFN(bcmstrstr)(const char *haystack, const char *needle)
1325 int len, nlen;
1326 int i;
1328 if ((haystack == NULL) || (needle == NULL))
1329 return DISCARD_QUAL(haystack, char);
1331 nlen = strlen(needle);
1332 len = strlen(haystack) - nlen + 1;
1334 for (i = 0; i < len; i++)
1335 if (memcmp(needle, &haystack[i], nlen) == 0)
1336 return DISCARD_QUAL(&haystack[i], char);
1337 return (NULL);
1340 char *
1341 BCMROMFN(bcmstrcat)(char *dest, const char *src)
1343 char *p;
1345 p = dest + strlen(dest);
1347 while ((*p++ = *src++) != '\0')
1350 return (dest);
1353 char *
1354 BCMROMFN(bcmstrncat)(char *dest, const char *src, uint size)
1356 char *endp;
1357 char *p;
1359 p = dest + strlen(dest);
1360 endp = p + size;
1362 while (p != endp && (*p++ = *src++) != '\0')
1365 return (dest);
1369 /****************************************************************************
1370 * Function: bcmstrtok
1372 * Purpose:
1373 * Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
1374 * but allows strToken() to be used by different strings or callers at the same
1375 * time. Each call modifies '*string' by substituting a NULL character for the
1376 * first delimiter that is encountered, and updates 'string' to point to the char
1377 * after the delimiter. Leading delimiters are skipped.
1379 * Parameters:
1380 * string (mod) Ptr to string ptr, updated by token.
1381 * delimiters (in) Set of delimiter characters.
1382 * tokdelim (out) Character that delimits the returned token. (May
1383 * be set to NULL if token delimiter is not required).
1385 * Returns: Pointer to the next token found. NULL when no more tokens are found.
1386 *****************************************************************************
1388 char *
1389 bcmstrtok(char **string, const char *delimiters, char *tokdelim)
1391 unsigned char *str;
1392 unsigned long map[8];
1393 int count;
1394 char *nextoken;
1396 if (tokdelim != NULL) {
1397 /* Prime the token delimiter */
1398 *tokdelim = '\0';
1401 /* Clear control map */
1402 for (count = 0; count < 8; count++) {
1403 map[count] = 0;
1406 /* Set bits in delimiter table */
1407 do {
1408 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
1410 while (*delimiters++);
1412 str = (unsigned char*)*string;
1414 /* Find beginning of token (skip over leading delimiters). Note that
1415 * there is no token iff this loop sets str to point to the terminal
1416 * null (*str == '\0')
1418 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
1419 str++;
1422 nextoken = (char*)str;
1424 /* Find the end of the token. If it is not the end of the string,
1425 * put a null there.
1427 for (; *str; str++) {
1428 if (map[*str >> 5] & (1 << (*str & 31))) {
1429 if (tokdelim != NULL) {
1430 *tokdelim = *str;
1433 *str++ = '\0';
1434 break;
1438 *string = (char*)str;
1440 /* Determine if a token has been found. */
1441 if (nextoken == (char *) str) {
1442 return NULL;
1444 else {
1445 return nextoken;
1450 #define xToLower(C) \
1451 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
1454 /****************************************************************************
1455 * Function: bcmstricmp
1457 * Purpose: Compare to strings case insensitively.
1459 * Parameters: s1 (in) First string to compare.
1460 * s2 (in) Second string to compare.
1462 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1463 * t1 > t2, when ignoring case sensitivity.
1464 *****************************************************************************
1467 bcmstricmp(const char *s1, const char *s2)
1469 char dc, sc;
1471 while (*s2 && *s1) {
1472 dc = xToLower(*s1);
1473 sc = xToLower(*s2);
1474 if (dc < sc) return -1;
1475 if (dc > sc) return 1;
1476 s1++;
1477 s2++;
1480 if (*s1 && !*s2) return 1;
1481 if (!*s1 && *s2) return -1;
1482 return 0;
1486 /****************************************************************************
1487 * Function: bcmstrnicmp
1489 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
1490 * characters.
1492 * Parameters: s1 (in) First string to compare.
1493 * s2 (in) Second string to compare.
1494 * cnt (in) Max characters to compare.
1496 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1497 * t1 > t2, when ignoring case sensitivity.
1498 *****************************************************************************
1501 bcmstrnicmp(const char* s1, const char* s2, int cnt)
1503 char dc, sc;
1505 while (*s2 && *s1 && cnt) {
1506 dc = xToLower(*s1);
1507 sc = xToLower(*s2);
1508 if (dc < sc) return -1;
1509 if (dc > sc) return 1;
1510 s1++;
1511 s2++;
1512 cnt--;
1515 if (!cnt) return 0;
1516 if (*s1 && !*s2) return 1;
1517 if (!*s1 && *s2) return -1;
1518 return 0;
1521 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
1523 BCMROMFN(bcm_ether_atoe)(const char *p, struct ether_addr *ea)
1525 int i = 0;
1526 char *ep;
1528 for (;;) {
1529 ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16);
1530 p = ep;
1531 if (!*p++ || i == 6)
1532 break;
1535 return (i == 6);
1539 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
1540 /* registry routine buffer preparation utility functions:
1541 * parameter order is like strncpy, but returns count
1542 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
1544 ulong
1545 wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
1547 ulong copyct = 1;
1548 ushort i;
1550 if (abuflen == 0)
1551 return 0;
1553 /* wbuflen is in bytes */
1554 wbuflen /= sizeof(ushort);
1556 for (i = 0; i < wbuflen; ++i) {
1557 if (--abuflen == 0)
1558 break;
1559 *abuf++ = (char) *wbuf++;
1560 ++copyct;
1562 *abuf = '\0';
1564 return copyct;
1566 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
1568 char *
1569 bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
1571 static const char hex[] =
1573 '0', '1', '2', '3', '4', '5', '6', '7',
1574 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
1576 const uint8 *octet = ea->octet;
1577 char *p = buf;
1578 int i;
1580 for (i = 0; i < 6; i++, octet++) {
1581 *p++ = hex[(*octet >> 4) & 0xf];
1582 *p++ = hex[*octet & 0xf];
1583 *p++ = ':';
1586 *(p-1) = '\0';
1588 return (buf);
1591 char *
1592 bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
1594 snprintf(buf, 16, "%d.%d.%d.%d",
1595 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
1596 return (buf);
1599 #ifdef BCMDRIVER
1601 void
1602 bcm_mdelay(uint ms)
1604 uint i;
1606 for (i = 0; i < ms; i++) {
1607 OSL_DELAY(1000);
1612 * Search the name=value vars for a specific one and return its value.
1613 * Returns NULL if not found.
1615 char *
1616 getvar(char *vars, const char *name)
1618 #ifdef _MINOSL_
1619 return NULL;
1620 #else
1621 char *s;
1622 int len;
1624 if (!name)
1625 return NULL;
1627 len = strlen(name);
1628 if (len == 0)
1629 return NULL;
1631 /* first look in vars[] */
1632 for (s = vars; s && *s;) {
1633 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
1634 return (&s[len+1]);
1636 while (*s++)
1640 /* then query nvram */
1641 return (nvram_get(name));
1642 #endif /* defined(_MINOSL_) */
1646 * Search the vars for a specific one and return its value as
1647 * an integer. Returns 0 if not found.
1650 getintvar(char *vars, const char *name)
1652 #ifdef _MINOSL_
1653 return 0;
1654 #else
1655 char *val;
1657 if ((val = getvar(vars, name)) == NULL)
1658 return (0);
1660 return (bcm_strtoul(val, NULL, 0));
1661 #endif /* _MINOSL_ */
1665 getintvararray(char *vars, const char *name, int index)
1667 #ifdef _MINOSL_
1668 return 0;
1669 #else
1670 char *buf, *endp;
1671 int i = 0;
1672 int val = 0;
1674 if ((buf = getvar(vars, name)) == NULL) {
1675 return (0);
1678 /* table values are always separated by "," or " " */
1679 while (*buf != '\0') {
1680 val = bcm_strtoul(buf, &endp, 0);
1681 if (i == index) {
1682 return val;
1684 buf = endp;
1685 /* delimiter is ',' */
1686 if (*buf == ',')
1687 buf++;
1688 i++;
1690 return 0;
1691 #endif /* _MINOSL_ */
1695 getintvararraysize(char *vars, const char *name)
1697 #ifdef _MINOSL_
1698 return 0;
1699 #else
1700 char *buf, *endp;
1701 int count = 0;
1702 int val = 0;
1704 if ((buf = getvar(vars, name)) == NULL) {
1705 return (0);
1708 /* table values are always separated by "," or " " */
1709 while (*buf != '\0') {
1710 val = bcm_strtoul(buf, &endp, 0);
1711 buf = endp;
1712 /* delimiter is ',' */
1713 if (*buf == ',')
1714 buf++;
1715 count++;
1717 BCM_REFERENCE(val);
1718 return count;
1719 #endif /* _MINOSL_ */
1722 /* Search for token in comma separated token-string */
1723 static int
1724 findmatch(const char *string, const char *name)
1726 uint len;
1727 char *c;
1729 len = strlen(name);
1730 while ((c = strchr(string, ',')) != NULL) {
1731 if (len == (uint)(c - string) && !strncmp(string, name, len))
1732 return 1;
1733 string = c + 1;
1736 return (!strcmp(string, name));
1739 /* Return gpio pin number assigned to the named pin
1741 * Variable should be in format:
1743 * gpio<N>=pin_name,pin_name
1745 * This format allows multiple features to share the gpio with mutual
1746 * understanding.
1748 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
1749 * and if def_pin is not used by others.
1751 uint
1752 getgpiopin(char *vars, char *pin_name, uint def_pin)
1754 char name[] = "gpioXXXX";
1755 char *val;
1756 uint pin;
1758 /* Go thru all possibilities till a match in pin name */
1759 for (pin = 0; pin < GPIO_NUMPINS; pin ++) {
1760 snprintf(name, sizeof(name), "gpio%d", pin);
1761 val = getvar(vars, name);
1762 if (val && findmatch(val, pin_name))
1763 return pin;
1766 if (def_pin != GPIO_PIN_NOTDEFINED) {
1767 /* make sure the default pin is not used by someone else */
1768 snprintf(name, sizeof(name), "gpio%d", def_pin);
1769 if (getvar(vars, name)) {
1770 def_pin = GPIO_PIN_NOTDEFINED;
1773 return def_pin;
1776 #if defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS)
1778 #define LOGSIZE 256 /* should be power of 2 to avoid div below */
1779 static struct {
1780 uint cycles;
1781 char *fmt;
1782 uint a1;
1783 uint a2;
1784 } logtab[LOGSIZE];
1786 /* last entry logged */
1787 static uint logi = 0;
1788 /* next entry to read */
1789 static uint readi = 0;
1790 #endif /* defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS) */
1792 #ifdef BCMPERFSTATS
1793 void
1794 bcm_perf_enable()
1796 BCMPERF_ENABLE_INSTRCOUNT();
1797 BCMPERF_ENABLE_ICACHE_MISS();
1798 BCMPERF_ENABLE_ICACHE_HIT();
1801 /* WARNING: This routine uses OSL_GETCYCLES(), which can give unexpected results on
1802 * modern speed stepping CPUs. Use bcmtslog() instead in combination with TSF counter.
1804 void
1805 bcmlog(char *fmt, uint a1, uint a2)
1807 static uint last = 0;
1808 uint cycles, i;
1809 OSL_GETCYCLES(cycles);
1811 i = logi;
1813 logtab[i].cycles = cycles - last;
1814 logtab[i].fmt = fmt;
1815 logtab[i].a1 = a1;
1816 logtab[i].a2 = a2;
1818 logi = (i + 1) % LOGSIZE;
1819 last = cycles;
1823 void
1824 bcmstats(char *fmt)
1826 static uint last = 0;
1827 static uint32 ic_miss = 0;
1828 static uint32 instr_count = 0;
1829 uint32 ic_miss_cur;
1830 uint32 instr_count_cur;
1831 uint cycles, i;
1833 OSL_GETCYCLES(cycles);
1834 BCMPERF_GETICACHE_MISS(ic_miss_cur);
1835 BCMPERF_GETINSTRCOUNT(instr_count_cur);
1837 i = logi;
1839 logtab[i].cycles = cycles - last;
1840 logtab[i].a1 = ic_miss_cur - ic_miss;
1841 logtab[i].a2 = instr_count_cur - instr_count;
1842 logtab[i].fmt = fmt;
1844 logi = (i + 1) % LOGSIZE;
1846 last = cycles;
1847 instr_count = instr_count_cur;
1848 ic_miss = ic_miss_cur;
1852 void
1853 bcmdumplog(char *buf, int size)
1855 char *limit;
1856 int j = 0;
1857 int num;
1859 limit = buf + size - 80;
1860 *buf = '\0';
1862 num = logi - readi;
1864 if (num < 0)
1865 num += LOGSIZE;
1867 /* print in chronological order */
1869 for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) {
1870 if (logtab[readi].fmt == NULL)
1871 continue;
1872 buf += snprintf(buf, (limit - buf), "%d\t", logtab[readi].cycles);
1873 buf += snprintf(buf, (limit - buf), logtab[readi].fmt, logtab[readi].a1,
1874 logtab[readi].a2);
1875 buf += snprintf(buf, (limit - buf), "\n");
1882 * Dump one log entry at a time.
1883 * Return index of next entry or -1 when no more .
1886 bcmdumplogent(char *buf, uint i)
1888 bool hit;
1891 * If buf is NULL, return the starting index,
1892 * interpreting i as the indicator of last 'i' entries to dump.
1894 if (buf == NULL) {
1895 i = ((i > 0) && (i < (LOGSIZE - 1))) ? i : (LOGSIZE - 1);
1896 return ((logi - i) % LOGSIZE);
1899 *buf = '\0';
1901 ASSERT(i < LOGSIZE);
1903 if (i == logi)
1904 return (-1);
1906 hit = FALSE;
1907 for (; (i != logi) && !hit; i = (i + 1) % LOGSIZE) {
1908 if (logtab[i].fmt == NULL)
1909 continue;
1910 buf += sprintf(buf, "%d: %d\t", i, logtab[i].cycles);
1911 buf += sprintf(buf, logtab[i].fmt, logtab[i].a1, logtab[i].a2);
1912 buf += sprintf(buf, "\n");
1913 hit = TRUE;
1916 return (i);
1919 #endif /* BCMPERFSTATS */
1921 #if defined(BCMTSTAMPEDLOGS)
1922 /* Store a TSF timestamp and a log line in the log buffer */
1923 void
1924 bcmtslog(uint32 tstamp, char *fmt, uint a1, uint a2)
1926 uint i = logi;
1927 bool use_delta = FALSE;
1928 static uint32 last = 0; /* used only when use_delta is true */
1930 logtab[i].cycles = tstamp;
1931 if (use_delta)
1932 logtab[i].cycles -= last;
1934 logtab[i].fmt = fmt;
1935 logtab[i].a1 = a1;
1936 logtab[i].a2 = a2;
1938 if (use_delta)
1939 last = tstamp;
1940 logi = (i + 1) % LOGSIZE;
1943 /* Print out a microsecond timestamp as "sec.ms.us " */
1944 void
1945 bcmprinttstamp(uint32 ticks)
1947 uint us, ms, sec;
1949 us = (ticks % TSF_TICKS_PER_MS) * 1000 / TSF_TICKS_PER_MS;
1950 ms = ticks / TSF_TICKS_PER_MS;
1951 sec = ms / 1000;
1952 ms -= sec * 1000;
1953 printf("%04u.%03u.%03u ", sec, ms, us);
1956 /* Print out the log buffer with timestamps */
1957 void
1958 bcmprinttslogs(void)
1960 int j = 0;
1961 int num;
1963 num = logi - readi;
1964 if (num < 0)
1965 num += LOGSIZE;
1967 /* Format and print the log entries directly in chronological order */
1968 for (j = 0; j < num; readi = (readi + 1) % LOGSIZE, j++) {
1969 if (logtab[readi].fmt == NULL)
1970 continue;
1971 bcmprinttstamp(logtab[readi].cycles);
1972 printf(logtab[readi].fmt, logtab[readi].a1, logtab[readi].a2);
1973 printf("\n");
1977 void
1978 bcmdumptslog(char *buf, int size)
1980 char *limit;
1981 int j = 0;
1982 int num;
1983 uint us, ms, sec;
1985 limit = buf + size - 80;
1986 *buf = '\0';
1988 num = logi - readi;
1990 if (num < 0)
1991 num += LOGSIZE;
1993 /* print in chronological order */
1994 for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) {
1995 if (logtab[readi].fmt == NULL)
1996 continue;
1997 us = (logtab[readi].cycles % TSF_TICKS_PER_MS) * 1000 / TSF_TICKS_PER_MS;
1998 ms = logtab[readi].cycles / TSF_TICKS_PER_MS;
1999 sec = ms / 1000;
2000 ms -= sec * 1000;
2002 buf += snprintf(buf, (limit - buf), "%04u.%03u.%03u ", sec, ms, us);
2003 /* buf += snprintf(buf, (limit - buf), "%d\t", logtab[readi].cycles); */
2004 buf += snprintf(buf, (limit - buf), logtab[readi].fmt, logtab[readi].a1,
2005 logtab[readi].a2);
2006 buf += snprintf(buf, (limit - buf), "\n");
2010 #endif /* BCMTSTAMPEDLOGS */
2012 #if defined(BCMDBG) || defined(DHD_DEBUG)
2013 /* pretty hex print a pkt buffer chain */
2014 void
2015 prpkt(const char *msg, osl_t *osh, void *p0)
2017 void *p;
2019 if (msg && (msg[0] != '\0'))
2020 printf("%s:\n", msg);
2022 for (p = p0; p; p = PKTNEXT(osh, p))
2023 prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
2025 #endif /* BCMDBG || DHD_DEBUG */
2027 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
2028 * Also updates the inplace vlan tag if requested.
2029 * For debugging, it returns an indication of what it did.
2031 uint BCMFASTPATH
2032 pktsetprio(void *pkt, bool update_vtag)
2034 struct ether_header *eh;
2035 struct ethervlan_header *evh;
2036 uint8 *pktdata;
2037 int priority = 0;
2038 int rc = 0;
2040 pktdata = (uint8 *)PKTDATA(NULL, pkt);
2041 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
2043 eh = (struct ether_header *) pktdata;
2045 if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) {
2046 uint16 vlan_tag;
2047 int vlan_prio, dscp_prio = 0;
2049 evh = (struct ethervlan_header *)eh;
2051 vlan_tag = ntoh16(evh->vlan_tag);
2052 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
2054 if (evh->ether_type == hton16(ETHER_TYPE_IP)) {
2055 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
2056 uint8 tos_tc = IP_TOS46(ip_body);
2057 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
2060 /* DSCP priority gets precedence over 802.1P (vlan tag) */
2061 if (dscp_prio != 0) {
2062 priority = dscp_prio;
2063 rc |= PKTPRIO_VDSCP;
2064 } else {
2065 priority = vlan_prio;
2066 rc |= PKTPRIO_VLAN;
2069 * If the DSCP priority is not the same as the VLAN priority,
2070 * then overwrite the priority field in the vlan tag, with the
2071 * DSCP priority value. This is required for Linux APs because
2072 * the VLAN driver on Linux, overwrites the skb->priority field
2073 * with the priority value in the vlan tag
2075 if (update_vtag && (priority != vlan_prio)) {
2076 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
2077 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
2078 evh->vlan_tag = hton16(vlan_tag);
2079 rc |= PKTPRIO_UPD;
2081 } else if (eh->ether_type == hton16(ETHER_TYPE_IP)) {
2082 uint8 *ip_body = pktdata + sizeof(struct ether_header);
2083 uint8 tos_tc = IP_TOS46(ip_body);
2084 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
2085 rc |= PKTPRIO_DSCP;
2088 ASSERT(priority >= 0 && priority <= MAXPRIO);
2089 PKTSETPRIO(pkt, priority);
2090 return (rc | priority);
2093 #ifndef BCM_BOOTLOADER
2095 static char bcm_undeferrstr[32];
2096 static const char *const bcmerrorstrtable[] = BCMERRSTRINGTABLE;
2098 /* Convert the error codes into related error strings */
2099 const char *
2100 bcmerrorstr(int bcmerror)
2102 /* check if someone added a bcmerror code but forgot to add errorstring */
2103 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
2105 if (bcmerror > 0 || bcmerror < BCME_LAST) {
2106 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
2107 return bcm_undeferrstr;
2110 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
2112 return bcmerrorstrtable[-bcmerror];
2115 #endif /* !BCM_BOOTLOADER */
2117 #ifdef WLC_LOW
2118 static void
2119 BCMINITFN(bcm_nvram_refresh)(char *flash)
2121 int i;
2122 int ret = 0;
2124 ASSERT(flash != NULL);
2126 /* default "empty" vars cache */
2127 bzero(flash, 2);
2129 if ((ret = nvram_getall(flash, NVRAM_SPACE)))
2130 return;
2132 /* determine nvram length */
2133 for (i = 0; i < NVRAM_SPACE; i++) {
2134 if (flash[i] == '\0' && flash[i+1] == '\0')
2135 break;
2138 if (i > 1)
2139 vars_len = i + 2;
2140 else
2141 vars_len = 0;
2144 char *
2145 bcm_nvram_vars(uint *length)
2147 #ifndef BCMNVRAMR
2148 /* cache may be stale if nvram is read/write */
2149 if (nvram_vars) {
2150 ASSERT(!bcmreclaimed);
2151 bcm_nvram_refresh(nvram_vars);
2153 #endif
2154 if (length)
2155 *length = vars_len;
2156 return nvram_vars;
2159 /* copy nvram vars into locally-allocated multi-string array */
2161 BCMINITFN(bcm_nvram_cache)(void *sih)
2163 int ret = 0;
2164 void *osh;
2165 char *flash = NULL;
2167 if (vars_len >= 0) {
2168 #ifndef BCMNVRAMR
2169 bcm_nvram_refresh(nvram_vars);
2170 #endif
2171 return 0;
2174 osh = si_osh((si_t *)sih);
2176 /* allocate memory and read in flash */
2177 if (!(flash = MALLOC(osh, NVRAM_SPACE))) {
2178 ret = BCME_NOMEM;
2179 goto exit;
2182 bcm_nvram_refresh(flash);
2184 #ifdef BCMNVRAMR
2185 if (vars_len > 3) {
2186 /* copy into a properly-sized buffer */
2187 if (!(nvram_vars = MALLOC(osh, vars_len))) {
2188 ret = BCME_NOMEM;
2189 } else
2190 bcopy(flash, nvram_vars, vars_len);
2192 MFREE(osh, flash, NVRAM_SPACE);
2193 #else
2194 /* cache must be full size of nvram if read/write */
2195 nvram_vars = flash;
2196 #endif /* BCMNVRAMR */
2198 exit:
2199 return ret;
2201 #endif /* WLC_LOW */
2204 /* iovar table lookup */
2205 const bcm_iovar_t*
2206 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
2208 const bcm_iovar_t *vi;
2209 const char *lookup_name;
2211 /* skip any ':' delimited option prefixes */
2212 lookup_name = strrchr(name, ':');
2213 if (lookup_name != NULL)
2214 lookup_name++;
2215 else
2216 lookup_name = name;
2218 ASSERT(table != NULL);
2220 for (vi = table; vi->name; vi++) {
2221 if (!strcmp(vi->name, lookup_name))
2222 return vi;
2224 /* ran to end of table */
2226 return NULL; /* var name not found */
2230 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
2232 int bcmerror = 0;
2234 /* length check on io buf */
2235 switch (vi->type) {
2236 case IOVT_BOOL:
2237 case IOVT_INT8:
2238 case IOVT_INT16:
2239 case IOVT_INT32:
2240 case IOVT_UINT8:
2241 case IOVT_UINT16:
2242 case IOVT_UINT32:
2243 /* all integers are int32 sized args at the ioctl interface */
2244 if (len < (int)sizeof(int)) {
2245 bcmerror = BCME_BUFTOOSHORT;
2247 break;
2249 case IOVT_BUFFER:
2250 /* buffer must meet minimum length requirement */
2251 if (len < vi->minlen) {
2252 bcmerror = BCME_BUFTOOSHORT;
2254 break;
2256 case IOVT_VOID:
2257 if (!set) {
2258 /* Cannot return nil... */
2259 bcmerror = BCME_UNSUPPORTED;
2260 } else if (len) {
2261 /* Set is an action w/o parameters */
2262 bcmerror = BCME_BUFTOOLONG;
2264 break;
2266 default:
2267 /* unknown type for length check in iovar info */
2268 ASSERT(0);
2269 bcmerror = BCME_UNSUPPORTED;
2272 return bcmerror;
2275 #endif /* BCMDRIVER */
2278 /*******************************************************************************
2279 * crc8
2281 * Computes a crc8 over the input data using the polynomial:
2283 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
2285 * The caller provides the initial value (either CRC8_INIT_VALUE
2286 * or the previous returned value) to allow for processing of
2287 * discontiguous blocks of data. When generating the CRC the
2288 * caller is responsible for complementing the final return value
2289 * and inserting it into the byte stream. When checking, a final
2290 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
2292 * Reference: Dallas Semiconductor Application Note 27
2293 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2294 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2295 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2297 * ****************************************************************************
2300 static const uint8 crc8_table[256] = {
2301 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
2302 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
2303 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
2304 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
2305 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
2306 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
2307 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
2308 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
2309 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
2310 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
2311 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
2312 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
2313 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
2314 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
2315 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
2316 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
2317 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
2318 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
2319 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
2320 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
2321 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
2322 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
2323 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
2324 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
2325 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
2326 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
2327 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
2328 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
2329 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
2330 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
2331 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
2332 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
2335 #define CRC_INNER_LOOP(n, c, x) \
2336 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
2338 uint8
2339 BCMROMFN(hndcrc8)(
2340 uint8 *pdata, /* pointer to array of data to process */
2341 uint nbytes, /* number of input data bytes to process */
2342 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
2345 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
2346 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
2348 while (nbytes-- > 0)
2349 crc = crc8_table[(crc ^ *pdata++) & 0xff];
2351 return crc;
2354 /*******************************************************************************
2355 * crc16
2357 * Computes a crc16 over the input data using the polynomial:
2359 * x^16 + x^12 +x^5 + 1
2361 * The caller provides the initial value (either CRC16_INIT_VALUE
2362 * or the previous returned value) to allow for processing of
2363 * discontiguous blocks of data. When generating the CRC the
2364 * caller is responsible for complementing the final return value
2365 * and inserting it into the byte stream. When checking, a final
2366 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
2368 * Reference: Dallas Semiconductor Application Note 27
2369 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2370 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2371 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2373 * ****************************************************************************
2376 static const uint16 crc16_table[256] = {
2377 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
2378 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
2379 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
2380 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
2381 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
2382 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
2383 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
2384 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
2385 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
2386 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
2387 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
2388 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
2389 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
2390 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
2391 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
2392 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
2393 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
2394 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
2395 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
2396 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
2397 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
2398 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
2399 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
2400 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
2401 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
2402 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
2403 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
2404 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
2405 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
2406 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
2407 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
2408 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
2411 uint16
2412 BCMROMFN(hndcrc16)(
2413 uint8 *pdata, /* pointer to array of data to process */
2414 uint nbytes, /* number of input data bytes to process */
2415 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
2418 while (nbytes-- > 0)
2419 CRC_INNER_LOOP(16, crc, *pdata++);
2420 return crc;
2423 static const uint32 crc32_table[256] = {
2424 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
2425 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
2426 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
2427 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
2428 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
2429 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
2430 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
2431 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
2432 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
2433 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
2434 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
2435 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
2436 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
2437 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
2438 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
2439 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
2440 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
2441 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
2442 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
2443 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
2444 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
2445 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
2446 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
2447 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
2448 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
2449 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
2450 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
2451 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
2452 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
2453 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
2454 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
2455 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
2456 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
2457 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
2458 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
2459 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
2460 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
2461 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
2462 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
2463 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
2464 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
2465 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
2466 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
2467 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
2468 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
2469 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
2470 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
2471 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
2472 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
2473 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
2474 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
2475 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
2476 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
2477 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
2478 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
2479 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
2480 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
2481 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
2482 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
2483 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
2484 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
2485 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
2486 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
2487 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
2491 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
2492 * accumulating over multiple pieces.
2494 uint32
2495 BCMROMFN(hndcrc32)(uint8 *pdata, uint nbytes, uint32 crc)
2497 uint8 *pend;
2498 #ifdef __mips__
2499 uint8 tmp[4];
2500 ulong *tptr = (ulong *)tmp;
2502 if (nbytes > 3) {
2503 /* in case the beginning of the buffer isn't aligned */
2504 pend = (uint8 *)((uint)(pdata + 3) & ~0x3);
2505 nbytes -= (pend - pdata);
2506 while (pdata < pend)
2507 CRC_INNER_LOOP(32, crc, *pdata++);
2510 if (nbytes > 3) {
2511 /* handle bulk of data as 32-bit words */
2512 pend = pdata + (nbytes & ~0x3);
2513 while (pdata < pend) {
2514 *tptr = *(ulong *)pdata;
2515 pdata += sizeof(ulong *);
2516 CRC_INNER_LOOP(32, crc, tmp[0]);
2517 CRC_INNER_LOOP(32, crc, tmp[1]);
2518 CRC_INNER_LOOP(32, crc, tmp[2]);
2519 CRC_INNER_LOOP(32, crc, tmp[3]);
2523 /* 1-3 bytes at end of buffer */
2524 pend = pdata + (nbytes & 0x03);
2525 while (pdata < pend)
2526 CRC_INNER_LOOP(32, crc, *pdata++);
2527 #else
2528 pend = pdata + nbytes;
2529 while (pdata < pend)
2530 CRC_INNER_LOOP(32, crc, *pdata++);
2531 #endif /* __mips__ */
2533 return crc;
2536 #ifdef notdef
2537 #define CLEN 1499 /* CRC Length */
2538 #define CBUFSIZ (CLEN+4)
2539 #define CNBUFS 5 /* # of bufs */
2541 void
2542 testcrc32(void)
2544 uint j, k, l;
2545 uint8 *buf;
2546 uint len[CNBUFS];
2547 uint32 crcr;
2548 uint32 crc32tv[CNBUFS] =
2549 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
2551 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
2553 /* step through all possible alignments */
2554 for (l = 0; l <= 4; l++) {
2555 for (j = 0; j < CNBUFS; j++) {
2556 len[j] = CLEN;
2557 for (k = 0; k < len[j]; k++)
2558 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
2561 for (j = 0; j < CNBUFS; j++) {
2562 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
2563 ASSERT(crcr == crc32tv[j]);
2567 MFREE(buf, CBUFSIZ*CNBUFS);
2568 return;
2570 #endif /* notdef */
2573 * Advance from the current 1-byte tag/1-byte length/variable-length value
2574 * triple, to the next, returning a pointer to the next.
2575 * If the current or next TLV is invalid (does not fit in given buffer length),
2576 * NULL is returned.
2577 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
2578 * by the TLV parameter's length if it is valid.
2580 bcm_tlv_t *
2581 BCMROMFN(bcm_next_tlv)(bcm_tlv_t *elt, int *buflen)
2583 int len;
2585 /* validate current elt */
2586 if (!bcm_valid_tlv(elt, *buflen))
2587 return NULL;
2589 /* advance to next elt */
2590 len = elt->len;
2591 elt = (bcm_tlv_t*)(elt->data + len);
2592 *buflen -= (TLV_HDR_LEN + len);
2594 /* validate next elt */
2595 if (!bcm_valid_tlv(elt, *buflen))
2596 return NULL;
2598 return elt;
2602 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2603 * triples, returning a pointer to the substring whose first element
2604 * matches tag
2606 bcm_tlv_t *
2607 BCMROMFN(bcm_parse_tlvs)(void *buf, int buflen, uint key)
2609 bcm_tlv_t *elt;
2610 int totlen;
2612 elt = (bcm_tlv_t*)buf;
2613 totlen = buflen;
2615 /* find tagged parameter */
2616 while (totlen >= TLV_HDR_LEN) {
2617 int len = elt->len;
2619 /* validate remaining totlen */
2620 if ((elt->id == key) &&
2621 (totlen >= (len + TLV_HDR_LEN)))
2622 return (elt);
2624 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
2625 totlen -= (len + TLV_HDR_LEN);
2628 return NULL;
2632 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2633 * triples, returning a pointer to the substring whose first element
2634 * matches tag. Stop parsing when we see an element whose ID is greater
2635 * than the target key.
2637 bcm_tlv_t *
2638 BCMROMFN(bcm_parse_ordered_tlvs)(void *buf, int buflen, uint key)
2640 bcm_tlv_t *elt;
2641 int totlen;
2643 elt = (bcm_tlv_t*)buf;
2644 totlen = buflen;
2646 /* find tagged parameter */
2647 while (totlen >= TLV_HDR_LEN) {
2648 uint id = elt->id;
2649 int len = elt->len;
2651 /* Punt if we start seeing IDs > than target key */
2652 if (id > key)
2653 return (NULL);
2655 /* validate remaining totlen */
2656 if ((id == key) &&
2657 (totlen >= (len + TLV_HDR_LEN)))
2658 return (elt);
2660 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
2661 totlen -= (len + TLV_HDR_LEN);
2663 return NULL;
2666 #if defined(BCMDBG) || defined(BCMDBG_ERR) || defined(WLMSG_PRHDRS) || \
2667 defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || defined(DHD_DEBUG)
2669 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
2671 int i;
2672 char* p = buf;
2673 char hexstr[16];
2674 int slen = 0, nlen = 0;
2675 uint32 bit;
2676 const char* name;
2678 if (len < 2 || !buf)
2679 return 0;
2681 buf[0] = '\0';
2683 for (i = 0; flags != 0; i++) {
2684 bit = bd[i].bit;
2685 name = bd[i].name;
2686 if (bit == 0 && flags != 0) {
2687 /* print any unnamed bits */
2688 snprintf(hexstr, 16, "0x%X", flags);
2689 name = hexstr;
2690 flags = 0; /* exit loop */
2691 } else if ((flags & bit) == 0)
2692 continue;
2693 flags &= ~bit;
2694 nlen = strlen(name);
2695 slen += nlen;
2696 /* count btwn flag space */
2697 if (flags != 0)
2698 slen += 1;
2699 /* need NULL char as well */
2700 if (len <= slen)
2701 break;
2702 /* copy NULL char but don't count it */
2703 strncpy(p, name, nlen + 1);
2704 p += nlen;
2705 /* copy btwn flag space and NULL char */
2706 if (flags != 0)
2707 p += snprintf(p, 2, " ");
2710 /* indicate the str was too short */
2711 if (flags != 0) {
2712 if (len < 2)
2713 p -= 2 - len; /* overwrite last char */
2714 p += snprintf(p, 2, ">");
2717 return (int)(p - buf);
2720 /* print bytes formatted as hex to a string. return the resulting string length */
2722 bcm_format_hex(char *str, const void *bytes, int len)
2724 int i;
2725 char *p = str;
2726 const uint8 *src = (const uint8*)bytes;
2728 for (i = 0; i < len; i++) {
2729 p += snprintf(p, 3, "%02X", *src);
2730 src++;
2732 return (int)(p - str);
2734 #endif
2736 /* pretty hex print a contiguous buffer */
2737 void
2738 prhex(const char *msg, uchar *buf, uint nbytes)
2740 char line[128], *p;
2741 int len = sizeof(line);
2742 int nchar;
2743 uint i;
2745 if (msg && (msg[0] != '\0'))
2746 printf("%s:\n", msg);
2748 p = line;
2749 for (i = 0; i < nbytes; i++) {
2750 if (i % 16 == 0) {
2751 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
2752 p += nchar;
2753 len -= nchar;
2755 if (len > 0) {
2756 nchar = snprintf(p, len, "%02x ", buf[i]);
2757 p += nchar;
2758 len -= nchar;
2761 if (i % 16 == 15) {
2762 printf("%s\n", line); /* flush line */
2763 p = line;
2764 len = sizeof(line);
2768 /* flush last partial line */
2769 if (p != line)
2770 printf("%s\n", line);
2773 static const char *crypto_algo_names[] = {
2774 "NONE",
2775 "WEP1",
2776 "TKIP",
2777 "WEP128",
2778 "AES_CCM",
2779 "AES_OCB_MSDU",
2780 "AES_OCB_MPDU",
2781 "NALG"
2782 "UNDEF",
2783 "UNDEF",
2784 "UNDEF",
2785 "UNDEF"
2788 const char *
2789 bcm_crypto_algo_name(uint algo)
2791 return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
2794 #ifdef BCMDBG
2795 void
2796 deadbeef(void *p, size_t len)
2798 static uint8 meat[] = { 0xde, 0xad, 0xbe, 0xef };
2800 while (len-- > 0) {
2801 *(uint8*)p = meat[((uintptr)p) & 3];
2802 p = (uint8*)p + 1;
2805 #endif /* BCMDBG */
2807 char *
2808 bcm_chipname(uint chipid, char *buf, uint len)
2810 const char *fmt;
2812 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
2813 snprintf(buf, len, fmt, chipid);
2814 return buf;
2817 /* Produce a human-readable string for boardrev */
2818 char *
2819 bcm_brev_str(uint32 brev, char *buf)
2821 if (brev < 0x100)
2822 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
2823 else
2824 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
2826 return (buf);
2829 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
2831 /* dump large strings to console */
2832 void
2833 printbig(char *buf)
2835 uint len, max_len;
2836 char c;
2838 len = strlen(buf);
2840 max_len = BUFSIZE_TODUMP_ATONCE;
2842 while (len > max_len) {
2843 c = buf[max_len];
2844 buf[max_len] = '\0';
2845 printf("%s", buf);
2846 buf[max_len] = c;
2848 buf += max_len;
2849 len -= max_len;
2851 /* print the remaining string */
2852 printf("%s\n", buf);
2853 return;
2856 /* routine to dump fields in a fileddesc structure */
2857 uint
2858 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
2859 char *buf, uint32 bufsize)
2861 uint filled_len;
2862 int len;
2863 struct fielddesc *cur_ptr;
2865 filled_len = 0;
2866 cur_ptr = fielddesc_array;
2868 while (bufsize > 1) {
2869 if (cur_ptr->nameandfmt == NULL)
2870 break;
2871 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
2872 read_rtn(arg0, arg1, cur_ptr->offset));
2873 /* check for snprintf overflow or error */
2874 if (len < 0 || (uint32)len >= bufsize)
2875 len = bufsize - 1;
2876 buf += len;
2877 bufsize -= len;
2878 filled_len += len;
2879 cur_ptr++;
2881 return filled_len;
2884 uint
2885 bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
2887 uint len;
2889 len = strlen(name) + 1;
2891 if ((len + datalen) > buflen)
2892 return 0;
2894 strncpy(buf, name, buflen);
2896 /* append data onto the end of the name string */
2897 memcpy(&buf[len], data, datalen);
2898 len += datalen;
2900 return len;
2903 /* Quarter dBm units to mW
2904 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
2905 * Table is offset so the last entry is largest mW value that fits in
2906 * a uint16.
2909 #define QDBM_OFFSET 153 /* Offset for first entry */
2910 #define QDBM_TABLE_LEN 40 /* Table size */
2912 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
2913 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
2915 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
2917 /* Largest mW value that will round down to the last table entry,
2918 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
2919 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
2921 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
2923 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
2924 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
2925 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
2926 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
2927 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
2928 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
2929 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
2932 uint16
2933 BCMROMFN(bcm_qdbm_to_mw)(uint8 qdbm)
2935 uint factor = 1;
2936 int idx = qdbm - QDBM_OFFSET;
2938 if (idx >= QDBM_TABLE_LEN) {
2939 /* clamp to max uint16 mW value */
2940 return 0xFFFF;
2943 /* scale the qdBm index up to the range of the table 0-40
2944 * where an offset of 40 qdBm equals a factor of 10 mW.
2946 while (idx < 0) {
2947 idx += 40;
2948 factor *= 10;
2951 /* return the mW value scaled down to the correct factor of 10,
2952 * adding in factor/2 to get proper rounding.
2954 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
2957 uint8
2958 BCMROMFN(bcm_mw_to_qdbm)(uint16 mw)
2960 uint8 qdbm;
2961 int offset;
2962 uint mw_uint = mw;
2963 uint boundary;
2965 /* handle boundary case */
2966 if (mw_uint <= 1)
2967 return 0;
2969 offset = QDBM_OFFSET;
2971 /* move mw into the range of the table */
2972 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
2973 mw_uint *= 10;
2974 offset -= 40;
2977 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
2978 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
2979 nqdBm_to_mW_map[qdbm])/2;
2980 if (mw_uint < boundary) break;
2983 qdbm += (uint8)offset;
2985 return (qdbm);
2989 uint
2990 BCMROMFN(bcm_bitcount)(uint8 *bitmap, uint length)
2992 uint bitcount = 0, i;
2993 uint8 tmp;
2994 for (i = 0; i < length; i++) {
2995 tmp = bitmap[i];
2996 while (tmp) {
2997 bitcount++;
2998 tmp &= (tmp - 1);
3001 return bitcount;
3004 #ifdef BCMDRIVER
3006 /* Initialization of bcmstrbuf structure */
3007 void
3008 bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
3010 b->origsize = b->size = size;
3011 b->origbuf = b->buf = buf;
3014 /* Buffer sprintf wrapper to guard against buffer overflow */
3016 bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
3018 va_list ap;
3019 int r;
3021 va_start(ap, fmt);
3023 r = vsnprintf(b->buf, b->size, fmt, ap);
3025 /* Non Ansi C99 compliant returns -1,
3026 * Ansi compliant return r >= b->size,
3027 * bcmstdlib returns 0, handle all
3029 /* r == 0 is also the case when strlen(fmt) is zero.
3030 * typically the case when "" is passed as argument.
3032 if ((r == -1) || (r >= (int)b->size)) {
3033 b->size = 0;
3034 } else {
3035 b->size -= r;
3036 b->buf += r;
3039 va_end(ap);
3041 return r;
3044 void
3045 bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len)
3047 int i;
3049 if (msg != NULL && msg[0] != '\0')
3050 bcm_bprintf(b, "%s", msg);
3051 for (i = 0; i < len; i ++)
3052 bcm_bprintf(b, "%02X", buf[i]);
3053 if (newline)
3054 bcm_bprintf(b, "\n");
3057 void
3058 bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
3060 int i;
3062 for (i = 0; i < num_bytes; i++) {
3063 num[i] += amount;
3064 if (num[i] >= amount)
3065 break;
3066 amount = 1;
3071 bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes)
3073 int i;
3075 for (i = nbytes - 1; i >= 0; i--) {
3076 if (arg1[i] != arg2[i])
3077 return (arg1[i] - arg2[i]);
3079 return 0;
3082 void
3083 bcm_print_bytes(const char *name, const uchar *data, int len)
3085 int i;
3086 int per_line = 0;
3088 printf("%s: %d \n", name ? name : "", len);
3089 for (i = 0; i < len; i++) {
3090 printf("%02x ", *data++);
3091 per_line++;
3092 if (per_line == 16) {
3093 per_line = 0;
3094 printf("\n");
3097 printf("\n");
3099 #if defined(WLTINYDUMP) || defined(BCMDBG) || defined(WLMSG_INFORM) || \
3100 defined(WLMSG_ASSOC) || defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
3101 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
3104 bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
3106 uint i, c;
3107 char *p = buf;
3108 char *endp = buf + SSID_FMT_BUF_LEN;
3110 if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
3112 for (i = 0; i < ssid_len; i++) {
3113 c = (uint)ssid[i];
3114 if (c == '\\') {
3115 *p++ = '\\';
3116 *p++ = '\\';
3117 } else if (bcm_isprint((uchar)c)) {
3118 *p++ = (char)c;
3119 } else {
3120 p += snprintf(p, (endp - p), "\\x%02X", c);
3123 *p = '\0';
3124 ASSERT(p < endp);
3126 return (int)(p - buf);
3128 #endif /* WLTINYDUMP || BCMDBG || WLMSG_INFORM || WLMSG_ASSOC || WLMSG_PRPKT */
3130 #endif /* BCMDRIVER */
3133 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
3134 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
3135 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
3136 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
3139 unsigned int
3140 process_nvram_vars(char *varbuf, unsigned int len)
3142 char *dp;
3143 bool findNewline;
3144 int column;
3145 unsigned int buf_len, n;
3146 unsigned int pad = 0;
3148 dp = varbuf;
3150 findNewline = FALSE;
3151 column = 0;
3153 for (n = 0; n < len; n++) {
3154 if (varbuf[n] == '\r')
3155 continue;
3156 if (findNewline && varbuf[n] != '\n')
3157 continue;
3158 findNewline = FALSE;
3159 if (varbuf[n] == '#') {
3160 findNewline = TRUE;
3161 continue;
3163 if (varbuf[n] == '\n') {
3164 if (column == 0)
3165 continue;
3166 *dp++ = 0;
3167 column = 0;
3168 continue;
3170 *dp++ = varbuf[n];
3171 column++;
3173 buf_len = (unsigned int)(dp - varbuf);
3174 if (buf_len % 4) {
3175 pad = 4 - buf_len % 4;
3176 if (pad && (buf_len + pad <= len)) {
3177 buf_len += pad;
3181 while (dp < varbuf + n)
3182 *dp++ = 0;
3184 return buf_len;