2 * Driver O/S-independent utility routines
4 * Copyright (C) 2012, 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 371895 2012-11-29 20:15:08Z $
23 #if defined(__FreeBSD__) || defined(__NetBSD__)
24 #include <sys/param.h>
25 #if __NetBSD_Version__ >= 500000003
26 #include <sys/stdarg.h>
28 #include <machine/stdarg.h>
40 #else /* !BCMDRIVER */
46 #if defined(BCMEXTSUP)
51 #endif /* !BCMDRIVER */
53 #if defined(_WIN32) || defined(NDIS) || defined(__vxworks) || defined(_CFE_)
54 #include <bcmstdlib.h>
56 #include <bcmendian.h>
58 #include <proto/ethernet.h>
59 #include <proto/vlan.h>
60 #include <proto/bcmip.h>
61 #include <proto/802.1d.h>
62 #include <proto/802.11.h>
66 #include <proto/bcmipv6.h>
67 void *_bcmutils_dummy_fn
= NULL
;
72 /* nvram vars cache */
73 static char *nvram_vars
= NULL
;
74 static int vars_len
= -1;
78 pktpool_init(osl_t
*osh
, pktpool_t
*pktp
, int *pplen
, int plen
, bool istx
)
86 ASSERT(pplen
!= NULL
);
90 bzero(pktp
, sizeof(pktpool_t
));
92 pktp
->istx
= istx
? TRUE
: FALSE
;
93 pktp
->plen
= (uint16
)plen
;
96 pktp
->maxlen
= PKTPOOL_LEN_MAX
;
97 if (pktplen
> pktp
->maxlen
)
98 pktplen
= pktp
->maxlen
;
100 for (i
= 0; i
< pktplen
; i
++) {
101 p
= PKTGET(osh
, plen
, pktp
->istx
);
103 /* Not able to allocate all requested pkts
104 * so just return what was actually allocated
105 * We can add to the pool later
113 PKTSETPOOL(osh
, p
, TRUE
, pktp
);
118 pktp
->dbg_q
[pktp
->dbg_qlen
++].p
= p
;
124 pktp
->len
++; /* Add one for end */
129 pktpool_deinit(osl_t
*osh
, pktpool_t
*pktp
)
135 ASSERT(pktp
!= NULL
);
138 for (i
= 0; i
< cnt
; i
++) {
139 if (pktp
->q
[i
] != NULL
) {
140 PKTSETPOOL(osh
, pktp
->q
[i
], FALSE
, NULL
);
141 PKTFREE(osh
, pktp
->q
[i
], pktp
->istx
);
146 if (pktp
->dbg_q
[i
].p
!= NULL
)
147 pktp
->dbg_q
[i
].p
= NULL
;
150 pktp
->inited
= FALSE
;
152 /* Are there still pending pkts? */
153 ASSERT(pktpool_len(pktp
) == 0);
159 pktpool_fill(osl_t
*osh
, pktpool_t
*pktp
, bool minimal
)
163 int len
, psize
, maxlen
;
165 ASSERT(pktpool_plen(pktp
) != 0);
167 maxlen
= pktpool_maxlen(pktp
);
168 psize
= minimal
? (maxlen
>> 2) : maxlen
;
169 len
= pktpool_len(pktp
);
170 for (; len
< psize
; len
++) {
171 p
= PKTGET(osh
, pktpool_plen(pktp
), FALSE
);
177 if (pktpool_add(pktp
, p
) != BCME_OK
) {
178 PKTFREE(osh
, p
, FALSE
);
188 pktpool_avail(pktpool_t
*pktp
)
190 if (pktp
->w
== pktp
->r
)
193 return (pktp
->w
> pktp
->r
) ? (pktp
->w
- pktp
->r
) : ((pktp
->len
) - (pktp
->r
- pktp
->w
));
197 pktpool_deq(pktpool_t
*pktp
)
201 if (pktp
->r
== pktp
->w
)
204 p
= pktp
->q
[pktp
->r
];
207 pktp
->q
[pktp
->r
++] = NULL
;
208 pktp
->r
%= (pktp
->len
);
214 pktpool_enq(pktpool_t
*pktp
, void *p
)
220 next
= (pktp
->w
+ 1) % (pktp
->len
);
221 if (next
== pktp
->r
) {
222 /* Should not happen; otherwise pkt leak */
227 ASSERT(pktp
->q
[pktp
->w
] == NULL
);
229 pktp
->q
[pktp
->w
] = p
;
234 pktpool_avail_register(pktpool_t
*pktp
, pktpool_cb_t cb
, void *arg
)
241 if (i
== PKTPOOL_CB_MAX
)
244 ASSERT(pktp
->cbs
[i
].cb
== NULL
);
245 pktp
->cbs
[i
].cb
= cb
;
246 pktp
->cbs
[i
].arg
= arg
;
253 pktpool_empty_register(pktpool_t
*pktp
, pktpool_cb_t cb
, void *arg
)
260 if (i
== PKTPOOL_CB_MAX
)
263 ASSERT(pktp
->ecbs
[i
].cb
== NULL
);
264 pktp
->ecbs
[i
].cb
= cb
;
265 pktp
->ecbs
[i
].arg
= arg
;
272 pktpool_empty_notify(pktpool_t
*pktp
)
277 for (i
= 0; i
< pktp
->ecbcnt
; i
++) {
278 ASSERT(pktp
->ecbs
[i
].cb
!= NULL
);
279 pktp
->ecbs
[i
].cb(pktp
, pktp
->ecbs
[i
].arg
);
288 pktpool_dbg_register(pktpool_t
*pktp
, pktpool_cb_t cb
, void *arg
)
295 if (i
== PKTPOOL_CB_MAX
)
298 ASSERT(pktp
->dbg_cbs
[i
].cb
== NULL
);
299 pktp
->dbg_cbs
[i
].cb
= cb
;
300 pktp
->dbg_cbs
[i
].arg
= arg
;
306 int pktpool_dbg_notify(pktpool_t
*pktp
);
309 pktpool_dbg_notify(pktpool_t
*pktp
)
313 for (i
= 0; i
< pktp
->dbg_cbcnt
; i
++) {
314 ASSERT(pktp
->dbg_cbs
[i
].cb
);
315 pktp
->dbg_cbs
[i
].cb(pktp
, pktp
->dbg_cbs
[i
].arg
);
322 pktpool_dbg_dump(pktpool_t
*pktp
)
326 printf("pool len=%d maxlen=%d\n", pktp
->dbg_qlen
, pktp
->maxlen
);
327 for (i
= 0; i
< pktp
->dbg_qlen
; i
++) {
328 ASSERT(pktp
->dbg_q
[i
].p
);
329 printf("%d, p: 0x%x dur:%lu us state:%d\n", i
,
330 pktp
->dbg_q
[i
].p
, pktp
->dbg_q
[i
].dur
/100, PKTPOOLSTATE(pktp
->dbg_q
[i
].p
));
337 pktpool_stats_dump(pktpool_t
*pktp
, pktpool_stats_t
*stats
)
342 bzero(stats
, sizeof(pktpool_stats_t
));
343 for (i
= 0; i
< pktp
->dbg_qlen
; i
++) {
344 ASSERT(pktp
->dbg_q
[i
].p
!= NULL
);
346 state
= PKTPOOLSTATE(pktp
->dbg_q
[i
].p
);
351 stats
->txdh
++; break;
353 stats
->txd11
++; break;
355 stats
->rxdh
++; break;
357 stats
->rxd11
++; break;
359 stats
->rxfill
++; break;
361 stats
->idle
++; break;
369 pktpool_start_trigger(pktpool_t
*pktp
, void *p
)
373 if (!PKTPOOL(NULL
, p
))
376 OSL_GETCYCLES(cycles
);
378 for (i
= 0; i
< pktp
->dbg_qlen
; i
++) {
379 ASSERT(pktp
->dbg_q
[i
].p
!= NULL
);
381 if (pktp
->dbg_q
[i
].p
== p
) {
382 pktp
->dbg_q
[i
].cycles
= cycles
;
390 int pktpool_stop_trigger(pktpool_t
*pktp
, void *p
);
392 pktpool_stop_trigger(pktpool_t
*pktp
, void *p
)
396 if (!PKTPOOL(NULL
, p
))
399 OSL_GETCYCLES(cycles
);
401 for (i
= 0; i
< pktp
->dbg_qlen
; i
++) {
402 ASSERT(pktp
->dbg_q
[i
].p
!= NULL
);
404 if (pktp
->dbg_q
[i
].p
== p
) {
405 if (pktp
->dbg_q
[i
].cycles
== 0)
408 if (cycles
>= pktp
->dbg_q
[i
].cycles
)
409 pktp
->dbg_q
[i
].dur
= cycles
- pktp
->dbg_q
[i
].cycles
;
412 (((uint32
)-1) - pktp
->dbg_q
[i
].cycles
) + cycles
+ 1;
414 pktp
->dbg_q
[i
].cycles
= 0;
421 #endif /* BCMDBG_POOL */
424 pktpool_avail_notify_normal(osl_t
*osh
, pktpool_t
*pktp
)
427 pktp
->availcb_excl
= NULL
;
432 pktpool_avail_notify_exclusive(osl_t
*osh
, pktpool_t
*pktp
, pktpool_cb_t cb
)
437 ASSERT(pktp
->availcb_excl
== NULL
);
438 for (i
= 0; i
< pktp
->cbcnt
; i
++) {
439 if (cb
== pktp
->cbs
[i
].cb
) {
440 pktp
->availcb_excl
= &pktp
->cbs
[i
];
445 if (pktp
->availcb_excl
== NULL
)
452 pktpool_avail_notify(pktpool_t
*pktp
)
458 if (pktp
->availcb_excl
!= NULL
) {
459 pktp
->availcb_excl
->cb(pktp
, pktp
->availcb_excl
->arg
);
464 for (i
= 0; i
< pktp
->cbcnt
; i
++) {
465 avail
= pktpool_avail(pktp
);
473 ASSERT(pktp
->cbs
[idx
].cb
!= NULL
);
474 pktp
->cbs
[idx
].cb(pktp
, pktp
->cbs
[idx
].arg
);
478 /* Alternate between filling from head or tail
486 pktpool_get(pktpool_t
*pktp
)
490 p
= pktpool_deq(pktp
);
493 /* Notify and try to reclaim tx pkts */
495 pktpool_empty_notify(pktp
);
497 p
= pktpool_deq(pktp
);
504 pktpool_free(pktpool_t
*pktp
, void *p
)
509 /* pktpool_stop_trigger(pktp, p); */
512 pktpool_enq(pktp
, p
);
514 if (pktp
->emptycb_disable
)
518 if (pktp
->empty
== FALSE
)
519 pktpool_avail_notify(pktp
);
524 pktpool_add(pktpool_t
*pktp
, void *p
)
528 if (pktpool_len(pktp
) == pktp
->maxlen
)
531 ASSERT(pktpool_plen(pktp
) == PKTLEN(NULL
, p
)); /* pkts in pool have same length */
532 PKTSETPOOL(NULL
, p
, TRUE
, pktp
);
535 if (pktp
->r
> pktp
->w
) {
537 ASSERT(pktp
->q
[pktp
->len
- 1] == NULL
);
538 pktp
->q
[pktp
->len
- 1] = p
;
540 pktpool_enq(pktp
, p
);
543 pktp
->dbg_q
[pktp
->dbg_qlen
++].p
= p
;
550 pktpool_setmaxlen(pktpool_t
*pktp
, uint16 maxlen
)
552 if (maxlen
> PKTPOOL_LEN_MAX
)
553 maxlen
= PKTPOOL_LEN_MAX
;
555 /* if pool is already beyond maxlen, then just cap it
556 * since we currently do not reduce the pool len
559 pktp
->maxlen
= (pktpool_len(pktp
) > maxlen
) ? pktpool_len(pktp
) : maxlen
;
565 pktpool_emptycb_disable(pktpool_t
*pktp
, bool disable
)
569 pktp
->emptycb_disable
= disable
;
573 pktpool_emptycb_disabled(pktpool_t
*pktp
)
576 return pktp
->emptycb_disable
;
579 /* copy a pkt buffer chain into a buffer */
581 pktcopy(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
586 len
= 4096; /* "infinite" */
588 /* skip 'offset' bytes */
589 for (; p
&& offset
; p
= PKTNEXT(osh
, p
)) {
590 if (offset
< (uint
)PKTLEN(osh
, p
))
592 offset
-= PKTLEN(osh
, p
);
599 for (; p
&& len
; p
= PKTNEXT(osh
, p
)) {
600 n
= MIN((uint
)PKTLEN(osh
, p
) - offset
, (uint
)len
);
601 bcopy(PKTDATA(osh
, p
) + offset
, buf
, n
);
611 /* copy a buffer into a pkt buffer chain */
613 pktfrombuf(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
617 /* skip 'offset' bytes */
618 for (; p
&& offset
; p
= PKTNEXT(osh
, p
)) {
619 if (offset
< (uint
)PKTLEN(osh
, p
))
621 offset
-= PKTLEN(osh
, p
);
628 for (; p
&& len
; p
= PKTNEXT(osh
, p
)) {
629 n
= MIN((uint
)PKTLEN(osh
, p
) - offset
, (uint
)len
);
630 bcopy(buf
, PKTDATA(osh
, p
) + offset
, n
);
641 /* copy data from one pkt buffer (chain) to another */
643 pkt2pktcopy(osl_t
*osh
, void *p1
, uint offs1
, void *p2
, uint offs2
, int maxlen
)
646 uint len1
, len2
, copylen
, totallen
;
648 for (; p1
&& offs
; p1
= PKTNEXT(osh
, p1
)) {
649 if (offs1
< (uint
)PKTLEN(osh
, p1
))
651 offs1
-= PKTLEN(osh
, p1
);
653 for (; p2
&& offs
; p2
= PKTNEXT(osh
, p2
)) {
654 if (offs2
< (uint
)PKTLEN(osh
, p2
))
656 offs2
-= PKTLEN(osh
, p2
);
659 /* Heck w/it, only need the above for now */
664 /* return total length of buffer chain */
666 pkttotlen(osl_t
*osh
, void *p
)
672 for (; p
; p
= PKTNEXT(osh
, p
)) {
673 len
= PKTLEN(osh
, p
);
676 /* Bad packet length, just drop and exit */
677 printf("wl: pkttotlen bad (%p,%d)\n", p
, len
);
687 /* return the last buffer of chained pkt */
689 pktlast(osl_t
*osh
, void *p
)
691 for (; PKTNEXT(osh
, p
); p
= PKTNEXT(osh
, p
))
697 /* count segments of a chained packet */
699 pktsegcnt(osl_t
*osh
, void *p
)
703 for (cnt
= 0; p
; p
= PKTNEXT(osh
, p
))
710 /* count segments of a chained packet */
712 pktsegcnt_war(osl_t
*osh
, void *p
)
716 uint len
, remain
, align64
;
718 for (cnt
= 0; p
; p
= PKTNEXT(osh
, p
)) {
720 len
= PKTLEN(osh
, p
);
722 pktdata
= (uint8
*)PKTDATA(osh
, p
); /* starting address of data */
723 /* Check for page boundary straddle (2048B) */
724 if (((uintptr
)pktdata
& ~0x7ff) != ((uintptr
)(pktdata
+len
) & ~0x7ff))
727 align64
= (uint
)((uintptr
)pktdata
& 0x3f); /* aligned to 64B */
728 align64
= (64 - align64
) & 0x3f;
729 len
-= align64
; /* bytes from aligned 64B to end */
730 /* if aligned to 128B, check for MOD 128 between 1 to 4B */
732 if (remain
> 0 && remain
<= 4)
733 cnt
++; /* add extra seg */
741 pktdataoffset(osl_t
*osh
, void *p
, uint offset
)
743 uint total
= pkttotlen(osh
, p
);
744 uint pkt_off
= 0, len
= 0;
745 uint8
*pdata
= (uint8
*) PKTDATA(osh
, p
);
750 for (; p
; p
= PKTNEXT(osh
, p
)) {
751 pdata
= (uint8
*) PKTDATA(osh
, p
);
752 pkt_off
= offset
- len
;
753 len
+= PKTLEN(osh
, p
);
757 return (uint8
*) (pdata
+pkt_off
);
761 /* given a offset in pdata, find the pkt seg hdr */
763 pktoffset(osl_t
*osh
, void *p
, uint offset
)
765 uint total
= pkttotlen(osh
, p
);
771 for (; p
; p
= PKTNEXT(osh
, p
)) {
772 len
+= PKTLEN(osh
, p
);
780 * osl multiple-precedence packet queue
781 * hi_prec is always >= the number of the highest non-empty precedence
784 pktq_penq(struct pktq
*pq
, int prec
, void *p
)
788 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
789 ASSERT(PKTLINK(p
) == NULL
); /* queueing chains not allowed */
791 ASSERT(!pktq_full(pq
));
792 ASSERT(!pktq_pfull(pq
, prec
));
797 PKTSETLINK(q
->tail
, p
);
806 if (pq
->hi_prec
< prec
)
807 pq
->hi_prec
= (uint8
)prec
;
813 pktq_penq_head(struct pktq
*pq
, int prec
, void *p
)
817 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
818 ASSERT(PKTLINK(p
) == NULL
); /* queueing chains not allowed */
820 ASSERT(!pktq_full(pq
));
821 ASSERT(!pktq_pfull(pq
, prec
));
828 PKTSETLINK(p
, q
->head
);
834 if (pq
->hi_prec
< prec
)
835 pq
->hi_prec
= (uint8
)prec
;
841 pktq_pdeq(struct pktq
*pq
, int prec
)
846 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
850 if ((p
= q
->head
) == NULL
)
853 if ((q
->head
= PKTLINK(p
)) == NULL
)
866 pktq_pdeq_prev(struct pktq
*pq
, int prec
, void *prev_p
)
871 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
878 if ((p
= PKTLINK(prev_p
)) == NULL
)
888 PKTSETLINK(prev_p
, PKTLINK(p
));
895 pktq_pdeq_tail(struct pktq
*pq
, int prec
)
900 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
904 if ((p
= q
->head
) == NULL
)
907 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK(p
))
911 PKTSETLINK(prev
, NULL
);
924 pktq_pflush(osl_t
*osh
, struct pktq
*pq
, int prec
, bool dir
, ifpkt_cb_t fn
, int arg
)
927 void *p
, *prev
= NULL
;
932 if (fn
== NULL
|| (*fn
)(p
, arg
)) {
933 bool head
= (p
== q
->head
);
935 q
->head
= PKTLINK(p
);
937 PKTSETLINK(prev
, PKTLINK(p
));
939 PKTFREE(osh
, p
, dir
);
942 p
= (head
? q
->head
: PKTLINK(prev
));
949 if (q
->head
== NULL
) {
956 pktq_pdel(struct pktq
*pq
, void *pktbuf
, int prec
)
961 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
968 if (q
->head
== pktbuf
) {
969 if ((q
->head
= PKTLINK(pktbuf
)) == NULL
)
972 for (p
= q
->head
; p
&& PKTLINK(p
) != pktbuf
; p
= PKTLINK(p
))
977 PKTSETLINK(p
, PKTLINK(pktbuf
));
978 if (q
->tail
== pktbuf
)
984 PKTSETLINK(pktbuf
, NULL
);
989 pktq_init(struct pktq
*pq
, int num_prec
, int max_len
)
993 ASSERT(num_prec
> 0 && num_prec
<= PKTQ_MAX_PREC
);
995 /* pq is variable size; only zero out what's requested */
996 bzero(pq
, OFFSETOF(struct pktq
, q
) + (sizeof(struct pktq_prec
) * num_prec
));
998 pq
->num_prec
= (uint16
)num_prec
;
1000 pq
->max
= (uint16
)max_len
;
1002 for (prec
= 0; prec
< num_prec
; prec
++)
1003 pq
->q
[prec
].max
= pq
->max
;
1007 pktq_set_max_plen(struct pktq
*pq
, int prec
, int max_len
)
1009 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
1011 if (prec
< pq
->num_prec
)
1012 pq
->q
[prec
].max
= (uint16
)max_len
;
1016 pktq_deq(struct pktq
*pq
, int *prec_out
)
1018 struct pktq_prec
*q
;
1025 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
1030 if ((p
= q
->head
) == NULL
)
1033 if ((q
->head
= PKTLINK(p
)) == NULL
)
1043 PKTSETLINK(p
, NULL
);
1049 pktq_deq_tail(struct pktq
*pq
, int *prec_out
)
1051 struct pktq_prec
*q
;
1058 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
1059 if (pq
->q
[prec
].head
)
1064 if ((p
= q
->head
) == NULL
)
1067 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK(p
))
1071 PKTSETLINK(prev
, NULL
);
1083 PKTSETLINK(p
, NULL
);
1089 pktq_peek(struct pktq
*pq
, int *prec_out
)
1096 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
1102 return (pq
->q
[prec
].head
);
1106 pktq_peek_tail(struct pktq
*pq
, int *prec_out
)
1113 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
1114 if (pq
->q
[prec
].head
)
1120 return (pq
->q
[prec
].tail
);
1124 pktq_flush(osl_t
*osh
, struct pktq
*pq
, bool dir
, ifpkt_cb_t fn
, int arg
)
1128 /* Optimize flush, if pktq len = 0, just return.
1129 * pktq len of 0 means pktq's prec q's are all empty.
1135 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
1136 pktq_pflush(osh
, pq
, prec
, dir
, fn
, arg
);
1138 ASSERT(pq
->len
== 0);
1141 /* Return sum of lengths of a specific set of precedences */
1143 pktq_mlen(struct pktq
*pq
, uint prec_bmp
)
1149 for (prec
= 0; prec
<= pq
->hi_prec
; prec
++)
1150 if (prec_bmp
& (1 << prec
))
1151 len
+= pq
->q
[prec
].len
;
1156 /* Priority peek from a specific set of precedences */
1158 pktq_mpeek(struct pktq
*pq
, uint prec_bmp
, int *prec_out
)
1160 struct pktq_prec
*q
;
1168 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
1171 while ((prec_bmp
& (1 << prec
)) == 0 || pq
->q
[prec
].head
== NULL
)
1177 if ((p
= q
->head
) == NULL
)
1185 /* Priority dequeue from a specific set of precedences */
1187 pktq_mdeq(struct pktq
*pq
, uint prec_bmp
, int *prec_out
)
1189 struct pktq_prec
*q
;
1196 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
1199 while ((pq
->q
[prec
].head
== NULL
) || ((prec_bmp
& (1 << prec
)) == 0))
1205 if ((p
= q
->head
) == NULL
)
1208 if ((q
->head
= PKTLINK(p
)) == NULL
)
1218 PKTSETLINK(p
, NULL
);
1223 #endif /* BCMDRIVER */
1225 #if defined(BCMROMBUILD)
1226 const unsigned char BCMROMDATA(bcm_ctype
)[] = {
1228 const unsigned char bcm_ctype
[] = {
1231 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 0-7 */
1232 _BCM_C
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
|_BCM_S
, _BCM_C
,
1234 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 16-23 */
1235 _BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
,_BCM_C
, /* 24-31 */
1236 _BCM_S
|_BCM_SP
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 32-39 */
1237 _BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 40-47 */
1238 _BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
,_BCM_D
, /* 48-55 */
1239 _BCM_D
,_BCM_D
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 56-63 */
1240 _BCM_P
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
, _BCM_U
|_BCM_X
,
1241 _BCM_U
|_BCM_X
, _BCM_U
, /* 64-71 */
1242 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
, /* 72-79 */
1243 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
,_BCM_U
, /* 80-87 */
1244 _BCM_U
,_BCM_U
,_BCM_U
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
, /* 88-95 */
1245 _BCM_P
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
, _BCM_L
|_BCM_X
,
1246 _BCM_L
|_BCM_X
, _BCM_L
, /* 96-103 */
1247 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
, /* 104-111 */
1248 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
,_BCM_L
, /* 112-119 */
1249 _BCM_L
,_BCM_L
,_BCM_L
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_P
,_BCM_C
, /* 120-127 */
1250 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
1251 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
1252 _BCM_S
|_BCM_SP
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
,
1253 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 160-175 */
1254 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
,
1255 _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, _BCM_P
, /* 176-191 */
1256 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
,
1257 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, /* 192-207 */
1258 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_P
, _BCM_U
, _BCM_U
, _BCM_U
,
1259 _BCM_U
, _BCM_U
, _BCM_U
, _BCM_U
, _BCM_L
, /* 208-223 */
1260 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
,
1261 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, /* 224-239 */
1262 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_P
, _BCM_L
, _BCM_L
, _BCM_L
,
1263 _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
, _BCM_L
/* 240-255 */
1267 BCMROMFN(bcm_strtoul
)(const char *cp
, char **endp
, uint base
)
1269 ulong result
, last_result
= 0, value
;
1274 while (bcm_isspace(*cp
))
1279 else if (cp
[0] == '-') {
1286 if ((cp
[1] == 'x') || (cp
[1] == 'X')) {
1295 } else if (base
== 16 && (cp
[0] == '0') && ((cp
[1] == 'x') || (cp
[1] == 'X'))) {
1301 while (bcm_isxdigit(*cp
) &&
1302 (value
= bcm_isdigit(*cp
) ? *cp
-'0' : bcm_toupper(*cp
)-'A'+10) < base
) {
1303 result
= result
*base
+ value
;
1304 /* Detected overflow */
1305 if (result
< last_result
&& !minus
)
1307 last_result
= result
;
1312 result
= (ulong
)(-(long)result
);
1315 *endp
= DISCARD_QUAL(cp
, char);
1321 BCMROMFN(bcm_atoi
)(const char *s
)
1323 return (int)bcm_strtoul(s
, NULL
, 10);
1326 /* return pointer to location of substring 'needle' in 'haystack' */
1328 BCMROMFN(bcmstrstr
)(const char *haystack
, const char *needle
)
1333 if ((haystack
== NULL
) || (needle
== NULL
))
1334 return DISCARD_QUAL(haystack
, char);
1336 nlen
= strlen(needle
);
1337 len
= strlen(haystack
) - nlen
+ 1;
1339 for (i
= 0; i
< len
; i
++)
1340 if (memcmp(needle
, &haystack
[i
], nlen
) == 0)
1341 return DISCARD_QUAL(&haystack
[i
], char);
1346 BCMROMFN(bcmstrcat
)(char *dest
, const char *src
)
1350 p
= dest
+ strlen(dest
);
1352 while ((*p
++ = *src
++) != '\0')
1359 BCMROMFN(bcmstrncat
)(char *dest
, const char *src
, uint size
)
1364 p
= dest
+ strlen(dest
);
1367 while (p
!= endp
&& (*p
++ = *src
++) != '\0')
1374 /****************************************************************************
1375 * Function: bcmstrtok
1378 * Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
1379 * but allows strToken() to be used by different strings or callers at the same
1380 * time. Each call modifies '*string' by substituting a NULL character for the
1381 * first delimiter that is encountered, and updates 'string' to point to the char
1382 * after the delimiter. Leading delimiters are skipped.
1385 * string (mod) Ptr to string ptr, updated by token.
1386 * delimiters (in) Set of delimiter characters.
1387 * tokdelim (out) Character that delimits the returned token. (May
1388 * be set to NULL if token delimiter is not required).
1390 * Returns: Pointer to the next token found. NULL when no more tokens are found.
1391 *****************************************************************************
1394 bcmstrtok(char **string
, const char *delimiters
, char *tokdelim
)
1397 unsigned long map
[8];
1401 if (tokdelim
!= NULL
) {
1402 /* Prime the token delimiter */
1406 /* Clear control map */
1407 for (count
= 0; count
< 8; count
++) {
1411 /* Set bits in delimiter table */
1413 map
[*delimiters
>> 5] |= (1 << (*delimiters
& 31));
1415 while (*delimiters
++);
1417 str
= (unsigned char*)*string
;
1419 /* Find beginning of token (skip over leading delimiters). Note that
1420 * there is no token iff this loop sets str to point to the terminal
1421 * null (*str == '\0')
1423 while (((map
[*str
>> 5] & (1 << (*str
& 31))) && *str
) || (*str
== ' ')) {
1427 nextoken
= (char*)str
;
1429 /* Find the end of the token. If it is not the end of the string,
1432 for (; *str
; str
++) {
1433 if (map
[*str
>> 5] & (1 << (*str
& 31))) {
1434 if (tokdelim
!= NULL
) {
1443 *string
= (char*)str
;
1445 /* Determine if a token has been found. */
1446 if (nextoken
== (char *) str
) {
1455 #define xToLower(C) \
1456 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
1459 /****************************************************************************
1460 * Function: bcmstricmp
1462 * Purpose: Compare to strings case insensitively.
1464 * Parameters: s1 (in) First string to compare.
1465 * s2 (in) Second string to compare.
1467 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1468 * t1 > t2, when ignoring case sensitivity.
1469 *****************************************************************************
1472 bcmstricmp(const char *s1
, const char *s2
)
1476 while (*s2
&& *s1
) {
1479 if (dc
< sc
) return -1;
1480 if (dc
> sc
) return 1;
1485 if (*s1
&& !*s2
) return 1;
1486 if (!*s1
&& *s2
) return -1;
1491 /****************************************************************************
1492 * Function: bcmstrnicmp
1494 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
1497 * Parameters: s1 (in) First string to compare.
1498 * s2 (in) Second string to compare.
1499 * cnt (in) Max characters to compare.
1501 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1502 * t1 > t2, when ignoring case sensitivity.
1503 *****************************************************************************
1506 bcmstrnicmp(const char* s1
, const char* s2
, int cnt
)
1510 while (*s2
&& *s1
&& cnt
) {
1513 if (dc
< sc
) return -1;
1514 if (dc
> sc
) return 1;
1521 if (*s1
&& !*s2
) return 1;
1522 if (!*s1
&& *s2
) return -1;
1526 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
1528 BCMROMFN(bcm_ether_atoe
)(const char *p
, struct ether_addr
*ea
)
1534 ea
->octet
[i
++] = (char) bcm_strtoul(p
, &ep
, 16);
1536 if (!*p
++ || i
== 6)
1544 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
1545 /* registry routine buffer preparation utility functions:
1546 * parameter order is like strncpy, but returns count
1547 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
1550 wchar2ascii(char *abuf
, ushort
*wbuf
, ushort wbuflen
, ulong abuflen
)
1558 /* wbuflen is in bytes */
1559 wbuflen
/= sizeof(ushort
);
1561 for (i
= 0; i
< wbuflen
; ++i
) {
1564 *abuf
++ = (char) *wbuf
++;
1571 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
1574 bcm_ether_ntoa(const struct ether_addr
*ea
, char *buf
)
1576 static const char hex
[] =
1578 '0', '1', '2', '3', '4', '5', '6', '7',
1579 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
1581 const uint8
*octet
= ea
->octet
;
1585 for (i
= 0; i
< 6; i
++, octet
++) {
1586 *p
++ = hex
[(*octet
>> 4) & 0xf];
1587 *p
++ = hex
[*octet
& 0xf];
1597 bcm_ip_ntoa(struct ipv4_addr
*ia
, char *buf
)
1599 snprintf(buf
, 16, "%d.%d.%d.%d",
1600 ia
->addr
[0], ia
->addr
[1], ia
->addr
[2], ia
->addr
[3]);
1611 for (i
= 0; i
< ms
; i
++) {
1617 * Search the name=value vars for a specific one and return its value.
1618 * Returns NULL if not found.
1621 getvar(char *vars
, const char *name
)
1636 /* first look in vars[] */
1637 for (s
= vars
; s
&& *s
;) {
1638 if ((bcmp(s
, name
, len
) == 0) && (s
[len
] == '='))
1645 /* then query nvram */
1646 return (nvram_get(name
));
1647 #endif /* defined(_MINOSL_) */
1651 * Search the vars for a specific one and return its value as
1652 * an integer. Returns 0 if not found.
1655 getintvar(char *vars
, const char *name
)
1662 if ((val
= getvar(vars
, name
)) == NULL
)
1665 return (bcm_strtoul(val
, NULL
, 0));
1666 #endif /* _MINOSL_ */
1670 getintvararray(char *vars
, const char *name
, int index
)
1679 if ((buf
= getvar(vars
, name
)) == NULL
) {
1683 /* table values are always separated by "," or " " */
1684 while (*buf
!= '\0') {
1685 val
= bcm_strtoul(buf
, &endp
, 0);
1690 /* delimiter is ',' */
1696 #endif /* _MINOSL_ */
1700 getintvararraysize(char *vars
, const char *name
)
1709 if ((buf
= getvar(vars
, name
)) == NULL
) {
1713 /* table values are always separated by "," or " " */
1714 while (*buf
!= '\0') {
1715 val
= bcm_strtoul(buf
, &endp
, 0);
1717 /* delimiter is ',' */
1724 #endif /* _MINOSL_ */
1727 /* Search for token in comma separated token-string */
1729 findmatch(const char *string
, const char *name
)
1735 while ((c
= strchr(string
, ',')) != NULL
) {
1736 if (len
== (uint
)(c
- string
) && !strncmp(string
, name
, len
))
1741 return (!strcmp(string
, name
));
1744 /* Return gpio pin number assigned to the named pin
1746 * Variable should be in format:
1748 * gpio<N>=pin_name,pin_name
1750 * This format allows multiple features to share the gpio with mutual
1753 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
1754 * and if def_pin is not used by others.
1757 getgpiopin(char *vars
, char *pin_name
, uint def_pin
)
1759 char name
[] = "gpioXXXX";
1763 /* Go thru all possibilities till a match in pin name */
1764 for (pin
= 0; pin
< GPIO_NUMPINS
; pin
++) {
1765 snprintf(name
, sizeof(name
), "gpio%d", pin
);
1766 val
= getvar(vars
, name
);
1767 if (val
&& findmatch(val
, pin_name
))
1771 if (def_pin
!= GPIO_PIN_NOTDEFINED
) {
1772 /* make sure the default pin is not used by someone else */
1773 snprintf(name
, sizeof(name
), "gpio%d", def_pin
);
1774 if (getvar(vars
, name
)) {
1775 def_pin
= GPIO_PIN_NOTDEFINED
;
1781 #if defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS)
1783 #define LOGSIZE 256 /* should be power of 2 to avoid div below */
1791 /* last entry logged */
1792 static uint logi
= 0;
1793 /* next entry to read */
1794 static uint readi
= 0;
1795 #endif /* defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS) */
1801 BCMPERF_ENABLE_INSTRCOUNT();
1802 BCMPERF_ENABLE_ICACHE_MISS();
1803 BCMPERF_ENABLE_ICACHE_HIT();
1806 /* WARNING: This routine uses OSL_GETCYCLES(), which can give unexpected results on
1807 * modern speed stepping CPUs. Use bcmtslog() instead in combination with TSF counter.
1810 bcmlog(char *fmt
, uint a1
, uint a2
)
1812 static uint last
= 0;
1814 OSL_GETCYCLES(cycles
);
1818 logtab
[i
].cycles
= cycles
- last
;
1819 logtab
[i
].fmt
= fmt
;
1823 logi
= (i
+ 1) % LOGSIZE
;
1831 static uint last
= 0;
1832 static uint32 ic_miss
= 0;
1833 static uint32 instr_count
= 0;
1835 uint32 instr_count_cur
;
1838 OSL_GETCYCLES(cycles
);
1839 BCMPERF_GETICACHE_MISS(ic_miss_cur
);
1840 BCMPERF_GETINSTRCOUNT(instr_count_cur
);
1844 logtab
[i
].cycles
= cycles
- last
;
1845 logtab
[i
].a1
= ic_miss_cur
- ic_miss
;
1846 logtab
[i
].a2
= instr_count_cur
- instr_count
;
1847 logtab
[i
].fmt
= fmt
;
1849 logi
= (i
+ 1) % LOGSIZE
;
1852 instr_count
= instr_count_cur
;
1853 ic_miss
= ic_miss_cur
;
1858 bcmdumplog(char *buf
, int size
)
1864 limit
= buf
+ size
- 80;
1872 /* print in chronological order */
1874 for (j
= 0; j
< num
&& (buf
< limit
); readi
= (readi
+ 1) % LOGSIZE
, j
++) {
1875 if (logtab
[readi
].fmt
== NULL
)
1877 buf
+= snprintf(buf
, (limit
- buf
), "%d\t", logtab
[readi
].cycles
);
1878 buf
+= snprintf(buf
, (limit
- buf
), logtab
[readi
].fmt
, logtab
[readi
].a1
,
1880 buf
+= snprintf(buf
, (limit
- buf
), "\n");
1887 * Dump one log entry at a time.
1888 * Return index of next entry or -1 when no more .
1891 bcmdumplogent(char *buf
, uint i
)
1896 * If buf is NULL, return the starting index,
1897 * interpreting i as the indicator of last 'i' entries to dump.
1900 i
= ((i
> 0) && (i
< (LOGSIZE
- 1))) ? i
: (LOGSIZE
- 1);
1901 return ((logi
- i
) % LOGSIZE
);
1906 ASSERT(i
< LOGSIZE
);
1912 for (; (i
!= logi
) && !hit
; i
= (i
+ 1) % LOGSIZE
) {
1913 if (logtab
[i
].fmt
== NULL
)
1915 buf
+= sprintf(buf
, "%d: %d\t", i
, logtab
[i
].cycles
);
1916 buf
+= sprintf(buf
, logtab
[i
].fmt
, logtab
[i
].a1
, logtab
[i
].a2
);
1917 buf
+= sprintf(buf
, "\n");
1924 #endif /* BCMPERFSTATS */
1926 #if defined(BCMTSTAMPEDLOGS)
1927 /* Store a TSF timestamp and a log line in the log buffer */
1929 bcmtslog(uint32 tstamp
, char *fmt
, uint a1
, uint a2
)
1932 bool use_delta
= FALSE
;
1933 static uint32 last
= 0; /* used only when use_delta is true */
1935 logtab
[i
].cycles
= tstamp
;
1937 logtab
[i
].cycles
-= last
;
1939 logtab
[i
].fmt
= fmt
;
1945 logi
= (i
+ 1) % LOGSIZE
;
1948 /* Print out a microsecond timestamp as "sec.ms.us " */
1950 bcmprinttstamp(uint32 ticks
)
1954 us
= (ticks
% TSF_TICKS_PER_MS
) * 1000 / TSF_TICKS_PER_MS
;
1955 ms
= ticks
/ TSF_TICKS_PER_MS
;
1958 printf("%04u.%03u.%03u ", sec
, ms
, us
);
1961 /* Print out the log buffer with timestamps */
1963 bcmprinttslogs(void)
1972 /* Format and print the log entries directly in chronological order */
1973 for (j
= 0; j
< num
; readi
= (readi
+ 1) % LOGSIZE
, j
++) {
1974 if (logtab
[readi
].fmt
== NULL
)
1976 bcmprinttstamp(logtab
[readi
].cycles
);
1977 printf(logtab
[readi
].fmt
, logtab
[readi
].a1
, logtab
[readi
].a2
);
1983 bcmdumptslog(char *buf
, int size
)
1990 limit
= buf
+ size
- 80;
1998 /* print in chronological order */
1999 for (j
= 0; j
< num
&& (buf
< limit
); readi
= (readi
+ 1) % LOGSIZE
, j
++) {
2000 if (logtab
[readi
].fmt
== NULL
)
2002 us
= (logtab
[readi
].cycles
% TSF_TICKS_PER_MS
) * 1000 / TSF_TICKS_PER_MS
;
2003 ms
= logtab
[readi
].cycles
/ TSF_TICKS_PER_MS
;
2007 buf
+= snprintf(buf
, (limit
- buf
), "%04u.%03u.%03u ", sec
, ms
, us
);
2008 /* buf += snprintf(buf, (limit - buf), "%d\t", logtab[readi].cycles); */
2009 buf
+= snprintf(buf
, (limit
- buf
), logtab
[readi
].fmt
, logtab
[readi
].a1
,
2011 buf
+= snprintf(buf
, (limit
- buf
), "\n");
2015 #endif /* BCMTSTAMPEDLOGS */
2017 #if defined(BCMDBG) || defined(DHD_DEBUG)
2018 /* pretty hex print a pkt buffer chain */
2020 prpkt(const char *msg
, osl_t
*osh
, void *p0
)
2024 if (msg
&& (msg
[0] != '\0'))
2025 printf("%s:\n", msg
);
2027 for (p
= p0
; p
; p
= PKTNEXT(osh
, p
))
2028 prhex(NULL
, PKTDATA(osh
, p
), PKTLEN(osh
, p
));
2030 #endif /* BCMDBG || DHD_DEBUG */
2032 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
2033 * Also updates the inplace vlan tag if requested.
2034 * For debugging, it returns an indication of what it did.
2037 pktsetprio(void *pkt
, bool update_vtag
)
2039 struct ether_header
*eh
;
2040 struct ethervlan_header
*evh
;
2045 pktdata
= (uint8
*)PKTDATA(NULL
, pkt
);
2046 ASSERT(ISALIGNED((uintptr
)pktdata
, sizeof(uint16
)));
2048 eh
= (struct ether_header
*) pktdata
;
2050 if (eh
->ether_type
== hton16(ETHER_TYPE_8021Q
)) {
2052 int vlan_prio
, dscp_prio
= 0;
2054 evh
= (struct ethervlan_header
*)eh
;
2056 vlan_tag
= ntoh16(evh
->vlan_tag
);
2057 vlan_prio
= (int) (vlan_tag
>> VLAN_PRI_SHIFT
) & VLAN_PRI_MASK
;
2059 if (evh
->ether_type
== hton16(ETHER_TYPE_IP
)) {
2060 uint8
*ip_body
= pktdata
+ sizeof(struct ethervlan_header
);
2061 uint8 tos_tc
= IP_TOS46(ip_body
);
2062 dscp_prio
= (int)(tos_tc
>> IPV4_TOS_PREC_SHIFT
);
2065 /* DSCP priority gets precedence over 802.1P (vlan tag) */
2066 if (dscp_prio
!= 0) {
2067 priority
= dscp_prio
;
2068 rc
|= PKTPRIO_VDSCP
;
2070 priority
= vlan_prio
;
2074 * If the DSCP priority is not the same as the VLAN priority,
2075 * then overwrite the priority field in the vlan tag, with the
2076 * DSCP priority value. This is required for Linux APs because
2077 * the VLAN driver on Linux, overwrites the skb->priority field
2078 * with the priority value in the vlan tag
2080 if (update_vtag
&& (priority
!= vlan_prio
)) {
2081 vlan_tag
&= ~(VLAN_PRI_MASK
<< VLAN_PRI_SHIFT
);
2082 vlan_tag
|= (uint16
)priority
<< VLAN_PRI_SHIFT
;
2083 evh
->vlan_tag
= hton16(vlan_tag
);
2086 } else if (eh
->ether_type
== hton16(ETHER_TYPE_IP
)) {
2087 uint8
*ip_body
= pktdata
+ sizeof(struct ether_header
);
2088 uint8 tos_tc
= IP_TOS46(ip_body
);
2089 priority
= (int)(tos_tc
>> IPV4_TOS_PREC_SHIFT
);
2093 ASSERT(priority
>= 0 && priority
<= MAXPRIO
);
2094 PKTSETPRIO(pkt
, priority
);
2095 return (rc
| priority
);
2098 #ifndef BCM_BOOTLOADER
2100 static char bcm_undeferrstr
[32];
2101 static const char *const bcmerrorstrtable
[] = BCMERRSTRINGTABLE
;
2103 /* Convert the error codes into related error strings */
2105 bcmerrorstr(int bcmerror
)
2107 /* check if someone added a bcmerror code but forgot to add errorstring */
2108 ASSERT(ABS(BCME_LAST
) == (ARRAYSIZE(bcmerrorstrtable
) - 1));
2110 if (bcmerror
> 0 || bcmerror
< BCME_LAST
) {
2111 snprintf(bcm_undeferrstr
, sizeof(bcm_undeferrstr
), "Undefined error %d", bcmerror
);
2112 return bcm_undeferrstr
;
2115 ASSERT(strlen(bcmerrorstrtable
[-bcmerror
]) < BCME_STRLEN
);
2117 return bcmerrorstrtable
[-bcmerror
];
2120 #endif /* !BCM_BOOTLOADER */
2124 BCMINITFN(bcm_nvram_refresh
)(char *flash
)
2129 ASSERT(flash
!= NULL
);
2131 /* default "empty" vars cache */
2134 if ((ret
= nvram_getall(flash
, MAX_NVRAM_SPACE
)))
2137 /* determine nvram length */
2138 for (i
= 0; i
< MAX_NVRAM_SPACE
; i
++) {
2139 if (flash
[i
] == '\0' && flash
[i
+1] == '\0')
2150 bcm_nvram_vars(uint
*length
)
2153 /* cache may be stale if nvram is read/write */
2155 ASSERT(!bcmreclaimed
);
2156 bcm_nvram_refresh(nvram_vars
);
2164 /* copy nvram vars into locally-allocated multi-string array */
2166 BCMINITFN(bcm_nvram_cache
)(void *sih
)
2172 if (vars_len
>= 0) {
2174 bcm_nvram_refresh(nvram_vars
);
2179 osh
= si_osh((si_t
*)sih
);
2181 /* allocate memory and read in flash */
2182 if (!(flash
= MALLOC(osh
, MAX_NVRAM_SPACE
))) {
2187 bcm_nvram_refresh(flash
);
2191 /* copy into a properly-sized buffer */
2192 if (!(nvram_vars
= MALLOC(osh
, vars_len
))) {
2195 bcopy(flash
, nvram_vars
, vars_len
);
2197 MFREE(osh
, flash
, MAX_NVRAM_SPACE
);
2199 /* cache must be full size of nvram if read/write */
2201 #endif /* BCMNVRAMR */
2206 #endif /* WLC_LOW */
2209 /* iovar table lookup */
2211 bcm_iovar_lookup(const bcm_iovar_t
*table
, const char *name
)
2213 const bcm_iovar_t
*vi
;
2214 const char *lookup_name
;
2216 /* skip any ':' delimited option prefixes */
2217 lookup_name
= strrchr(name
, ':');
2218 if (lookup_name
!= NULL
)
2223 ASSERT(table
!= NULL
);
2225 for (vi
= table
; vi
->name
; vi
++) {
2226 if (!strcmp(vi
->name
, lookup_name
))
2229 /* ran to end of table */
2231 return NULL
; /* var name not found */
2235 bcm_iovar_lencheck(const bcm_iovar_t
*vi
, void *arg
, int len
, bool set
)
2239 /* length check on io buf */
2248 /* all integers are int32 sized args at the ioctl interface */
2249 if (len
< (int)sizeof(int)) {
2250 bcmerror
= BCME_BUFTOOSHORT
;
2255 /* buffer must meet minimum length requirement */
2256 if (len
< vi
->minlen
) {
2257 bcmerror
= BCME_BUFTOOSHORT
;
2263 /* Cannot return nil... */
2264 bcmerror
= BCME_UNSUPPORTED
;
2266 /* Set is an action w/o parameters */
2267 bcmerror
= BCME_BUFTOOLONG
;
2272 /* unknown type for length check in iovar info */
2274 bcmerror
= BCME_UNSUPPORTED
;
2280 #endif /* BCMDRIVER */
2283 /*******************************************************************************
2286 * Computes a crc8 over the input data using the polynomial:
2288 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
2290 * The caller provides the initial value (either CRC8_INIT_VALUE
2291 * or the previous returned value) to allow for processing of
2292 * discontiguous blocks of data. When generating the CRC the
2293 * caller is responsible for complementing the final return value
2294 * and inserting it into the byte stream. When checking, a final
2295 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
2297 * Reference: Dallas Semiconductor Application Note 27
2298 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2299 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2300 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2302 * ****************************************************************************
2305 static const uint8 crc8_table
[256] = {
2306 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
2307 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
2308 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
2309 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
2310 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
2311 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
2312 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
2313 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
2314 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
2315 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
2316 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
2317 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
2318 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
2319 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
2320 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
2321 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
2322 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
2323 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
2324 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
2325 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
2326 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
2327 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
2328 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
2329 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
2330 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
2331 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
2332 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
2333 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
2334 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
2335 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
2336 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
2337 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
2340 #define CRC_INNER_LOOP(n, c, x) \
2341 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
2345 uint8
*pdata
, /* pointer to array of data to process */
2346 uint nbytes
, /* number of input data bytes to process */
2347 uint8 crc
/* either CRC8_INIT_VALUE or previous return value */
2350 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
2351 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
2353 while (nbytes
-- > 0)
2354 crc
= crc8_table
[(crc
^ *pdata
++) & 0xff];
2359 /*******************************************************************************
2362 * Computes a crc16 over the input data using the polynomial:
2364 * x^16 + x^12 +x^5 + 1
2366 * The caller provides the initial value (either CRC16_INIT_VALUE
2367 * or the previous returned value) to allow for processing of
2368 * discontiguous blocks of data. When generating the CRC the
2369 * caller is responsible for complementing the final return value
2370 * and inserting it into the byte stream. When checking, a final
2371 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
2373 * Reference: Dallas Semiconductor Application Note 27
2374 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2375 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2376 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2378 * ****************************************************************************
2381 static const uint16 crc16_table
[256] = {
2382 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
2383 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
2384 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
2385 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
2386 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
2387 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
2388 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
2389 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
2390 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
2391 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
2392 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
2393 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
2394 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
2395 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
2396 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
2397 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
2398 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
2399 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
2400 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
2401 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
2402 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
2403 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
2404 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
2405 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
2406 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
2407 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
2408 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
2409 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
2410 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
2411 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
2412 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
2413 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
2418 uint8
*pdata
, /* pointer to array of data to process */
2419 uint nbytes
, /* number of input data bytes to process */
2420 uint16 crc
/* either CRC16_INIT_VALUE or previous return value */
2423 while (nbytes
-- > 0)
2424 CRC_INNER_LOOP(16, crc
, *pdata
++);
2428 static const uint32 crc32_table
[256] = {
2429 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
2430 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
2431 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
2432 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
2433 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
2434 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
2435 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
2436 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
2437 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
2438 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
2439 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
2440 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
2441 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
2442 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
2443 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
2444 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
2445 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
2446 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
2447 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
2448 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
2449 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
2450 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
2451 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
2452 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
2453 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
2454 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
2455 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
2456 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
2457 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
2458 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
2459 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
2460 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
2461 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
2462 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
2463 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
2464 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
2465 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
2466 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
2467 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
2468 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
2469 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
2470 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
2471 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
2472 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
2473 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
2474 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
2475 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
2476 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
2477 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
2478 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
2479 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
2480 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
2481 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
2482 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
2483 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
2484 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
2485 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
2486 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
2487 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
2488 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
2489 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
2490 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
2491 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
2492 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
2496 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
2497 * accumulating over multiple pieces.
2500 BCMROMFN(hndcrc32
)(uint8
*pdata
, uint nbytes
, uint32 crc
)
2505 ulong
*tptr
= (ulong
*)tmp
;
2508 /* in case the beginning of the buffer isn't aligned */
2509 pend
= (uint8
*)((uint
)(pdata
+ 3) & ~0x3);
2510 nbytes
-= (pend
- pdata
);
2511 while (pdata
< pend
)
2512 CRC_INNER_LOOP(32, crc
, *pdata
++);
2516 /* handle bulk of data as 32-bit words */
2517 pend
= pdata
+ (nbytes
& ~0x3);
2518 while (pdata
< pend
) {
2519 *tptr
= *(ulong
*)pdata
;
2520 pdata
+= sizeof(ulong
*);
2521 CRC_INNER_LOOP(32, crc
, tmp
[0]);
2522 CRC_INNER_LOOP(32, crc
, tmp
[1]);
2523 CRC_INNER_LOOP(32, crc
, tmp
[2]);
2524 CRC_INNER_LOOP(32, crc
, tmp
[3]);
2528 /* 1-3 bytes at end of buffer */
2529 pend
= pdata
+ (nbytes
& 0x03);
2530 while (pdata
< pend
)
2531 CRC_INNER_LOOP(32, crc
, *pdata
++);
2533 pend
= pdata
+ nbytes
;
2534 while (pdata
< pend
)
2535 CRC_INNER_LOOP(32, crc
, *pdata
++);
2536 #endif /* __mips__ */
2542 #define CLEN 1499 /* CRC Length */
2543 #define CBUFSIZ (CLEN+4)
2544 #define CNBUFS 5 /* # of bufs */
2553 uint32 crc32tv
[CNBUFS
] =
2554 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
2556 ASSERT((buf
= MALLOC(CBUFSIZ
*CNBUFS
)) != NULL
);
2558 /* step through all possible alignments */
2559 for (l
= 0; l
<= 4; l
++) {
2560 for (j
= 0; j
< CNBUFS
; j
++) {
2562 for (k
= 0; k
< len
[j
]; k
++)
2563 *(buf
+ j
*CBUFSIZ
+ (k
+l
)) = (j
+k
) & 0xff;
2566 for (j
= 0; j
< CNBUFS
; j
++) {
2567 crcr
= crc32(buf
+ j
*CBUFSIZ
+ l
, len
[j
], CRC32_INIT_VALUE
);
2568 ASSERT(crcr
== crc32tv
[j
]);
2572 MFREE(buf
, CBUFSIZ
*CNBUFS
);
2578 * Advance from the current 1-byte tag/1-byte length/variable-length value
2579 * triple, to the next, returning a pointer to the next.
2580 * If the current or next TLV is invalid (does not fit in given buffer length),
2582 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
2583 * by the TLV parameter's length if it is valid.
2586 BCMROMFN(bcm_next_tlv
)(bcm_tlv_t
*elt
, int *buflen
)
2590 /* validate current elt */
2591 if (!bcm_valid_tlv(elt
, *buflen
))
2594 /* advance to next elt */
2596 elt
= (bcm_tlv_t
*)(elt
->data
+ len
);
2597 *buflen
-= (TLV_HDR_LEN
+ len
);
2599 /* validate next elt */
2600 if (!bcm_valid_tlv(elt
, *buflen
))
2607 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2608 * triples, returning a pointer to the substring whose first element
2612 BCMROMFN(bcm_parse_tlvs
)(void *buf
, int buflen
, uint key
)
2617 elt
= (bcm_tlv_t
*)buf
;
2620 /* find tagged parameter */
2621 while (totlen
>= TLV_HDR_LEN
) {
2624 /* validate remaining totlen */
2625 if ((elt
->id
== key
) &&
2626 (totlen
>= (len
+ TLV_HDR_LEN
)))
2629 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ TLV_HDR_LEN
));
2630 totlen
-= (len
+ TLV_HDR_LEN
);
2637 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2638 * triples, returning a pointer to the substring whose first element
2639 * matches tag. Stop parsing when we see an element whose ID is greater
2640 * than the target key.
2643 BCMROMFN(bcm_parse_ordered_tlvs
)(void *buf
, int buflen
, uint key
)
2648 elt
= (bcm_tlv_t
*)buf
;
2651 /* find tagged parameter */
2652 while (totlen
>= TLV_HDR_LEN
) {
2656 /* Punt if we start seeing IDs > than target key */
2660 /* validate remaining totlen */
2662 (totlen
>= (len
+ TLV_HDR_LEN
)))
2665 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ TLV_HDR_LEN
));
2666 totlen
-= (len
+ TLV_HDR_LEN
);
2671 #if defined(BCMDBG) || defined(BCMDBG_ERR) || defined(WLMSG_PRHDRS) || \
2672 defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || defined(DHD_DEBUG)
2674 bcm_format_field(const bcm_bit_desc_ex_t
*bd
, uint32 flags
, char* buf
, int len
)
2680 if (len
< 2 || !buf
)
2685 for (i
= 0; (name
= bd
->bitfield
[i
].name
) != NULL
; i
++) {
2686 bit
= bd
->bitfield
[i
].bit
;
2687 if ((flags
& mask
) == bit
) {
2688 if (len
> (int)strlen(name
)) {
2689 slen
= strlen(name
);
2690 strncpy(buf
, name
, slen
+1);
2699 bcm_format_flags(const bcm_bit_desc_t
*bd
, uint32 flags
, char* buf
, int len
)
2704 int slen
= 0, nlen
= 0;
2708 if (len
< 2 || !buf
)
2713 for (i
= 0; flags
!= 0; i
++) {
2716 if (bit
== 0 && flags
!= 0) {
2717 /* print any unnamed bits */
2718 snprintf(hexstr
, 16, "0x%X", flags
);
2720 flags
= 0; /* exit loop */
2721 } else if ((flags
& bit
) == 0)
2724 nlen
= strlen(name
);
2726 /* count btwn flag space */
2729 /* need NULL char as well */
2732 /* copy NULL char but don't count it */
2733 strncpy(p
, name
, nlen
+ 1);
2735 /* copy btwn flag space and NULL char */
2737 p
+= snprintf(p
, 2, " ");
2740 /* indicate the str was too short */
2743 p
-= 2 - len
; /* overwrite last char */
2744 p
+= snprintf(p
, 2, ">");
2747 return (int)(p
- buf
);
2750 /* print bytes formatted as hex to a string. return the resulting string length */
2752 bcm_format_hex(char *str
, const void *bytes
, int len
)
2756 const uint8
*src
= (const uint8
*)bytes
;
2758 for (i
= 0; i
< len
; i
++) {
2759 p
+= snprintf(p
, 3, "%02X", *src
);
2762 return (int)(p
- str
);
2766 /* pretty hex print a contiguous buffer */
2768 prhex(const char *msg
, uchar
*buf
, uint nbytes
)
2771 int len
= sizeof(line
);
2775 if (msg
&& (msg
[0] != '\0'))
2776 printf("%s:\n", msg
);
2779 for (i
= 0; i
< nbytes
; i
++) {
2781 nchar
= snprintf(p
, len
, " %04d: ", i
); /* line prefix */
2786 nchar
= snprintf(p
, len
, "%02x ", buf
[i
]);
2792 printf("%s\n", line
); /* flush line */
2798 /* flush last partial line */
2800 printf("%s\n", line
);
2803 static const char *crypto_algo_names
[] = {
2819 bcm_crypto_algo_name(uint algo
)
2821 return (algo
< ARRAYSIZE(crypto_algo_names
)) ? crypto_algo_names
[algo
] : "ERR";
2826 deadbeef(void *p
, uint len
)
2828 static uint8 meat
[] = { 0xde, 0xad, 0xbe, 0xef };
2831 *(uint8
*)p
= meat
[((uintptr
)p
) & 3];
2838 bcm_chipname(uint chipid
, char *buf
, uint len
)
2842 fmt
= ((chipid
> 0xa000) || (chipid
< 0x4000)) ? "%d" : "%x";
2843 snprintf(buf
, len
, fmt
, chipid
);
2847 /* Produce a human-readable string for boardrev */
2849 bcm_brev_str(uint32 brev
, char *buf
)
2852 snprintf(buf
, 8, "%d.%d", (brev
& 0xf0) >> 4, brev
& 0xf);
2854 snprintf(buf
, 8, "%c%03x", ((brev
& 0xf000) == 0x1000) ? 'P' : 'A', brev
& 0xfff);
2859 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
2861 /* dump large strings to console */
2870 max_len
= BUFSIZE_TODUMP_ATONCE
;
2872 while (len
> max_len
) {
2874 buf
[max_len
] = '\0';
2881 /* print the remaining string */
2882 printf("%s\n", buf
);
2886 /* routine to dump fields in a fileddesc structure */
2888 bcmdumpfields(bcmutl_rdreg_rtn read_rtn
, void *arg0
, uint arg1
, struct fielddesc
*fielddesc_array
,
2889 char *buf
, uint32 bufsize
)
2893 struct fielddesc
*cur_ptr
;
2896 cur_ptr
= fielddesc_array
;
2898 while (bufsize
> 1) {
2899 if (cur_ptr
->nameandfmt
== NULL
)
2901 len
= snprintf(buf
, bufsize
, cur_ptr
->nameandfmt
,
2902 read_rtn(arg0
, arg1
, cur_ptr
->offset
));
2903 /* check for snprintf overflow or error */
2904 if (len
< 0 || (uint32
)len
>= bufsize
)
2915 bcm_mkiovar(char *name
, char *data
, uint datalen
, char *buf
, uint buflen
)
2919 len
= strlen(name
) + 1;
2921 if ((len
+ datalen
) > buflen
)
2924 strncpy(buf
, name
, buflen
);
2926 /* append data onto the end of the name string */
2927 memcpy(&buf
[len
], data
, datalen
);
2933 /* Quarter dBm units to mW
2934 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
2935 * Table is offset so the last entry is largest mW value that fits in
2939 #define QDBM_OFFSET 153 /* Offset for first entry */
2940 #define QDBM_TABLE_LEN 40 /* Table size */
2942 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
2943 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
2945 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
2947 /* Largest mW value that will round down to the last table entry,
2948 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
2949 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
2951 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
2953 static const uint16 nqdBm_to_mW_map
[QDBM_TABLE_LEN
] = {
2954 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
2955 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
2956 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
2957 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
2958 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
2959 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
2963 BCMROMFN(bcm_qdbm_to_mw
)(uint8 qdbm
)
2966 int idx
= qdbm
- QDBM_OFFSET
;
2968 if (idx
>= QDBM_TABLE_LEN
) {
2969 /* clamp to max uint16 mW value */
2973 /* scale the qdBm index up to the range of the table 0-40
2974 * where an offset of 40 qdBm equals a factor of 10 mW.
2981 /* return the mW value scaled down to the correct factor of 10,
2982 * adding in factor/2 to get proper rounding.
2984 return ((nqdBm_to_mW_map
[idx
] + factor
/2) / factor
);
2988 BCMROMFN(bcm_mw_to_qdbm
)(uint16 mw
)
2995 /* handle boundary case */
2999 offset
= QDBM_OFFSET
;
3001 /* move mw into the range of the table */
3002 while (mw_uint
< QDBM_TABLE_LOW_BOUND
) {
3007 for (qdbm
= 0; qdbm
< QDBM_TABLE_LEN
-1; qdbm
++) {
3008 boundary
= nqdBm_to_mW_map
[qdbm
] + (nqdBm_to_mW_map
[qdbm
+1] -
3009 nqdBm_to_mW_map
[qdbm
])/2;
3010 if (mw_uint
< boundary
) break;
3013 qdbm
+= (uint8
)offset
;
3020 BCMROMFN(bcm_bitcount
)(uint8
*bitmap
, uint length
)
3022 uint bitcount
= 0, i
;
3024 for (i
= 0; i
< length
; i
++) {
3036 /* Initialization of bcmstrbuf structure */
3038 bcm_binit(struct bcmstrbuf
*b
, char *buf
, uint size
)
3040 b
->origsize
= b
->size
= size
;
3041 b
->origbuf
= b
->buf
= buf
;
3044 /* Buffer sprintf wrapper to guard against buffer overflow */
3046 bcm_bprintf(struct bcmstrbuf
*b
, const char *fmt
, ...)
3053 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
3055 /* Non Ansi C99 compliant returns -1,
3056 * Ansi compliant return r >= b->size,
3057 * bcmstdlib returns 0, handle all
3059 /* r == 0 is also the case when strlen(fmt) is zero.
3060 * typically the case when "" is passed as argument.
3062 if ((r
== -1) || (r
>= (int)b
->size
)) {
3075 bcm_bprhex(struct bcmstrbuf
*b
, const char *msg
, bool newline
, uint8
*buf
, int len
)
3079 if (msg
!= NULL
&& msg
[0] != '\0')
3080 bcm_bprintf(b
, "%s", msg
);
3081 for (i
= 0; i
< len
; i
++)
3082 bcm_bprintf(b
, "%02X", buf
[i
]);
3084 bcm_bprintf(b
, "\n");
3088 bcm_inc_bytes(uchar
*num
, int num_bytes
, uint8 amount
)
3092 for (i
= 0; i
< num_bytes
; i
++) {
3094 if (num
[i
] >= amount
)
3101 bcm_cmp_bytes(const uchar
*arg1
, const uchar
*arg2
, uint8 nbytes
)
3105 for (i
= nbytes
- 1; i
>= 0; i
--) {
3106 if (arg1
[i
] != arg2
[i
])
3107 return (arg1
[i
] - arg2
[i
]);
3113 bcm_print_bytes(const char *name
, const uchar
*data
, int len
)
3118 printf("%s: %d \n", name
? name
: "", len
);
3119 for (i
= 0; i
< len
; i
++) {
3120 printf("%02x ", *data
++);
3122 if (per_line
== 16) {
3129 #if defined(WLTINYDUMP) || defined(BCMDBG) || defined(WLMSG_INFORM) || \
3130 defined(WLMSG_ASSOC) || defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
3131 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
3134 bcm_format_ssid(char* buf
, const uchar ssid
[], uint ssid_len
)
3138 char *endp
= buf
+ SSID_FMT_BUF_LEN
;
3140 if (ssid_len
> DOT11_MAX_SSID_LEN
) ssid_len
= DOT11_MAX_SSID_LEN
;
3142 for (i
= 0; i
< ssid_len
; i
++) {
3147 } else if (bcm_isprint((uchar
)c
)) {
3150 p
+= snprintf(p
, (endp
- p
), "\\x%02X", c
);
3156 return (int)(p
- buf
);
3158 #endif /* WLTINYDUMP || BCMDBG || WLMSG_INFORM || WLMSG_ASSOC || WLMSG_PRPKT */
3160 #endif /* BCMDRIVER */
3163 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
3164 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
3165 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
3166 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
3170 process_nvram_vars(char *varbuf
, unsigned int len
)
3175 unsigned int buf_len
, n
;
3176 unsigned int pad
= 0;
3180 findNewline
= FALSE
;
3183 for (n
= 0; n
< len
; n
++) {
3184 if (varbuf
[n
] == '\r')
3186 if (findNewline
&& varbuf
[n
] != '\n')
3188 findNewline
= FALSE
;
3189 if (varbuf
[n
] == '#') {
3193 if (varbuf
[n
] == '\n') {
3203 buf_len
= (unsigned int)(dp
- varbuf
);
3205 pad
= 4 - buf_len
% 4;
3206 if (pad
&& (buf_len
+ pad
<= len
)) {
3211 while (dp
< varbuf
+ n
)
3217 /* calculate a * b + c */
3219 bcm_uint64_multiple_add(uint32
* r_high
, uint32
* r_low
, uint32 a
, uint32 b
, uint32 c
)
3221 #define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;}
3223 uint32 a1
, a0
, b1
, b0
, t
, cc
= 0;
3233 t
= (a1
* b0
) << 16;
3239 t
= (a0
* b1
) << 16;
3250 r0
|= (cc
% 2) ? 0x80000000 : 0;
3251 r1
= a1
* b1
+ ((a1
* b0
) >> 16) + ((b1
* a0
) >> 16) + (cc
/ 2);
3257 /* calculate a / b */
3259 bcm_uint64_divide(uint32
* r
, uint32 a_high
, uint32 a_low
, uint32 b
)
3261 uint32 a1
= a_high
, a0
= a_low
, r0
= 0;
3267 r0
+= (0xffffffff / b
) * a1
;
3268 bcm_uint64_multiple_add(&a1
, &a0
, ((0xffffffff % b
) + 1) % b
, a1
, a0
);