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