2 * Driver O/S-independent utility routines
4 * Copyright (C) 2011, Broadcom Corporation. All Rights Reserved.
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.
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 $
23 #if defined(__FreeBSD__) || defined(__NetBSD__)
24 #include <machine/stdarg.h>
35 #else /* !BCMDRIVER */
41 #if defined(BCMEXTSUP)
46 #endif /* !BCMDRIVER */
48 #if defined(_WIN32) || defined(NDIS) || defined(__vxworks) || defined(_CFE_)
49 #include <bcmstdlib.h>
51 #include <bcmendian.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>
61 #include <proto/bcmipv6.h>
62 void *_bcmutils_dummy_fn
= NULL
;
67 /* nvram vars cache */
68 static char *nvram_vars
= NULL
;
69 static int vars_len
= -1;
73 pktpool_init(osl_t
*osh
, pktpool_t
*pktp
, int *pplen
, int plen
, bool istx
)
81 ASSERT(pplen
!= NULL
);
85 bzero(pktp
, sizeof(pktpool_t
));
87 pktp
->istx
= istx
? TRUE
: FALSE
;
88 pktp
->plen
= (uint16
)plen
;
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
);
98 /* Not able to allocate all requested pkts
99 * so just return what was actually allocated
100 * We can add to the pool later
108 PKTSETPOOL(osh
, p
, TRUE
, pktp
);
113 pktp
->dbg_q
[pktp
->dbg_qlen
++].p
= p
;
119 pktp
->len
++; /* Add one for end */
124 pktpool_deinit(osl_t
*osh
, pktpool_t
*pktp
)
130 ASSERT(pktp
!= NULL
);
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
);
141 if (pktp
->dbg_q
[i
].p
!= NULL
)
142 pktp
->dbg_q
[i
].p
= NULL
;
145 pktp
->inited
= FALSE
;
147 /* Are there still pending pkts? */
148 ASSERT(pktpool_len(pktp
) == 0);
154 pktpool_fill(osl_t
*osh
, pktpool_t
*pktp
, bool minimal
)
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
);
172 if (pktpool_add(pktp
, p
) != BCME_OK
) {
173 PKTFREE(osh
, p
, FALSE
);
183 pktpool_avail(pktpool_t
*pktp
)
185 if (pktp
->w
== pktp
->r
)
188 return (pktp
->w
> pktp
->r
) ? (pktp
->w
- pktp
->r
) : ((pktp
->len
) - (pktp
->r
- pktp
->w
));
192 pktpool_deq(pktpool_t
*pktp
)
196 if (pktp
->r
== pktp
->w
)
199 p
= pktp
->q
[pktp
->r
];
202 pktp
->q
[pktp
->r
++] = NULL
;
203 pktp
->r
%= (pktp
->len
);
209 pktpool_enq(pktpool_t
*pktp
, void *p
)
215 next
= (pktp
->w
+ 1) % (pktp
->len
);
216 if (next
== pktp
->r
) {
217 /* Should not happen; otherwise pkt leak */
222 ASSERT(pktp
->q
[pktp
->w
] == NULL
);
224 pktp
->q
[pktp
->w
] = p
;
229 pktpool_avail_register(pktpool_t
*pktp
, pktpool_cb_t cb
, void *arg
)
236 if (i
== PKTPOOL_CB_MAX
)
239 ASSERT(pktp
->cbs
[i
].cb
== NULL
);
240 pktp
->cbs
[i
].cb
= cb
;
241 pktp
->cbs
[i
].arg
= arg
;
248 pktpool_empty_register(pktpool_t
*pktp
, pktpool_cb_t cb
, void *arg
)
255 if (i
== PKTPOOL_CB_MAX
)
258 ASSERT(pktp
->ecbs
[i
].cb
== NULL
);
259 pktp
->ecbs
[i
].cb
= cb
;
260 pktp
->ecbs
[i
].arg
= arg
;
267 pktpool_empty_notify(pktpool_t
*pktp
)
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
);
283 pktpool_dbg_register(pktpool_t
*pktp
, pktpool_cb_t cb
, void *arg
)
290 if (i
== PKTPOOL_CB_MAX
)
293 ASSERT(pktp
->dbg_cbs
[i
].cb
== NULL
);
294 pktp
->dbg_cbs
[i
].cb
= cb
;
295 pktp
->dbg_cbs
[i
].arg
= arg
;
301 int pktpool_dbg_notify(pktpool_t
*pktp
);
304 pktpool_dbg_notify(pktpool_t
*pktp
)
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
);
317 pktpool_dbg_dump(pktpool_t
*pktp
)
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
));
332 pktpool_stats_dump(pktpool_t
*pktp
, pktpool_stats_t
*stats
)
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
);
346 stats
->txdh
++; break;
348 stats
->txd11
++; break;
350 stats
->rxdh
++; break;
352 stats
->rxd11
++; break;
354 stats
->rxfill
++; break;
356 stats
->idle
++; break;
364 pktpool_start_trigger(pktpool_t
*pktp
, void *p
)
368 if (!PKTPOOL(NULL
, p
))
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
;
385 int pktpool_stop_trigger(pktpool_t
*pktp
, void *p
);
387 pktpool_stop_trigger(pktpool_t
*pktp
, void *p
)
391 if (!PKTPOOL(NULL
, p
))
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)
403 if (cycles
>= pktp
->dbg_q
[i
].cycles
)
404 pktp
->dbg_q
[i
].dur
= cycles
- pktp
->dbg_q
[i
].cycles
;
407 (((uint32
)-1) - pktp
->dbg_q
[i
].cycles
) + cycles
+ 1;
409 pktp
->dbg_q
[i
].cycles
= 0;
416 #endif /* BCMDBG_POOL */
419 pktpool_avail_notify_normal(osl_t
*osh
, pktpool_t
*pktp
)
422 pktp
->availcb_excl
= NULL
;
427 pktpool_avail_notify_exclusive(osl_t
*osh
, pktpool_t
*pktp
, pktpool_cb_t cb
)
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
];
440 if (pktp
->availcb_excl
== NULL
)
447 pktpool_avail_notify(pktpool_t
*pktp
)
453 if (pktp
->availcb_excl
!= NULL
) {
454 pktp
->availcb_excl
->cb(pktp
, pktp
->availcb_excl
->arg
);
459 for (i
= 0; i
< pktp
->cbcnt
; i
++) {
460 avail
= pktpool_avail(pktp
);
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
481 pktpool_get(pktpool_t
*pktp
)
485 p
= pktpool_deq(pktp
);
488 /* Notify and try to reclaim tx pkts */
490 pktpool_empty_notify(pktp
);
492 p
= pktpool_deq(pktp
);
499 pktpool_free(pktpool_t
*pktp
, void *p
)
504 /* pktpool_stop_trigger(pktp, p); */
507 pktpool_enq(pktp
, p
);
509 if (pktp
->emptycb_disable
)
513 if (pktp
->empty
== FALSE
)
514 pktpool_avail_notify(pktp
);
519 pktpool_add(pktpool_t
*pktp
, void *p
)
523 if (pktpool_len(pktp
) == pktp
->maxlen
)
526 ASSERT(pktpool_plen(pktp
) == PKTLEN(NULL
, p
)); /* pkts in pool have same length */
527 PKTSETPOOL(NULL
, p
, TRUE
, pktp
);
530 if (pktp
->r
> pktp
->w
) {
532 ASSERT(pktp
->q
[pktp
->len
- 1] == NULL
);
533 pktp
->q
[pktp
->len
- 1] = p
;
535 pktpool_enq(pktp
, p
);
538 pktp
->dbg_q
[pktp
->dbg_qlen
++].p
= p
;
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
554 pktp
->maxlen
= (pktpool_len(pktp
) > maxlen
) ? pktpool_len(pktp
) : maxlen
;
560 pktpool_emptycb_disable(pktpool_t
*pktp
, bool disable
)
564 pktp
->emptycb_disable
= disable
;
568 pktpool_emptycb_disabled(pktpool_t
*pktp
)
571 return pktp
->emptycb_disable
;
574 /* copy a pkt buffer chain into a buffer */
576 pktcopy(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
581 len
= 4096; /* "infinite" */
583 /* skip 'offset' bytes */
584 for (; p
&& offset
; p
= PKTNEXT(osh
, p
)) {
585 if (offset
< (uint
)PKTLEN(osh
, p
))
587 offset
-= PKTLEN(osh
, p
);
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
);
606 /* copy a buffer into a pkt buffer chain */
608 pktfrombuf(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
612 /* skip 'offset' bytes */
613 for (; p
&& offset
; p
= PKTNEXT(osh
, p
)) {
614 if (offset
< (uint
)PKTLEN(osh
, p
))
616 offset
-= PKTLEN(osh
, p
);
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
);
636 /* copy data from one pkt buffer (chain) to another */
638 pkt2pktcopy(osl_t
*osh
, void *p1
, uint offs1
, void *p2
, uint offs2
, int maxlen
)
641 uint len1
, len2
, copylen
, totallen
;
643 for (; p1
&& offs
; p1
= PKTNEXT(osh
, p1
)) {
644 if (offs1
< (uint
)PKTLEN(osh
, p1
))
646 offs1
-= PKTLEN(osh
, p1
);
648 for (; p2
&& offs
; p2
= PKTNEXT(osh
, p2
)) {
649 if (offs2
< (uint
)PKTLEN(osh
, p2
))
651 offs2
-= PKTLEN(osh
, p2
);
654 /* Heck w/it, only need the above for now */
659 /* return total length of buffer chain */
661 pkttotlen(osl_t
*osh
, void *p
)
667 for (; p
; p
= PKTNEXT(osh
, p
)) {
668 len
= PKTLEN(osh
, p
);
671 /* Bad packet length, just drop and exit */
672 printf("wl: pkttotlen bad (%p,%d)\n", p
, len
);
682 /* return the last buffer of chained pkt */
684 pktlast(osl_t
*osh
, void *p
)
686 for (; PKTNEXT(osh
, p
); p
= PKTNEXT(osh
, p
))
692 /* count segments of a chained packet */
694 pktsegcnt(osl_t
*osh
, void *p
)
698 for (cnt
= 0; p
; p
= PKTNEXT(osh
, p
))
705 /* count segments of a chained packet */
707 pktsegcnt_war(osl_t
*osh
, void *p
)
711 uint len
, remain
, align64
;
713 for (cnt
= 0; p
; p
= PKTNEXT(osh
, p
)) {
715 len
= PKTLEN(osh
, p
);
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))
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 */
727 if (remain
> 0 && remain
<= 4)
728 cnt
++; /* add extra seg */
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
);
745 for (; p
; p
= PKTNEXT(osh
, p
)) {
746 pdata
= (uint8
*) PKTDATA(osh
, p
);
747 pkt_off
= offset
- len
;
748 len
+= PKTLEN(osh
, p
);
752 return (uint8
*) (pdata
+pkt_off
);
756 /* given a offset in pdata, find the pkt seg hdr */
758 pktoffset(osl_t
*osh
, void *p
, uint offset
)
760 uint total
= pkttotlen(osh
, p
);
766 for (; p
; p
= PKTNEXT(osh
, p
)) {
767 len
+= PKTLEN(osh
, p
);
775 * osl multiple-precedence packet queue
776 * hi_prec is always >= the number of the highest non-empty precedence
779 pktq_penq(struct pktq
*pq
, int prec
, void *p
)
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
));
792 PKTSETLINK(q
->tail
, p
);
801 if (pq
->hi_prec
< prec
)
802 pq
->hi_prec
= (uint8
)prec
;
808 pktq_penq_head(struct pktq
*pq
, int prec
, void *p
)
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
));
823 PKTSETLINK(p
, q
->head
);
829 if (pq
->hi_prec
< prec
)
830 pq
->hi_prec
= (uint8
)prec
;
836 pktq_pdeq(struct pktq
*pq
, int prec
)
841 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
845 if ((p
= q
->head
) == NULL
)
848 if ((q
->head
= PKTLINK(p
)) == NULL
)
861 pktq_pdeq_prev(struct pktq
*pq
, int prec
, void *prev_p
)
866 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
873 if ((p
= PKTLINK(prev_p
)) == NULL
)
883 PKTSETLINK(prev_p
, PKTLINK(p
));
890 pktq_pdeq_tail(struct pktq
*pq
, int prec
)
895 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
899 if ((p
= q
->head
) == NULL
)
902 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK(p
))
906 PKTSETLINK(prev
, NULL
);
919 pktq_pflush(osl_t
*osh
, struct pktq
*pq
, int prec
, bool dir
, ifpkt_cb_t fn
, int arg
)
922 void *p
, *prev
= NULL
;
927 if (fn
== NULL
|| (*fn
)(p
, arg
)) {
928 bool head
= (p
== q
->head
);
930 q
->head
= PKTLINK(p
);
932 PKTSETLINK(prev
, PKTLINK(p
));
934 PKTFREE(osh
, p
, dir
);
937 p
= (head
? q
->head
: PKTLINK(prev
));
944 if (q
->head
== NULL
) {
951 pktq_pdel(struct pktq
*pq
, void *pktbuf
, int prec
)
956 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
963 if (q
->head
== pktbuf
) {
964 if ((q
->head
= PKTLINK(pktbuf
)) == NULL
)
967 for (p
= q
->head
; p
&& PKTLINK(p
) != pktbuf
; p
= PKTLINK(p
))
972 PKTSETLINK(p
, PKTLINK(pktbuf
));
973 if (q
->tail
== pktbuf
)
979 PKTSETLINK(pktbuf
, NULL
);
984 pktq_init(struct pktq
*pq
, int num_prec
, int max_len
)
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
;
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
;
1011 pktq_deq(struct pktq
*pq
, int *prec_out
)
1013 struct pktq_prec
*q
;
1020 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
1025 if ((p
= q
->head
) == NULL
)
1028 if ((q
->head
= PKTLINK(p
)) == NULL
)
1038 PKTSETLINK(p
, NULL
);
1044 pktq_deq_tail(struct pktq
*pq
, int *prec_out
)
1046 struct pktq_prec
*q
;
1053 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
1054 if (pq
->q
[prec
].head
)
1059 if ((p
= q
->head
) == NULL
)
1062 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK(p
))
1066 PKTSETLINK(prev
, NULL
);
1078 PKTSETLINK(p
, NULL
);
1084 pktq_peek(struct pktq
*pq
, int *prec_out
)
1091 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
1097 return (pq
->q
[prec
].head
);
1101 pktq_peek_tail(struct pktq
*pq
, int *prec_out
)
1108 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
1109 if (pq
->q
[prec
].head
)
1115 return (pq
->q
[prec
].tail
);
1119 pktq_flush(osl_t
*osh
, struct pktq
*pq
, bool dir
, ifpkt_cb_t fn
, int arg
)
1123 /* Optimize flush, if pktq len = 0, just return.
1124 * pktq len of 0 means pktq's prec q's are all empty.
1130 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
1131 pktq_pflush(osh
, pq
, prec
, dir
, fn
, arg
);
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
)
1144 for (prec
= 0; prec
<= pq
->hi_prec
; prec
++)
1145 if (prec_bmp
& (1 << prec
))
1146 len
+= pq
->q
[prec
].len
;
1151 /* Priority peek from a specific set of precedences */
1153 pktq_mpeek(struct pktq
*pq
, uint prec_bmp
, int *prec_out
)
1155 struct pktq_prec
*q
;
1163 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
1166 while ((prec_bmp
& (1 << prec
)) == 0 || pq
->q
[prec
].head
== NULL
)
1172 if ((p
= q
->head
) == NULL
)
1180 /* Priority dequeue from a specific set of precedences */
1182 pktq_mdeq(struct pktq
*pq
, uint prec_bmp
, int *prec_out
)
1184 struct pktq_prec
*q
;
1191 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
1194 while ((pq
->q
[prec
].head
== NULL
) || ((prec_bmp
& (1 << prec
)) == 0))
1200 if ((p
= q
->head
) == NULL
)
1203 if ((q
->head
= PKTLINK(p
)) == NULL
)
1213 PKTSETLINK(p
, NULL
);
1218 #endif /* BCMDRIVER */
1220 #if defined(BCMROMBUILD)
1221 const unsigned char BCMROMDATA(bcm_ctype
)[] = {
1223 const unsigned char bcm_ctype
[] = {
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
,
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 */
1262 BCMROMFN(bcm_strtoul
)(const char *cp
, char **endp
, uint base
)
1264 ulong result
, last_result
= 0, value
;
1269 while (bcm_isspace(*cp
))
1274 else if (cp
[0] == '-') {
1281 if ((cp
[1] == 'x') || (cp
[1] == 'X')) {
1290 } else if (base
== 16 && (cp
[0] == '0') && ((cp
[1] == 'x') || (cp
[1] == 'X'))) {
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
)
1302 last_result
= result
;
1307 result
= (ulong
)(-(long)result
);
1310 *endp
= DISCARD_QUAL(cp
, char);
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' */
1323 BCMROMFN(bcmstrstr
)(const char *haystack
, const char *needle
)
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);
1341 BCMROMFN(bcmstrcat
)(char *dest
, const char *src
)
1345 p
= dest
+ strlen(dest
);
1347 while ((*p
++ = *src
++) != '\0')
1354 BCMROMFN(bcmstrncat
)(char *dest
, const char *src
, uint size
)
1359 p
= dest
+ strlen(dest
);
1362 while (p
!= endp
&& (*p
++ = *src
++) != '\0')
1369 /****************************************************************************
1370 * Function: bcmstrtok
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.
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 *****************************************************************************
1389 bcmstrtok(char **string
, const char *delimiters
, char *tokdelim
)
1392 unsigned long map
[8];
1396 if (tokdelim
!= NULL
) {
1397 /* Prime the token delimiter */
1401 /* Clear control map */
1402 for (count
= 0; count
< 8; count
++) {
1406 /* Set bits in delimiter table */
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
== ' ')) {
1422 nextoken
= (char*)str
;
1424 /* Find the end of the token. If it is not the end of the string,
1427 for (; *str
; str
++) {
1428 if (map
[*str
>> 5] & (1 << (*str
& 31))) {
1429 if (tokdelim
!= NULL
) {
1438 *string
= (char*)str
;
1440 /* Determine if a token has been found. */
1441 if (nextoken
== (char *) str
) {
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
)
1471 while (*s2
&& *s1
) {
1474 if (dc
< sc
) return -1;
1475 if (dc
> sc
) return 1;
1480 if (*s1
&& !*s2
) return 1;
1481 if (!*s1
&& *s2
) return -1;
1486 /****************************************************************************
1487 * Function: bcmstrnicmp
1489 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
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
)
1505 while (*s2
&& *s1
&& cnt
) {
1508 if (dc
< sc
) return -1;
1509 if (dc
> sc
) return 1;
1516 if (*s1
&& !*s2
) return 1;
1517 if (!*s1
&& *s2
) return -1;
1521 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
1523 BCMROMFN(bcm_ether_atoe
)(const char *p
, struct ether_addr
*ea
)
1529 ea
->octet
[i
++] = (char) bcm_strtoul(p
, &ep
, 16);
1531 if (!*p
++ || 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)
1545 wchar2ascii(char *abuf
, ushort
*wbuf
, ushort wbuflen
, ulong abuflen
)
1553 /* wbuflen is in bytes */
1554 wbuflen
/= sizeof(ushort
);
1556 for (i
= 0; i
< wbuflen
; ++i
) {
1559 *abuf
++ = (char) *wbuf
++;
1566 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
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
;
1580 for (i
= 0; i
< 6; i
++, octet
++) {
1581 *p
++ = hex
[(*octet
>> 4) & 0xf];
1582 *p
++ = hex
[*octet
& 0xf];
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]);
1606 for (i
= 0; i
< ms
; i
++) {
1612 * Search the name=value vars for a specific one and return its value.
1613 * Returns NULL if not found.
1616 getvar(char *vars
, const char *name
)
1631 /* first look in vars[] */
1632 for (s
= vars
; s
&& *s
;) {
1633 if ((bcmp(s
, name
, len
) == 0) && (s
[len
] == '='))
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
)
1657 if ((val
= getvar(vars
, name
)) == NULL
)
1660 return (bcm_strtoul(val
, NULL
, 0));
1661 #endif /* _MINOSL_ */
1665 getintvararray(char *vars
, const char *name
, int index
)
1674 if ((buf
= getvar(vars
, name
)) == NULL
) {
1678 /* table values are always separated by "," or " " */
1679 while (*buf
!= '\0') {
1680 val
= bcm_strtoul(buf
, &endp
, 0);
1685 /* delimiter is ',' */
1691 #endif /* _MINOSL_ */
1695 getintvararraysize(char *vars
, const char *name
)
1704 if ((buf
= getvar(vars
, name
)) == NULL
) {
1708 /* table values are always separated by "," or " " */
1709 while (*buf
!= '\0') {
1710 val
= bcm_strtoul(buf
, &endp
, 0);
1712 /* delimiter is ',' */
1719 #endif /* _MINOSL_ */
1722 /* Search for token in comma separated token-string */
1724 findmatch(const char *string
, const char *name
)
1730 while ((c
= strchr(string
, ',')) != NULL
) {
1731 if (len
== (uint
)(c
- string
) && !strncmp(string
, name
, len
))
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
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.
1752 getgpiopin(char *vars
, char *pin_name
, uint def_pin
)
1754 char name
[] = "gpioXXXX";
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
))
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
;
1776 #if defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS)
1778 #define LOGSIZE 256 /* should be power of 2 to avoid div below */
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) */
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.
1805 bcmlog(char *fmt
, uint a1
, uint a2
)
1807 static uint last
= 0;
1809 OSL_GETCYCLES(cycles
);
1813 logtab
[i
].cycles
= cycles
- last
;
1814 logtab
[i
].fmt
= fmt
;
1818 logi
= (i
+ 1) % LOGSIZE
;
1826 static uint last
= 0;
1827 static uint32 ic_miss
= 0;
1828 static uint32 instr_count
= 0;
1830 uint32 instr_count_cur
;
1833 OSL_GETCYCLES(cycles
);
1834 BCMPERF_GETICACHE_MISS(ic_miss_cur
);
1835 BCMPERF_GETINSTRCOUNT(instr_count_cur
);
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
;
1847 instr_count
= instr_count_cur
;
1848 ic_miss
= ic_miss_cur
;
1853 bcmdumplog(char *buf
, int size
)
1859 limit
= buf
+ size
- 80;
1867 /* print in chronological order */
1869 for (j
= 0; j
< num
&& (buf
< limit
); readi
= (readi
+ 1) % LOGSIZE
, j
++) {
1870 if (logtab
[readi
].fmt
== NULL
)
1872 buf
+= snprintf(buf
, (limit
- buf
), "%d\t", logtab
[readi
].cycles
);
1873 buf
+= snprintf(buf
, (limit
- buf
), logtab
[readi
].fmt
, logtab
[readi
].a1
,
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
)
1891 * If buf is NULL, return the starting index,
1892 * interpreting i as the indicator of last 'i' entries to dump.
1895 i
= ((i
> 0) && (i
< (LOGSIZE
- 1))) ? i
: (LOGSIZE
- 1);
1896 return ((logi
- i
) % LOGSIZE
);
1901 ASSERT(i
< LOGSIZE
);
1907 for (; (i
!= logi
) && !hit
; i
= (i
+ 1) % LOGSIZE
) {
1908 if (logtab
[i
].fmt
== NULL
)
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");
1919 #endif /* BCMPERFSTATS */
1921 #if defined(BCMTSTAMPEDLOGS)
1922 /* Store a TSF timestamp and a log line in the log buffer */
1924 bcmtslog(uint32 tstamp
, char *fmt
, uint a1
, uint a2
)
1927 bool use_delta
= FALSE
;
1928 static uint32 last
= 0; /* used only when use_delta is true */
1930 logtab
[i
].cycles
= tstamp
;
1932 logtab
[i
].cycles
-= last
;
1934 logtab
[i
].fmt
= fmt
;
1940 logi
= (i
+ 1) % LOGSIZE
;
1943 /* Print out a microsecond timestamp as "sec.ms.us " */
1945 bcmprinttstamp(uint32 ticks
)
1949 us
= (ticks
% TSF_TICKS_PER_MS
) * 1000 / TSF_TICKS_PER_MS
;
1950 ms
= ticks
/ TSF_TICKS_PER_MS
;
1953 printf("%04u.%03u.%03u ", sec
, ms
, us
);
1956 /* Print out the log buffer with timestamps */
1958 bcmprinttslogs(void)
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
)
1971 bcmprinttstamp(logtab
[readi
].cycles
);
1972 printf(logtab
[readi
].fmt
, logtab
[readi
].a1
, logtab
[readi
].a2
);
1978 bcmdumptslog(char *buf
, int size
)
1985 limit
= buf
+ size
- 80;
1993 /* print in chronological order */
1994 for (j
= 0; j
< num
&& (buf
< limit
); readi
= (readi
+ 1) % LOGSIZE
, j
++) {
1995 if (logtab
[readi
].fmt
== NULL
)
1997 us
= (logtab
[readi
].cycles
% TSF_TICKS_PER_MS
) * 1000 / TSF_TICKS_PER_MS
;
1998 ms
= logtab
[readi
].cycles
/ TSF_TICKS_PER_MS
;
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
,
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 */
2015 prpkt(const char *msg
, osl_t
*osh
, void *p0
)
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.
2032 pktsetprio(void *pkt
, bool update_vtag
)
2034 struct ether_header
*eh
;
2035 struct ethervlan_header
*evh
;
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
)) {
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
;
2065 priority
= vlan_prio
;
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
);
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
);
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 */
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 */
2119 BCMINITFN(bcm_nvram_refresh
)(char *flash
)
2124 ASSERT(flash
!= NULL
);
2126 /* default "empty" vars cache */
2129 if ((ret
= nvram_getall(flash
, NVRAM_SPACE
)))
2132 /* determine nvram length */
2133 for (i
= 0; i
< NVRAM_SPACE
; i
++) {
2134 if (flash
[i
] == '\0' && flash
[i
+1] == '\0')
2145 bcm_nvram_vars(uint
*length
)
2148 /* cache may be stale if nvram is read/write */
2150 ASSERT(!bcmreclaimed
);
2151 bcm_nvram_refresh(nvram_vars
);
2159 /* copy nvram vars into locally-allocated multi-string array */
2161 BCMINITFN(bcm_nvram_cache
)(void *sih
)
2167 if (vars_len
>= 0) {
2169 bcm_nvram_refresh(nvram_vars
);
2174 osh
= si_osh((si_t
*)sih
);
2176 /* allocate memory and read in flash */
2177 if (!(flash
= MALLOC(osh
, NVRAM_SPACE
))) {
2182 bcm_nvram_refresh(flash
);
2186 /* copy into a properly-sized buffer */
2187 if (!(nvram_vars
= MALLOC(osh
, vars_len
))) {
2190 bcopy(flash
, nvram_vars
, vars_len
);
2192 MFREE(osh
, flash
, NVRAM_SPACE
);
2194 /* cache must be full size of nvram if read/write */
2196 #endif /* BCMNVRAMR */
2201 #endif /* WLC_LOW */
2204 /* iovar table lookup */
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
)
2218 ASSERT(table
!= NULL
);
2220 for (vi
= table
; vi
->name
; vi
++) {
2221 if (!strcmp(vi
->name
, lookup_name
))
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
)
2234 /* length check on io buf */
2243 /* all integers are int32 sized args at the ioctl interface */
2244 if (len
< (int)sizeof(int)) {
2245 bcmerror
= BCME_BUFTOOSHORT
;
2250 /* buffer must meet minimum length requirement */
2251 if (len
< vi
->minlen
) {
2252 bcmerror
= BCME_BUFTOOSHORT
;
2258 /* Cannot return nil... */
2259 bcmerror
= BCME_UNSUPPORTED
;
2261 /* Set is an action w/o parameters */
2262 bcmerror
= BCME_BUFTOOLONG
;
2267 /* unknown type for length check in iovar info */
2269 bcmerror
= BCME_UNSUPPORTED
;
2275 #endif /* BCMDRIVER */
2278 /*******************************************************************************
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]
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];
2354 /*******************************************************************************
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
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
++);
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.
2495 BCMROMFN(hndcrc32
)(uint8
*pdata
, uint nbytes
, uint32 crc
)
2500 ulong
*tptr
= (ulong
*)tmp
;
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
++);
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
++);
2528 pend
= pdata
+ nbytes
;
2529 while (pdata
< pend
)
2530 CRC_INNER_LOOP(32, crc
, *pdata
++);
2531 #endif /* __mips__ */
2537 #define CLEN 1499 /* CRC Length */
2538 #define CBUFSIZ (CLEN+4)
2539 #define CNBUFS 5 /* # of bufs */
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
++) {
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
);
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),
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.
2581 BCMROMFN(bcm_next_tlv
)(bcm_tlv_t
*elt
, int *buflen
)
2585 /* validate current elt */
2586 if (!bcm_valid_tlv(elt
, *buflen
))
2589 /* advance to next elt */
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
))
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
2607 BCMROMFN(bcm_parse_tlvs
)(void *buf
, int buflen
, uint key
)
2612 elt
= (bcm_tlv_t
*)buf
;
2615 /* find tagged parameter */
2616 while (totlen
>= TLV_HDR_LEN
) {
2619 /* validate remaining totlen */
2620 if ((elt
->id
== key
) &&
2621 (totlen
>= (len
+ TLV_HDR_LEN
)))
2624 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ TLV_HDR_LEN
));
2625 totlen
-= (len
+ TLV_HDR_LEN
);
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.
2638 BCMROMFN(bcm_parse_ordered_tlvs
)(void *buf
, int buflen
, uint key
)
2643 elt
= (bcm_tlv_t
*)buf
;
2646 /* find tagged parameter */
2647 while (totlen
>= TLV_HDR_LEN
) {
2651 /* Punt if we start seeing IDs > than target key */
2655 /* validate remaining totlen */
2657 (totlen
>= (len
+ TLV_HDR_LEN
)))
2660 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ TLV_HDR_LEN
));
2661 totlen
-= (len
+ TLV_HDR_LEN
);
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
)
2674 int slen
= 0, nlen
= 0;
2678 if (len
< 2 || !buf
)
2683 for (i
= 0; flags
!= 0; i
++) {
2686 if (bit
== 0 && flags
!= 0) {
2687 /* print any unnamed bits */
2688 snprintf(hexstr
, 16, "0x%X", flags
);
2690 flags
= 0; /* exit loop */
2691 } else if ((flags
& bit
) == 0)
2694 nlen
= strlen(name
);
2696 /* count btwn flag space */
2699 /* need NULL char as well */
2702 /* copy NULL char but don't count it */
2703 strncpy(p
, name
, nlen
+ 1);
2705 /* copy btwn flag space and NULL char */
2707 p
+= snprintf(p
, 2, " ");
2710 /* indicate the str was too short */
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
)
2726 const uint8
*src
= (const uint8
*)bytes
;
2728 for (i
= 0; i
< len
; i
++) {
2729 p
+= snprintf(p
, 3, "%02X", *src
);
2732 return (int)(p
- str
);
2736 /* pretty hex print a contiguous buffer */
2738 prhex(const char *msg
, uchar
*buf
, uint nbytes
)
2741 int len
= sizeof(line
);
2745 if (msg
&& (msg
[0] != '\0'))
2746 printf("%s:\n", msg
);
2749 for (i
= 0; i
< nbytes
; i
++) {
2751 nchar
= snprintf(p
, len
, " %04d: ", i
); /* line prefix */
2756 nchar
= snprintf(p
, len
, "%02x ", buf
[i
]);
2762 printf("%s\n", line
); /* flush line */
2768 /* flush last partial line */
2770 printf("%s\n", line
);
2773 static const char *crypto_algo_names
[] = {
2789 bcm_crypto_algo_name(uint algo
)
2791 return (algo
< ARRAYSIZE(crypto_algo_names
)) ? crypto_algo_names
[algo
] : "ERR";
2796 deadbeef(void *p
, size_t len
)
2798 static uint8 meat
[] = { 0xde, 0xad, 0xbe, 0xef };
2801 *(uint8
*)p
= meat
[((uintptr
)p
) & 3];
2808 bcm_chipname(uint chipid
, char *buf
, uint len
)
2812 fmt
= ((chipid
> 0xa000) || (chipid
< 0x4000)) ? "%d" : "%x";
2813 snprintf(buf
, len
, fmt
, chipid
);
2817 /* Produce a human-readable string for boardrev */
2819 bcm_brev_str(uint32 brev
, char *buf
)
2822 snprintf(buf
, 8, "%d.%d", (brev
& 0xf0) >> 4, brev
& 0xf);
2824 snprintf(buf
, 8, "%c%03x", ((brev
& 0xf000) == 0x1000) ? 'P' : 'A', brev
& 0xfff);
2829 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
2831 /* dump large strings to console */
2840 max_len
= BUFSIZE_TODUMP_ATONCE
;
2842 while (len
> max_len
) {
2844 buf
[max_len
] = '\0';
2851 /* print the remaining string */
2852 printf("%s\n", buf
);
2856 /* routine to dump fields in a fileddesc structure */
2858 bcmdumpfields(bcmutl_rdreg_rtn read_rtn
, void *arg0
, uint arg1
, struct fielddesc
*fielddesc_array
,
2859 char *buf
, uint32 bufsize
)
2863 struct fielddesc
*cur_ptr
;
2866 cur_ptr
= fielddesc_array
;
2868 while (bufsize
> 1) {
2869 if (cur_ptr
->nameandfmt
== NULL
)
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
)
2885 bcm_mkiovar(char *name
, char *data
, uint datalen
, char *buf
, uint buflen
)
2889 len
= strlen(name
) + 1;
2891 if ((len
+ datalen
) > buflen
)
2894 strncpy(buf
, name
, buflen
);
2896 /* append data onto the end of the name string */
2897 memcpy(&buf
[len
], data
, datalen
);
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
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
2933 BCMROMFN(bcm_qdbm_to_mw
)(uint8 qdbm
)
2936 int idx
= qdbm
- QDBM_OFFSET
;
2938 if (idx
>= QDBM_TABLE_LEN
) {
2939 /* clamp to max uint16 mW value */
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.
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
);
2958 BCMROMFN(bcm_mw_to_qdbm
)(uint16 mw
)
2965 /* handle boundary case */
2969 offset
= QDBM_OFFSET
;
2971 /* move mw into the range of the table */
2972 while (mw_uint
< QDBM_TABLE_LOW_BOUND
) {
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
;
2990 BCMROMFN(bcm_bitcount
)(uint8
*bitmap
, uint length
)
2992 uint bitcount
= 0, i
;
2994 for (i
= 0; i
< length
; i
++) {
3006 /* Initialization of bcmstrbuf structure */
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
, ...)
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
)) {
3045 bcm_bprhex(struct bcmstrbuf
*b
, const char *msg
, bool newline
, uint8
*buf
, int len
)
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
]);
3054 bcm_bprintf(b
, "\n");
3058 bcm_inc_bytes(uchar
*num
, int num_bytes
, uint8 amount
)
3062 for (i
= 0; i
< num_bytes
; i
++) {
3064 if (num
[i
] >= amount
)
3071 bcm_cmp_bytes(const uchar
*arg1
, const uchar
*arg2
, uint8 nbytes
)
3075 for (i
= nbytes
- 1; i
>= 0; i
--) {
3076 if (arg1
[i
] != arg2
[i
])
3077 return (arg1
[i
] - arg2
[i
]);
3083 bcm_print_bytes(const char *name
, const uchar
*data
, int len
)
3088 printf("%s: %d \n", name
? name
: "", len
);
3089 for (i
= 0; i
< len
; i
++) {
3090 printf("%02x ", *data
++);
3092 if (per_line
== 16) {
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
)
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
++) {
3117 } else if (bcm_isprint((uchar
)c
)) {
3120 p
+= snprintf(p
, (endp
- p
), "\\x%02X", c
);
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.
3140 process_nvram_vars(char *varbuf
, unsigned int len
)
3145 unsigned int buf_len
, n
;
3146 unsigned int pad
= 0;
3150 findNewline
= FALSE
;
3153 for (n
= 0; n
< len
; n
++) {
3154 if (varbuf
[n
] == '\r')
3156 if (findNewline
&& varbuf
[n
] != '\n')
3158 findNewline
= FALSE
;
3159 if (varbuf
[n
] == '#') {
3163 if (varbuf
[n
] == '\n') {
3173 buf_len
= (unsigned int)(dp
- varbuf
);
3175 pad
= 4 - buf_len
% 4;
3176 if (pad
&& (buf_len
+ pad
<= len
)) {
3181 while (dp
< varbuf
+ n
)