2 * Misc useful OS-independent routines.
4 * Copyright 2006, Broadcom Corporation
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 * $Id: bcmutils.c,v 1.1.1.12 2006/02/27 03:43:16 honor Exp $
18 #include "linux_osl.h"
23 #include <bcmendian.h>
27 #define ETHER_TYPE_8021Q 0x8100
28 #define ETHER_TYPE_IP 0x0800
29 #define VLAN_PRI_SHIFT 13
30 #define VLAN_PRI_MASK 7
37 } __attribute__((packed
));
40 struct ethervlan_header
{
43 uint16 vlan_type
; /* 0x8100 */
44 uint16 vlan_tag
; /* priority, cfi and vid */
48 /* copy a pkt buffer chain into a buffer */
50 pktcopy(osl_t
*osh
, void *p
, uint offset
, int len
, uchar
*buf
)
55 len
= 4096; /* "infinite" */
57 /* skip 'offset' bytes */
58 for (; p
&& offset
; p
= PKTNEXT(osh
, p
)) {
59 if (offset
< (uint
)PKTLEN(osh
, p
))
61 offset
-= PKTLEN(osh
, p
);
68 for (; p
&& len
; p
= PKTNEXT(osh
, p
)) {
69 n
= MIN((uint
)PKTLEN(osh
, p
) - offset
, (uint
)len
);
70 bcopy(PKTDATA(osh
, p
) + offset
, buf
, n
);
80 /* return total length of buffer chain */
82 pkttotlen(osl_t
*osh
, void *p
)
87 for (; p
; p
= PKTNEXT(osh
, p
))
88 total
+= PKTLEN(osh
, p
);
92 /* return the last buffer of chained pkt */
94 pktlast(osl_t
*osh
, void *p
)
96 for (; PKTNEXT(osh
, p
); p
= PKTNEXT(osh
, p
))
104 * osl multiple-precedence packet queue
105 * hi_prec is always >= the number of the highest non-empty queue
108 pktq_penq(struct pktq
*pq
, int prec
, void *p
)
112 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
113 ASSERT(PKTLINK(p
) == NULL
); /* queueing chains not allowed */
115 ASSERT(!pktq_full(pq
));
116 ASSERT(!pktq_pfull(pq
, prec
));
121 PKTSETLINK(q
->tail
, p
);
130 if (pq
->hi_prec
< prec
)
131 pq
->hi_prec
= (uint8
)prec
;
137 pktq_penq_head(struct pktq
*pq
, int prec
, void *p
)
141 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
142 ASSERT(PKTLINK(p
) == NULL
); /* queueing chains not allowed */
144 ASSERT(!pktq_full(pq
));
145 ASSERT(!pktq_pfull(pq
, prec
));
152 PKTSETLINK(p
, q
->head
);
158 if (pq
->hi_prec
< prec
)
159 pq
->hi_prec
= (uint8
)prec
;
165 pktq_pdeq(struct pktq
*pq
, int prec
)
170 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
174 if ((p
= q
->head
) == NULL
)
177 if ((q
->head
= PKTLINK(p
)) == NULL
)
190 pktq_pdeq_tail(struct pktq
*pq
, int prec
)
195 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
199 if ((p
= q
->head
) == NULL
)
202 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK(p
))
206 PKTSETLINK(prev
, NULL
);
219 pktq_pflush(osl_t
*osh
, struct pktq
*pq
, int prec
, bool dir
)
227 q
->head
= PKTLINK(p
);
229 PKTFREE(osh
, p
, dir
);
239 pktq_pdel(struct pktq
*pq
, void *pktbuf
, int prec
)
244 ASSERT(prec
>= 0 && prec
< pq
->num_prec
);
251 if (q
->head
== pktbuf
) {
252 if ((q
->head
= PKTLINK(pktbuf
)) == NULL
)
255 for (p
= q
->head
; p
&& PKTLINK(p
) != pktbuf
; p
= PKTLINK(p
))
260 PKTSETLINK(p
, PKTLINK(pktbuf
));
261 if (q
->tail
== pktbuf
)
267 PKTSETLINK(pktbuf
, NULL
);
272 pktq_init(struct pktq
*pq
, int num_prec
, int max_len
)
276 ASSERT(num_prec
> 0 && num_prec
<= PKTQ_MAX_PREC
);
278 bzero(pq
, sizeof(*pq
));
280 pq
->num_prec
= (uint16
)num_prec
;
282 pq
->max
= (uint16
)max_len
;
284 for (prec
= 0; prec
< num_prec
; prec
++)
285 pq
->q
[prec
].max
= pq
->max
;
289 pktq_deq(struct pktq
*pq
, int *prec_out
)
298 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
303 if ((p
= q
->head
) == NULL
)
306 if ((q
->head
= PKTLINK(p
)) == NULL
)
322 pktq_deq_tail(struct pktq
*pq
, int *prec_out
)
331 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
332 if (pq
->q
[prec
].head
)
337 if ((p
= q
->head
) == NULL
)
340 for (prev
= NULL
; p
!= q
->tail
; p
= PKTLINK(p
))
344 PKTSETLINK(prev
, NULL
);
362 pktq_peek(struct pktq
*pq
, int *prec_out
)
369 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
375 return (pq
->q
[prec
].head
);
379 pktq_peek_tail(struct pktq
*pq
, int *prec_out
)
386 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
387 if (pq
->q
[prec
].head
)
393 return (pq
->q
[prec
].tail
);
397 pktq_flush(osl_t
*osh
, struct pktq
*pq
, bool dir
)
400 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
401 pktq_pflush(osh
, pq
, prec
, dir
);
402 ASSERT(pq
->len
== 0);
405 /* Return sum of lengths of a specific set of precedences */
407 pktq_mlen(struct pktq
*pq
, uint prec_bmp
)
413 for (prec
= 0; prec
<= pq
->hi_prec
; prec
++)
414 if (prec_bmp
& (1 << prec
))
415 len
+= pq
->q
[prec
].len
;
420 /* Priority dequeue from a specific set of precedences */
422 pktq_mdeq(struct pktq
*pq
, uint prec_bmp
, int *prec_out
)
431 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
434 while ((prec_bmp
& (1 << prec
)) == 0 || pq
->q
[prec
].head
== NULL
)
440 if ((p
= q
->head
) == NULL
)
443 if ((q
->head
= PKTLINK(p
)) == NULL
)
459 bcmstrcat(char *dest
, const char *src
)
461 strcpy(&dest
[strlen(dest
)], src
);
466 bcm_ether_ntoa(struct ether_addr
*ea
, char *buf
)
468 sprintf(buf
, "%02x:%02x:%02x:%02x:%02x:%02x",
469 ea
->octet
[0]&0xff, ea
->octet
[1]&0xff, ea
->octet
[2]&0xff,
470 ea
->octet
[3]&0xff, ea
->octet
[4]&0xff, ea
->octet
[5]&0xff);
474 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
476 bcm_ether_atoe(char *p
, struct ether_addr
*ea
)
481 ea
->octet
[i
++] = (char) bcm_strtoul(p
, &p
, 16);
489 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO
490 * Also updates the inplace vlan tag if requested
493 pktsetprio(void *pkt
, bool update_vtag
)
495 struct ether_header
*eh
;
496 struct ethervlan_header
*evh
;
500 pktdata
= (uint8
*) PKTDATA(NULL
, pkt
);
501 ASSERT(ISALIGNED((uintptr
)pktdata
, sizeof(uint16
)));
503 eh
= (struct ether_header
*) pktdata
;
505 if (ntoh16(eh
->ether_type
) == ETHER_TYPE_8021Q
) {
507 int vlan_prio
, dscp_prio
= 0;
509 evh
= (struct ethervlan_header
*)eh
;
511 vlan_tag
= ntoh16(evh
->vlan_tag
);
512 vlan_prio
= (int) (vlan_tag
>> VLAN_PRI_SHIFT
) & VLAN_PRI_MASK
;
514 if (ntoh16(evh
->ether_type
) == ETHER_TYPE_IP
) {
515 uint8
*ip_body
= pktdata
+ sizeof(struct ethervlan_header
);
516 uint8 tos_tc
= IP_TOS(ip_body
);
517 dscp_prio
= (int)(tos_tc
>> IPV4_TOS_PREC_SHIFT
);
520 /* DSCP priority gets precedence over 802.1P (vlan tag) */
521 priority
= (dscp_prio
!= 0) ? dscp_prio
: vlan_prio
;
524 * If the DSCP priority is not the same as the VLAN priority,
525 * then overwrite the priority field in the vlan tag, with the
526 * DSCP priority value. This is required for Linux APs because
527 * the VLAN driver on Linux, overwrites the skb->priority field
528 * with the priority value in the vlan tag
530 if (update_vtag
&& (priority
!= vlan_prio
)) {
531 vlan_tag
&= ~(VLAN_PRI_MASK
<< VLAN_PRI_SHIFT
);
532 vlan_tag
|= (uint16
)priority
<< VLAN_PRI_SHIFT
;
533 evh
->vlan_tag
= hton16(vlan_tag
);
535 } else if (ntoh16(eh
->ether_type
) == ETHER_TYPE_IP
) {
536 uint8
*ip_body
= pktdata
+ sizeof(struct ether_header
);
537 uint8 tos_tc
= IP_TOS(ip_body
);
538 priority
= (int)(tos_tc
>> IPV4_TOS_PREC_SHIFT
);
541 ASSERT(priority
>= 0 && priority
<= MAXPRIO
);
542 PKTSETPRIO(pkt
, priority
);
545 static char bcm_undeferrstr
[BCME_STRLEN
];
547 static const char *bcmerrorstrtable
[] = BCMERRSTRINGTABLE
;
549 /* Convert the Error codes into related Error strings */
551 bcmerrorstr(int bcmerror
)
555 abs_bcmerror
= ABS(bcmerror
);
557 /* check if someone added a bcmerror code but forgot to add errorstring */
558 ASSERT(ABS(BCME_LAST
) == (ARRAYSIZE(bcmerrorstrtable
) - 1));
559 if ((bcmerror
> 0) || (abs_bcmerror
> ABS(BCME_LAST
))) {
560 sprintf(bcm_undeferrstr
, "undefined Error %d", bcmerror
);
561 return bcm_undeferrstr
;
564 ASSERT((strlen((char*)bcmerrorstrtable
[abs_bcmerror
])) < BCME_STRLEN
);
566 return bcmerrorstrtable
[abs_bcmerror
];
571 bcm_iovar_lencheck(const bcm_iovar_t
*vi
, void *arg
, int len
, bool set
)
575 /* length check on io buf */
584 /* all integers are int32 sized args at the ioctl interface */
585 if (len
< (int)sizeof(int)) {
586 bcmerror
= BCME_BUFTOOSHORT
;
591 /* buffer must meet minimum length requirement */
592 if (len
< vi
->minlen
) {
593 bcmerror
= BCME_BUFTOOSHORT
;
599 /* Cannot return nil... */
600 bcmerror
= BCME_UNSUPPORTED
;
602 /* Set is an action w/o parameters */
603 bcmerror
= BCME_BUFTOOLONG
;
608 /* unknown type for length check in iovar info */
610 bcmerror
= BCME_UNSUPPORTED
;
616 #define CRC_INNER_LOOP(n, c, x) \
617 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
619 static uint32 crc32_table
[256] = {
620 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
621 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
622 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
623 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
624 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
625 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
626 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
627 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
628 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
629 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
630 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
631 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
632 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
633 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
634 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
635 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
636 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
637 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
638 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
639 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
640 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
641 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
642 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
643 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
644 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
645 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
646 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
647 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
648 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
649 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
650 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
651 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
652 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
653 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
654 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
655 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
656 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
657 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
658 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
659 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
660 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
661 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
662 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
663 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
664 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
665 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
666 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
667 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
668 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
669 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
670 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
671 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
672 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
673 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
674 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
675 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
676 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
677 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
678 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
679 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
680 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
681 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
682 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
683 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
688 uint8
*pdata
, /* pointer to array of data to process */
689 uint nbytes
, /* number of input data bytes to process */
690 uint32 crc
/* either CRC32_INIT_VALUE or previous return value */
696 ulong
*tptr
= (ulong
*)tmp
;
698 /* in case the beginning of the buffer isn't aligned */
699 pend
= (uint8
*)((uint
)(pdata
+ 3) & 0xfffffffc);
700 nbytes
-= (pend
- pdata
);
702 CRC_INNER_LOOP(32, crc
, *pdata
++);
704 /* handle bulk of data as 32-bit words */
705 pend
= pdata
+ (nbytes
& 0xfffffffc);
706 while (pdata
< pend
) {
707 *tptr
= *(ulong
*)pdata
;
708 pdata
+= sizeof(ulong
*);
709 CRC_INNER_LOOP(32, crc
, tmp
[0]);
710 CRC_INNER_LOOP(32, crc
, tmp
[1]);
711 CRC_INNER_LOOP(32, crc
, tmp
[2]);
712 CRC_INNER_LOOP(32, crc
, tmp
[3]);
715 /* 1-3 bytes at end of buffer */
716 pend
= pdata
+ (nbytes
& 0x03);
718 CRC_INNER_LOOP(32, crc
, *pdata
++);
720 pend
= pdata
+ nbytes
;
722 CRC_INNER_LOOP(32, crc
, *pdata
++);
723 #endif /* __mips__ */
730 * Advance from the current 1-byte tag/1-byte length/variable-length value
731 * triple, to the next, returning a pointer to the next.
732 * If the current or next TLV is invalid (does not fit in given buffer length),
734 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
735 * by the TLV paramter's length if it is valid.
738 bcm_next_tlv(bcm_tlv_t
*elt
, int *buflen
)
742 /* validate current elt */
743 if (!bcm_valid_tlv(elt
, *buflen
))
746 /* advance to next elt */
748 elt
= (bcm_tlv_t
*)(elt
->data
+ len
);
749 *buflen
-= (2 + len
);
751 /* validate next elt */
752 if (!bcm_valid_tlv(elt
, *buflen
))
759 * Traverse a string of 1-byte tag/1-byte length/variable-length value
760 * triples, returning a pointer to the substring whose first element
764 bcm_parse_tlvs(void *buf
, int buflen
, uint key
)
769 elt
= (bcm_tlv_t
*)buf
;
772 /* find tagged parameter */
773 while (totlen
>= 2) {
776 /* validate remaining totlen */
777 if ((elt
->id
== key
) && (totlen
>= (len
+ 2)))
780 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ 2));
788 * Traverse a string of 1-byte tag/1-byte length/variable-length value
789 * triples, returning a pointer to the substring whose first element
790 * matches tag. Stop parsing when we see an element whose ID is greater
791 * than the target key.
794 bcm_parse_ordered_tlvs(void *buf
, int buflen
, uint key
)
799 elt
= (bcm_tlv_t
*)buf
;
802 /* find tagged parameter */
803 while (totlen
>= 2) {
807 /* Punt if we start seeing IDs > than target key */
811 /* validate remaining totlen */
812 if ((id
== key
) && (totlen
>= (len
+ 2)))
815 elt
= (bcm_tlv_t
*)((uint8
*)elt
+ (len
+ 2));
822 /* Initialization of bcmstrbuf structure */
824 bcm_binit(struct bcmstrbuf
*b
, char *buf
, uint size
)
826 b
->origsize
= b
->size
= size
;
827 b
->origbuf
= b
->buf
= buf
;
830 /* Buffer sprintf wrapper to guard against buffer overflow */
832 bcm_bprintf(struct bcmstrbuf
*b
, const char *fmt
, ...)
838 r
= vsnprintf(b
->buf
, b
->size
, fmt
, ap
);
840 /* Non Ansi C99 compliant returns -1,
841 * Ansi compliant return r >= b->size,
842 * bcmstdlib returns 0, handle all
844 if ((r
== -1) || (r
>= (int)b
->size
) || (r
== 0))
This page took 0.084691 seconds and 5 git commands to generate.