finally move buildroot-ng to trunk
[openwrt.git] / package / broadcom-wl / src / kmod / bcmutils.c
1 /*
2  * Misc useful OS-independent routines.
3  *
4  * Copyright 2006, 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.12 2006/02/27 03:43:16 honor Exp $
12  */
13
14 #include <typedefs.h>
15 #include <bcmdefs.h>
16 #include <stdarg.h>
17 #include <osl.h>
18 #include "linux_osl.h"
19 #include "pktq.h"
20 #include <bcmutils.h>
21 #include <sbutils.h>
22 #include <bcmnvram.h>
23 #include <bcmendian.h>
24 #include <bcmdevs.h>
25 #include "bcmip.h"
26
27 #define ETHER_TYPE_8021Q       0x8100
28 #define ETHER_TYPE_IP          0x0800
29 #define VLAN_PRI_SHIFT             13
30 #define VLAN_PRI_MASK               7
31
32
33 struct  ether_header {
34         uint8   ether_dhost[6];
35         uint8   ether_shost[6];
36         uint16  ether_type;
37 } __attribute__((packed));
38
39
40 struct ethervlan_header {
41         uint8   ether_dhost[6];
42         uint8   ether_shost[6];
43         uint16  vlan_type;              /* 0x8100 */
44         uint16  vlan_tag;               /* priority, cfi and vid */
45         uint16  ether_type;
46 };
47
48 /* copy a pkt buffer chain into a buffer */
49 uint
50 pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
51 {
52         uint n, ret = 0;
53
54         if (len < 0)
55                 len = 4096;     /* "infinite" */
56
57         /* skip 'offset' bytes */
58         for (; p && offset; p = PKTNEXT(osh, p)) {
59                 if (offset < (uint)PKTLEN(osh, p))
60                         break;
61                 offset -= PKTLEN(osh, p);
62         }
63
64         if (!p)
65                 return 0;
66
67         /* copy the data */
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);
71                 buf += n;
72                 len -= n;
73                 ret += n;
74                 offset = 0;
75         }
76
77         return ret;
78 }
79
80 /* return total length of buffer chain */
81 uint
82 pkttotlen(osl_t *osh, void *p)
83 {
84         uint total;
85
86         total = 0;
87         for (; p; p = PKTNEXT(osh, p))
88                 total += PKTLEN(osh, p);
89         return (total);
90 }
91
92 /* return the last buffer of chained pkt */
93 void *
94 pktlast(osl_t *osh, void *p)
95 {
96         for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
97                 ;
98
99         return (p);
100 }
101
102
103 /*
104  * osl multiple-precedence packet queue
105  * hi_prec is always >= the number of the highest non-empty queue
106  */
107 void *
108 pktq_penq(struct pktq *pq, int prec, void *p)
109 {
110         struct pktq_prec *q;
111
112         ASSERT(prec >= 0 && prec < pq->num_prec);
113         ASSERT(PKTLINK(p) == NULL);         /* queueing chains not allowed */
114
115         ASSERT(!pktq_full(pq));
116         ASSERT(!pktq_pfull(pq, prec));
117
118         q = &pq->q[prec];
119
120         if (q->head)
121                 PKTSETLINK(q->tail, p);
122         else
123                 q->head = p;
124
125         q->tail = p;
126         q->len++;
127
128         pq->len++;
129
130         if (pq->hi_prec < prec)
131                 pq->hi_prec = (uint8)prec;
132
133         return p;
134 }
135
136 void *
137 pktq_penq_head(struct pktq *pq, int prec, void *p)
138 {
139         struct pktq_prec *q;
140
141         ASSERT(prec >= 0 && prec < pq->num_prec);
142         ASSERT(PKTLINK(p) == NULL);         /* queueing chains not allowed */
143
144         ASSERT(!pktq_full(pq));
145         ASSERT(!pktq_pfull(pq, prec));
146
147         q = &pq->q[prec];
148
149         if (q->head == NULL)
150                 q->tail = p;
151
152         PKTSETLINK(p, q->head);
153         q->head = p;
154         q->len++;
155
156         pq->len++;
157
158         if (pq->hi_prec < prec)
159                 pq->hi_prec = (uint8)prec;
160
161         return p;
162 }
163
164 void *
165 pktq_pdeq(struct pktq *pq, int prec)
166 {
167         struct pktq_prec *q;
168         void *p;
169
170         ASSERT(prec >= 0 && prec < pq->num_prec);
171
172         q = &pq->q[prec];
173
174         if ((p = q->head) == NULL)
175                 return NULL;
176
177         if ((q->head = PKTLINK(p)) == NULL)
178                 q->tail = NULL;
179
180         q->len--;
181
182         pq->len--;
183
184         PKTSETLINK(p, NULL);
185
186         return p;
187 }
188
189 void *
190 pktq_pdeq_tail(struct pktq *pq, int prec)
191 {
192         struct pktq_prec *q;
193         void *p, *prev;
194
195         ASSERT(prec >= 0 && prec < pq->num_prec);
196
197         q = &pq->q[prec];
198
199         if ((p = q->head) == NULL)
200                 return NULL;
201
202         for (prev = NULL; p != q->tail; p = PKTLINK(p))
203                 prev = p;
204
205         if (prev)
206                 PKTSETLINK(prev, NULL);
207         else
208                 q->head = NULL;
209
210         q->tail = prev;
211         q->len--;
212
213         pq->len--;
214
215         return p;
216 }
217
218 void
219 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
220 {
221         struct pktq_prec *q;
222         void *p;
223
224         q = &pq->q[prec];
225         p = q->head;
226         while (p) {
227                 q->head = PKTLINK(p);
228                 PKTSETLINK(p, NULL);
229                 PKTFREE(osh, p, dir);
230                 q->len--;
231                 pq->len--;
232                 p = q->head;
233         }
234         ASSERT(q->len == 0);
235         q->tail = NULL;
236 }
237
238 bool
239 pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
240 {
241         struct pktq_prec *q;
242         void *p;
243
244         ASSERT(prec >= 0 && prec < pq->num_prec);
245
246         if (!pktbuf)
247                 return FALSE;
248
249         q = &pq->q[prec];
250
251         if (q->head == pktbuf) {
252                 if ((q->head = PKTLINK(pktbuf)) == NULL)
253                         q->tail = NULL;
254         } else {
255                 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
256                         ;
257                 if (p == NULL)
258                         return FALSE;
259
260                 PKTSETLINK(p, PKTLINK(pktbuf));
261                 if (q->tail == pktbuf)
262                         q->tail = p;
263         }
264
265         q->len--;
266         pq->len--;
267         PKTSETLINK(pktbuf, NULL);
268         return TRUE;
269 }
270
271 void
272 pktq_init(struct pktq *pq, int num_prec, int max_len)
273 {
274         int prec;
275
276         ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
277
278         bzero(pq, sizeof(*pq));
279
280         pq->num_prec = (uint16)num_prec;
281
282         pq->max = (uint16)max_len;
283
284         for (prec = 0; prec < num_prec; prec++)
285                 pq->q[prec].max = pq->max;
286 }
287
288 void *
289 pktq_deq(struct pktq *pq, int *prec_out)
290 {
291         struct pktq_prec *q;
292         void *p;
293         int prec;
294
295         if (pq->len == 0)
296                 return NULL;
297
298         while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
299                 pq->hi_prec--;
300
301         q = &pq->q[prec];
302
303         if ((p = q->head) == NULL)
304                 return NULL;
305
306         if ((q->head = PKTLINK(p)) == NULL)
307                 q->tail = NULL;
308
309         q->len--;
310
311         pq->len--;
312
313         if (prec_out)
314                 *prec_out = prec;
315
316         PKTSETLINK(p, NULL);
317
318         return p;
319 }
320
321 void *
322 pktq_deq_tail(struct pktq *pq, int *prec_out)
323 {
324         struct pktq_prec *q;
325         void *p, *prev;
326         int prec;
327
328         if (pq->len == 0)
329                 return NULL;
330
331         for (prec = 0; prec < pq->hi_prec; prec++)
332                 if (pq->q[prec].head)
333                         break;
334
335         q = &pq->q[prec];
336
337         if ((p = q->head) == NULL)
338                 return NULL;
339
340         for (prev = NULL; p != q->tail; p = PKTLINK(p))
341                 prev = p;
342
343         if (prev)
344                 PKTSETLINK(prev, NULL);
345         else
346                 q->head = NULL;
347
348         q->tail = prev;
349         q->len--;
350
351         pq->len--;
352
353         if (prec_out)
354                 *prec_out = prec;
355
356         PKTSETLINK(p, NULL);
357
358         return p;
359 }
360
361 void *
362 pktq_peek(struct pktq *pq, int *prec_out)
363 {
364         int prec;
365
366         if (pq->len == 0)
367                 return NULL;
368
369         while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
370                 pq->hi_prec--;
371
372         if (prec_out)
373                 *prec_out = prec;
374
375         return (pq->q[prec].head);
376 }
377
378 void *
379 pktq_peek_tail(struct pktq *pq, int *prec_out)
380 {
381         int prec;
382
383         if (pq->len == 0)
384                 return NULL;
385
386         for (prec = 0; prec < pq->hi_prec; prec++)
387                 if (pq->q[prec].head)
388                         break;
389
390         if (prec_out)
391                 *prec_out = prec;
392
393         return (pq->q[prec].tail);
394 }
395
396 void
397 pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
398 {
399         int prec;
400         for (prec = 0; prec < pq->num_prec; prec++)
401                 pktq_pflush(osh, pq, prec, dir);
402         ASSERT(pq->len == 0);
403 }
404
405 /* Return sum of lengths of a specific set of precedences */
406 int
407 pktq_mlen(struct pktq *pq, uint prec_bmp)
408 {
409         int prec, len;
410
411         len = 0;
412
413         for (prec = 0; prec <= pq->hi_prec; prec++)
414                 if (prec_bmp & (1 << prec))
415                         len += pq->q[prec].len;
416
417         return len;
418 }
419
420 /* Priority dequeue from a specific set of precedences */
421 void *
422 pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
423 {
424         struct pktq_prec *q;
425         void *p;
426         int prec;
427
428         if (pq->len == 0)
429                 return NULL;
430
431         while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
432                 pq->hi_prec--;
433
434         while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
435                 if (prec-- == 0)
436                         return NULL;
437
438         q = &pq->q[prec];
439
440         if ((p = q->head) == NULL)
441                 return NULL;
442
443         if ((q->head = PKTLINK(p)) == NULL)
444                 q->tail = NULL;
445
446         q->len--;
447
448         if (prec_out)
449                 *prec_out = prec;
450
451         pq->len--;
452
453         PKTSETLINK(p, NULL);
454
455         return p;
456 }
457
458 char*
459 bcmstrcat(char *dest, const char *src)
460 {
461         strcpy(&dest[strlen(dest)], src);
462         return (dest);
463 }
464
465 char*
466 bcm_ether_ntoa(struct ether_addr *ea, char *buf)
467 {
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);
471         return (buf);
472 }
473
474 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
475 int
476 bcm_ether_atoe(char *p, struct ether_addr *ea)
477 {
478         int i = 0;
479
480         for (;;) {
481                 ea->octet[i++] = (char) bcm_strtoul(p, &p, 16);
482                 if (!*p++ || i == 6)
483                         break;
484         }
485
486         return (i == 6);
487 }
488
489 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO
490  * Also updates the inplace vlan tag if requested
491  */
492 void
493 pktsetprio(void *pkt, bool update_vtag)
494 {
495         struct ether_header *eh;
496         struct ethervlan_header *evh;
497         uint8 *pktdata;
498         int priority = 0;
499
500         pktdata = (uint8 *) PKTDATA(NULL, pkt);
501         ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
502
503         eh = (struct ether_header *) pktdata;
504
505         if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
506                 uint16 vlan_tag;
507                 int vlan_prio, dscp_prio = 0;
508
509                 evh = (struct ethervlan_header *)eh;
510
511                 vlan_tag = ntoh16(evh->vlan_tag);
512                 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
513
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);
518                 }
519
520                 /* DSCP priority gets precedence over 802.1P (vlan tag) */
521                 priority = (dscp_prio != 0) ? dscp_prio : vlan_prio;
522
523                 /* 
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
529                  */
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);
534                 }
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);
539         }
540
541         ASSERT(priority >= 0 && priority <= MAXPRIO);
542         PKTSETPRIO(pkt, priority);
543 }
544
545 static char bcm_undeferrstr[BCME_STRLEN];
546
547 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
548
549 /* Convert the Error codes into related Error strings  */
550 const char *
551 bcmerrorstr(int bcmerror)
552 {
553         int abs_bcmerror;
554
555         abs_bcmerror = ABS(bcmerror);
556
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;
562         }
563
564         ASSERT((strlen((char*)bcmerrorstrtable[abs_bcmerror])) < BCME_STRLEN);
565
566         return bcmerrorstrtable[abs_bcmerror];
567 }
568
569
570 int
571 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
572 {
573         int bcmerror = 0;
574
575         /* length check on io buf */
576         switch (vi->type) {
577         case IOVT_BOOL:
578         case IOVT_INT8:
579         case IOVT_INT16:
580         case IOVT_INT32:
581         case IOVT_UINT8:
582         case IOVT_UINT16:
583         case IOVT_UINT32:
584                 /* all integers are int32 sized args at the ioctl interface */
585                 if (len < (int)sizeof(int)) {
586                         bcmerror = BCME_BUFTOOSHORT;
587                 }
588                 break;
589
590         case IOVT_BUFFER:
591                 /* buffer must meet minimum length requirement */
592                 if (len < vi->minlen) {
593                         bcmerror = BCME_BUFTOOSHORT;
594                 }
595                 break;
596
597         case IOVT_VOID:
598                 if (!set) {
599                         /* Cannot return nil... */
600                         bcmerror = BCME_UNSUPPORTED;
601                 } else if (len) {
602                         /* Set is an action w/o parameters */
603                         bcmerror = BCME_BUFTOOLONG;
604                 }
605                 break;
606
607         default:
608                 /* unknown type for length check in iovar info */
609                 ASSERT(0);
610                 bcmerror = BCME_UNSUPPORTED;
611         }
612
613         return bcmerror;
614 }
615
616 #define CRC_INNER_LOOP(n, c, x) \
617                     (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
618
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
684 };
685
686 uint32
687 hndcrc32(
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 */
691 )
692 {
693         uint8 *pend;
694 #ifdef __mips__
695         uint8 tmp[4];
696         ulong *tptr = (ulong *)tmp;
697
698         /* in case the beginning of the buffer isn't aligned */
699         pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
700         nbytes -= (pend - pdata);
701         while (pdata < pend)
702                 CRC_INNER_LOOP(32, crc, *pdata++);
703
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]);
713         }
714
715         /* 1-3 bytes at end of buffer */
716         pend = pdata + (nbytes & 0x03);
717         while (pdata < pend)
718                 CRC_INNER_LOOP(32, crc, *pdata++);
719 #else
720         pend = pdata + nbytes;
721         while (pdata < pend)
722                 CRC_INNER_LOOP(32, crc, *pdata++);
723 #endif /* __mips__ */
724
725         return crc;
726 }
727
728
729 /*
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),
733  * NULL is returned.
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.
736  */
737 bcm_tlv_t *
738 bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
739 {
740         int len;
741
742         /* validate current elt */
743         if (!bcm_valid_tlv(elt, *buflen))
744                 return NULL;
745
746         /* advance to next elt */
747         len = elt->len;
748         elt = (bcm_tlv_t*)(elt->data + len);
749         *buflen -= (2 + len);
750
751         /* validate next elt */
752         if (!bcm_valid_tlv(elt, *buflen))
753                 return NULL;
754
755         return elt;
756 }
757
758 /*
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
761  * matches tag
762  */
763 bcm_tlv_t *
764 bcm_parse_tlvs(void *buf, int buflen, uint key)
765 {
766         bcm_tlv_t *elt;
767         int totlen;
768
769         elt = (bcm_tlv_t*)buf;
770         totlen = buflen;
771
772         /* find tagged parameter */
773         while (totlen >= 2) {
774                 int len = elt->len;
775
776                 /* validate remaining totlen */
777                 if ((elt->id == key) && (totlen >= (len + 2)))
778                         return (elt);
779
780                 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
781                 totlen -= (len + 2);
782         }
783
784         return NULL;
785 }
786
787 /*
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.
792  */
793 bcm_tlv_t *
794 bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
795 {
796         bcm_tlv_t *elt;
797         int totlen;
798
799         elt = (bcm_tlv_t*)buf;
800         totlen = buflen;
801
802         /* find tagged parameter */
803         while (totlen >= 2) {
804                 uint id = elt->id;
805                 int len = elt->len;
806
807                 /* Punt if we start seeing IDs > than target key */
808                 if (id > key)
809                         return (NULL);
810
811                 /* validate remaining totlen */
812                 if ((id == key) && (totlen >= (len + 2)))
813                         return (elt);
814
815                 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
816                 totlen -= (len + 2);
817         }
818         return NULL;
819 }
820
821
822 /* Initialization of bcmstrbuf structure */
823 void
824 bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
825 {
826         b->origsize = b->size = size;
827         b->origbuf = b->buf = buf;
828 }
829
830 /* Buffer sprintf wrapper to guard against buffer overflow */
831 int
832 bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
833 {
834         va_list ap;
835         int r;
836
837         va_start(ap, fmt);
838         r = vsnprintf(b->buf, b->size, fmt, ap);
839
840         /* Non Ansi C99 compliant returns -1,
841          * Ansi compliant return r >= b->size,
842          * bcmstdlib returns 0, handle all
843          */
844         if ((r == -1) || (r >= (int)b->size) || (r == 0))
845         {
846                 b->size = 0;
847         }
848         else
849         {
850                 b->size -= r;
851                 b->buf += r;
852         }
853
854         va_end(ap);
855
856         return r;
857 }