blob: 6b578e65364838b1c0d239416e48da6638765c59 [file] [log] [blame]
Dmitry Shmidt66eb9fa2011-05-24 11:14:33 -07001/*
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.
Dmitry Shmidt1dddb0c2012-01-24 13:37:34 -080023 * $Id: bcmutils.c,v 1.277.2.18 2011-01-26 02:32:08 $
Dmitry Shmidt66eb9fa2011-05-24 11:14:33 -070024 */
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
Dmitry Shmidt66eb9fa2011-05-24 11:14:33 -0700990
991static char bcm_undeferrstr[32];
992static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
993
994/* Convert the error codes into related error strings */
995const char *
996bcmerrorstr(int bcmerror)
997{
998 /* check if someone added a bcmerror code but forgot to add errorstring */
999 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
1000
1001 if (bcmerror > 0 || bcmerror < BCME_LAST) {
1002 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
1003 return bcm_undeferrstr;
1004 }
1005
1006 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
1007
1008 return bcmerrorstrtable[-bcmerror];
1009}
1010
Dmitry Shmidt66eb9fa2011-05-24 11:14:33 -07001011
1012
1013
1014/* iovar table lookup */
1015const bcm_iovar_t*
1016bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
1017{
1018 const bcm_iovar_t *vi;
1019 const char *lookup_name;
1020
1021 /* skip any ':' delimited option prefixes */
1022 lookup_name = strrchr(name, ':');
1023 if (lookup_name != NULL)
1024 lookup_name++;
1025 else
1026 lookup_name = name;
1027
1028 ASSERT(table != NULL);
1029
1030 for (vi = table; vi->name; vi++) {
1031 if (!strcmp(vi->name, lookup_name))
1032 return vi;
1033 }
1034 /* ran to end of table */
1035
1036 return NULL; /* var name not found */
1037}
1038
1039int
1040bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
1041{
1042 int bcmerror = 0;
1043
1044 /* length check on io buf */
1045 switch (vi->type) {
1046 case IOVT_BOOL:
1047 case IOVT_INT8:
1048 case IOVT_INT16:
1049 case IOVT_INT32:
1050 case IOVT_UINT8:
1051 case IOVT_UINT16:
1052 case IOVT_UINT32:
1053 /* all integers are int32 sized args at the ioctl interface */
1054 if (len < (int)sizeof(int)) {
1055 bcmerror = BCME_BUFTOOSHORT;
1056 }
1057 break;
1058
1059 case IOVT_BUFFER:
1060 /* buffer must meet minimum length requirement */
1061 if (len < vi->minlen) {
1062 bcmerror = BCME_BUFTOOSHORT;
1063 }
1064 break;
1065
1066 case IOVT_VOID:
1067 if (!set) {
1068 /* Cannot return nil... */
1069 bcmerror = BCME_UNSUPPORTED;
1070 } else if (len) {
1071 /* Set is an action w/o parameters */
1072 bcmerror = BCME_BUFTOOLONG;
1073 }
1074 break;
1075
1076 default:
1077 /* unknown type for length check in iovar info */
1078 ASSERT(0);
1079 bcmerror = BCME_UNSUPPORTED;
1080 }
1081
1082 return bcmerror;
1083}
1084
1085#endif /* BCMDRIVER */
1086
1087
1088/*******************************************************************************
1089 * crc8
1090 *
1091 * Computes a crc8 over the input data using the polynomial:
1092 *
1093 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1094 *
1095 * The caller provides the initial value (either CRC8_INIT_VALUE
1096 * or the previous returned value) to allow for processing of
1097 * discontiguous blocks of data. When generating the CRC the
1098 * caller is responsible for complementing the final return value
1099 * and inserting it into the byte stream. When checking, a final
1100 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1101 *
1102 * Reference: Dallas Semiconductor Application Note 27
1103 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1104 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1105 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1106 *
1107 * ****************************************************************************
1108 */
1109
1110static const uint8 crc8_table[256] = {
1111 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1112 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1113 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1114 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1115 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1116 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1117 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1118 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1119 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1120 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1121 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1122 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1123 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1124 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1125 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1126 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1127 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1128 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1129 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1130 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1131 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1132 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1133 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1134 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1135 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1136 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1137 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1138 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1139 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1140 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1141 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1142 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1143};
1144
1145#define CRC_INNER_LOOP(n, c, x) \
1146 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1147
1148uint8
1149hndcrc8(
1150 uint8 *pdata, /* pointer to array of data to process */
1151 uint nbytes, /* number of input data bytes to process */
1152 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1153)
1154{
1155 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1156 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1157 */
1158 while (nbytes-- > 0)
1159 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1160
1161 return crc;
1162}
1163
1164/*******************************************************************************
1165 * crc16
1166 *
1167 * Computes a crc16 over the input data using the polynomial:
1168 *
1169 * x^16 + x^12 +x^5 + 1
1170 *
1171 * The caller provides the initial value (either CRC16_INIT_VALUE
1172 * or the previous returned value) to allow for processing of
1173 * discontiguous blocks of data. When generating the CRC the
1174 * caller is responsible for complementing the final return value
1175 * and inserting it into the byte stream. When checking, a final
1176 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1177 *
1178 * Reference: Dallas Semiconductor Application Note 27
1179 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1180 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1181 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1182 *
1183 * ****************************************************************************
1184 */
1185
1186static const uint16 crc16_table[256] = {
1187 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1188 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1189 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1190 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1191 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1192 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1193 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1194 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1195 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1196 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1197 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1198 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1199 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1200 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1201 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1202 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1203 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1204 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1205 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1206 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1207 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1208 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1209 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1210 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1211 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1212 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1213 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1214 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1215 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1216 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1217 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1218 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1219};
1220
1221uint16
1222hndcrc16(
1223 uint8 *pdata, /* pointer to array of data to process */
1224 uint nbytes, /* number of input data bytes to process */
1225 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1226)
1227{
1228 while (nbytes-- > 0)
1229 CRC_INNER_LOOP(16, crc, *pdata++);
1230 return crc;
1231}
1232
1233static const uint32 crc32_table[256] = {
1234 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1235 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1236 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1237 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1238 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1239 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1240 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1241 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1242 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1243 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1244 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1245 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1246 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1247 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1248 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1249 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1250 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1251 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1252 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1253 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1254 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1255 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1256 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1257 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1258 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1259 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1260 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1261 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1262 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1263 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1264 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1265 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1266 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1267 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1268 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1269 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1270 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1271 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1272 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1273 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1274 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1275 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1276 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1277 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1278 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1279 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1280 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1281 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1282 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1283 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1284 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1285 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1286 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1287 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1288 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1289 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1290 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1291 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1292 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1293 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1294 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1295 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1296 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1297 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1298};
1299
1300/*
1301 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
1302 * accumulating over multiple pieces.
1303 */
1304uint32
1305hndcrc32(uint8 *pdata, uint nbytes, uint32 crc)
1306{
1307 uint8 *pend;
1308#ifdef __mips__
1309 uint8 tmp[4];
1310 ulong *tptr = (ulong *)tmp;
1311
1312 /* in case the beginning of the buffer isn't aligned */
1313 pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
1314 nbytes -= (pend - pdata);
1315 while (pdata < pend)
1316 CRC_INNER_LOOP(32, crc, *pdata++);
1317
1318 /* handle bulk of data as 32-bit words */
1319 pend = pdata + (nbytes & 0xfffffffc);
1320 while (pdata < pend) {
1321 *tptr = *(ulong *)pdata;
1322 pdata += sizeof(ulong *);
1323 CRC_INNER_LOOP(32, crc, tmp[0]);
1324 CRC_INNER_LOOP(32, crc, tmp[1]);
1325 CRC_INNER_LOOP(32, crc, tmp[2]);
1326 CRC_INNER_LOOP(32, crc, tmp[3]);
1327 }
1328
1329 /* 1-3 bytes at end of buffer */
1330 pend = pdata + (nbytes & 0x03);
1331 while (pdata < pend)
1332 CRC_INNER_LOOP(32, crc, *pdata++);
1333#else
1334 pend = pdata + nbytes;
1335 while (pdata < pend)
1336 CRC_INNER_LOOP(32, crc, *pdata++);
1337#endif /* __mips__ */
1338
1339 return crc;
1340}
1341
1342#ifdef notdef
1343#define CLEN 1499 /* CRC Length */
1344#define CBUFSIZ (CLEN+4)
1345#define CNBUFS 5 /* # of bufs */
1346
1347void
1348testcrc32(void)
1349{
1350 uint j, k, l;
1351 uint8 *buf;
1352 uint len[CNBUFS];
1353 uint32 crcr;
1354 uint32 crc32tv[CNBUFS] =
1355 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1356
1357 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
1358
1359 /* step through all possible alignments */
1360 for (l = 0; l <= 4; l++) {
1361 for (j = 0; j < CNBUFS; j++) {
1362 len[j] = CLEN;
1363 for (k = 0; k < len[j]; k++)
1364 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
1365 }
1366
1367 for (j = 0; j < CNBUFS; j++) {
1368 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1369 ASSERT(crcr == crc32tv[j]);
1370 }
1371 }
1372
1373 MFREE(buf, CBUFSIZ*CNBUFS);
1374 return;
1375}
1376#endif /* notdef */
1377
1378/*
1379 * Advance from the current 1-byte tag/1-byte length/variable-length value
1380 * triple, to the next, returning a pointer to the next.
1381 * If the current or next TLV is invalid (does not fit in given buffer length),
1382 * NULL is returned.
1383 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1384 * by the TLV parameter's length if it is valid.
1385 */
1386bcm_tlv_t *
1387bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
1388{
1389 int len;
1390
1391 /* validate current elt */
1392 if (!bcm_valid_tlv(elt, *buflen))
1393 return NULL;
1394
1395 /* advance to next elt */
1396 len = elt->len;
1397 elt = (bcm_tlv_t*)(elt->data + len);
1398 *buflen -= (2 + len);
1399
1400 /* validate next elt */
1401 if (!bcm_valid_tlv(elt, *buflen))
1402 return NULL;
1403
1404 return elt;
1405}
1406
1407/*
1408 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1409 * triples, returning a pointer to the substring whose first element
1410 * matches tag
1411 */
1412bcm_tlv_t *
1413bcm_parse_tlvs(void *buf, int buflen, uint key)
1414{
1415 bcm_tlv_t *elt;
1416 int totlen;
1417
1418 elt = (bcm_tlv_t*)buf;
1419 totlen = buflen;
1420
1421 /* find tagged parameter */
1422 while (totlen >= 2) {
1423 int len = elt->len;
1424
1425 /* validate remaining totlen */
1426 if ((elt->id == key) && (totlen >= (len + 2)))
1427 return (elt);
1428
1429 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1430 totlen -= (len + 2);
1431 }
1432
1433 return NULL;
1434}
1435
1436/*
1437 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1438 * triples, returning a pointer to the substring whose first element
1439 * matches tag. Stop parsing when we see an element whose ID is greater
1440 * than the target key.
1441 */
1442bcm_tlv_t *
1443bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
1444{
1445 bcm_tlv_t *elt;
1446 int totlen;
1447
1448 elt = (bcm_tlv_t*)buf;
1449 totlen = buflen;
1450
1451 /* find tagged parameter */
1452 while (totlen >= 2) {
1453 uint id = elt->id;
1454 int len = elt->len;
1455
1456 /* Punt if we start seeing IDs > than target key */
1457 if (id > key)
1458 return (NULL);
1459
1460 /* validate remaining totlen */
1461 if ((id == key) && (totlen >= (len + 2)))
1462 return (elt);
1463
1464 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1465 totlen -= (len + 2);
1466 }
1467 return NULL;
1468}
1469
1470#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1471 defined(DHD_DEBUG)
1472int
1473bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
1474{
1475 int i;
1476 char* p = buf;
1477 char hexstr[16];
1478 int slen = 0, nlen = 0;
1479 uint32 bit;
1480 const char* name;
1481
1482 if (len < 2 || !buf)
1483 return 0;
1484
1485 buf[0] = '\0';
1486
1487 for (i = 0; flags != 0; i++) {
1488 bit = bd[i].bit;
1489 name = bd[i].name;
1490 if (bit == 0 && flags != 0) {
1491 /* print any unnamed bits */
1492 snprintf(hexstr, 16, "0x%X", flags);
1493 name = hexstr;
1494 flags = 0; /* exit loop */
1495 } else if ((flags & bit) == 0)
1496 continue;
1497 flags &= ~bit;
1498 nlen = strlen(name);
1499 slen += nlen;
1500 /* count btwn flag space */
1501 if (flags != 0)
1502 slen += 1;
1503 /* need NULL char as well */
1504 if (len <= slen)
1505 break;
1506 /* copy NULL char but don't count it */
1507 strncpy(p, name, nlen + 1);
1508 p += nlen;
1509 /* copy btwn flag space and NULL char */
1510 if (flags != 0)
1511 p += snprintf(p, 2, " ");
1512 len -= slen;
1513 }
1514
1515 /* indicate the str was too short */
1516 if (flags != 0) {
1517 if (len < 2)
1518 p -= 2 - len; /* overwrite last char */
1519 p += snprintf(p, 2, ">");
1520 }
1521
1522 return (int)(p - buf);
1523}
1524#endif
1525
1526#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1527 defined(DHD_DEBUG) || defined(WLMEDIA_PEAKRATE)
1528/* print bytes formatted as hex to a string. return the resulting string length */
1529int
1530bcm_format_hex(char *str, const void *bytes, int len)
1531{
1532 int i;
1533 char *p = str;
1534 const uint8 *src = (const uint8*)bytes;
1535
1536 for (i = 0; i < len; i++) {
1537 p += snprintf(p, 3, "%02X", *src);
1538 src++;
1539 }
1540 return (int)(p - str);
1541}
1542#endif
1543
1544/* pretty hex print a contiguous buffer */
1545void
1546prhex(const char *msg, uchar *buf, uint nbytes)
1547{
1548 char line[128], *p;
1549 int len = sizeof(line);
1550 int nchar;
1551 uint i;
1552
1553 if (msg && (msg[0] != '\0'))
1554 printf("%s:\n", msg);
1555
1556 p = line;
1557 for (i = 0; i < nbytes; i++) {
1558 if (i % 16 == 0) {
1559 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
1560 p += nchar;
1561 len -= nchar;
1562 }
1563 if (len > 0) {
1564 nchar = snprintf(p, len, "%02x ", buf[i]);
1565 p += nchar;
1566 len -= nchar;
1567 }
1568
1569 if (i % 16 == 15) {
1570 printf("%s\n", line); /* flush line */
1571 p = line;
1572 len = sizeof(line);
1573 }
1574 }
1575
1576 /* flush last partial line */
1577 if (p != line)
1578 printf("%s\n", line);
1579}
1580
1581static const char *crypto_algo_names[] = {
1582 "NONE",
1583 "WEP1",
1584 "TKIP",
1585 "WEP128",
1586 "AES_CCM",
1587 "AES_OCB_MSDU",
1588 "AES_OCB_MPDU",
1589 "NALG"
1590 "UNDEF",
1591 "UNDEF",
1592 "UNDEF",
1593 "UNDEF"
1594};
1595
1596const char *
1597bcm_crypto_algo_name(uint algo)
1598{
1599 return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
1600}
1601
1602
1603char *
1604bcm_chipname(uint chipid, char *buf, uint len)
1605{
1606 const char *fmt;
1607
1608 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
1609 snprintf(buf, len, fmt, chipid);
1610 return buf;
1611}
1612
1613/* Produce a human-readable string for boardrev */
1614char *
1615bcm_brev_str(uint32 brev, char *buf)
1616{
1617 if (brev < 0x100)
1618 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1619 else
1620 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
1621
1622 return (buf);
1623}
1624
1625#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1626
1627/* dump large strings to console */
1628void
1629printbig(char *buf)
1630{
1631 uint len, max_len;
1632 char c;
1633
1634 len = strlen(buf);
1635
1636 max_len = BUFSIZE_TODUMP_ATONCE;
1637
1638 while (len > max_len) {
1639 c = buf[max_len];
1640 buf[max_len] = '\0';
1641 printf("%s", buf);
1642 buf[max_len] = c;
1643
1644 buf += max_len;
1645 len -= max_len;
1646 }
1647 /* print the remaining string */
1648 printf("%s\n", buf);
1649 return;
1650}
1651
1652/* routine to dump fields in a fileddesc structure */
1653uint
1654bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
1655 char *buf, uint32 bufsize)
1656{
1657 uint filled_len;
1658 int len;
1659 struct fielddesc *cur_ptr;
1660
1661 filled_len = 0;
1662 cur_ptr = fielddesc_array;
1663
1664 while (bufsize > 1) {
1665 if (cur_ptr->nameandfmt == NULL)
1666 break;
1667 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
1668 read_rtn(arg0, arg1, cur_ptr->offset));
1669 /* check for snprintf overflow or error */
1670 if (len < 0 || (uint32)len >= bufsize)
1671 len = bufsize - 1;
1672 buf += len;
1673 bufsize -= len;
1674 filled_len += len;
1675 cur_ptr++;
1676 }
1677 return filled_len;
1678}
1679
1680uint
1681bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1682{
1683 uint len;
1684
1685 len = strlen(name) + 1;
1686
1687 if ((len + datalen) > buflen)
1688 return 0;
1689
1690 strncpy(buf, name, buflen);
1691
1692 /* append data onto the end of the name string */
1693 memcpy(&buf[len], data, datalen);
1694 len += datalen;
1695
1696 return len;
1697}
1698
1699/* Quarter dBm units to mW
1700 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1701 * Table is offset so the last entry is largest mW value that fits in
1702 * a uint16.
1703 */
1704
1705#define QDBM_OFFSET 153 /* Offset for first entry */
1706#define QDBM_TABLE_LEN 40 /* Table size */
1707
1708/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1709 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1710 */
1711#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1712
1713/* Largest mW value that will round down to the last table entry,
1714 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1715 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1716 */
1717#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1718
1719static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1720/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1721/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1722/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1723/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1724/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1725/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1726};
1727
1728uint16
1729bcm_qdbm_to_mw(uint8 qdbm)
1730{
1731 uint factor = 1;
1732 int idx = qdbm - QDBM_OFFSET;
1733
1734 if (idx >= QDBM_TABLE_LEN) {
1735 /* clamp to max uint16 mW value */
1736 return 0xFFFF;
1737 }
1738
1739 /* scale the qdBm index up to the range of the table 0-40
1740 * where an offset of 40 qdBm equals a factor of 10 mW.
1741 */
1742 while (idx < 0) {
1743 idx += 40;
1744 factor *= 10;
1745 }
1746
1747 /* return the mW value scaled down to the correct factor of 10,
1748 * adding in factor/2 to get proper rounding.
1749 */
1750 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
1751}
1752
1753uint8
1754bcm_mw_to_qdbm(uint16 mw)
1755{
1756 uint8 qdbm;
1757 int offset;
1758 uint mw_uint = mw;
1759 uint boundary;
1760
1761 /* handle boundary case */
1762 if (mw_uint <= 1)
1763 return 0;
1764
1765 offset = QDBM_OFFSET;
1766
1767 /* move mw into the range of the table */
1768 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1769 mw_uint *= 10;
1770 offset -= 40;
1771 }
1772
1773 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
1774 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
1775 nqdBm_to_mW_map[qdbm])/2;
1776 if (mw_uint < boundary)
1777 break;
1778 }
1779
1780 qdbm += (uint8)offset;
1781
1782 return (qdbm);
1783}
1784
1785
1786uint
1787bcm_bitcount(uint8 *bitmap, uint length)
1788{
1789 uint bitcount = 0, i;
1790 uint8 tmp;
1791 for (i = 0; i < length; i++) {
1792 tmp = bitmap[i];
1793 while (tmp) {
1794 bitcount++;
1795 tmp &= (tmp - 1);
1796 }
1797 }
1798 return bitcount;
1799}
1800
1801#ifdef BCMDRIVER
1802
1803/* Initialization of bcmstrbuf structure */
1804void
1805bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1806{
1807 b->origsize = b->size = size;
1808 b->origbuf = b->buf = buf;
1809}
1810
1811/* Buffer sprintf wrapper to guard against buffer overflow */
1812int
1813bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1814{
1815 va_list ap;
1816 int r;
1817
1818 va_start(ap, fmt);
1819 r = vsnprintf(b->buf, b->size, fmt, ap);
1820
1821 /* Non Ansi C99 compliant returns -1,
1822 * Ansi compliant return r >= b->size,
1823 * bcmstdlib returns 0, handle all
1824 */
1825 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1826 b->size = 0;
1827 } else {
1828 b->size -= r;
1829 b->buf += r;
1830 }
1831
1832 va_end(ap);
1833
1834 return r;
1835}
1836
1837void
1838bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
1839{
1840 int i;
1841
1842 for (i = 0; i < num_bytes; i++) {
1843 num[i] += amount;
1844 if (num[i] >= amount)
1845 break;
1846 amount = 1;
1847 }
1848}
1849
1850int
1851bcm_cmp_bytes(uchar *arg1, uchar *arg2, uint8 nbytes)
1852{
1853 int i;
1854
1855 for (i = nbytes - 1; i >= 0; i--) {
1856 if (arg1[i] != arg2[i])
1857 return (arg1[i] - arg2[i]);
1858 }
1859 return 0;
1860}
1861
1862void
1863bcm_print_bytes(char *name, const uchar *data, int len)
1864{
1865 int i;
1866 int per_line = 0;
1867
1868 printf("%s: %d \n", name ? name : "", len);
1869 for (i = 0; i < len; i++) {
1870 printf("%02x ", *data++);
1871 per_line++;
1872 if (per_line == 16) {
1873 per_line = 0;
1874 printf("\n");
1875 }
1876 }
1877 printf("\n");
1878}
1879#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
1880 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
1881#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
1882
1883int
1884bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
1885{
1886 uint i, c;
1887 char *p = buf;
1888 char *endp = buf + SSID_FMT_BUF_LEN;
1889
1890 if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
1891
1892 for (i = 0; i < ssid_len; i++) {
1893 c = (uint)ssid[i];
1894 if (c == '\\') {
1895 *p++ = '\\';
1896 *p++ = '\\';
1897 } else if (bcm_isprint((uchar)c)) {
1898 *p++ = (char)c;
1899 } else {
1900 p += snprintf(p, (endp - p), "\\x%02X", c);
1901 }
1902 }
1903 *p = '\0';
1904 ASSERT(p < endp);
1905
1906 return (int)(p - buf);
1907}
1908#endif
1909
1910#endif /* BCMDRIVER */
1911
1912/*
1913 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
1914 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
1915 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
1916 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
1917*/
1918
1919unsigned int
1920process_nvram_vars(char *varbuf, unsigned int len)
1921{
1922 char *dp;
1923 bool findNewline;
1924 int column;
1925 unsigned int buf_len, n;
1926 unsigned int pad = 0;
1927
1928 dp = varbuf;
1929
1930 findNewline = FALSE;
1931 column = 0;
1932
1933 for (n = 0; n < len; n++) {
1934 if (varbuf[n] == '\r')
1935 continue;
1936 if (findNewline && varbuf[n] != '\n')
1937 continue;
1938 findNewline = FALSE;
1939 if (varbuf[n] == '#') {
1940 findNewline = TRUE;
1941 continue;
1942 }
1943 if (varbuf[n] == '\n') {
1944 if (column == 0)
1945 continue;
1946 *dp++ = 0;
1947 column = 0;
1948 continue;
1949 }
1950 *dp++ = varbuf[n];
1951 column++;
1952 }
1953 buf_len = (unsigned int)(dp - varbuf);
1954 if (buf_len % 4) {
1955 pad = 4 - buf_len % 4;
1956 if (pad && (buf_len + pad <= len)) {
1957 buf_len += pad;
1958 }
1959 }
1960
1961 while (dp < varbuf + n)
1962 *dp++ = 0;
1963
1964 return buf_len;
1965}