]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/staging/brcm80211/util/bcmutils.c
Staging: brcm80211: remove typedefs.h
[mv-sheeva.git] / drivers / staging / brcm80211 / util / bcmutils.c
1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <linux/ctype.h>
18 #include <linux/kernel.h>
19 #include <linux/string.h>
20 #include <bcmdefs.h>
21 #include <stdarg.h>
22 #include <osl.h>
23 #include <linuxver.h>
24 #include <bcmutils.h>
25 #include <siutils.h>
26 #include <bcmnvram.h>
27 #include <bcmendian.h>
28 #include <bcmdevs.h>
29 #include <proto/ethernet.h>
30 #include <proto/vlan.h>
31 #include <proto/bcmip.h>
32 #include <proto/802.1d.h>
33 #include <proto/802.11.h>
34
35
36 /* copy a buffer into a pkt buffer chain */
37 uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, unsigned char *buf)
38 {
39         uint n, ret = 0;
40
41         /* skip 'offset' bytes */
42         for (; p && offset; p = PKTNEXT(p)) {
43                 if (offset < (uint) PKTLEN(p))
44                         break;
45                 offset -= PKTLEN(p);
46         }
47
48         if (!p)
49                 return 0;
50
51         /* copy the data */
52         for (; p && len; p = PKTNEXT(p)) {
53                 n = min((uint) PKTLEN(p) - offset, (uint) len);
54                 bcopy(buf, PKTDATA(p) + offset, n);
55                 buf += n;
56                 len -= n;
57                 ret += n;
58                 offset = 0;
59         }
60
61         return ret;
62 }
63 /* return total length of buffer chain */
64 uint BCMFASTPATH pkttotlen(osl_t *osh, void *p)
65 {
66         uint total;
67
68         total = 0;
69         for (; p; p = PKTNEXT(p))
70                 total += PKTLEN(p);
71         return total;
72 }
73
74 /*
75  * osl multiple-precedence packet queue
76  * hi_prec is always >= the number of the highest non-empty precedence
77  */
78 void *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, void *p)
79 {
80         struct pktq_prec *q;
81
82         ASSERT(prec >= 0 && prec < pq->num_prec);
83         ASSERT(PKTLINK(p) == NULL);     /* queueing chains not allowed */
84
85         ASSERT(!pktq_full(pq));
86         ASSERT(!pktq_pfull(pq, prec));
87
88         q = &pq->q[prec];
89
90         if (q->head)
91                 PKTSETLINK(q->tail, p);
92         else
93                 q->head = p;
94
95         q->tail = p;
96         q->len++;
97
98         pq->len++;
99
100         if (pq->hi_prec < prec)
101                 pq->hi_prec = (u8) prec;
102
103         return p;
104 }
105
106 void *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, void *p)
107 {
108         struct pktq_prec *q;
109
110         ASSERT(prec >= 0 && prec < pq->num_prec);
111         ASSERT(PKTLINK(p) == NULL);     /* queueing chains not allowed */
112
113         ASSERT(!pktq_full(pq));
114         ASSERT(!pktq_pfull(pq, prec));
115
116         q = &pq->q[prec];
117
118         if (q->head == NULL)
119                 q->tail = p;
120
121         PKTSETLINK(p, q->head);
122         q->head = p;
123         q->len++;
124
125         pq->len++;
126
127         if (pq->hi_prec < prec)
128                 pq->hi_prec = (u8) prec;
129
130         return p;
131 }
132
133 void *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
134 {
135         struct pktq_prec *q;
136         void *p;
137
138         ASSERT(prec >= 0 && prec < pq->num_prec);
139
140         q = &pq->q[prec];
141
142         p = q->head;
143         if (p == NULL)
144                 return NULL;
145
146         q->head = PKTLINK(p);
147         if (q->head == NULL)
148                 q->tail = NULL;
149
150         q->len--;
151
152         pq->len--;
153
154         PKTSETLINK(p, NULL);
155
156         return p;
157 }
158
159 void *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
160 {
161         struct pktq_prec *q;
162         void *p, *prev;
163
164         ASSERT(prec >= 0 && prec < pq->num_prec);
165
166         q = &pq->q[prec];
167
168         p = q->head;
169         if (p == NULL)
170                 return NULL;
171
172         for (prev = NULL; p != q->tail; p = PKTLINK(p))
173                 prev = p;
174
175         if (prev)
176                 PKTSETLINK(prev, NULL);
177         else
178                 q->head = NULL;
179
180         q->tail = prev;
181         q->len--;
182
183         pq->len--;
184
185         return p;
186 }
187
188 #ifdef BRCM_FULLMAC
189 void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
190 {
191         struct pktq_prec *q;
192         void *p;
193
194         q = &pq->q[prec];
195         p = q->head;
196         while (p) {
197                 q->head = PKTLINK(p);
198                 PKTSETLINK(p, NULL);
199                 PKTFREE(osh, p, dir);
200                 q->len--;
201                 pq->len--;
202                 p = q->head;
203         }
204         ASSERT(q->len == 0);
205         q->tail = NULL;
206 }
207
208 void pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
209 {
210         int prec;
211         for (prec = 0; prec < pq->num_prec; prec++)
212                 pktq_pflush(osh, pq, prec, dir);
213         ASSERT(pq->len == 0);
214 }
215 #else /* !BRCM_FULLMAC */
216 void
217 pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn,
218             int arg)
219 {
220         struct pktq_prec *q;
221         void *p, *prev = NULL;
222
223         q = &pq->q[prec];
224         p = q->head;
225         while (p) {
226                 if (fn == NULL || (*fn) (p, arg)) {
227                         bool head = (p == q->head);
228                         if (head)
229                                 q->head = PKTLINK(p);
230                         else
231                                 PKTSETLINK(prev, PKTLINK(p));
232                         PKTSETLINK(p, NULL);
233                         PKTFREE(osh, p, dir);
234                         q->len--;
235                         pq->len--;
236                         p = (head ? q->head : PKTLINK(prev));
237                 } else {
238                         prev = p;
239                         p = PKTLINK(p);
240                 }
241         }
242
243         if (q->head == NULL) {
244                 ASSERT(q->len == 0);
245                 q->tail = NULL;
246         }
247 }
248
249 void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
250 {
251         int prec;
252         for (prec = 0; prec < pq->num_prec; prec++)
253                 pktq_pflush(osh, pq, prec, dir, fn, arg);
254         if (fn == NULL)
255                 ASSERT(pq->len == 0);
256 }
257 #endif /* BRCM_FULLMAC */
258
259 void pktq_init(struct pktq *pq, int num_prec, int max_len)
260 {
261         int prec;
262
263         ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
264
265         /* pq is variable size; only zero out what's requested */
266         bzero(pq,
267               offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
268
269         pq->num_prec = (u16) num_prec;
270
271         pq->max = (u16) max_len;
272
273         for (prec = 0; prec < num_prec; prec++)
274                 pq->q[prec].max = pq->max;
275 }
276
277 void *pktq_peek_tail(struct pktq *pq, int *prec_out)
278 {
279         int prec;
280
281         if (pq->len == 0)
282                 return NULL;
283
284         for (prec = 0; prec < pq->hi_prec; prec++)
285                 if (pq->q[prec].head)
286                         break;
287
288         if (prec_out)
289                 *prec_out = prec;
290
291         return pq->q[prec].tail;
292 }
293
294 /* Return sum of lengths of a specific set of precedences */
295 int pktq_mlen(struct pktq *pq, uint prec_bmp)
296 {
297         int prec, len;
298
299         len = 0;
300
301         for (prec = 0; prec <= pq->hi_prec; prec++)
302                 if (prec_bmp & (1 << prec))
303                         len += pq->q[prec].len;
304
305         return len;
306 }
307 /* Priority dequeue from a specific set of precedences */
308 void *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
309 {
310         struct pktq_prec *q;
311         void *p;
312         int prec;
313
314         if (pq->len == 0)
315                 return NULL;
316
317         while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
318                 pq->hi_prec--;
319
320         while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
321                 if (prec-- == 0)
322                         return NULL;
323
324         q = &pq->q[prec];
325
326         p = q->head;
327         if (p == NULL)
328                 return NULL;
329
330         q->head = PKTLINK(p);
331         if (q->head == NULL)
332                 q->tail = NULL;
333
334         q->len--;
335
336         if (prec_out)
337                 *prec_out = prec;
338
339         pq->len--;
340
341         PKTSETLINK(p, NULL);
342
343         return p;
344 }
345
346 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
347 int bcm_ether_atoe(char *p, struct ether_addr *ea)
348 {
349         int i = 0;
350
351         for (;;) {
352                 ea->octet[i++] = (char)simple_strtoul(p, &p, 16);
353                 if (!*p++ || i == 6)
354                         break;
355         }
356
357         return i == 6;
358 }
359
360 /*
361  * Search the name=value vars for a specific one and return its value.
362  * Returns NULL if not found.
363  */
364 char *getvar(char *vars, const char *name)
365 {
366         char *s;
367         int len;
368
369         if (!name)
370                 return NULL;
371
372         len = strlen(name);
373         if (len == 0)
374                 return NULL;
375
376         /* first look in vars[] */
377         for (s = vars; s && *s;) {
378                 if ((bcmp(s, name, len) == 0) && (s[len] == '='))
379                         return &s[len + 1];
380
381                 while (*s++)
382                         ;
383         }
384 #ifdef BRCM_FULLMAC
385         return NULL;
386 #else
387         /* then query nvram */
388         return nvram_get(name);
389 #endif
390 }
391
392 /*
393  * Search the vars for a specific one and return its value as
394  * an integer. Returns 0 if not found.
395  */
396 int getintvar(char *vars, const char *name)
397 {
398         char *val;
399
400         val = getvar(vars, name);
401         if (val == NULL)
402                 return 0;
403
404         return simple_strtoul(val, NULL, 0);
405 }
406
407 #if defined(BCMDBG)
408 /* pretty hex print a pkt buffer chain */
409 void prpkt(const char *msg, osl_t *osh, void *p0)
410 {
411         void *p;
412
413         if (msg && (msg[0] != '\0'))
414                 printf("%s:\n", msg);
415
416         for (p = p0; p; p = PKTNEXT(p))
417                 prhex(NULL, PKTDATA(p), PKTLEN(p));
418 }
419 #endif                          /* defined(BCMDBG) */
420
421 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
422  * Also updates the inplace vlan tag if requested.
423  * For debugging, it returns an indication of what it did.
424  */
425 uint pktsetprio(void *pkt, bool update_vtag)
426 {
427         struct ether_header *eh;
428         struct ethervlan_header *evh;
429         u8 *pktdata;
430         int priority = 0;
431         int rc = 0;
432
433         pktdata = (u8 *) PKTDATA(pkt);
434         ASSERT(IS_ALIGNED((unsigned long)pktdata, sizeof(u16)));
435
436         eh = (struct ether_header *)pktdata;
437
438         if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
439                 u16 vlan_tag;
440                 int vlan_prio, dscp_prio = 0;
441
442                 evh = (struct ethervlan_header *)eh;
443
444                 vlan_tag = ntoh16(evh->vlan_tag);
445                 vlan_prio = (int)(vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
446
447                 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
448                         u8 *ip_body =
449                             pktdata + sizeof(struct ethervlan_header);
450                         u8 tos_tc = IP_TOS(ip_body);
451                         dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
452                 }
453
454                 /* DSCP priority gets precedence over 802.1P (vlan tag) */
455                 if (dscp_prio != 0) {
456                         priority = dscp_prio;
457                         rc |= PKTPRIO_VDSCP;
458                 } else {
459                         priority = vlan_prio;
460                         rc |= PKTPRIO_VLAN;
461                 }
462                 /*
463                  * If the DSCP priority is not the same as the VLAN priority,
464                  * then overwrite the priority field in the vlan tag, with the
465                  * DSCP priority value. This is required for Linux APs because
466                  * the VLAN driver on Linux, overwrites the skb->priority field
467                  * with the priority value in the vlan tag
468                  */
469                 if (update_vtag && (priority != vlan_prio)) {
470                         vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
471                         vlan_tag |= (u16) priority << VLAN_PRI_SHIFT;
472                         evh->vlan_tag = hton16(vlan_tag);
473                         rc |= PKTPRIO_UPD;
474                 }
475         } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
476                 u8 *ip_body = pktdata + sizeof(struct ether_header);
477                 u8 tos_tc = IP_TOS(ip_body);
478                 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
479                 rc |= PKTPRIO_DSCP;
480         }
481
482         ASSERT(priority >= 0 && priority <= MAXPRIO);
483         PKTSETPRIO(pkt, priority);
484         return rc | priority;
485 }
486
487 static char bcm_undeferrstr[BCME_STRLEN];
488
489 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
490
491 /* Convert the error codes into related error strings  */
492 const char *bcmerrorstr(int bcmerror)
493 {
494         /* check if someone added a bcmerror code but
495                  forgot to add errorstring */
496         ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(bcmerrorstrtable) - 1));
497
498         if (bcmerror > 0 || bcmerror < BCME_LAST) {
499                 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d",
500                          bcmerror);
501                 return bcm_undeferrstr;
502         }
503
504         ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
505
506         return bcmerrorstrtable[-bcmerror];
507 }
508
509 /* iovar table lookup */
510 const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
511 {
512         const bcm_iovar_t *vi;
513         const char *lookup_name;
514
515         /* skip any ':' delimited option prefixes */
516         lookup_name = strrchr(name, ':');
517         if (lookup_name != NULL)
518                 lookup_name++;
519         else
520                 lookup_name = name;
521
522         ASSERT(table != NULL);
523
524         for (vi = table; vi->name; vi++) {
525                 if (!strcmp(vi->name, lookup_name))
526                         return vi;
527         }
528         /* ran to end of table */
529
530         return NULL;            /* var name not found */
531 }
532
533 int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
534 {
535         int bcmerror = 0;
536
537         /* length check on io buf */
538         switch (vi->type) {
539         case IOVT_BOOL:
540         case IOVT_INT8:
541         case IOVT_INT16:
542         case IOVT_INT32:
543         case IOVT_UINT8:
544         case IOVT_UINT16:
545         case IOVT_UINT32:
546                 /* all integers are s32 sized args at the ioctl interface */
547                 if (len < (int)sizeof(int)) {
548                         bcmerror = BCME_BUFTOOSHORT;
549                 }
550                 break;
551
552         case IOVT_BUFFER:
553                 /* buffer must meet minimum length requirement */
554                 if (len < vi->minlen) {
555                         bcmerror = BCME_BUFTOOSHORT;
556                 }
557                 break;
558
559         case IOVT_VOID:
560                 if (!set) {
561                         /* Cannot return nil... */
562                         bcmerror = BCME_UNSUPPORTED;
563                 } else if (len) {
564                         /* Set is an action w/o parameters */
565                         bcmerror = BCME_BUFTOOLONG;
566                 }
567                 break;
568
569         default:
570                 /* unknown type for length check in iovar info */
571                 ASSERT(0);
572                 bcmerror = BCME_UNSUPPORTED;
573         }
574
575         return bcmerror;
576 }
577
578 /*******************************************************************************
579  * crc8
580  *
581  * Computes a crc8 over the input data using the polynomial:
582  *
583  *       x^8 + x^7 +x^6 + x^4 + x^2 + 1
584  *
585  * The caller provides the initial value (either CRC8_INIT_VALUE
586  * or the previous returned value) to allow for processing of
587  * discontiguous blocks of data.  When generating the CRC the
588  * caller is responsible for complementing the final return value
589  * and inserting it into the byte stream.  When checking, a final
590  * return value of CRC8_GOOD_VALUE indicates a valid CRC.
591  *
592  * Reference: Dallas Semiconductor Application Note 27
593  *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
594  *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
595  *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
596  *
597  * ****************************************************************************
598  */
599
600 static const u8 crc8_table[256] = {
601         0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
602         0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
603         0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
604         0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
605         0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
606         0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
607         0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
608         0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
609         0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
610         0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
611         0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
612         0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
613         0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
614         0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
615         0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
616         0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
617         0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
618         0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
619         0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
620         0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
621         0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
622         0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
623         0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
624         0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
625         0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
626         0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
627         0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
628         0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
629         0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
630         0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
631         0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
632         0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
633 };
634
635 #define CRC_INNER_LOOP(n, c, x) \
636         ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
637
638 u8 hndcrc8(u8 *pdata,   /* pointer to array of data to process */
639                          uint nbytes,   /* number of input data bytes to process */
640                          u8 crc /* either CRC8_INIT_VALUE or previous return value */
641     ) {
642         /* hard code the crc loop instead of using CRC_INNER_LOOP macro
643          * to avoid the undefined and unnecessary (u8 >> 8) operation.
644          */
645         while (nbytes-- > 0)
646                 crc = crc8_table[(crc ^ *pdata++) & 0xff];
647
648         return crc;
649 }
650
651 /*******************************************************************************
652  * crc16
653  *
654  * Computes a crc16 over the input data using the polynomial:
655  *
656  *       x^16 + x^12 +x^5 + 1
657  *
658  * The caller provides the initial value (either CRC16_INIT_VALUE
659  * or the previous returned value) to allow for processing of
660  * discontiguous blocks of data.  When generating the CRC the
661  * caller is responsible for complementing the final return value
662  * and inserting it into the byte stream.  When checking, a final
663  * return value of CRC16_GOOD_VALUE indicates a valid CRC.
664  *
665  * Reference: Dallas Semiconductor Application Note 27
666  *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
667  *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
668  *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
669  *
670  * ****************************************************************************
671  */
672
673 static const u16 crc16_table[256] = {
674         0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
675         0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
676         0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
677         0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
678         0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
679         0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
680         0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
681         0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
682         0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
683         0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
684         0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
685         0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
686         0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
687         0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
688         0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
689         0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
690         0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
691         0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
692         0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
693         0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
694         0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
695         0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
696         0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
697         0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
698         0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
699         0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
700         0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
701         0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
702         0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
703         0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
704         0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
705         0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
706 };
707
708 u16 hndcrc16(u8 *pdata, /* pointer to array of data to process */
709         uint nbytes,    /* number of input data bytes to process */
710         u16 crc /* either CRC16_INIT_VALUE or previous return value */
711     ) {
712         while (nbytes-- > 0)
713                 CRC_INNER_LOOP(16, crc, *pdata++);
714         return crc;
715 }
716
717 static const u32 crc32_table[256] = {
718         0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
719         0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
720         0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
721         0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
722         0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
723         0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
724         0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
725         0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
726         0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
727         0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
728         0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
729         0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
730         0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
731         0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
732         0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
733         0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
734         0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
735         0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
736         0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
737         0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
738         0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
739         0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
740         0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
741         0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
742         0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
743         0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
744         0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
745         0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
746         0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
747         0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
748         0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
749         0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
750         0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
751         0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
752         0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
753         0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
754         0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
755         0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
756         0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
757         0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
758         0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
759         0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
760         0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
761         0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
762         0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
763         0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
764         0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
765         0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
766         0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
767         0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
768         0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
769         0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
770         0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
771         0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
772         0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
773         0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
774         0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
775         0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
776         0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
777         0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
778         0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
779         0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
780         0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
781         0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
782 };
783
784 u32 hndcrc32(u8 *pdata, /* pointer to array of data to process */
785                 uint nbytes,    /* number of input data bytes to process */
786                 u32 crc /* either CRC32_INIT_VALUE or previous
787                                          return value */
788 )
789 {
790         u8 *pend;
791 #ifdef __mips__
792         u8 tmp[4];
793         unsigned long *tptr = (unsigned long *) tmp;
794
795         /* in case the beginning of the buffer isn't aligned */
796         pend = (u8 *) ((uint) (pdata + 3) & 0xfffffffc);
797         nbytes -= (pend - pdata);
798         while (pdata < pend)
799                 CRC_INNER_LOOP(32, crc, *pdata++);
800
801         /* handle bulk of data as 32-bit words */
802         pend = pdata + (nbytes & 0xfffffffc);
803         while (pdata < pend) {
804                 *tptr = *(unsigned long *) pdata;
805                 pdata += sizeof(unsigned long *);
806                 CRC_INNER_LOOP(32, crc, tmp[0]);
807                 CRC_INNER_LOOP(32, crc, tmp[1]);
808                 CRC_INNER_LOOP(32, crc, tmp[2]);
809                 CRC_INNER_LOOP(32, crc, tmp[3]);
810         }
811
812         /* 1-3 bytes at end of buffer */
813         pend = pdata + (nbytes & 0x03);
814         while (pdata < pend)
815                 CRC_INNER_LOOP(32, crc, *pdata++);
816 #else
817         pend = pdata + nbytes;
818         while (pdata < pend)
819                 CRC_INNER_LOOP(32, crc, *pdata++);
820 #endif                          /* __mips__ */
821
822         return crc;
823 }
824 /*
825  * Traverse a string of 1-byte tag/1-byte length/variable-length value
826  * triples, returning a pointer to the substring whose first element
827  * matches tag
828  */
829 bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key)
830 {
831         bcm_tlv_t *elt;
832         int totlen;
833
834         elt = (bcm_tlv_t *) buf;
835         totlen = buflen;
836
837         /* find tagged parameter */
838         while (totlen >= 2) {
839                 int len = elt->len;
840
841                 /* validate remaining totlen */
842                 if ((elt->id == key) && (totlen >= (len + 2)))
843                         return elt;
844
845                 elt = (bcm_tlv_t *) ((u8 *) elt + (len + 2));
846                 totlen -= (len + 2);
847         }
848
849         return NULL;
850 }
851
852
853 #if defined(BCMDBG)
854 int
855 bcm_format_flags(const bcm_bit_desc_t *bd, u32 flags, char *buf, int len)
856 {
857         int i;
858         char *p = buf;
859         char hexstr[16];
860         int slen = 0, nlen = 0;
861         u32 bit;
862         const char *name;
863
864         if (len < 2 || !buf)
865                 return 0;
866
867         buf[0] = '\0';
868
869         for (i = 0; flags != 0; i++) {
870                 bit = bd[i].bit;
871                 name = bd[i].name;
872                 if (bit == 0 && flags != 0) {
873                         /* print any unnamed bits */
874                         snprintf(hexstr, 16, "0x%X", flags);
875                         name = hexstr;
876                         flags = 0;      /* exit loop */
877                 } else if ((flags & bit) == 0)
878                         continue;
879                 flags &= ~bit;
880                 nlen = strlen(name);
881                 slen += nlen;
882                 /* count btwn flag space */
883                 if (flags != 0)
884                         slen += 1;
885                 /* need NULL char as well */
886                 if (len <= slen)
887                         break;
888                 /* copy NULL char but don't count it */
889                 strncpy(p, name, nlen + 1);
890                 p += nlen;
891                 /* copy btwn flag space and NULL char */
892                 if (flags != 0)
893                         p += snprintf(p, 2, " ");
894                 len -= slen;
895         }
896
897         /* indicate the str was too short */
898         if (flags != 0) {
899                 if (len < 2)
900                         p -= 2 - len;   /* overwrite last char */
901                 p += snprintf(p, 2, ">");
902         }
903
904         return (int)(p - buf);
905 }
906
907 /* print bytes formatted as hex to a string. return the resulting string length */
908 int bcm_format_hex(char *str, const void *bytes, int len)
909 {
910         int i;
911         char *p = str;
912         const u8 *src = (const u8 *)bytes;
913
914         for (i = 0; i < len; i++) {
915                 p += snprintf(p, 3, "%02X", *src);
916                 src++;
917         }
918         return (int)(p - str);
919 }
920 #endif                          /* defined(BCMDBG) */
921
922 /* pretty hex print a contiguous buffer */
923 void prhex(const char *msg, unsigned char *buf, uint nbytes)
924 {
925         char line[128], *p;
926         int len = sizeof(line);
927         int nchar;
928         uint i;
929
930         if (msg && (msg[0] != '\0'))
931                 printf("%s:\n", msg);
932
933         p = line;
934         for (i = 0; i < nbytes; i++) {
935                 if (i % 16 == 0) {
936                         nchar = snprintf(p, len, "  %04d: ", i);        /* line prefix */
937                         p += nchar;
938                         len -= nchar;
939                 }
940                 if (len > 0) {
941                         nchar = snprintf(p, len, "%02x ", buf[i]);
942                         p += nchar;
943                         len -= nchar;
944                 }
945
946                 if (i % 16 == 15) {
947                         printf("%s\n", line);   /* flush line */
948                         p = line;
949                         len = sizeof(line);
950                 }
951         }
952
953         /* flush last partial line */
954         if (p != line)
955                 printf("%s\n", line);
956 }
957
958 char *bcm_chipname(uint chipid, char *buf, uint len)
959 {
960         const char *fmt;
961
962         fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
963         snprintf(buf, len, fmt, chipid);
964         return buf;
965 }
966
967 uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
968 {
969         uint len;
970
971         len = strlen(name) + 1;
972
973         if ((len + datalen) > buflen)
974                 return 0;
975
976         strncpy(buf, name, buflen);
977
978         /* append data onto the end of the name string */
979         memcpy(&buf[len], data, datalen);
980         len += datalen;
981
982         return len;
983 }
984
985 /* Quarter dBm units to mW
986  * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
987  * Table is offset so the last entry is largest mW value that fits in
988  * a u16.
989  */
990
991 #define QDBM_OFFSET 153         /* Offset for first entry */
992 #define QDBM_TABLE_LEN 40       /* Table size */
993
994 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
995  * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
996  */
997 #define QDBM_TABLE_LOW_BOUND 6493       /* Low bound */
998
999 /* Largest mW value that will round down to the last table entry,
1000  * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1001  * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
1002  * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1003  */
1004 #define QDBM_TABLE_HIGH_BOUND 64938     /* High bound */
1005
1006 static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1007 /* qdBm:        +0      +1      +2      +3      +4      +5      +6      +7 */
1008 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1009 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1010 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1011 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1012 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1013 };
1014
1015 u16 bcm_qdbm_to_mw(u8 qdbm)
1016 {
1017         uint factor = 1;
1018         int idx = qdbm - QDBM_OFFSET;
1019
1020         if (idx >= QDBM_TABLE_LEN) {
1021                 /* clamp to max u16 mW value */
1022                 return 0xFFFF;
1023         }
1024
1025         /* scale the qdBm index up to the range of the table 0-40
1026          * where an offset of 40 qdBm equals a factor of 10 mW.
1027          */
1028         while (idx < 0) {
1029                 idx += 40;
1030                 factor *= 10;
1031         }
1032
1033         /* return the mW value scaled down to the correct factor of 10,
1034          * adding in factor/2 to get proper rounding.
1035          */
1036         return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
1037 }
1038 u8 bcm_mw_to_qdbm(u16 mw)
1039 {
1040         u8 qdbm;
1041         int offset;
1042         uint mw_uint = mw;
1043         uint boundary;
1044
1045         /* handle boundary case */
1046         if (mw_uint <= 1)
1047                 return 0;
1048
1049         offset = QDBM_OFFSET;
1050
1051         /* move mw into the range of the table */
1052         while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1053                 mw_uint *= 10;
1054                 offset -= 40;
1055         }
1056
1057         for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
1058                 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
1059                                                     nqdBm_to_mW_map[qdbm]) / 2;
1060                 if (mw_uint < boundary)
1061                         break;
1062         }
1063
1064         qdbm += (u8) offset;
1065
1066         return qdbm;
1067 }
1068 uint bcm_bitcount(u8 *bitmap, uint length)
1069 {
1070         uint bitcount = 0, i;
1071         u8 tmp;
1072         for (i = 0; i < length; i++) {
1073                 tmp = bitmap[i];
1074                 while (tmp) {
1075                         bitcount++;
1076                         tmp &= (tmp - 1);
1077                 }
1078         }
1079         return bitcount;
1080 }
1081 /* Initialization of bcmstrbuf structure */
1082 void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1083 {
1084         b->origsize = b->size = size;
1085         b->origbuf = b->buf = buf;
1086 }
1087
1088 /* Buffer sprintf wrapper to guard against buffer overflow */
1089 int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1090 {
1091         va_list ap;
1092         int r;
1093
1094         va_start(ap, fmt);
1095         r = vsnprintf(b->buf, b->size, fmt, ap);
1096
1097         /* Non Ansi C99 compliant returns -1,
1098          * Ansi compliant return r >= b->size,
1099          * bcmstdlib returns 0, handle all
1100          */
1101         if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1102                 b->size = 0;
1103         } else {
1104                 b->size -= r;
1105                 b->buf += r;
1106         }
1107
1108         va_end(ap);
1109
1110         return r;
1111 }
1112