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