TomatoVPN 1.27vpn3.6 release
[tomato.git] / release / src / shared / bcmutils.c
blob1cc10c6e675c8428a7cd45a825f14612beb6fd24
1 /*
2 * Misc useful OS-independent routines.
4 * Copyright 2005, Broadcom Corporation
5 * All Rights Reserved.
6 *
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.9 2005/03/07 07:31:12 kanki Exp $
14 #include <typedefs.h>
15 #ifdef BCMDRIVER
16 #include <osl.h>
17 #include <bcmnvram.h>
18 #else
19 #include <stdio.h>
20 #include <string.h>
21 #endif
22 #include <bcmutils.h>
23 #include <bcmendian.h>
24 #include <bcmdevs.h>
26 #ifdef BCMDRIVER
27 /* copy a pkt buffer chain into a buffer */
28 uint
29 pktcopy(void *drv, void *p, uint offset, int len, uchar *buf)
31 uint n, ret = 0;
33 if (len < 0)
34 len = 4096; /* "infinite" */
36 /* skip 'offset' bytes */
37 for (; p && offset; p = PKTNEXT(drv, p)) {
38 if (offset < (uint)PKTLEN(drv, p))
39 break;
40 offset -= PKTLEN(drv, p);
43 if (!p)
44 return 0;
46 /* copy the data */
47 for (; p && len; p = PKTNEXT(drv, p)) {
48 n = MIN((uint)PKTLEN(drv, p) - offset, (uint)len);
49 bcopy(PKTDATA(drv, p) + offset, buf, n);
50 buf += n;
51 len -= n;
52 ret += n;
53 offset = 0;
56 return ret;
59 /* return total length of buffer chain */
60 uint
61 pkttotlen(void *drv, void *p)
63 uint total;
65 total = 0;
66 for (; p; p = PKTNEXT(drv, p))
67 total += PKTLEN(drv, p);
68 return (total);
71 void
72 pktq_init(struct pktq *q, uint maxlen, const uint8 prio_map[])
74 q->head = q->tail = NULL;
75 q->maxlen = maxlen;
76 q->len = 0;
77 if (prio_map) {
78 q->priority = TRUE;
79 bcopy(prio_map, q->prio_map, sizeof(q->prio_map));
81 else
82 q->priority = FALSE;
85 /* should always check pktq_full before calling pktenq */
86 void
87 pktenq(struct pktq *q, void *p, bool lifo)
89 void *next, *prev;
91 /* allow 10 pkts slack */
92 ASSERT(q->len < (q->maxlen + 10));
94 /* Queueing chains not allowed */
95 ASSERT(PKTLINK(p) == NULL);
97 /* Queue is empty */
98 if (q->tail == NULL) {
99 ASSERT(q->head == NULL);
100 q->head = q->tail = p;
103 /* Insert at head or tail */
104 else if (q->priority == FALSE) {
105 /* Insert at head (LIFO) */
106 if (lifo) {
107 PKTSETLINK(p, q->head);
108 q->head = p;
110 /* Insert at tail (FIFO) */
111 else {
112 ASSERT(PKTLINK(q->tail) == NULL);
113 PKTSETLINK(q->tail, p);
114 PKTSETLINK(p, NULL);
115 q->tail = p;
119 /* Insert by priority */
120 else {
121 /* legal priorities 0-7 */
122 ASSERT(PKTPRIO(p) <= MAXPRIO);
124 ASSERT(q->head);
125 ASSERT(q->tail);
126 /* Shortcut to insertion at tail */
127 if (_pktq_pri(q, PKTPRIO(p)) < _pktq_pri(q, PKTPRIO(q->tail)) ||
128 (!lifo && _pktq_pri(q, PKTPRIO(p)) <= _pktq_pri(q, PKTPRIO(q->tail)))) {
129 prev = q->tail;
130 next = NULL;
132 /* Insert at head or in the middle */
133 else {
134 prev = NULL;
135 next = q->head;
137 /* Walk the queue */
138 for (; next; prev = next, next = PKTLINK(next)) {
139 /* Priority queue invariant */
140 ASSERT(!prev || _pktq_pri(q, PKTPRIO(prev)) >= _pktq_pri(q, PKTPRIO(next)));
141 /* Insert at head of string of packets of same priority (LIFO) */
142 if (lifo) {
143 if (_pktq_pri(q, PKTPRIO(p)) >= _pktq_pri(q, PKTPRIO(next)))
144 break;
146 /* Insert at tail of string of packets of same priority (FIFO) */
147 else {
148 if (_pktq_pri(q, PKTPRIO(p)) > _pktq_pri(q, PKTPRIO(next)))
149 break;
152 /* Insert at tail */
153 if (next == NULL) {
154 ASSERT(PKTLINK(q->tail) == NULL);
155 PKTSETLINK(q->tail, p);
156 PKTSETLINK(p, NULL);
157 q->tail = p;
159 /* Insert in the middle */
160 else if (prev) {
161 PKTSETLINK(prev, p);
162 PKTSETLINK(p, next);
164 /* Insert at head */
165 else {
166 PKTSETLINK(p, q->head);
167 q->head = p;
171 /* List invariants after insertion */
172 ASSERT(q->head);
173 ASSERT(PKTLINK(q->tail) == NULL);
175 q->len++;
178 /* dequeue packet at head */
179 void*
180 pktdeq(struct pktq *q)
182 void *p;
184 if ((p = q->head)) {
185 ASSERT(q->tail);
186 q->head = PKTLINK(p);
187 PKTSETLINK(p, NULL);
188 q->len--;
189 if (q->head == NULL)
190 q->tail = NULL;
192 else {
193 ASSERT(q->tail == NULL);
196 return (p);
199 /* dequeue packet at tail */
200 void*
201 pktdeqtail(struct pktq *q)
203 void *p;
204 void *next, *prev;
206 if (q->head == q->tail) { /* last packet on queue or queue empty */
207 p = q->head;
208 q->head = q->tail = NULL;
209 q->len = 0;
210 return(p);
213 /* start walk at head */
214 prev = NULL;
215 next = q->head;
217 /* Walk the queue to find prev of q->tail */
218 for (; next; prev = next, next = PKTLINK(next)) {
219 if (next == q->tail)
220 break;
223 ASSERT(prev);
225 PKTSETLINK(prev, NULL);
226 q->tail = prev;
227 q->len--;
228 p = next;
230 return (p);
233 unsigned char bcm_ctype[] = {
234 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
235 _BCM_C,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C,_BCM_C, /* 8-15 */
236 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
237 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
238 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
239 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
240 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
241 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
242 _BCM_P,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U, /* 64-71 */
243 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
244 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
245 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
246 _BCM_P,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L, /* 96-103 */
247 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
248 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
249 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
250 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
251 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
252 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 160-175 */
253 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 176-191 */
254 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 192-207 */
255 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_L, /* 208-223 */
256 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 224-239 */
257 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L /* 240-255 */
260 uchar
261 bcm_toupper(uchar c)
263 if (bcm_islower(c))
264 c -= 'a'-'A';
265 return (c);
268 ulong
269 bcm_strtoul(char *cp, char **endp, uint base)
271 ulong result, value;
272 bool minus;
274 minus = FALSE;
276 while (bcm_isspace(*cp))
277 cp++;
279 if (cp[0] == '+')
280 cp++;
281 else if (cp[0] == '-') {
282 minus = TRUE;
283 cp++;
286 if (base == 0) {
287 if (cp[0] == '0') {
288 if ((cp[1] == 'x') || (cp[1] == 'X')) {
289 base = 16;
290 cp = &cp[2];
291 } else {
292 base = 8;
293 cp = &cp[1];
295 } else
296 base = 10;
297 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
298 cp = &cp[2];
301 result = 0;
303 while (bcm_isxdigit(*cp) &&
304 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
305 result = result*base + value;
306 cp++;
309 if (minus)
310 result = (ulong)(result * -1);
312 if (endp)
313 *endp = (char *)cp;
315 return (result);
318 uint
319 bcm_atoi(char *s)
321 uint n;
323 n = 0;
325 while (bcm_isdigit(*s))
326 n = (n * 10) + *s++ - '0';
327 return (n);
330 /* return pointer to location of substring 'needle' in 'haystack' */
331 char*
332 bcmstrstr(char *haystack, char *needle)
334 int len, nlen;
335 int i;
337 if ((haystack == NULL) || (needle == NULL))
338 return (haystack);
340 nlen = strlen(needle);
341 len = strlen(haystack) - nlen + 1;
343 for (i = 0; i < len; i++)
344 if (bcmp(needle, &haystack[i], nlen) == 0)
345 return (&haystack[i]);
346 return (NULL);
349 char*
350 bcmstrcat(char *dest, const char *src)
352 strcpy(&dest[strlen(dest)], src);
353 return (dest);
356 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
357 /* registry routine buffer preparation utility functions:
358 * parameter order is like strncpy, but returns count
359 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
361 ulong
362 wchar2ascii(
363 char *abuf,
364 ushort *wbuf,
365 ushort wbuflen,
366 ulong abuflen
369 ulong copyct = 1;
370 ushort i;
372 if (abuflen == 0)
373 return 0;
375 /* wbuflen is in bytes */
376 wbuflen /= sizeof(ushort);
378 for (i = 0; i < wbuflen; ++i) {
379 if (--abuflen == 0)
380 break;
381 *abuf++ = (char) *wbuf++;
382 ++copyct;
384 *abuf = '\0';
386 return copyct;
388 #endif
390 char*
391 bcm_ether_ntoa(char *ea, char *buf)
393 sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x",
394 (uchar)ea[0]&0xff, (uchar)ea[1]&0xff, (uchar)ea[2]&0xff,
395 (uchar)ea[3]&0xff, (uchar)ea[4]&0xff, (uchar)ea[5]&0xff);
396 return (buf);
399 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
401 bcm_ether_atoe(char *p, char *ea)
403 int i = 0;
405 for (;;) {
406 ea[i++] = (char) bcm_strtoul(p, &p, 16);
407 if (!*p++ || i == 6)
408 break;
411 return (i == 6);
414 void
415 bcm_mdelay(uint ms)
417 uint i;
419 for (i = 0; i < ms; i++) {
420 OSL_DELAY(1000);
425 * Search the name=value vars for a specific one and return its value.
426 * Returns NULL if not found.
428 char*
429 getvar(char *vars, char *name)
431 char *s;
432 int len;
434 len = strlen(name);
436 /* first look in vars[] */
437 for (s = vars; s && *s; ) {
438 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
439 return (&s[len+1]);
441 while (*s++)
445 /* then query nvram */
446 return (BCMINIT(nvram_get)(name));
450 * Search the vars for a specific one and return its value as
451 * an integer. Returns 0 if not found.
454 getintvar(char *vars, char *name)
456 char *val;
458 if ((val = getvar(vars, name)) == NULL)
459 return (0);
461 return (bcm_strtoul(val, NULL, 0));
464 /* Return gpio pin number assigned to the named pin */
466 * Variable should be in format:
468 * gpio<N>=pin_name
470 * 'def_pin' is returned if there is no such variable found.
472 uint
473 getgpiopin(char *vars, char *pin_name, uint def_pin)
475 char name[] = "gpioXXXX";
476 char *val;
477 uint pin;
479 /* Go thru all possibilities till a match in pin name */
480 for (pin = 0; pin < GPIO_NUMPINS; pin ++) {
481 sprintf(name, "gpio%d", pin);
482 val = getvar(vars, name);
483 if (val && !strcmp(val, pin_name))
484 return pin;
486 return def_pin;
489 #endif /* #ifdef BCMDRIVER */
491 /*******************************************************************************
492 * crc8
494 * Computes a crc8 over the input data using the polynomial:
496 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
498 * The caller provides the initial value (either CRC8_INIT_VALUE
499 * or the previous returned value) to allow for processing of
500 * discontiguous blocks of data. When generating the CRC the
501 * caller is responsible for complementing the final return value
502 * and inserting it into the byte stream. When checking, a final
503 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
505 * Reference: Dallas Semiconductor Application Note 27
506 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
507 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
508 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
510 ******************************************************************************/
512 static uint8 crc8_table[256] = {
513 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
514 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
515 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
516 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
517 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
518 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
519 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
520 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
521 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
522 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
523 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
524 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
525 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
526 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
527 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
528 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
529 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
530 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
531 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
532 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
533 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
534 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
535 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
536 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
537 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
538 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
539 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
540 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
541 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
542 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
543 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
544 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
547 #define CRC_INNER_LOOP(n, c, x) \
548 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
550 uint8
551 hndcrc8(
552 uint8 *pdata, /* pointer to array of data to process */
553 uint nbytes, /* number of input data bytes to process */
554 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
557 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
558 * to avoid the undefined and unnecessary (uint8 >> 8) operation. */
559 while (nbytes-- > 0)
560 crc = crc8_table[(crc ^ *pdata++) & 0xff];
562 return crc;
565 /*******************************************************************************
566 * crc16
568 * Computes a crc16 over the input data using the polynomial:
570 * x^16 + x^12 +x^5 + 1
572 * The caller provides the initial value (either CRC16_INIT_VALUE
573 * or the previous returned value) to allow for processing of
574 * discontiguous blocks of data. When generating the CRC the
575 * caller is responsible for complementing the final return value
576 * and inserting it into the byte stream. When checking, a final
577 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
579 * Reference: Dallas Semiconductor Application Note 27
580 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
581 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
582 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
584 ******************************************************************************/
586 static uint16 crc16_table[256] = {
587 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
588 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
589 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
590 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
591 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
592 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
593 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
594 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
595 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
596 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
597 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
598 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
599 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
600 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
601 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
602 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
603 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
604 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
605 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
606 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
607 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
608 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
609 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
610 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
611 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
612 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
613 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
614 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
615 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
616 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
617 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
618 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
621 uint16
622 hndcrc16(
623 uint8 *pdata, /* pointer to array of data to process */
624 uint nbytes, /* number of input data bytes to process */
625 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
628 while (nbytes-- > 0)
629 CRC_INNER_LOOP(16, crc, *pdata++);
630 return crc;
633 static uint32 crc32_table[256] = {
634 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
635 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
636 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
637 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
638 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
639 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
640 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
641 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
642 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
643 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
644 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
645 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
646 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
647 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
648 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
649 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
650 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
651 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
652 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
653 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
654 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
655 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
656 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
657 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
658 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
659 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
660 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
661 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
662 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
663 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
664 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
665 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
666 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
667 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
668 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
669 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
670 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
671 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
672 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
673 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
674 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
675 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
676 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
677 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
678 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
679 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
680 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
681 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
682 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
683 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
684 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
685 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
686 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
687 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
688 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
689 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
690 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
691 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
692 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
693 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
694 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
695 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
696 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
697 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
700 uint32
701 hndcrc32(
702 uint8 *pdata, /* pointer to array of data to process */
703 uint nbytes, /* number of input data bytes to process */
704 uint32 crc /* either CRC32_INIT_VALUE or previous return value */
707 uint8 *pend;
708 #ifdef __mips__
709 uint8 tmp[4];
710 ulong *tptr = (ulong *)tmp;
712 /* in case the beginning of the buffer isn't aligned */
713 pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
714 nbytes -= (pend - pdata);
715 while (pdata < pend)
716 CRC_INNER_LOOP(32, crc, *pdata++);
718 /* handle bulk of data as 32-bit words */
719 pend = pdata + (nbytes & 0xfffffffc);
720 while (pdata < pend) {
721 *tptr = *((ulong *)pdata)++;
722 CRC_INNER_LOOP(32, crc, tmp[0]);
723 CRC_INNER_LOOP(32, crc, tmp[1]);
724 CRC_INNER_LOOP(32, crc, tmp[2]);
725 CRC_INNER_LOOP(32, crc, tmp[3]);
728 /* 1-3 bytes at end of buffer */
729 pend = pdata + (nbytes & 0x03);
730 while (pdata < pend)
731 CRC_INNER_LOOP(32, crc, *pdata++);
732 #else
733 pend = pdata + nbytes;
734 while (pdata < pend)
735 CRC_INNER_LOOP(32, crc, *pdata++);
736 #endif
738 return crc;
741 #ifdef notdef
742 #define CLEN 1499
743 #define CBUFSIZ (CLEN+4)
744 #define CNBUFS 5
746 void testcrc32(void)
748 uint j,k,l;
749 uint8 *buf;
750 uint len[CNBUFS];
751 uint32 crcr;
752 uint32 crc32tv[CNBUFS] =
753 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
755 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
757 /* step through all possible alignments */
758 for (l=0;l<=4;l++) {
759 for (j=0; j<CNBUFS; j++) {
760 len[j] = CLEN;
761 for (k=0; k<len[j]; k++)
762 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
765 for (j=0; j<CNBUFS; j++) {
766 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
767 ASSERT(crcr == crc32tv[j]);
771 MFREE(buf, CBUFSIZ*CNBUFS);
772 return;
774 #endif
778 * Advance from the current 1-byte tag/1-byte length/variable-length value
779 * triple, to the next, returning a pointer to the next.
781 bcm_tlv_t *
782 bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
784 int len;
786 /* validate current elt */
787 if (*buflen < 2) {
788 return NULL;
791 len = elt->len;
793 /* validate remaining buflen */
794 if (*buflen >= (2 + len + 2)) {
795 elt = (bcm_tlv_t*)(elt->data + len);
796 *buflen -= (2 + len);
797 } else {
798 elt = NULL;
801 return elt;
805 * Traverse a string of 1-byte tag/1-byte length/variable-length value
806 * triples, returning a pointer to the substring whose first element
807 * matches tag
809 bcm_tlv_t *
810 bcm_parse_tlvs(void *buf, int buflen, uint key)
812 bcm_tlv_t *elt;
813 int totlen;
815 elt = (bcm_tlv_t*)buf;
816 totlen = buflen;
818 /* find tagged parameter */
819 while (totlen >= 2) {
820 int len = elt->len;
822 /* validate remaining totlen */
823 if ((elt->id == key) && (totlen >= (len + 2)))
824 return (elt);
826 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
827 totlen -= (len + 2);
830 return NULL;
834 * Traverse a string of 1-byte tag/1-byte length/variable-length value
835 * triples, returning a pointer to the substring whose first element
836 * matches tag. Stop parsing when we see an element whose ID is greater
837 * than the target key.
839 bcm_tlv_t *
840 bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
842 bcm_tlv_t *elt;
843 int totlen;
845 elt = (bcm_tlv_t*)buf;
846 totlen = buflen;
848 /* find tagged parameter */
849 while (totlen >= 2) {
850 uint id = elt->id;
851 int len = elt->len;
853 /* Punt if we start seeing IDs > than target key */
854 if (id > key)
855 return(NULL);
857 /* validate remaining totlen */
858 if ((id == key) && (totlen >= (len + 2)))
859 return (elt);
861 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
862 totlen -= (len + 2);
864 return NULL;