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