aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcmdhd/bcmutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcmdhd/bcmutils.c')
-rw-r--r--drivers/net/wireless/bcmdhd/bcmutils.c1967
1 files changed, 1967 insertions, 0 deletions
diff --git a/drivers/net/wireless/bcmdhd/bcmutils.c b/drivers/net/wireless/bcmdhd/bcmutils.c
new file mode 100644
index 00000000000..fbdd7cd2d19
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmutils.c
@@ -0,0 +1,1967 @@
1/*
2 * Driver O/S-independent utility routines
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 * $Id: bcmutils.c,v 1.277.2.18 2011-01-26 02:32:08 Exp $
24 */
25
26#include <typedefs.h>
27#include <bcmdefs.h>
28#include <stdarg.h>
29
30#ifdef BCMDRIVER
31
32#include <osl.h>
33#include <bcmutils.h>
34#include <siutils.h>
35
36#else /* !BCMDRIVER */
37
38#include <stdio.h>
39#include <string.h>
40#include <bcmutils.h>
41
42#if defined(BCMEXTSUP)
43#include <bcm_osl.h>
44#endif
45
46
47#endif /* !BCMDRIVER */
48
49#include <bcmendian.h>
50#include <bcmdevs.h>
51#include <proto/ethernet.h>
52#include <proto/vlan.h>
53#include <proto/bcmip.h>
54#include <proto/802.1d.h>
55#include <proto/802.11.h>
56
57void *_bcmutils_dummy_fn = NULL;
58
59#ifdef BCMDRIVER
60
61
62
63/* copy a pkt buffer chain into a buffer */
64uint
65pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
66{
67 uint n, ret = 0;
68
69 if (len < 0)
70 len = 4096; /* "infinite" */
71
72 /* skip 'offset' bytes */
73 for (; p && offset; p = PKTNEXT(osh, p)) {
74 if (offset < (uint)PKTLEN(osh, p))
75 break;
76 offset -= PKTLEN(osh, p);
77 }
78
79 if (!p)
80 return 0;
81
82 /* copy the data */
83 for (; p && len; p = PKTNEXT(osh, p)) {
84 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
85 bcopy(PKTDATA(osh, p) + offset, buf, n);
86 buf += n;
87 len -= n;
88 ret += n;
89 offset = 0;
90 }
91
92 return ret;
93}
94
95/* copy a buffer into a pkt buffer chain */
96uint
97pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
98{
99 uint n, ret = 0;
100
101 /* skip 'offset' bytes */
102 for (; p && offset; p = PKTNEXT(osh, p)) {
103 if (offset < (uint)PKTLEN(osh, p))
104 break;
105 offset -= PKTLEN(osh, p);
106 }
107
108 if (!p)
109 return 0;
110
111 /* copy the data */
112 for (; p && len; p = PKTNEXT(osh, p)) {
113 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
114 bcopy(buf, PKTDATA(osh, p) + offset, n);
115 buf += n;
116 len -= n;
117 ret += n;
118 offset = 0;
119 }
120
121 return ret;
122}
123
124
125
126/* return total length of buffer chain */
127uint BCMFASTPATH
128pkttotlen(osl_t *osh, void *p)
129{
130 uint total;
131
132 total = 0;
133 for (; p; p = PKTNEXT(osh, p))
134 total += PKTLEN(osh, p);
135 return (total);
136}
137
138/* return the last buffer of chained pkt */
139void *
140pktlast(osl_t *osh, void *p)
141{
142 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
143 ;
144
145 return (p);
146}
147
148/* count segments of a chained packet */
149uint BCMFASTPATH
150pktsegcnt(osl_t *osh, void *p)
151{
152 uint cnt;
153
154 for (cnt = 0; p; p = PKTNEXT(osh, p))
155 cnt++;
156
157 return cnt;
158}
159
160
161/*
162 * osl multiple-precedence packet queue
163 * hi_prec is always >= the number of the highest non-empty precedence
164 */
165void * BCMFASTPATH
166pktq_penq(struct pktq *pq, int prec, void *p)
167{
168 struct pktq_prec *q;
169
170 ASSERT(prec >= 0 && prec < pq->num_prec);
171 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
172
173 ASSERT(!pktq_full(pq));
174 ASSERT(!pktq_pfull(pq, prec));
175
176 q = &pq->q[prec];
177
178 if (q->head)
179 PKTSETLINK(q->tail, p);
180 else
181 q->head = p;
182
183 q->tail = p;
184 q->len++;
185
186 pq->len++;
187
188 if (pq->hi_prec < prec)
189 pq->hi_prec = (uint8)prec;
190
191 return p;
192}
193
194void * BCMFASTPATH
195pktq_penq_head(struct pktq *pq, int prec, void *p)
196{
197 struct pktq_prec *q;
198
199 ASSERT(prec >= 0 && prec < pq->num_prec);
200 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
201
202 ASSERT(!pktq_full(pq));
203 ASSERT(!pktq_pfull(pq, prec));
204
205 q = &pq->q[prec];
206
207 if (q->head == NULL)
208 q->tail = p;
209
210 PKTSETLINK(p, q->head);
211 q->head = p;
212 q->len++;
213
214 pq->len++;
215
216 if (pq->hi_prec < prec)
217 pq->hi_prec = (uint8)prec;
218
219 return p;
220}
221
222void * BCMFASTPATH
223pktq_pdeq(struct pktq *pq, int prec)
224{
225 struct pktq_prec *q;
226 void *p;
227
228 ASSERT(prec >= 0 && prec < pq->num_prec);
229
230 q = &pq->q[prec];
231
232 if ((p = q->head) == NULL)
233 return NULL;
234
235 if ((q->head = PKTLINK(p)) == NULL)
236 q->tail = NULL;
237
238 q->len--;
239
240 pq->len--;
241
242 PKTSETLINK(p, NULL);
243
244 return p;
245}
246
247void * BCMFASTPATH
248pktq_pdeq_tail(struct pktq *pq, int prec)
249{
250 struct pktq_prec *q;
251 void *p, *prev;
252
253 ASSERT(prec >= 0 && prec < pq->num_prec);
254
255 q = &pq->q[prec];
256
257 if ((p = q->head) == NULL)
258 return NULL;
259
260 for (prev = NULL; p != q->tail; p = PKTLINK(p))
261 prev = p;
262
263 if (prev)
264 PKTSETLINK(prev, NULL);
265 else
266 q->head = NULL;
267
268 q->tail = prev;
269 q->len--;
270
271 pq->len--;
272
273 return p;
274}
275
276void
277pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg)
278{
279 struct pktq_prec *q;
280 void *p, *prev = NULL;
281
282 q = &pq->q[prec];
283 p = q->head;
284 while (p) {
285 if (fn == NULL || (*fn)(p, arg)) {
286 bool head = (p == q->head);
287 if (head)
288 q->head = PKTLINK(p);
289 else
290 PKTSETLINK(prev, PKTLINK(p));
291 PKTSETLINK(p, NULL);
292 PKTFREE(osh, p, dir);
293 q->len--;
294 pq->len--;
295 p = (head ? q->head : PKTLINK(prev));
296 } else {
297 prev = p;
298 p = PKTLINK(p);
299 }
300 }
301
302 if (q->head == NULL) {
303 ASSERT(q->len == 0);
304 q->tail = NULL;
305 }
306}
307
308bool BCMFASTPATH
309pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
310{
311 struct pktq_prec *q;
312 void *p;
313
314 ASSERT(prec >= 0 && prec < pq->num_prec);
315
316 if (!pktbuf)
317 return FALSE;
318
319 q = &pq->q[prec];
320
321 if (q->head == pktbuf) {
322 if ((q->head = PKTLINK(pktbuf)) == NULL)
323 q->tail = NULL;
324 } else {
325 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
326 ;
327 if (p == NULL)
328 return FALSE;
329
330 PKTSETLINK(p, PKTLINK(pktbuf));
331 if (q->tail == pktbuf)
332 q->tail = p;
333 }
334
335 q->len--;
336 pq->len--;
337 PKTSETLINK(pktbuf, NULL);
338 return TRUE;
339}
340
341void
342pktq_init(struct pktq *pq, int num_prec, int max_len)
343{
344 int prec;
345
346 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
347
348 /* pq is variable size; only zero out what's requested */
349 bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
350
351 pq->num_prec = (uint16)num_prec;
352
353 pq->max = (uint16)max_len;
354
355 for (prec = 0; prec < num_prec; prec++)
356 pq->q[prec].max = pq->max;
357}
358
359void * BCMFASTPATH
360pktq_deq(struct pktq *pq, int *prec_out)
361{
362 struct pktq_prec *q;
363 void *p;
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 q = &pq->q[prec];
373
374 if ((p = q->head) == NULL)
375 return NULL;
376
377 if ((q->head = PKTLINK(p)) == NULL)
378 q->tail = NULL;
379
380 q->len--;
381
382 pq->len--;
383
384 if (prec_out)
385 *prec_out = prec;
386
387 PKTSETLINK(p, NULL);
388
389 return p;
390}
391
392void * BCMFASTPATH
393pktq_deq_tail(struct pktq *pq, int *prec_out)
394{
395 struct pktq_prec *q;
396 void *p, *prev;
397 int prec;
398
399 if (pq->len == 0)
400 return NULL;
401
402 for (prec = 0; prec < pq->hi_prec; prec++)
403 if (pq->q[prec].head)
404 break;
405
406 q = &pq->q[prec];
407
408 if ((p = q->head) == NULL)
409 return NULL;
410
411 for (prev = NULL; p != q->tail; p = PKTLINK(p))
412 prev = p;
413
414 if (prev)
415 PKTSETLINK(prev, NULL);
416 else
417 q->head = NULL;
418
419 q->tail = prev;
420 q->len--;
421
422 pq->len--;
423
424 if (prec_out)
425 *prec_out = prec;
426
427 PKTSETLINK(p, NULL);
428
429 return p;
430}
431
432void *
433pktq_peek(struct pktq *pq, int *prec_out)
434{
435 int prec;
436
437 if (pq->len == 0)
438 return NULL;
439
440 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
441 pq->hi_prec--;
442
443 if (prec_out)
444 *prec_out = prec;
445
446 return (pq->q[prec].head);
447}
448
449void *
450pktq_peek_tail(struct pktq *pq, int *prec_out)
451{
452 int prec;
453
454 if (pq->len == 0)
455 return NULL;
456
457 for (prec = 0; prec < pq->hi_prec; prec++)
458 if (pq->q[prec].head)
459 break;
460
461 if (prec_out)
462 *prec_out = prec;
463
464 return (pq->q[prec].tail);
465}
466
467void
468pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
469{
470 int prec;
471 for (prec = 0; prec < pq->num_prec; prec++)
472 pktq_pflush(osh, pq, prec, dir, fn, arg);
473 if (fn == NULL)
474 ASSERT(pq->len == 0);
475}
476
477/* Return sum of lengths of a specific set of precedences */
478int
479pktq_mlen(struct pktq *pq, uint prec_bmp)
480{
481 int prec, len;
482
483 len = 0;
484
485 for (prec = 0; prec <= pq->hi_prec; prec++)
486 if (prec_bmp & (1 << prec))
487 len += pq->q[prec].len;
488
489 return len;
490}
491
492/* Priority dequeue from a specific set of precedences */
493void * BCMFASTPATH
494pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
495{
496 struct pktq_prec *q;
497 void *p;
498 int prec;
499
500 if (pq->len == 0)
501 return NULL;
502
503 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
504 pq->hi_prec--;
505
506 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
507 if (prec-- == 0)
508 return NULL;
509
510 q = &pq->q[prec];
511
512 if ((p = q->head) == NULL)
513 return NULL;
514
515 if ((q->head = PKTLINK(p)) == NULL)
516 q->tail = NULL;
517
518 q->len--;
519
520 if (prec_out)
521 *prec_out = prec;
522
523 pq->len--;
524
525 PKTSETLINK(p, NULL);
526
527 return p;
528}
529
530#endif /* BCMDRIVER */
531
532const unsigned char bcm_ctype[] = {
533
534 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
535 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
536 _BCM_C, /* 8-15 */
537 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
538 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
539 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
540 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
541 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
542 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
543 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
544 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
545 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
546 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
547 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
548 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
549 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
550 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
551 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
552 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
553 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
554 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
555 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
556 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
557 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
558 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
559 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
560 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
561 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
562 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
563 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
564 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
565 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
566 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
567};
568
569ulong
570bcm_strtoul(char *cp, char **endp, uint base)
571{
572 ulong result, last_result = 0, value;
573 bool minus;
574
575 minus = FALSE;
576
577 while (bcm_isspace(*cp))
578 cp++;
579
580 if (cp[0] == '+')
581 cp++;
582 else if (cp[0] == '-') {
583 minus = TRUE;
584 cp++;
585 }
586
587 if (base == 0) {
588 if (cp[0] == '0') {
589 if ((cp[1] == 'x') || (cp[1] == 'X')) {
590 base = 16;
591 cp = &cp[2];
592 } else {
593 base = 8;
594 cp = &cp[1];
595 }
596 } else
597 base = 10;
598 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
599 cp = &cp[2];
600 }
601
602 result = 0;
603
604 while (bcm_isxdigit(*cp) &&
605 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base)
606 {
607 result = result*base + value;
608 /* Detected overflow */
609 if (result < last_result && !minus)
610 return (ulong)-1;
611 last_result = result;
612 cp++;
613 }
614
615 if (minus)
616 result = (ulong)(-(long)result);
617
618 if (endp)
619 *endp = (char *)cp;
620
621 return (result);
622}
623
624int
625bcm_atoi(char *s)
626{
627 return (int)bcm_strtoul(s, NULL, 10);
628}
629
630/* return pointer to location of substring 'needle' in 'haystack' */
631char*
632bcmstrstr(char *haystack, char *needle)
633{
634 int len, nlen;
635 int i;
636
637 if ((haystack == NULL) || (needle == NULL))
638 return (haystack);
639
640 nlen = strlen(needle);
641 len = strlen(haystack) - nlen + 1;
642
643 for (i = 0; i < len; i++)
644 if (memcmp(needle, &haystack[i], nlen) == 0)
645 return (&haystack[i]);
646 return (NULL);
647}
648
649char*
650bcmstrcat(char *dest, const char *src)
651{
652 char *p;
653
654 p = dest + strlen(dest);
655
656 while ((*p++ = *src++) != '\0')
657 ;
658
659 return (dest);
660}
661
662char*
663bcmstrncat(char *dest, const char *src, uint size)
664{
665 char *endp;
666 char *p;
667
668 p = dest + strlen(dest);
669 endp = p + size;
670
671 while (p != endp && (*p++ = *src++) != '\0')
672 ;
673
674 return (dest);
675}
676
677
678/****************************************************************************
679* Function: bcmstrtok
680*
681* Purpose:
682* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
683* but allows strToken() to be used by different strings or callers at the same
684* time. Each call modifies '*string' by substituting a NULL character for the
685* first delimiter that is encountered, and updates 'string' to point to the char
686* after the delimiter. Leading delimiters are skipped.
687*
688* Parameters:
689* string (mod) Ptr to string ptr, updated by token.
690* delimiters (in) Set of delimiter characters.
691* tokdelim (out) Character that delimits the returned token. (May
692* be set to NULL if token delimiter is not required).
693*
694* Returns: Pointer to the next token found. NULL when no more tokens are found.
695*****************************************************************************
696*/
697char *
698bcmstrtok(char **string, const char *delimiters, char *tokdelim)
699{
700 unsigned char *str;
701 unsigned long map[8];
702 int count;
703 char *nextoken;
704
705 if (tokdelim != NULL) {
706 /* Prime the token delimiter */
707 *tokdelim = '\0';
708 }
709
710 /* Clear control map */
711 for (count = 0; count < 8; count++) {
712 map[count] = 0;
713 }
714
715 /* Set bits in delimiter table */
716 do {
717 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
718 }
719 while (*delimiters++);
720
721 str = (unsigned char*)*string;
722
723 /* Find beginning of token (skip over leading delimiters). Note that
724 * there is no token iff this loop sets str to point to the terminal
725 * null (*str == '\0')
726 */
727 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
728 str++;
729 }
730
731 nextoken = (char*)str;
732
733 /* Find the end of the token. If it is not the end of the string,
734 * put a null there.
735 */
736 for (; *str; str++) {
737 if (map[*str >> 5] & (1 << (*str & 31))) {
738 if (tokdelim != NULL) {
739 *tokdelim = *str;
740 }
741
742 *str++ = '\0';
743 break;
744 }
745 }
746
747 *string = (char*)str;
748
749 /* Determine if a token has been found. */
750 if (nextoken == (char *) str) {
751 return NULL;
752 }
753 else {
754 return nextoken;
755 }
756}
757
758
759#define xToLower(C) \
760 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
761
762
763/****************************************************************************
764* Function: bcmstricmp
765*
766* Purpose: Compare to strings case insensitively.
767*
768* Parameters: s1 (in) First string to compare.
769* s2 (in) Second string to compare.
770*
771* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
772* t1 > t2, when ignoring case sensitivity.
773*****************************************************************************
774*/
775int
776bcmstricmp(const char *s1, const char *s2)
777{
778 char dc, sc;
779
780 while (*s2 && *s1) {
781 dc = xToLower(*s1);
782 sc = xToLower(*s2);
783 if (dc < sc) return -1;
784 if (dc > sc) return 1;
785 s1++;
786 s2++;
787 }
788
789 if (*s1 && !*s2) return 1;
790 if (!*s1 && *s2) return -1;
791 return 0;
792}
793
794
795/****************************************************************************
796* Function: bcmstrnicmp
797*
798* Purpose: Compare to strings case insensitively, upto a max of 'cnt'
799* characters.
800*
801* Parameters: s1 (in) First string to compare.
802* s2 (in) Second string to compare.
803* cnt (in) Max characters to compare.
804*
805* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
806* t1 > t2, when ignoring case sensitivity.
807*****************************************************************************
808*/
809int
810bcmstrnicmp(const char* s1, const char* s2, int cnt)
811{
812 char dc, sc;
813
814 while (*s2 && *s1 && cnt) {
815 dc = xToLower(*s1);
816 sc = xToLower(*s2);
817 if (dc < sc) return -1;
818 if (dc > sc) return 1;
819 s1++;
820 s2++;
821 cnt--;
822 }
823
824 if (!cnt) return 0;
825 if (*s1 && !*s2) return 1;
826 if (!*s1 && *s2) return -1;
827 return 0;
828}
829
830/* parse a xx:xx:xx:xx:xx:xx format ethernet address */
831int
832bcm_ether_atoe(char *p, struct ether_addr *ea)
833{
834 int i = 0;
835
836 for (;;) {
837 ea->octet[i++] = (char) bcm_strtoul(p, &p, 16);
838 if (!*p++ || i == 6)
839 break;
840 }
841
842 return (i == 6);
843}
844
845
846#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
847/* registry routine buffer preparation utility functions:
848 * parameter order is like strncpy, but returns count
849 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
850 */
851ulong
852wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
853{
854 ulong copyct = 1;
855 ushort i;
856
857 if (abuflen == 0)
858 return 0;
859
860 /* wbuflen is in bytes */
861 wbuflen /= sizeof(ushort);
862
863 for (i = 0; i < wbuflen; ++i) {
864 if (--abuflen == 0)
865 break;
866 *abuf++ = (char) *wbuf++;
867 ++copyct;
868 }
869 *abuf = '\0';
870
871 return copyct;
872}
873#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
874
875char *
876bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
877{
878 static const char template[] = "%02x:%02x:%02x:%02x:%02x:%02x";
879 snprintf(buf, 18, template,
880 ea->octet[0]&0xff, ea->octet[1]&0xff, ea->octet[2]&0xff,
881 ea->octet[3]&0xff, ea->octet[4]&0xff, ea->octet[5]&0xff);
882 return (buf);
883}
884
885char *
886bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
887{
888 snprintf(buf, 16, "%d.%d.%d.%d",
889 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
890 return (buf);
891}
892
893#ifdef BCMDRIVER
894
895void
896bcm_mdelay(uint ms)
897{
898 uint i;
899
900 for (i = 0; i < ms; i++) {
901 OSL_DELAY(1000);
902 }
903}
904
905
906
907
908
909#if defined(DHD_DEBUG)
910/* pretty hex print a pkt buffer chain */
911void
912prpkt(const char *msg, osl_t *osh, void *p0)
913{
914 void *p;
915
916 if (msg && (msg[0] != '\0'))
917 printf("%s:\n", msg);
918
919 for (p = p0; p; p = PKTNEXT(osh, p))
920 prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
921}
922#endif
923
924/* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
925 * Also updates the inplace vlan tag if requested.
926 * For debugging, it returns an indication of what it did.
927 */
928uint BCMFASTPATH
929pktsetprio(void *pkt, bool update_vtag)
930{
931 struct ether_header *eh;
932 struct ethervlan_header *evh;
933 uint8 *pktdata;
934 int priority = 0;
935 int rc = 0;
936
937 pktdata = (uint8 *) PKTDATA(NULL, pkt);
938 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
939
940 eh = (struct ether_header *) pktdata;
941
942 if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
943 uint16 vlan_tag;
944 int vlan_prio, dscp_prio = 0;
945
946 evh = (struct ethervlan_header *)eh;
947
948 vlan_tag = ntoh16(evh->vlan_tag);
949 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
950
951 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
952 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
953 uint8 tos_tc = IP_TOS46(ip_body);
954 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
955 }
956
957 /* DSCP priority gets precedence over 802.1P (vlan tag) */
958 if (dscp_prio != 0) {
959 priority = dscp_prio;
960 rc |= PKTPRIO_VDSCP;
961 } else {
962 priority = vlan_prio;
963 rc |= PKTPRIO_VLAN;
964 }
965 /*
966 * If the DSCP priority is not the same as the VLAN priority,
967 * then overwrite the priority field in the vlan tag, with the
968 * DSCP priority value. This is required for Linux APs because
969 * the VLAN driver on Linux, overwrites the skb->priority field
970 * with the priority value in the vlan tag
971 */
972 if (update_vtag && (priority != vlan_prio)) {
973 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
974 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
975 evh->vlan_tag = hton16(vlan_tag);
976 rc |= PKTPRIO_UPD;
977 }
978 } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
979 uint8 *ip_body = pktdata + sizeof(struct ether_header);
980 uint8 tos_tc = IP_TOS46(ip_body);
981 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
982 rc |= PKTPRIO_DSCP;
983 }
984
985 ASSERT(priority >= 0 && priority <= MAXPRIO);
986 PKTSETPRIO(pkt, priority);
987 return (rc | priority);
988}
989
990#ifndef BCM_BOOTLOADER
991
992static char bcm_undeferrstr[32];
993static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
994
995/* Convert the error codes into related error strings */
996const char *
997bcmerrorstr(int bcmerror)
998{
999 /* check if someone added a bcmerror code but forgot to add errorstring */
1000 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
1001
1002 if (bcmerror > 0 || bcmerror < BCME_LAST) {
1003 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
1004 return bcm_undeferrstr;
1005 }
1006
1007 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
1008
1009 return bcmerrorstrtable[-bcmerror];
1010}
1011
1012#endif /* !BCM_BOOTLOADER */
1013
1014
1015
1016/* iovar table lookup */
1017const bcm_iovar_t*
1018bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
1019{
1020 const bcm_iovar_t *vi;
1021 const char *lookup_name;
1022
1023 /* skip any ':' delimited option prefixes */
1024 lookup_name = strrchr(name, ':');
1025 if (lookup_name != NULL)
1026 lookup_name++;
1027 else
1028 lookup_name = name;
1029
1030 ASSERT(table != NULL);
1031
1032 for (vi = table; vi->name; vi++) {
1033 if (!strcmp(vi->name, lookup_name))
1034 return vi;
1035 }
1036 /* ran to end of table */
1037
1038 return NULL; /* var name not found */
1039}
1040
1041int
1042bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
1043{
1044 int bcmerror = 0;
1045
1046 /* length check on io buf */
1047 switch (vi->type) {
1048 case IOVT_BOOL:
1049 case IOVT_INT8:
1050 case IOVT_INT16:
1051 case IOVT_INT32:
1052 case IOVT_UINT8:
1053 case IOVT_UINT16:
1054 case IOVT_UINT32:
1055 /* all integers are int32 sized args at the ioctl interface */
1056 if (len < (int)sizeof(int)) {
1057 bcmerror = BCME_BUFTOOSHORT;
1058 }
1059 break;
1060
1061 case IOVT_BUFFER:
1062 /* buffer must meet minimum length requirement */
1063 if (len < vi->minlen) {
1064 bcmerror = BCME_BUFTOOSHORT;
1065 }
1066 break;
1067
1068 case IOVT_VOID:
1069 if (!set) {
1070 /* Cannot return nil... */
1071 bcmerror = BCME_UNSUPPORTED;
1072 } else if (len) {
1073 /* Set is an action w/o parameters */
1074 bcmerror = BCME_BUFTOOLONG;
1075 }
1076 break;
1077
1078 default:
1079 /* unknown type for length check in iovar info */
1080 ASSERT(0);
1081 bcmerror = BCME_UNSUPPORTED;
1082 }
1083
1084 return bcmerror;
1085}
1086
1087#endif /* BCMDRIVER */
1088
1089
1090/*******************************************************************************
1091 * crc8
1092 *
1093 * Computes a crc8 over the input data using the polynomial:
1094 *
1095 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1096 *
1097 * The caller provides the initial value (either CRC8_INIT_VALUE
1098 * or the previous returned value) to allow for processing of
1099 * discontiguous blocks of data. When generating the CRC the
1100 * caller is responsible for complementing the final return value
1101 * and inserting it into the byte stream. When checking, a final
1102 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1103 *
1104 * Reference: Dallas Semiconductor Application Note 27
1105 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1106 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1107 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1108 *
1109 * ****************************************************************************
1110 */
1111
1112static const uint8 crc8_table[256] = {
1113 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1114 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1115 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1116 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1117 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1118 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1119 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1120 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1121 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1122 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1123 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1124 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1125 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1126 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1127 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1128 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1129 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1130 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1131 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1132 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1133 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1134 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1135 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1136 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1137 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1138 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1139 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1140 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1141 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1142 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1143 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1144 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1145};
1146
1147#define CRC_INNER_LOOP(n, c, x) \
1148 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1149
1150uint8
1151hndcrc8(
1152 uint8 *pdata, /* pointer to array of data to process */
1153 uint nbytes, /* number of input data bytes to process */
1154 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1155)
1156{
1157 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1158 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1159 */
1160 while (nbytes-- > 0)
1161 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1162
1163 return crc;
1164}
1165
1166/*******************************************************************************
1167 * crc16
1168 *
1169 * Computes a crc16 over the input data using the polynomial:
1170 *
1171 * x^16 + x^12 +x^5 + 1
1172 *
1173 * The caller provides the initial value (either CRC16_INIT_VALUE
1174 * or the previous returned value) to allow for processing of
1175 * discontiguous blocks of data. When generating the CRC the
1176 * caller is responsible for complementing the final return value
1177 * and inserting it into the byte stream. When checking, a final
1178 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1179 *
1180 * Reference: Dallas Semiconductor Application Note 27
1181 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1182 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1183 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1184 *
1185 * ****************************************************************************
1186 */
1187
1188static const uint16 crc16_table[256] = {
1189 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1190 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1191 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1192 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1193 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1194 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1195 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1196 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1197 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1198 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1199 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1200 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1201 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1202 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1203 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1204 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1205 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1206 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1207 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1208 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1209 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1210 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1211 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1212 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1213 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1214 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1215 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1216 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1217 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1218 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1219 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1220 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1221};
1222
1223uint16
1224hndcrc16(
1225 uint8 *pdata, /* pointer to array of data to process */
1226 uint nbytes, /* number of input data bytes to process */
1227 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1228)
1229{
1230 while (nbytes-- > 0)
1231 CRC_INNER_LOOP(16, crc, *pdata++);
1232 return crc;
1233}
1234
1235static const uint32 crc32_table[256] = {
1236 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1237 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1238 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1239 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1240 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1241 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1242 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1243 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1244 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1245 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1246 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1247 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1248 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1249 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1250 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1251 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1252 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1253 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1254 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1255 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1256 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1257 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1258 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1259 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1260 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1261 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1262 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1263 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1264 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1265 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1266 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1267 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1268 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1269 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1270 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1271 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1272 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1273 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1274 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1275 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1276 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1277 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1278 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1279 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1280 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1281 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1282 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1283 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1284 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1285 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1286 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1287 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1288 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1289 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1290 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1291 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1292 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1293 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1294 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1295 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1296 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1297 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1298 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1299 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1300};
1301
1302/*
1303 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
1304 * accumulating over multiple pieces.
1305 */
1306uint32
1307hndcrc32(uint8 *pdata, uint nbytes, uint32 crc)
1308{
1309 uint8 *pend;
1310#ifdef __mips__
1311 uint8 tmp[4];
1312 ulong *tptr = (ulong *)tmp;
1313
1314 /* in case the beginning of the buffer isn't aligned */
1315 pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
1316 nbytes -= (pend - pdata);
1317 while (pdata < pend)
1318 CRC_INNER_LOOP(32, crc, *pdata++);
1319
1320 /* handle bulk of data as 32-bit words */
1321 pend = pdata + (nbytes & 0xfffffffc);
1322 while (pdata < pend) {
1323 *tptr = *(ulong *)pdata;
1324 pdata += sizeof(ulong *);
1325 CRC_INNER_LOOP(32, crc, tmp[0]);
1326 CRC_INNER_LOOP(32, crc, tmp[1]);
1327 CRC_INNER_LOOP(32, crc, tmp[2]);
1328 CRC_INNER_LOOP(32, crc, tmp[3]);
1329 }
1330
1331 /* 1-3 bytes at end of buffer */
1332 pend = pdata + (nbytes & 0x03);
1333 while (pdata < pend)
1334 CRC_INNER_LOOP(32, crc, *pdata++);
1335#else
1336 pend = pdata + nbytes;
1337 while (pdata < pend)
1338 CRC_INNER_LOOP(32, crc, *pdata++);
1339#endif /* __mips__ */
1340
1341 return crc;
1342}
1343
1344#ifdef notdef
1345#define CLEN 1499 /* CRC Length */
1346#define CBUFSIZ (CLEN+4)
1347#define CNBUFS 5 /* # of bufs */
1348
1349void
1350testcrc32(void)
1351{
1352 uint j, k, l;
1353 uint8 *buf;
1354 uint len[CNBUFS];
1355 uint32 crcr;
1356 uint32 crc32tv[CNBUFS] =
1357 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1358
1359 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
1360
1361 /* step through all possible alignments */
1362 for (l = 0; l <= 4; l++) {
1363 for (j = 0; j < CNBUFS; j++) {
1364 len[j] = CLEN;
1365 for (k = 0; k < len[j]; k++)
1366 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
1367 }
1368
1369 for (j = 0; j < CNBUFS; j++) {
1370 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1371 ASSERT(crcr == crc32tv[j]);
1372 }
1373 }
1374
1375 MFREE(buf, CBUFSIZ*CNBUFS);
1376 return;
1377}
1378#endif /* notdef */
1379
1380/*
1381 * Advance from the current 1-byte tag/1-byte length/variable-length value
1382 * triple, to the next, returning a pointer to the next.
1383 * If the current or next TLV is invalid (does not fit in given buffer length),
1384 * NULL is returned.
1385 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1386 * by the TLV parameter's length if it is valid.
1387 */
1388bcm_tlv_t *
1389bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
1390{
1391 int len;
1392
1393 /* validate current elt */
1394 if (!bcm_valid_tlv(elt, *buflen))
1395 return NULL;
1396
1397 /* advance to next elt */
1398 len = elt->len;
1399 elt = (bcm_tlv_t*)(elt->data + len);
1400 *buflen -= (2 + len);
1401
1402 /* validate next elt */
1403 if (!bcm_valid_tlv(elt, *buflen))
1404 return NULL;
1405
1406 return elt;
1407}
1408
1409/*
1410 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1411 * triples, returning a pointer to the substring whose first element
1412 * matches tag
1413 */
1414bcm_tlv_t *
1415bcm_parse_tlvs(void *buf, int buflen, uint key)
1416{
1417 bcm_tlv_t *elt;
1418 int totlen;
1419
1420 elt = (bcm_tlv_t*)buf;
1421 totlen = buflen;
1422
1423 /* find tagged parameter */
1424 while (totlen >= 2) {
1425 int len = elt->len;
1426
1427 /* validate remaining totlen */
1428 if ((elt->id == key) && (totlen >= (len + 2)))
1429 return (elt);
1430
1431 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1432 totlen -= (len + 2);
1433 }
1434
1435 return NULL;
1436}
1437
1438/*
1439 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1440 * triples, returning a pointer to the substring whose first element
1441 * matches tag. Stop parsing when we see an element whose ID is greater
1442 * than the target key.
1443 */
1444bcm_tlv_t *
1445bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
1446{
1447 bcm_tlv_t *elt;
1448 int totlen;
1449
1450 elt = (bcm_tlv_t*)buf;
1451 totlen = buflen;
1452
1453 /* find tagged parameter */
1454 while (totlen >= 2) {
1455 uint id = elt->id;
1456 int len = elt->len;
1457
1458 /* Punt if we start seeing IDs > than target key */
1459 if (id > key)
1460 return (NULL);
1461
1462 /* validate remaining totlen */
1463 if ((id == key) && (totlen >= (len + 2)))
1464 return (elt);
1465
1466 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1467 totlen -= (len + 2);
1468 }
1469 return NULL;
1470}
1471
1472#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1473 defined(DHD_DEBUG)
1474int
1475bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
1476{
1477 int i;
1478 char* p = buf;
1479 char hexstr[16];
1480 int slen = 0, nlen = 0;
1481 uint32 bit;
1482 const char* name;
1483
1484 if (len < 2 || !buf)
1485 return 0;
1486
1487 buf[0] = '\0';
1488
1489 for (i = 0; flags != 0; i++) {
1490 bit = bd[i].bit;
1491 name = bd[i].name;
1492 if (bit == 0 && flags != 0) {
1493 /* print any unnamed bits */
1494 snprintf(hexstr, 16, "0x%X", flags);
1495 name = hexstr;
1496 flags = 0; /* exit loop */
1497 } else if ((flags & bit) == 0)
1498 continue;
1499 flags &= ~bit;
1500 nlen = strlen(name);
1501 slen += nlen;
1502 /* count btwn flag space */
1503 if (flags != 0)
1504 slen += 1;
1505 /* need NULL char as well */
1506 if (len <= slen)
1507 break;
1508 /* copy NULL char but don't count it */
1509 strncpy(p, name, nlen + 1);
1510 p += nlen;
1511 /* copy btwn flag space and NULL char */
1512 if (flags != 0)
1513 p += snprintf(p, 2, " ");
1514 len -= slen;
1515 }
1516
1517 /* indicate the str was too short */
1518 if (flags != 0) {
1519 if (len < 2)
1520 p -= 2 - len; /* overwrite last char */
1521 p += snprintf(p, 2, ">");
1522 }
1523
1524 return (int)(p - buf);
1525}
1526#endif
1527
1528#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1529 defined(DHD_DEBUG) || defined(WLMEDIA_PEAKRATE)
1530/* print bytes formatted as hex to a string. return the resulting string length */
1531int
1532bcm_format_hex(char *str, const void *bytes, int len)
1533{
1534 int i;
1535 char *p = str;
1536 const uint8 *src = (const uint8*)bytes;
1537
1538 for (i = 0; i < len; i++) {
1539 p += snprintf(p, 3, "%02X", *src);
1540 src++;
1541 }
1542 return (int)(p - str);
1543}
1544#endif
1545
1546/* pretty hex print a contiguous buffer */
1547void
1548prhex(const char *msg, uchar *buf, uint nbytes)
1549{
1550 char line[128], *p;
1551 int len = sizeof(line);
1552 int nchar;
1553 uint i;
1554
1555 if (msg && (msg[0] != '\0'))
1556 printf("%s:\n", msg);
1557
1558 p = line;
1559 for (i = 0; i < nbytes; i++) {
1560 if (i % 16 == 0) {
1561 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
1562 p += nchar;
1563 len -= nchar;
1564 }
1565 if (len > 0) {
1566 nchar = snprintf(p, len, "%02x ", buf[i]);
1567 p += nchar;
1568 len -= nchar;
1569 }
1570
1571 if (i % 16 == 15) {
1572 printf("%s\n", line); /* flush line */
1573 p = line;
1574 len = sizeof(line);
1575 }
1576 }
1577
1578 /* flush last partial line */
1579 if (p != line)
1580 printf("%s\n", line);
1581}
1582
1583static const char *crypto_algo_names[] = {
1584 "NONE",
1585 "WEP1",
1586 "TKIP",
1587 "WEP128",
1588 "AES_CCM",
1589 "AES_OCB_MSDU",
1590 "AES_OCB_MPDU",
1591 "NALG"
1592 "UNDEF",
1593 "UNDEF",
1594 "UNDEF",
1595 "UNDEF"
1596};
1597
1598const char *
1599bcm_crypto_algo_name(uint algo)
1600{
1601 return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
1602}
1603
1604
1605char *
1606bcm_chipname(uint chipid, char *buf, uint len)
1607{
1608 const char *fmt;
1609
1610 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
1611 snprintf(buf, len, fmt, chipid);
1612 return buf;
1613}
1614
1615/* Produce a human-readable string for boardrev */
1616char *
1617bcm_brev_str(uint32 brev, char *buf)
1618{
1619 if (brev < 0x100)
1620 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1621 else
1622 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
1623
1624 return (buf);
1625}
1626
1627#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1628
1629/* dump large strings to console */
1630void
1631printbig(char *buf)
1632{
1633 uint len, max_len;
1634 char c;
1635
1636 len = strlen(buf);
1637
1638 max_len = BUFSIZE_TODUMP_ATONCE;
1639
1640 while (len > max_len) {
1641 c = buf[max_len];
1642 buf[max_len] = '\0';
1643 printf("%s", buf);
1644 buf[max_len] = c;
1645
1646 buf += max_len;
1647 len -= max_len;
1648 }
1649 /* print the remaining string */
1650 printf("%s\n", buf);
1651 return;
1652}
1653
1654/* routine to dump fields in a fileddesc structure */
1655uint
1656bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
1657 char *buf, uint32 bufsize)
1658{
1659 uint filled_len;
1660 int len;
1661 struct fielddesc *cur_ptr;
1662
1663 filled_len = 0;
1664 cur_ptr = fielddesc_array;
1665
1666 while (bufsize > 1) {
1667 if (cur_ptr->nameandfmt == NULL)
1668 break;
1669 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
1670 read_rtn(arg0, arg1, cur_ptr->offset));
1671 /* check for snprintf overflow or error */
1672 if (len < 0 || (uint32)len >= bufsize)
1673 len = bufsize - 1;
1674 buf += len;
1675 bufsize -= len;
1676 filled_len += len;
1677 cur_ptr++;
1678 }
1679 return filled_len;
1680}
1681
1682uint
1683bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1684{
1685 uint len;
1686
1687 len = strlen(name) + 1;
1688
1689 if ((len + datalen) > buflen)
1690 return 0;
1691
1692 strncpy(buf, name, buflen);
1693
1694 /* append data onto the end of the name string */
1695 memcpy(&buf[len], data, datalen);
1696 len += datalen;
1697
1698 return len;
1699}
1700
1701/* Quarter dBm units to mW
1702 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1703 * Table is offset so the last entry is largest mW value that fits in
1704 * a uint16.
1705 */
1706
1707#define QDBM_OFFSET 153 /* Offset for first entry */
1708#define QDBM_TABLE_LEN 40 /* Table size */
1709
1710/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1711 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1712 */
1713#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1714
1715/* Largest mW value that will round down to the last table entry,
1716 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1717 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1718 */
1719#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1720
1721static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1722/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1723/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1724/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1725/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1726/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1727/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1728};
1729
1730uint16
1731bcm_qdbm_to_mw(uint8 qdbm)
1732{
1733 uint factor = 1;
1734 int idx = qdbm - QDBM_OFFSET;
1735
1736 if (idx >= QDBM_TABLE_LEN) {
1737 /* clamp to max uint16 mW value */
1738 return 0xFFFF;
1739 }
1740
1741 /* scale the qdBm index up to the range of the table 0-40
1742 * where an offset of 40 qdBm equals a factor of 10 mW.
1743 */
1744 while (idx < 0) {
1745 idx += 40;
1746 factor *= 10;
1747 }
1748
1749 /* return the mW value scaled down to the correct factor of 10,
1750 * adding in factor/2 to get proper rounding.
1751 */
1752 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
1753}
1754
1755uint8
1756bcm_mw_to_qdbm(uint16 mw)
1757{
1758 uint8 qdbm;
1759 int offset;
1760 uint mw_uint = mw;
1761 uint boundary;
1762
1763 /* handle boundary case */
1764 if (mw_uint <= 1)
1765 return 0;
1766
1767 offset = QDBM_OFFSET;
1768
1769 /* move mw into the range of the table */
1770 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1771 mw_uint *= 10;
1772 offset -= 40;
1773 }
1774
1775 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
1776 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
1777 nqdBm_to_mW_map[qdbm])/2;
1778 if (mw_uint < boundary)
1779 break;
1780 }
1781
1782 qdbm += (uint8)offset;
1783
1784 return (qdbm);
1785}
1786
1787
1788uint
1789bcm_bitcount(uint8 *bitmap, uint length)
1790{
1791 uint bitcount = 0, i;
1792 uint8 tmp;
1793 for (i = 0; i < length; i++) {
1794 tmp = bitmap[i];
1795 while (tmp) {
1796 bitcount++;
1797 tmp &= (tmp - 1);
1798 }
1799 }
1800 return bitcount;
1801}
1802
1803#ifdef BCMDRIVER
1804
1805/* Initialization of bcmstrbuf structure */
1806void
1807bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1808{
1809 b->origsize = b->size = size;
1810 b->origbuf = b->buf = buf;
1811}
1812
1813/* Buffer sprintf wrapper to guard against buffer overflow */
1814int
1815bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1816{
1817 va_list ap;
1818 int r;
1819
1820 va_start(ap, fmt);
1821 r = vsnprintf(b->buf, b->size, fmt, ap);
1822
1823 /* Non Ansi C99 compliant returns -1,
1824 * Ansi compliant return r >= b->size,
1825 * bcmstdlib returns 0, handle all
1826 */
1827 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1828 b->size = 0;
1829 } else {
1830 b->size -= r;
1831 b->buf += r;
1832 }
1833
1834 va_end(ap);
1835
1836 return r;
1837}
1838
1839void
1840bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
1841{
1842 int i;
1843
1844 for (i = 0; i < num_bytes; i++) {
1845 num[i] += amount;
1846 if (num[i] >= amount)
1847 break;
1848 amount = 1;
1849 }
1850}
1851
1852int
1853bcm_cmp_bytes(uchar *arg1, uchar *arg2, uint8 nbytes)
1854{
1855 int i;
1856
1857 for (i = nbytes - 1; i >= 0; i--) {
1858 if (arg1[i] != arg2[i])
1859 return (arg1[i] - arg2[i]);
1860 }
1861 return 0;
1862}
1863
1864void
1865bcm_print_bytes(char *name, const uchar *data, int len)
1866{
1867 int i;
1868 int per_line = 0;
1869
1870 printf("%s: %d \n", name ? name : "", len);
1871 for (i = 0; i < len; i++) {
1872 printf("%02x ", *data++);
1873 per_line++;
1874 if (per_line == 16) {
1875 per_line = 0;
1876 printf("\n");
1877 }
1878 }
1879 printf("\n");
1880}
1881#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
1882 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
1883#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
1884
1885int
1886bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
1887{
1888 uint i, c;
1889 char *p = buf;
1890 char *endp = buf + SSID_FMT_BUF_LEN;
1891
1892 if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
1893
1894 for (i = 0; i < ssid_len; i++) {
1895 c = (uint)ssid[i];
1896 if (c == '\\') {
1897 *p++ = '\\';
1898 *p++ = '\\';
1899 } else if (bcm_isprint((uchar)c)) {
1900 *p++ = (char)c;
1901 } else {
1902 p += snprintf(p, (endp - p), "\\x%02X", c);
1903 }
1904 }
1905 *p = '\0';
1906 ASSERT(p < endp);
1907
1908 return (int)(p - buf);
1909}
1910#endif
1911
1912#endif /* BCMDRIVER */
1913
1914/*
1915 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
1916 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
1917 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
1918 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
1919*/
1920
1921unsigned int
1922process_nvram_vars(char *varbuf, unsigned int len)
1923{
1924 char *dp;
1925 bool findNewline;
1926 int column;
1927 unsigned int buf_len, n;
1928 unsigned int pad = 0;
1929
1930 dp = varbuf;
1931
1932 findNewline = FALSE;
1933 column = 0;
1934
1935 for (n = 0; n < len; n++) {
1936 if (varbuf[n] == '\r')
1937 continue;
1938 if (findNewline && varbuf[n] != '\n')
1939 continue;
1940 findNewline = FALSE;
1941 if (varbuf[n] == '#') {
1942 findNewline = TRUE;
1943 continue;
1944 }
1945 if (varbuf[n] == '\n') {
1946 if (column == 0)
1947 continue;
1948 *dp++ = 0;
1949 column = 0;
1950 continue;
1951 }
1952 *dp++ = varbuf[n];
1953 column++;
1954 }
1955 buf_len = (unsigned int)(dp - varbuf);
1956 if (buf_len % 4) {
1957 pad = 4 - buf_len % 4;
1958 if (pad && (buf_len + pad <= len)) {
1959 buf_len += pad;
1960 }
1961 }
1962
1963 while (dp < varbuf + n)
1964 *dp++ = 0;
1965
1966 return buf_len;
1967}