1/*
2 * Driver O/S-independent utility routines
3 *
4 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved.
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 * $Id: bcmutils.c 401759 2013-05-13 16:08:08Z $
18 */
19
20#include <bcm_cfg.h>
21#include <typedefs.h>
22#include <bcmdefs.h>
23#if defined(__FreeBSD__) || defined(__NetBSD__)
24#include <sys/param.h>
25#if __NetBSD_Version__ >= 500000003
26#include <sys/stdarg.h>
27#else
28#include <machine/stdarg.h>
29#endif
30#else
31#include <stdarg.h>
32#endif /* NetBSD */
33#ifdef BCMDRIVER
34
35#include <osl.h>
36#include <bcmutils.h>
37#include <siutils.h>
38#include <bcmnvram.h>
39
40#else /* !BCMDRIVER */
41
42#include <stdio.h>
43#include <string.h>
44#include <bcmutils.h>
45
46#if defined(BCMEXTSUP)
47#include <bcm_osl.h>
48#endif
49
50
51#endif /* !BCMDRIVER */
52
53#if defined(_WIN32) || defined(NDIS) || defined(__vxworks) || defined(_CFE_)
54#include <bcmstdlib.h>
55#endif
56#include <bcmendian.h>
57#include <bcmdevs.h>
58#include <proto/ethernet.h>
59#include <proto/vlan.h>
60#include <proto/bcmip.h>
61#include <proto/802.1d.h>
62#include <proto/802.11.h>
63#ifdef BCMPERFSTATS
64#include <bcmperf.h>
65#endif
66#include <proto/bcmipv6.h>
67void *_bcmutils_dummy_fn = NULL;
68
69#ifdef BCMDRIVER
70
71#ifdef WLC_LOW
72/* nvram vars cache */
73static char *nvram_vars = NULL;
74static int vars_len = -1;
75#endif /* WLC_LOW */
76
77int
78BCMATTACHFN(pktpool_init)(osl_t *osh, pktpool_t *pktp, int *pplen, int plen, bool istx)
79{
80	int i, err = BCME_OK;
81	void *p;
82	int pktplen;
83
84	ASSERT(pktp != NULL);
85	ASSERT(osh != NULL);
86	ASSERT(pplen != NULL);
87
88	pktplen = *pplen;
89
90	bzero(pktp, sizeof(pktpool_t));
91	pktp->inited = TRUE;
92	pktp->istx = istx ? TRUE : FALSE;
93	pktp->plen = (uint16)plen;
94	*pplen = 0;
95
96	pktp->maxlen = PKTPOOL_LEN_MAX;
97	if (pktplen > pktp->maxlen)
98		pktplen = pktp->maxlen;
99
100	for (i = 0; i < pktplen; i++) {
101		p = PKTGET(osh, plen, pktp->istx);
102		if (p == NULL) {
103			/* Not able to allocate all requested pkts
104			 * so just return what was actually allocated
105			 * We can add to the pool later
106			 */
107			if (pktp->w == 0)
108				err = BCME_NOMEM;
109
110			goto exit;
111		}
112
113		PKTSETPOOL(osh, p, TRUE, pktp);
114		pktp->q[i] = p;
115		pktp->w++;
116		pktp->len++;
117#ifdef BCMDBG_POOL
118		pktp->dbg_q[pktp->dbg_qlen++].p = p;
119#endif
120	}
121
122exit:
123	*pplen = pktp->w;
124	pktp->len++; /* Add one for end */
125	return err;
126}
127
128int
129BCMATTACHFN(pktpool_deinit)(osl_t *osh, pktpool_t *pktp)
130{
131	int i;
132	int cnt;
133
134	ASSERT(osh != NULL);
135	ASSERT(pktp != NULL);
136
137	cnt = pktp->len;
138	for (i = 0; i < cnt; i++) {
139		if (pktp->q[i] != NULL) {
140			PKTSETPOOL(osh, pktp->q[i], FALSE, NULL);
141			PKTFREE(osh, pktp->q[i], pktp->istx);
142			pktp->q[i] = NULL;
143			pktp->len--;
144		}
145#ifdef BCMDBG_POOL
146		if (pktp->dbg_q[i].p != NULL)
147			pktp->dbg_q[i].p = NULL;
148#endif
149	}
150	pktp->inited = FALSE;
151
152	/* Are there still pending pkts? */
153	ASSERT(pktpool_len(pktp) == 0);
154
155	return 0;
156}
157
158int
159pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal)
160{
161	void *p;
162	int err = 0;
163	int len, psize, maxlen;
164
165	ASSERT(pktpool_plen(pktp) != 0);
166
167	maxlen = pktpool_maxlen(pktp);
168	psize = minimal ? (maxlen >> 2) : maxlen;
169	len = pktpool_len(pktp);
170	for (; len < psize; len++) {
171		p = PKTGET(osh, pktpool_plen(pktp), FALSE);
172		if (p == NULL) {
173			err = BCME_NOMEM;
174			break;
175		}
176
177		if (pktpool_add(pktp, p) != BCME_OK) {
178			PKTFREE(osh, p, FALSE);
179			err = BCME_ERROR;
180			break;
181		}
182	}
183
184	return err;
185}
186
187uint16
188pktpool_avail(pktpool_t *pktp)
189{
190	if (pktp->w == pktp->r)
191		return 0;
192
193	return (pktp->w > pktp->r) ? (pktp->w - pktp->r) : ((pktp->len) - (pktp->r - pktp->w));
194}
195
196static void *
197pktpool_deq(pktpool_t *pktp)
198{
199	void *p;
200
201	if (pktp->r == pktp->w)
202		return NULL;
203
204	p = pktp->q[pktp->r];
205	ASSERT(p != NULL);
206
207	pktp->q[pktp->r++] = NULL;
208	pktp->r %= (pktp->len);
209
210	return p;
211}
212
213static void
214pktpool_enq(pktpool_t *pktp, void *p)
215{
216	uint16 next;
217
218	ASSERT(p != NULL);
219
220	next = (pktp->w + 1) % (pktp->len);
221	if (next == pktp->r) {
222	/* Should not happen; otherwise pkt leak */
223		ASSERT(0);
224		return;
225	}
226
227	ASSERT(pktp->q[pktp->w] == NULL);
228
229#ifdef BCMDBG_ASSERT
230	if (pktpool_avail(pktp)) {
231		int prev = (pktp->w == 0) ? (pktp->len - 1) : (pktp->w - 1);
232		ASSERT(pktp->q[prev] != p);
233	}
234#endif
235	pktp->q[pktp->w] = p;
236	pktp->w = next;
237}
238
239int
240BCMATTACHFN(pktpool_avail_register)(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
241{
242	int i;
243
244	ASSERT(cb != NULL);
245
246	i = pktp->cbcnt;
247	if (i == PKTPOOL_CB_MAX)
248		return BCME_ERROR;
249
250	ASSERT(pktp->cbs[i].cb == NULL);
251	pktp->cbs[i].cb = cb;
252	pktp->cbs[i].arg = arg;
253	pktp->cbcnt++;
254
255	return 0;
256}
257
258int
259BCMATTACHFN(pktpool_empty_register)(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
260{
261	int i;
262
263	ASSERT(cb != NULL);
264
265	i = pktp->ecbcnt;
266	if (i == PKTPOOL_CB_MAX)
267		return BCME_ERROR;
268
269	ASSERT(pktp->ecbs[i].cb == NULL);
270	pktp->ecbs[i].cb = cb;
271	pktp->ecbs[i].arg = arg;
272	pktp->ecbcnt++;
273
274	return 0;
275}
276
277static int
278pktpool_empty_notify(pktpool_t *pktp)
279{
280	int i;
281
282	pktp->empty = TRUE;
283	for (i = 0; i < pktp->ecbcnt; i++) {
284		ASSERT(pktp->ecbs[i].cb != NULL);
285		pktp->ecbs[i].cb(pktp, pktp->ecbs[i].arg);
286	}
287	pktp->empty = FALSE;
288
289	return 0;
290}
291
292#ifdef BCMDBG_POOL
293int
294pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
295{
296	int i;
297
298	ASSERT(cb);
299
300	i = pktp->dbg_cbcnt;
301	if (i == PKTPOOL_CB_MAX)
302		return BCME_ERROR;
303
304	ASSERT(pktp->dbg_cbs[i].cb == NULL);
305	pktp->dbg_cbs[i].cb = cb;
306	pktp->dbg_cbs[i].arg = arg;
307	pktp->dbg_cbcnt++;
308
309	return 0;
310}
311
312int pktpool_dbg_notify(pktpool_t *pktp);
313
314int
315pktpool_dbg_notify(pktpool_t *pktp)
316{
317	int i;
318
319	for (i = 0; i < pktp->dbg_cbcnt; i++) {
320		ASSERT(pktp->dbg_cbs[i].cb);
321		pktp->dbg_cbs[i].cb(pktp, pktp->dbg_cbs[i].arg);
322	}
323
324	return 0;
325}
326
327int
328pktpool_dbg_dump(pktpool_t *pktp)
329{
330	int i;
331
332	printf("pool len=%d maxlen=%d\n",  pktp->dbg_qlen, pktp->maxlen);
333	for (i = 0; i < pktp->dbg_qlen; i++) {
334		ASSERT(pktp->dbg_q[i].p);
335		printf("%d, p: 0x%x dur:%lu us state:%d\n", i,
336			pktp->dbg_q[i].p, pktp->dbg_q[i].dur/100, PKTPOOLSTATE(pktp->dbg_q[i].p));
337	}
338
339	return 0;
340}
341
342int
343pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats)
344{
345	int i;
346	int state;
347
348	bzero(stats, sizeof(pktpool_stats_t));
349	for (i = 0; i < pktp->dbg_qlen; i++) {
350		ASSERT(pktp->dbg_q[i].p != NULL);
351
352		state = PKTPOOLSTATE(pktp->dbg_q[i].p);
353		switch (state) {
354			case POOL_TXENQ:
355				stats->enq++; break;
356			case POOL_TXDH:
357				stats->txdh++; break;
358			case POOL_TXD11:
359				stats->txd11++; break;
360			case POOL_RXDH:
361				stats->rxdh++; break;
362			case POOL_RXD11:
363				stats->rxd11++; break;
364			case POOL_RXFILL:
365				stats->rxfill++; break;
366			case POOL_IDLE:
367				stats->idle++; break;
368		}
369	}
370
371	return 0;
372}
373
374int
375pktpool_start_trigger(pktpool_t *pktp, void *p)
376{
377	uint32 cycles, i;
378
379	if (!PKTPOOL(NULL, p))
380		return 0;
381
382	OSL_GETCYCLES(cycles);
383
384	for (i = 0; i < pktp->dbg_qlen; i++) {
385		ASSERT(pktp->dbg_q[i].p != NULL);
386
387		if (pktp->dbg_q[i].p == p) {
388			pktp->dbg_q[i].cycles = cycles;
389			break;
390		}
391	}
392
393	return 0;
394}
395
396int pktpool_stop_trigger(pktpool_t *pktp, void *p);
397int
398pktpool_stop_trigger(pktpool_t *pktp, void *p)
399{
400	uint32 cycles, i;
401
402	if (!PKTPOOL(NULL, p))
403		return 0;
404
405	OSL_GETCYCLES(cycles);
406
407	for (i = 0; i < pktp->dbg_qlen; i++) {
408		ASSERT(pktp->dbg_q[i].p != NULL);
409
410		if (pktp->dbg_q[i].p == p) {
411			if (pktp->dbg_q[i].cycles == 0)
412				break;
413
414			if (cycles >= pktp->dbg_q[i].cycles)
415				pktp->dbg_q[i].dur = cycles - pktp->dbg_q[i].cycles;
416			else
417				pktp->dbg_q[i].dur =
418					(((uint32)-1) - pktp->dbg_q[i].cycles) + cycles + 1;
419
420			pktp->dbg_q[i].cycles = 0;
421			break;
422		}
423	}
424
425	return 0;
426}
427#endif /* BCMDBG_POOL */
428
429int
430pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp)
431{
432	ASSERT(pktp);
433	pktp->availcb_excl = NULL;
434	return 0;
435}
436
437int
438pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb)
439{
440	int i;
441
442	ASSERT(pktp);
443	ASSERT(pktp->availcb_excl == NULL);
444	for (i = 0; i < pktp->cbcnt; i++) {
445		if (cb == pktp->cbs[i].cb) {
446			pktp->availcb_excl = &pktp->cbs[i];
447			break;
448		}
449	}
450
451	if (pktp->availcb_excl == NULL)
452		return BCME_ERROR;
453	else
454		return 0;
455}
456
457static int
458pktpool_avail_notify(pktpool_t *pktp)
459{
460	int i, k, idx;
461	int avail;
462
463	ASSERT(pktp);
464	if (pktp->availcb_excl != NULL) {
465		pktp->availcb_excl->cb(pktp, pktp->availcb_excl->arg);
466		return 0;
467	}
468
469	k = pktp->cbcnt - 1;
470	for (i = 0; i < pktp->cbcnt; i++) {
471		avail = pktpool_avail(pktp);
472
473		if (avail) {
474			if (pktp->cbtoggle)
475				idx = i;
476			else
477				idx = k--;
478
479			ASSERT(pktp->cbs[idx].cb != NULL);
480			pktp->cbs[idx].cb(pktp, pktp->cbs[idx].arg);
481		}
482	}
483
484	/* Alternate between filling from head or tail
485	 */
486	pktp->cbtoggle ^= 1;
487
488	return 0;
489}
490
491void *
492pktpool_get(pktpool_t *pktp)
493{
494	void *p;
495
496	p = pktpool_deq(pktp);
497
498	if (p == NULL) {
499		/* Notify and try to reclaim tx pkts */
500		if (pktp->ecbcnt)
501			pktpool_empty_notify(pktp);
502
503		p = pktpool_deq(pktp);
504	}
505
506	return p;
507}
508
509void
510pktpool_free(pktpool_t *pktp, void *p)
511{
512	ASSERT(p != NULL);
513
514#ifdef BCMDBG_POOL
515	/* pktpool_stop_trigger(pktp, p); */
516#endif
517
518	pktpool_enq(pktp, p);
519
520	if (pktp->emptycb_disable)
521		return;
522
523	if (pktp->cbcnt) {
524		if (pktp->empty == FALSE)
525			pktpool_avail_notify(pktp);
526	}
527}
528
529int
530pktpool_add(pktpool_t *pktp, void *p)
531{
532	ASSERT(p != NULL);
533
534	if (pktpool_len(pktp) == pktp->maxlen)
535		return BCME_RANGE;
536
537	ASSERT(pktpool_plen(pktp) == PKTLEN(NULL, p)); /* pkts in pool have same length */
538	PKTSETPOOL(NULL, p, TRUE, pktp);
539
540	pktp->len++;
541	if (pktp->r > pktp->w) {
542		/* Add to tail */
543		ASSERT(pktp->q[pktp->len - 1] == NULL);
544		pktp->q[pktp->len - 1] = p;
545	} else
546		pktpool_enq(pktp, p);
547
548#ifdef BCMDBG_POOL
549	pktp->dbg_q[pktp->dbg_qlen++].p = p;
550#endif
551
552	return 0;
553}
554
555int
556pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen)
557{
558	if (maxlen > PKTPOOL_LEN_MAX)
559		maxlen = PKTPOOL_LEN_MAX;
560
561	/* if pool is already beyond maxlen, then just cap it
562	 * since we currently do not reduce the pool len
563	 * already allocated
564	 */
565	pktp->maxlen = (pktpool_len(pktp) > maxlen) ? pktpool_len(pktp) : maxlen;
566
567	return pktp->maxlen;
568}
569
570void
571pktpool_emptycb_disable(pktpool_t *pktp, bool disable)
572{
573	ASSERT(pktp);
574
575	pktp->emptycb_disable = disable;
576}
577
578bool
579pktpool_emptycb_disabled(pktpool_t *pktp)
580{
581	ASSERT(pktp);
582	return pktp->emptycb_disable;
583}
584
585/* copy a pkt buffer chain into a buffer */
586uint
587pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
588{
589	uint n, ret = 0;
590
591	if (len < 0)
592		len = 4096;	/* "infinite" */
593
594	/* skip 'offset' bytes */
595	for (; p && offset; p = PKTNEXT(osh, p)) {
596		if (offset < (uint)PKTLEN(osh, p))
597			break;
598		offset -= PKTLEN(osh, p);
599	}
600
601	if (!p)
602		return 0;
603
604	/* copy the data */
605	for (; p && len; p = PKTNEXT(osh, p)) {
606		n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
607		bcopy(PKTDATA(osh, p) + offset, buf, n);
608		buf += n;
609		len -= n;
610		ret += n;
611		offset = 0;
612	}
613
614	return ret;
615}
616
617/* copy a buffer into a pkt buffer chain */
618uint
619pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
620{
621	uint n, ret = 0;
622
623	/* skip 'offset' bytes */
624	for (; p && offset; p = PKTNEXT(osh, p)) {
625		if (offset < (uint)PKTLEN(osh, p))
626			break;
627		offset -= PKTLEN(osh, p);
628	}
629
630	if (!p)
631		return 0;
632
633	/* copy the data */
634	for (; p && len; p = PKTNEXT(osh, p)) {
635		n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
636		bcopy(buf, PKTDATA(osh, p) + offset, n);
637		buf += n;
638		len -= n;
639		ret += n;
640		offset = 0;
641	}
642
643	return ret;
644}
645
646#ifdef NOTYET
647/* copy data from one pkt buffer (chain) to another */
648uint
649pkt2pktcopy(osl_t *osh, void *p1, uint offs1, void *p2, uint offs2, int maxlen)
650{
651	uint8 *dp1, *dp2;
652	uint len1, len2, copylen, totallen;
653
654	for (; p1 && offs; p1 = PKTNEXT(osh, p1)) {
655		if (offs1 < (uint)PKTLEN(osh, p1))
656			break;
657		offs1 -= PKTLEN(osh, p1);
658	}
659	for (; p2 && offs; p2 = PKTNEXT(osh, p2)) {
660		if (offs2 < (uint)PKTLEN(osh, p2))
661			break;
662		offs2 -= PKTLEN(osh, p2);
663	}
664
665	/* Heck w/it, only need the above for now */
666}
667#endif /* NOTYET */
668
669
670/* return total length of buffer chain */
671uint BCMFASTPATH
672pkttotlen(osl_t *osh, void *p)
673{
674	uint total;
675	int len;
676
677	total = 0;
678	for (; p; p = PKTNEXT(osh, p)) {
679		len = PKTLEN(osh, p);
680#ifdef MACOSX
681		if (len < 0) {
682			/* Bad packet length, just drop and exit */
683			printf("wl: pkttotlen bad (%p,%d)\n", p, len);
684			break;
685		}
686#endif /* MACOSX */
687		total += len;
688	}
689
690	return (total);
691}
692
693/* return the last buffer of chained pkt */
694void *
695pktlast(osl_t *osh, void *p)
696{
697	for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
698		;
699
700	return (p);
701}
702
703/* count segments of a chained packet */
704uint BCMFASTPATH
705pktsegcnt(osl_t *osh, void *p)
706{
707	uint cnt;
708
709	for (cnt = 0; p; p = PKTNEXT(osh, p))
710		cnt++;
711
712	return cnt;
713}
714
715
716/* count segments of a chained packet */
717uint BCMFASTPATH
718pktsegcnt_war(osl_t *osh, void *p)
719{
720	uint cnt;
721	uint8 *pktdata;
722	uint len, remain, align64;
723
724	for (cnt = 0; p; p = PKTNEXT(osh, p)) {
725		cnt++;
726		len = PKTLEN(osh, p);
727		if (len > 128) {
728			pktdata = (uint8 *)PKTDATA(osh, p);	/* starting address of data */
729			/* Check for page boundary straddle (2048B) */
730			if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff))
731				cnt++;
732
733			align64 = (uint)((uintptr)pktdata & 0x3f);	/* aligned to 64B */
734			align64 = (64 - align64) & 0x3f;
735			len -= align64;		/* bytes from aligned 64B to end */
736			/* if aligned to 128B, check for MOD 128 between 1 to 4B */
737			remain = len % 128;
738			if (remain > 0 && remain <= 4)
739				cnt++;		/* add extra seg */
740		}
741	}
742
743	return cnt;
744}
745
746uint8 * BCMFASTPATH
747pktdataoffset(osl_t *osh, void *p,  uint offset)
748{
749	uint total = pkttotlen(osh, p);
750	uint pkt_off = 0, len = 0;
751	uint8 *pdata = (uint8 *) PKTDATA(osh, p);
752
753	if (offset > total)
754		return NULL;
755
756	for (; p; p = PKTNEXT(osh, p)) {
757		pdata = (uint8 *) PKTDATA(osh, p);
758		pkt_off = offset - len;
759		len += PKTLEN(osh, p);
760		if (len > offset)
761			break;
762	}
763	return (uint8*) (pdata+pkt_off);
764}
765
766
767/* given a offset in pdata, find the pkt seg hdr */
768void *
769pktoffset(osl_t *osh, void *p,  uint offset)
770{
771	uint total = pkttotlen(osh, p);
772	uint len = 0;
773
774	if (offset > total)
775		return NULL;
776
777	for (; p; p = PKTNEXT(osh, p)) {
778		len += PKTLEN(osh, p);
779		if (len > offset)
780			break;
781	}
782	return p;
783}
784
785/*
786 * osl multiple-precedence packet queue
787 * hi_prec is always >= the number of the highest non-empty precedence
788 */
789void * BCMFASTPATH
790pktq_penq(struct pktq *pq, int prec, void *p)
791{
792	struct pktq_prec *q;
793
794	ASSERT(prec >= 0 && prec < pq->num_prec);
795	ASSERT(PKTLINK(p) == NULL);         /* queueing chains not allowed */
796
797	ASSERT(!pktq_full(pq));
798	ASSERT(!pktq_pfull(pq, prec));
799
800	q = &pq->q[prec];
801
802	if (q->head)
803		PKTSETLINK(q->tail, p);
804	else
805		q->head = p;
806
807	q->tail = p;
808	q->len++;
809
810	pq->len++;
811
812	if (pq->hi_prec < prec)
813		pq->hi_prec = (uint8)prec;
814
815	return p;
816}
817
818void * BCMFASTPATH
819pktq_penq_head(struct pktq *pq, int prec, void *p)
820{
821	struct pktq_prec *q;
822
823	ASSERT(prec >= 0 && prec < pq->num_prec);
824	ASSERT(PKTLINK(p) == NULL);         /* queueing chains not allowed */
825
826	ASSERT(!pktq_full(pq));
827	ASSERT(!pktq_pfull(pq, prec));
828
829	q = &pq->q[prec];
830
831	if (q->head == NULL)
832		q->tail = p;
833
834	PKTSETLINK(p, q->head);
835	q->head = p;
836	q->len++;
837
838	pq->len++;
839
840	if (pq->hi_prec < prec)
841		pq->hi_prec = (uint8)prec;
842
843	return p;
844}
845
846void * BCMFASTPATH
847pktq_pdeq(struct pktq *pq, int prec)
848{
849	struct pktq_prec *q;
850	void *p;
851
852	ASSERT(prec >= 0 && prec < pq->num_prec);
853
854	q = &pq->q[prec];
855
856	if ((p = q->head) == NULL)
857		return NULL;
858
859	if ((q->head = PKTLINK(p)) == NULL)
860		q->tail = NULL;
861
862	q->len--;
863
864	pq->len--;
865
866	PKTSETLINK(p, NULL);
867
868	return p;
869}
870
871void * BCMFASTPATH
872pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p)
873{
874	struct pktq_prec *q;
875	void *p;
876
877	ASSERT(prec >= 0 && prec < pq->num_prec);
878
879	q = &pq->q[prec];
880
881	if (prev_p == NULL)
882		return NULL;
883
884	if ((p = PKTLINK(prev_p)) == NULL)
885		return NULL;
886
887	if (q->tail == p)
888		q->tail = prev_p;
889
890	q->len--;
891
892	pq->len--;
893
894	PKTSETLINK(prev_p, PKTLINK(p));
895	PKTSETLINK(p, NULL);
896
897	return p;
898}
899
900void * BCMFASTPATH
901pktq_pdeq_tail(struct pktq *pq, int prec)
902{
903	struct pktq_prec *q;
904	void *p, *prev;
905
906	ASSERT(prec >= 0 && prec < pq->num_prec);
907
908	q = &pq->q[prec];
909
910	if ((p = q->head) == NULL)
911		return NULL;
912
913	for (prev = NULL; p != q->tail; p = PKTLINK(p))
914		prev = p;
915
916	if (prev)
917		PKTSETLINK(prev, NULL);
918	else
919		q->head = NULL;
920
921	q->tail = prev;
922	q->len--;
923
924	pq->len--;
925
926	return p;
927}
928
929void
930pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg)
931{
932	struct pktq_prec *q;
933	void *p, *prev = NULL;
934
935	q = &pq->q[prec];
936	p = q->head;
937	while (p) {
938		if (fn == NULL || (*fn)(p, arg)) {
939			bool head = (p == q->head);
940			if (head)
941				q->head = PKTLINK(p);
942			else
943				PKTSETLINK(prev, PKTLINK(p));
944			PKTSETLINK(p, NULL);
945			PKTFREE(osh, p, dir);
946			q->len--;
947			pq->len--;
948			p = (head ? q->head : PKTLINK(prev));
949		} else {
950			prev = p;
951			p = PKTLINK(p);
952		}
953	}
954
955	if (q->head == NULL) {
956		ASSERT(q->len == 0);
957		q->tail = NULL;
958	}
959}
960
961bool BCMFASTPATH
962pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
963{
964	struct pktq_prec *q;
965	void *p;
966
967	ASSERT(prec >= 0 && prec < pq->num_prec);
968
969	if (!pktbuf)
970		return FALSE;
971
972	q = &pq->q[prec];
973
974	if (q->head == pktbuf) {
975		if ((q->head = PKTLINK(pktbuf)) == NULL)
976			q->tail = NULL;
977	} else {
978		for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
979			;
980		if (p == NULL)
981			return FALSE;
982
983		PKTSETLINK(p, PKTLINK(pktbuf));
984		if (q->tail == pktbuf)
985			q->tail = p;
986	}
987
988	q->len--;
989	pq->len--;
990	PKTSETLINK(pktbuf, NULL);
991	return TRUE;
992}
993
994void
995pktq_init(struct pktq *pq, int num_prec, int max_len)
996{
997	int prec;
998
999	ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
1000
1001	/* pq is variable size; only zero out what's requested */
1002	bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
1003
1004	pq->num_prec = (uint16)num_prec;
1005
1006	pq->max = (uint16)max_len;
1007
1008	for (prec = 0; prec < num_prec; prec++)
1009		pq->q[prec].max = pq->max;
1010}
1011
1012void
1013pktq_set_max_plen(struct pktq *pq, int prec, int max_len)
1014{
1015	ASSERT(prec >= 0 && prec < pq->num_prec);
1016
1017	if (prec < pq->num_prec)
1018		pq->q[prec].max = (uint16)max_len;
1019}
1020
1021void * BCMFASTPATH
1022pktq_deq(struct pktq *pq, int *prec_out)
1023{
1024	struct pktq_prec *q;
1025	void *p;
1026	int prec;
1027
1028	if (pq->len == 0)
1029		return NULL;
1030
1031	while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1032		pq->hi_prec--;
1033
1034	q = &pq->q[prec];
1035
1036	if ((p = q->head) == NULL)
1037		return NULL;
1038
1039	if ((q->head = PKTLINK(p)) == NULL)
1040		q->tail = NULL;
1041
1042	q->len--;
1043
1044	pq->len--;
1045
1046	if (prec_out)
1047		*prec_out = prec;
1048
1049	PKTSETLINK(p, NULL);
1050
1051	return p;
1052}
1053
1054void * BCMFASTPATH
1055pktq_deq_tail(struct pktq *pq, int *prec_out)
1056{
1057	struct pktq_prec *q;
1058	void *p, *prev;
1059	int prec;
1060
1061	if (pq->len == 0)
1062		return NULL;
1063
1064	for (prec = 0; prec < pq->hi_prec; prec++)
1065		if (pq->q[prec].head)
1066			break;
1067
1068	q = &pq->q[prec];
1069
1070	if ((p = q->head) == NULL)
1071		return NULL;
1072
1073	for (prev = NULL; p != q->tail; p = PKTLINK(p))
1074		prev = p;
1075
1076	if (prev)
1077		PKTSETLINK(prev, NULL);
1078	else
1079		q->head = NULL;
1080
1081	q->tail = prev;
1082	q->len--;
1083
1084	pq->len--;
1085
1086	if (prec_out)
1087		*prec_out = prec;
1088
1089	PKTSETLINK(p, NULL);
1090
1091	return p;
1092}
1093
1094void *
1095pktq_peek(struct pktq *pq, int *prec_out)
1096{
1097	int prec;
1098
1099	if (pq->len == 0)
1100		return NULL;
1101
1102	while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1103		pq->hi_prec--;
1104
1105	if (prec_out)
1106		*prec_out = prec;
1107
1108	return (pq->q[prec].head);
1109}
1110
1111void *
1112pktq_peek_tail(struct pktq *pq, int *prec_out)
1113{
1114	int prec;
1115
1116	if (pq->len == 0)
1117		return NULL;
1118
1119	for (prec = 0; prec < pq->hi_prec; prec++)
1120		if (pq->q[prec].head)
1121			break;
1122
1123	if (prec_out)
1124		*prec_out = prec;
1125
1126	return (pq->q[prec].tail);
1127}
1128
1129void
1130pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
1131{
1132	int prec;
1133
1134	/* Optimize flush, if pktq len = 0, just return.
1135	 * pktq len of 0 means pktq's prec q's are all empty.
1136	 */
1137	if (pq->len == 0) {
1138		return;
1139	}
1140
1141	for (prec = 0; prec < pq->num_prec; prec++)
1142		pktq_pflush(osh, pq, prec, dir, fn, arg);
1143	if (fn == NULL)
1144		ASSERT(pq->len == 0);
1145}
1146
1147/* Return sum of lengths of a specific set of precedences */
1148int
1149pktq_mlen(struct pktq *pq, uint prec_bmp)
1150{
1151	int prec, len;
1152
1153	len = 0;
1154
1155	for (prec = 0; prec <= pq->hi_prec; prec++)
1156		if (prec_bmp & (1 << prec))
1157			len += pq->q[prec].len;
1158
1159	return len;
1160}
1161
1162/* Priority peek from a specific set of precedences */
1163void * BCMFASTPATH
1164pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out)
1165{
1166	struct pktq_prec *q;
1167	void *p;
1168	int prec;
1169
1170	if (pq->len == 0)
1171	{
1172		return NULL;
1173	}
1174	while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1175		pq->hi_prec--;
1176
1177	while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
1178		if (prec-- == 0)
1179			return NULL;
1180
1181	q = &pq->q[prec];
1182
1183	if ((p = q->head) == NULL)
1184		return NULL;
1185
1186	if (prec_out)
1187		*prec_out = prec;
1188
1189	return p;
1190}
1191/* Priority dequeue from a specific set of precedences */
1192void * BCMFASTPATH
1193pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
1194{
1195	struct pktq_prec *q;
1196	void *p;
1197	int prec;
1198
1199	if (pq->len == 0)
1200		return NULL;
1201
1202	while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
1203		pq->hi_prec--;
1204
1205	while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0))
1206		if (prec-- == 0)
1207			return NULL;
1208
1209	q = &pq->q[prec];
1210
1211	if ((p = q->head) == NULL)
1212		return NULL;
1213
1214	if ((q->head = PKTLINK(p)) == NULL)
1215		q->tail = NULL;
1216
1217	q->len--;
1218
1219	if (prec_out)
1220		*prec_out = prec;
1221
1222	pq->len--;
1223
1224	PKTSETLINK(p, NULL);
1225
1226	return p;
1227}
1228
1229#endif /* BCMDRIVER */
1230
1231#if defined(BCMROMBUILD)
1232const unsigned char BCMROMDATA(bcm_ctype)[] = {
1233#else
1234const unsigned char bcm_ctype[] = {
1235#endif
1236
1237	_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,			/* 0-7 */
1238	_BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
1239	_BCM_C,	/* 8-15 */
1240	_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,			/* 16-23 */
1241	_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,			/* 24-31 */
1242	_BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,		/* 32-39 */
1243	_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,			/* 40-47 */
1244	_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,			/* 48-55 */
1245	_BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,			/* 56-63 */
1246	_BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
1247	_BCM_U|_BCM_X, _BCM_U, /* 64-71 */
1248	_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,			/* 72-79 */
1249	_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,			/* 80-87 */
1250	_BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,			/* 88-95 */
1251	_BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
1252	_BCM_L|_BCM_X, _BCM_L, /* 96-103 */
1253	_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
1254	_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
1255	_BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
1256	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		/* 128-143 */
1257	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		/* 144-159 */
1258	_BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
1259	_BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,	/* 160-175 */
1260	_BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
1261	_BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,	/* 176-191 */
1262	_BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
1263	_BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,	/* 192-207 */
1264	_BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
1265	_BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L,	/* 208-223 */
1266	_BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
1267	_BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,	/* 224-239 */
1268	_BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
1269	_BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
1270};
1271
1272ulong
1273BCMROMFN(bcm_strtoul)(const char *cp, char **endp, uint base)
1274{
1275	ulong result, last_result = 0, value;
1276	bool minus;
1277
1278	minus = FALSE;
1279
1280	while (bcm_isspace(*cp))
1281		cp++;
1282
1283	if (cp[0] == '+')
1284		cp++;
1285	else if (cp[0] == '-') {
1286		minus = TRUE;
1287		cp++;
1288	}
1289
1290	if (base == 0) {
1291		if (cp[0] == '0') {
1292			if ((cp[1] == 'x') || (cp[1] == 'X')) {
1293				base = 16;
1294				cp = &cp[2];
1295			} else {
1296				base = 8;
1297				cp = &cp[1];
1298			}
1299		} else
1300			base = 10;
1301	} else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
1302		cp = &cp[2];
1303	}
1304
1305	result = 0;
1306
1307	while (bcm_isxdigit(*cp) &&
1308	       (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
1309		result = result*base + value;
1310		/* Detected overflow */
1311		if (result < last_result && !minus)
1312			return (ulong)-1;
1313		last_result = result;
1314		cp++;
1315	}
1316
1317	if (minus)
1318		result = (ulong)(-(long)result);
1319
1320	if (endp)
1321		*endp = DISCARD_QUAL(cp, char);
1322
1323	return (result);
1324}
1325
1326int
1327BCMROMFN(bcm_atoi)(const char *s)
1328{
1329	return (int)bcm_strtoul(s, NULL, 10);
1330}
1331
1332/* return pointer to location of substring 'needle' in 'haystack' */
1333char *
1334BCMROMFN(bcmstrstr)(const char *haystack, const char *needle)
1335{
1336	int len, nlen;
1337	int i;
1338
1339	if ((haystack == NULL) || (needle == NULL))
1340		return DISCARD_QUAL(haystack, char);
1341
1342	nlen = strlen(needle);
1343	len = strlen(haystack) - nlen + 1;
1344
1345	for (i = 0; i < len; i++)
1346		if (memcmp(needle, &haystack[i], nlen) == 0)
1347			return DISCARD_QUAL(&haystack[i], char);
1348	return (NULL);
1349}
1350
1351char *
1352BCMROMFN(bcmstrcat)(char *dest, const char *src)
1353{
1354	char *p;
1355
1356	p = dest + strlen(dest);
1357
1358	while ((*p++ = *src++) != '\0')
1359		;
1360
1361	return (dest);
1362}
1363
1364char *
1365BCMROMFN(bcmstrncat)(char *dest, const char *src, uint size)
1366{
1367	char *endp;
1368	char *p;
1369
1370	p = dest + strlen(dest);
1371	endp = p + size;
1372
1373	while (p != endp && (*p++ = *src++) != '\0')
1374		;
1375
1376	return (dest);
1377}
1378
1379
1380/****************************************************************************
1381* Function:   bcmstrtok
1382*
1383* Purpose:
1384*  Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
1385*  but allows strToken() to be used by different strings or callers at the same
1386*  time. Each call modifies '*string' by substituting a NULL character for the
1387*  first delimiter that is encountered, and updates 'string' to point to the char
1388*  after the delimiter. Leading delimiters are skipped.
1389*
1390* Parameters:
1391*  string      (mod) Ptr to string ptr, updated by token.
1392*  delimiters  (in)  Set of delimiter characters.
1393*  tokdelim    (out) Character that delimits the returned token. (May
1394*                    be set to NULL if token delimiter is not required).
1395*
1396* Returns:  Pointer to the next token found. NULL when no more tokens are found.
1397*****************************************************************************
1398*/
1399char *
1400bcmstrtok(char **string, const char *delimiters, char *tokdelim)
1401{
1402	unsigned char *str;
1403	unsigned long map[8];
1404	int count;
1405	char *nextoken;
1406
1407	if (tokdelim != NULL) {
1408		/* Prime the token delimiter */
1409		*tokdelim = '\0';
1410	}
1411
1412	/* Clear control map */
1413	for (count = 0; count < 8; count++) {
1414		map[count] = 0;
1415	}
1416
1417	/* Set bits in delimiter table */
1418	do {
1419		map[*delimiters >> 5] |= (1 << (*delimiters & 31));
1420	}
1421	while (*delimiters++);
1422
1423	str = (unsigned char*)*string;
1424
1425	/* Find beginning of token (skip over leading delimiters). Note that
1426	 * there is no token iff this loop sets str to point to the terminal
1427	 * null (*str == '\0')
1428	 */
1429	while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
1430		str++;
1431	}
1432
1433	nextoken = (char*)str;
1434
1435	/* Find the end of the token. If it is not the end of the string,
1436	 * put a null there.
1437	 */
1438	for (; *str; str++) {
1439		if (map[*str >> 5] & (1 << (*str & 31))) {
1440			if (tokdelim != NULL) {
1441				*tokdelim = *str;
1442			}
1443
1444			*str++ = '\0';
1445			break;
1446		}
1447	}
1448
1449	*string = (char*)str;
1450
1451	/* Determine if a token has been found. */
1452	if (nextoken == (char *) str) {
1453		return NULL;
1454	}
1455	else {
1456		return nextoken;
1457	}
1458}
1459
1460
1461#define xToLower(C) \
1462	((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
1463
1464
1465/****************************************************************************
1466* Function:   bcmstricmp
1467*
1468* Purpose:    Compare to strings case insensitively.
1469*
1470* Parameters: s1 (in) First string to compare.
1471*             s2 (in) Second string to compare.
1472*
1473* Returns:    Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1474*             t1 > t2, when ignoring case sensitivity.
1475*****************************************************************************
1476*/
1477int
1478bcmstricmp(const char *s1, const char *s2)
1479{
1480	char dc, sc;
1481
1482	while (*s2 && *s1) {
1483		dc = xToLower(*s1);
1484		sc = xToLower(*s2);
1485		if (dc < sc) return -1;
1486		if (dc > sc) return 1;
1487		s1++;
1488		s2++;
1489	}
1490
1491	if (*s1 && !*s2) return 1;
1492	if (!*s1 && *s2) return -1;
1493	return 0;
1494}
1495
1496
1497/****************************************************************************
1498* Function:   bcmstrnicmp
1499*
1500* Purpose:    Compare to strings case insensitively, upto a max of 'cnt'
1501*             characters.
1502*
1503* Parameters: s1  (in) First string to compare.
1504*             s2  (in) Second string to compare.
1505*             cnt (in) Max characters to compare.
1506*
1507* Returns:    Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1508*             t1 > t2, when ignoring case sensitivity.
1509*****************************************************************************
1510*/
1511int
1512bcmstrnicmp(const char* s1, const char* s2, int cnt)
1513{
1514	char dc, sc;
1515
1516	while (*s2 && *s1 && cnt) {
1517		dc = xToLower(*s1);
1518		sc = xToLower(*s2);
1519		if (dc < sc) return -1;
1520		if (dc > sc) return 1;
1521		s1++;
1522		s2++;
1523		cnt--;
1524	}
1525
1526	if (!cnt) return 0;
1527	if (*s1 && !*s2) return 1;
1528	if (!*s1 && *s2) return -1;
1529	return 0;
1530}
1531
1532/* parse a xx:xx:xx:xx:xx:xx format ethernet address */
1533int
1534BCMROMFN(bcm_ether_atoe)(const char *p, struct ether_addr *ea)
1535{
1536	int i = 0;
1537	char *ep;
1538
1539	for (;;) {
1540		ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16);
1541		p = ep;
1542		if (!*p++ || i == 6)
1543			break;
1544	}
1545
1546	return (i == 6);
1547}
1548
1549#ifdef _HNDRTE_
1550
1551const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}};
1552const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}};
1553const struct ether_addr ether_ipv6_mcast = {{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}};
1554
1555int
1556ether_isbcast(const void *ea)
1557{
1558	return (memcmp(ea, &ether_bcast, sizeof(struct ether_addr)) == 0);
1559}
1560
1561int
1562ether_isnulladdr(const void *ea)
1563{
1564	return (memcmp(ea, &ether_null, sizeof(struct ether_addr)) == 0);
1565}
1566
1567#endif /* _HNDRTE_ */
1568
1569#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
1570/* registry routine buffer preparation utility functions:
1571 * parameter order is like strncpy, but returns count
1572 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
1573 */
1574ulong
1575wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
1576{
1577	ulong copyct = 1;
1578	ushort i;
1579
1580	if (abuflen == 0)
1581		return 0;
1582
1583	/* wbuflen is in bytes */
1584	wbuflen /= sizeof(ushort);
1585
1586	for (i = 0; i < wbuflen; ++i) {
1587		if (--abuflen == 0)
1588			break;
1589		*abuf++ = (char) *wbuf++;
1590		++copyct;
1591	}
1592	*abuf = '\0';
1593
1594	return copyct;
1595}
1596#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
1597
1598char *
1599bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
1600{
1601	static const char hex[] =
1602	{
1603		'0', '1', '2', '3', '4', '5', '6', '7',
1604		'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
1605	};
1606	const uint8 *octet = ea->octet;
1607	char *p = buf;
1608	int i;
1609
1610	for (i = 0; i < 6; i++, octet++) {
1611		*p++ = hex[(*octet >> 4) & 0xf];
1612		*p++ = hex[*octet & 0xf];
1613		*p++ = ':';
1614	}
1615
1616	*(p-1) = '\0';
1617
1618	return (buf);
1619}
1620
1621char *
1622bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
1623{
1624	snprintf(buf, 16, "%d.%d.%d.%d",
1625	         ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
1626	return (buf);
1627}
1628
1629char *
1630bcm_ipv6_ntoa(void *ipv6, char *buf)
1631{
1632	/* Implementing RFC 5952 Sections 4 + 5 */
1633	/* Not thoroughly tested */
1634	uint16 *a = (uint16 *)ipv6;
1635	char *p = buf;
1636	int i, i_max = -1, cnt = 0, cnt_max = 1;
1637	uint8 *a4 = NULL;
1638
1639	for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
1640		if (a[i]) {
1641			if (cnt > cnt_max) {
1642				cnt_max = cnt;
1643				i_max = i - cnt;
1644			}
1645			cnt = 0;
1646		} else
1647			cnt++;
1648	}
1649	if (cnt > cnt_max) {
1650		cnt_max = cnt;
1651		i_max = i - cnt;
1652	}
1653	if (i_max == 0 &&
1654		/* IPv4-translated: ::ffff:0:a.b.c.d */
1655		((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) ||
1656		/* IPv4-mapped: ::ffff:a.b.c.d */
1657		(cnt_max == 5 && a[5] == 0xffff)))
1658		a4 = (uint8*) (a + 6);
1659
1660	for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
1661		if ((uint8*) (a + i) == a4) {
1662			snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]);
1663			break;
1664		} else if (i == i_max) {
1665			*p++ = ':';
1666			i += cnt_max - 1;
1667			p[0] = ':';
1668			p[1] = '\0';
1669		} else {
1670			if (i)
1671				*p++ = ':';
1672			p += snprintf(p, 8, "%x", ntoh16(a[i]));
1673		}
1674	}
1675
1676	return buf;
1677}
1678
1679#ifdef BCMDRIVER
1680
1681void
1682bcm_mdelay(uint ms)
1683{
1684	uint i;
1685
1686	for (i = 0; i < ms; i++) {
1687		OSL_DELAY(1000);
1688	}
1689}
1690
1691/*
1692 * Search the name=value vars for a specific one and return its value.
1693 * Returns NULL if not found.
1694 */
1695char *
1696getvar(char *vars, const char *name)
1697{
1698#ifdef _MINOSL_
1699	return NULL;
1700#else
1701	char *s;
1702	int len;
1703
1704	if (!name)
1705		return NULL;
1706
1707	len = strlen(name);
1708	if (len == 0)
1709		return NULL;
1710
1711	/* first look in vars[] */
1712	for (s = vars; s && *s;) {
1713		if ((bcmp(s, name, len) == 0) && (s[len] == '='))
1714			return (&s[len+1]);
1715
1716		while (*s++)
1717			;
1718	}
1719
1720	/* then query nvram */
1721	return (nvram_get(name));
1722#endif	/* defined(_MINOSL_) */
1723}
1724
1725/*
1726 * Search the vars for a specific one and return its value as
1727 * an integer. Returns 0 if not found.
1728 */
1729int
1730getintvar(char *vars, const char *name)
1731{
1732#ifdef	_MINOSL_
1733	return 0;
1734#else
1735	char *val;
1736
1737	if ((val = getvar(vars, name)) == NULL)
1738		return (0);
1739
1740	return (bcm_strtoul(val, NULL, 0));
1741#endif	/* _MINOSL_ */
1742}
1743
1744int
1745getintvararray(char *vars, const char *name, int index)
1746{
1747#ifdef	_MINOSL_
1748	return 0;
1749#else
1750	char *buf, *endp;
1751	int i = 0;
1752	int val = 0;
1753
1754	if ((buf = getvar(vars, name)) == NULL) {
1755		return (0);
1756	}
1757
1758	/* table values are always separated by "," or " " */
1759	while (*buf != '\0') {
1760		val = bcm_strtoul(buf, &endp, 0);
1761		if (i == index) {
1762			return val;
1763		}
1764		buf = endp;
1765		/* delimiter is ',' */
1766		if (*buf == ',')
1767			buf++;
1768		i++;
1769	}
1770	return 0;
1771#endif	/* _MINOSL_ */
1772}
1773
1774int
1775getintvararraysize(char *vars, const char *name)
1776{
1777#ifdef	_MINOSL_
1778	return 0;
1779#else
1780	char *buf, *endp;
1781	int count = 0;
1782	int val = 0;
1783
1784	if ((buf = getvar(vars, name)) == NULL) {
1785		return (0);
1786	}
1787
1788	/* table values are always separated by "," or " " */
1789	while (*buf != '\0') {
1790		val = bcm_strtoul(buf, &endp, 0);
1791		buf = endp;
1792		/* delimiter is ',' */
1793		if (*buf == ',')
1794			buf++;
1795		count++;
1796	}
1797	BCM_REFERENCE(val);
1798	return count;
1799#endif	/* _MINOSL_ */
1800}
1801
1802/* Search for token in comma separated token-string */
1803static int
1804findmatch(const char *string, const char *name)
1805{
1806	uint len;
1807	char *c;
1808
1809	len = strlen(name);
1810	while ((c = strchr(string, ',')) != NULL) {
1811		if (len == (uint)(c - string) && !strncmp(string, name, len))
1812			return 1;
1813		string = c + 1;
1814	}
1815
1816	return (!strcmp(string, name));
1817}
1818
1819/* Return gpio pin number assigned to the named pin
1820 *
1821 * Variable should be in format:
1822 *
1823 *	gpio<N>=pin_name,pin_name
1824 *
1825 * This format allows multiple features to share the gpio with mutual
1826 * understanding.
1827 *
1828 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
1829 * and if def_pin is not used by others.
1830 */
1831uint
1832getgpiopin(char *vars, char *pin_name, uint def_pin)
1833{
1834	char name[] = "gpioXXXX";
1835	char *val;
1836	uint pin;
1837
1838	/* Go thru all possibilities till a match in pin name */
1839	for (pin = 0; pin < GPIO_NUMPINS; pin ++) {
1840		snprintf(name, sizeof(name), "gpio%d", pin);
1841		val = getvar(vars, name);
1842		if (val && findmatch(val, pin_name))
1843			return pin;
1844	}
1845
1846	if (def_pin != GPIO_PIN_NOTDEFINED) {
1847		/* make sure the default pin is not used by someone else */
1848		snprintf(name, sizeof(name), "gpio%d", def_pin);
1849		if (getvar(vars, name)) {
1850			def_pin =  GPIO_PIN_NOTDEFINED;
1851		}
1852	}
1853	return def_pin;
1854}
1855
1856#if defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS)
1857
1858#define	LOGSIZE	256			/* should be power of 2 to avoid div below */
1859static struct {
1860	uint	cycles;
1861	char	*fmt;
1862	uint	a1;
1863	uint	a2;
1864} logtab[LOGSIZE];
1865
1866/* last entry logged  */
1867static uint logi = 0;
1868/* next entry to read */
1869static uint readi = 0;
1870#endif	/* defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS) */
1871
1872#ifdef BCMPERFSTATS
1873void
1874bcm_perf_enable()
1875{
1876	BCMPERF_ENABLE_INSTRCOUNT();
1877	BCMPERF_ENABLE_ICACHE_MISS();
1878	BCMPERF_ENABLE_ICACHE_HIT();
1879}
1880
1881/* WARNING:  This routine uses OSL_GETCYCLES(), which can give unexpected results on
1882 * modern speed stepping CPUs.  Use bcmtslog() instead in combination with TSF counter.
1883 */
1884void
1885bcmlog(char *fmt, uint a1, uint a2)
1886{
1887	static uint last = 0;
1888	uint cycles, i;
1889	OSL_GETCYCLES(cycles);
1890
1891	i = logi;
1892
1893	logtab[i].cycles = cycles - last;
1894	logtab[i].fmt = fmt;
1895	logtab[i].a1 = a1;
1896	logtab[i].a2 = a2;
1897
1898	logi = (i + 1) % LOGSIZE;
1899	last = cycles;
1900}
1901
1902
1903void
1904bcmstats(char *fmt)
1905{
1906	static uint last = 0;
1907	static uint32 ic_miss = 0;
1908	static uint32 instr_count = 0;
1909	uint32 ic_miss_cur;
1910	uint32 instr_count_cur;
1911	uint cycles, i;
1912
1913	OSL_GETCYCLES(cycles);
1914	BCMPERF_GETICACHE_MISS(ic_miss_cur);
1915	BCMPERF_GETINSTRCOUNT(instr_count_cur);
1916
1917	i = logi;
1918
1919	logtab[i].cycles = cycles - last;
1920	logtab[i].a1 = ic_miss_cur - ic_miss;
1921	logtab[i].a2 = instr_count_cur - instr_count;
1922	logtab[i].fmt = fmt;
1923
1924	logi = (i + 1) % LOGSIZE;
1925
1926	last = cycles;
1927	instr_count = instr_count_cur;
1928	ic_miss = ic_miss_cur;
1929}
1930
1931
1932void
1933bcmdumplog(char *buf, int size)
1934{
1935	char *limit;
1936	int j = 0;
1937	int num;
1938
1939	limit = buf + size - 80;
1940	*buf = '\0';
1941
1942	num = logi - readi;
1943
1944	if (num < 0)
1945		num += LOGSIZE;
1946
1947	/* print in chronological order */
1948
1949	for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) {
1950		if (logtab[readi].fmt == NULL)
1951		    continue;
1952		buf += snprintf(buf, (limit - buf), "%d\t", logtab[readi].cycles);
1953		buf += snprintf(buf, (limit - buf), logtab[readi].fmt, logtab[readi].a1,
1954		                logtab[readi].a2);
1955		buf += snprintf(buf, (limit - buf), "\n");
1956	}
1957
1958}
1959
1960
1961/*
1962 * Dump one log entry at a time.
1963 * Return index of next entry or -1 when no more .
1964 */
1965int
1966bcmdumplogent(char *buf, uint i)
1967{
1968	bool hit;
1969
1970	/*
1971	 * If buf is NULL, return the starting index,
1972	 * interpreting i as the indicator of last 'i' entries to dump.
1973	 */
1974	if (buf == NULL) {
1975		i = ((i > 0) && (i < (LOGSIZE - 1))) ? i : (LOGSIZE - 1);
1976		return ((logi - i) % LOGSIZE);
1977	}
1978
1979	*buf = '\0';
1980
1981	ASSERT(i < LOGSIZE);
1982
1983	if (i == logi)
1984		return (-1);
1985
1986	hit = FALSE;
1987	for (; (i != logi) && !hit; i = (i + 1) % LOGSIZE) {
1988		if (logtab[i].fmt == NULL)
1989			continue;
1990		buf += sprintf(buf, "%d: %d\t", i, logtab[i].cycles);
1991		buf += sprintf(buf, logtab[i].fmt, logtab[i].a1, logtab[i].a2);
1992		buf += sprintf(buf, "\n");
1993		hit = TRUE;
1994	}
1995
1996	return (i);
1997}
1998
1999#endif	/* BCMPERFSTATS */
2000
2001#if defined(BCMTSTAMPEDLOGS)
2002/* Store a TSF timestamp and a log line in the log buffer */
2003void
2004bcmtslog(uint32 tstamp, char *fmt, uint a1, uint a2)
2005{
2006	uint i = logi;
2007	bool use_delta = FALSE;
2008	static uint32 last = 0;	/* used only when use_delta is true */
2009
2010	logtab[i].cycles = tstamp;
2011	if (use_delta)
2012		logtab[i].cycles -= last;
2013
2014	logtab[i].fmt = fmt;
2015	logtab[i].a1 = a1;
2016	logtab[i].a2 = a2;
2017
2018	if (use_delta)
2019		last = tstamp;
2020	logi = (i + 1) % LOGSIZE;
2021}
2022
2023/* Print out a microsecond timestamp as "sec.ms.us " */
2024void
2025bcmprinttstamp(uint32 ticks)
2026{
2027	uint us, ms, sec;
2028
2029	us = (ticks % TSF_TICKS_PER_MS) * 1000 / TSF_TICKS_PER_MS;
2030	ms = ticks / TSF_TICKS_PER_MS;
2031	sec = ms / 1000;
2032	ms -= sec * 1000;
2033	printf("%04u.%03u.%03u ", sec, ms, us);
2034}
2035
2036/* Print out the log buffer with timestamps */
2037void
2038bcmprinttslogs(void)
2039{
2040	int j = 0;
2041	int num;
2042
2043	num = logi - readi;
2044	if (num < 0)
2045		num += LOGSIZE;
2046
2047	/* Format and print the log entries directly in chronological order */
2048	for (j = 0; j < num; readi = (readi + 1) % LOGSIZE, j++) {
2049		if (logtab[readi].fmt == NULL)
2050		    continue;
2051		bcmprinttstamp(logtab[readi].cycles);
2052		printf(logtab[readi].fmt, logtab[readi].a1, logtab[readi].a2);
2053		printf("\n");
2054	}
2055}
2056
2057void
2058bcmdumptslog(char *buf, int size)
2059{
2060	char *limit;
2061	int j = 0;
2062	int num;
2063	uint us, ms, sec;
2064
2065	limit = buf + size - 80;
2066	*buf = '\0';
2067
2068	num = logi - readi;
2069
2070	if (num < 0)
2071		num += LOGSIZE;
2072
2073	/* print in chronological order */
2074	for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) {
2075		if (logtab[readi].fmt == NULL)
2076			continue;
2077		us = (logtab[readi].cycles % TSF_TICKS_PER_MS) * 1000 / TSF_TICKS_PER_MS;
2078		ms = logtab[readi].cycles / TSF_TICKS_PER_MS;
2079		sec = ms / 1000;
2080		ms -= sec * 1000;
2081
2082		buf += snprintf(buf, (limit - buf), "%04u.%03u.%03u ", sec, ms, us);
2083		/*      buf += snprintf(buf, (limit - buf), "%d\t", logtab[readi].cycles); */
2084		buf += snprintf(buf, (limit - buf), logtab[readi].fmt, logtab[readi].a1,
2085		logtab[readi].a2);
2086		buf += snprintf(buf, (limit - buf), "\n");
2087	}
2088}
2089
2090#endif	/* BCMTSTAMPEDLOGS */
2091
2092#if defined(DHD_DEBUG)
2093/* pretty hex print a pkt buffer chain */
2094void
2095prpkt(const char *msg, osl_t *osh, void *p0)
2096{
2097	void *p;
2098
2099	if (msg && (msg[0] != '\0'))
2100		printf("%s:\n", msg);
2101
2102	for (p = p0; p; p = PKTNEXT(osh, p))
2103		prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
2104}
2105#endif
2106
2107/* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
2108 * Also updates the inplace vlan tag if requested.
2109 * For debugging, it returns an indication of what it did.
2110 */
2111uint BCMFASTPATH
2112pktsetprio(void *pkt, bool update_vtag)
2113{
2114	struct ether_header *eh;
2115	struct ethervlan_header *evh;
2116	uint8 *pktdata;
2117	int priority = 0;
2118	int rc = 0;
2119
2120	pktdata = (uint8 *)PKTDATA(NULL, pkt);
2121	ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
2122
2123	eh = (struct ether_header *) pktdata;
2124
2125	if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) {
2126		uint16 vlan_tag;
2127		int vlan_prio, dscp_prio = 0;
2128
2129		evh = (struct ethervlan_header *)eh;
2130
2131		vlan_tag = ntoh16(evh->vlan_tag);
2132		vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
2133
2134		if (evh->ether_type == hton16(ETHER_TYPE_IP)) {
2135			uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
2136			uint8 tos_tc = IP_TOS46(ip_body);
2137			dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
2138		}
2139
2140		/* DSCP priority gets precedence over 802.1P (vlan tag) */
2141		if (dscp_prio != 0) {
2142			priority = dscp_prio;
2143			rc |= PKTPRIO_VDSCP;
2144		} else {
2145			priority = vlan_prio;
2146			rc |= PKTPRIO_VLAN;
2147		}
2148		/*
2149		 * If the DSCP priority is not the same as the VLAN priority,
2150		 * then overwrite the priority field in the vlan tag, with the
2151		 * DSCP priority value. This is required for Linux APs because
2152		 * the VLAN driver on Linux, overwrites the skb->priority field
2153		 * with the priority value in the vlan tag
2154		 */
2155		if (update_vtag && (priority != vlan_prio)) {
2156			vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
2157			vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
2158			evh->vlan_tag = hton16(vlan_tag);
2159			rc |= PKTPRIO_UPD;
2160		}
2161	} else if (eh->ether_type == hton16(ETHER_TYPE_IP)) {
2162		uint8 *ip_body = pktdata + sizeof(struct ether_header);
2163		uint8 tos_tc = IP_TOS46(ip_body);
2164		priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
2165		rc |= PKTPRIO_DSCP;
2166	}
2167
2168	ASSERT(priority >= 0 && priority <= MAXPRIO);
2169	PKTSETPRIO(pkt, priority);
2170	return (rc | priority);
2171}
2172
2173#ifndef BCM_BOOTLOADER
2174
2175static char bcm_undeferrstr[32];
2176static const char *const bcmerrorstrtable[] = BCMERRSTRINGTABLE;
2177
2178/* Convert the error codes into related error strings  */
2179const char *
2180bcmerrorstr(int bcmerror)
2181{
2182	/* check if someone added a bcmerror code but forgot to add errorstring */
2183	ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
2184
2185	if (bcmerror > 0 || bcmerror < BCME_LAST) {
2186		snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
2187		return bcm_undeferrstr;
2188	}
2189
2190	ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
2191
2192	return bcmerrorstrtable[-bcmerror];
2193}
2194
2195#endif /* !BCM_BOOTLOADER */
2196
2197#ifdef WLC_LOW
2198static void
2199BCMINITFN(bcm_nvram_refresh)(char *flash)
2200{
2201	int i;
2202	int ret = 0;
2203
2204	ASSERT(flash != NULL);
2205
2206	/* default "empty" vars cache */
2207	bzero(flash, 2);
2208
2209	if ((ret = nvram_getall(flash, MAX_NVRAM_SPACE)))
2210		return;
2211
2212	/* determine nvram length */
2213	for (i = 0; i < MAX_NVRAM_SPACE; i++) {
2214		if (flash[i] == '\0' && flash[i+1] == '\0')
2215			break;
2216	}
2217
2218	if (i > 1)
2219		vars_len = i + 2;
2220	else
2221		vars_len = 0;
2222}
2223
2224char *
2225bcm_nvram_vars(uint *length)
2226{
2227#ifndef BCMNVRAMR
2228	/* cache may be stale if nvram is read/write */
2229	if (nvram_vars) {
2230		ASSERT(!bcmreclaimed);
2231		bcm_nvram_refresh(nvram_vars);
2232	}
2233#endif
2234	if (length)
2235		*length = vars_len;
2236	return nvram_vars;
2237}
2238
2239/* copy nvram vars into locally-allocated multi-string array */
2240int
2241BCMINITFN(bcm_nvram_cache)(void *sih)
2242{
2243	int ret = 0;
2244	void *osh;
2245	char *flash = NULL;
2246
2247	if (vars_len >= 0) {
2248#ifndef BCMNVRAMR
2249		bcm_nvram_refresh(nvram_vars);
2250#endif
2251		return 0;
2252	}
2253
2254	osh = si_osh((si_t *)sih);
2255
2256	/* allocate memory and read in flash */
2257	if (!(flash = MALLOC(osh, MAX_NVRAM_SPACE))) {
2258		ret = BCME_NOMEM;
2259		goto exit;
2260	}
2261
2262	bcm_nvram_refresh(flash);
2263
2264#ifdef BCMNVRAMR
2265	if (vars_len > 3) {
2266		/* copy into a properly-sized buffer */
2267		if (!(nvram_vars = MALLOC(osh, vars_len))) {
2268			ret = BCME_NOMEM;
2269		} else
2270			bcopy(flash, nvram_vars, vars_len);
2271	}
2272	MFREE(osh, flash, MAX_NVRAM_SPACE);
2273#else
2274	/* cache must be full size of nvram if read/write */
2275	nvram_vars = flash;
2276#endif	/* BCMNVRAMR */
2277
2278exit:
2279	return ret;
2280}
2281#endif /* WLC_LOW */
2282
2283#ifdef BCMDBG_PKT   /* pkt logging for debugging */
2284/* Add a packet to the pktlist */
2285static void
2286_pktlist_add(pktlist_info_t *pktlist, void *pkt, int line, char *file)
2287{
2288	uint16 i;
2289	char *basename;
2290#ifdef BCMDBG_PTRACE
2291	uint16 *idx = PKTLIST_IDX(pkt);
2292#endif /* BCMDBG_PTRACE */
2293
2294	ASSERT(pktlist->count < PKTLIST_SIZE);
2295
2296	/* Verify the packet is not already part of the list */
2297	for (i = 0; i < pktlist->count; i++) {
2298		if (pktlist->list[i].pkt == pkt)
2299			ASSERT(0);
2300	}
2301	pktlist->list[pktlist->count].pkt = pkt;
2302	pktlist->list[pktlist->count].line = line;
2303
2304	basename = strrchr(file, '/');
2305	if (basename)
2306		basename++;
2307	else
2308		basename = file;
2309	pktlist->list[pktlist->count].file = basename;
2310#ifdef BCMDBG_PTRACE
2311	*idx = pktlist->count;
2312	bzero(pktlist->list[pktlist->count].pkt_trace, PKTTRACE_MAX_BYTES);
2313#endif /* BCMDBG_PTRACE */
2314	pktlist->count++;
2315
2316	return;
2317}
2318
2319void
2320pktlist_add(pktlist_info_t *pktlist, void *pkt, int line, char *file)
2321{
2322	void *p;
2323	for (p = pkt; p != NULL; p = PKTCLINK(p))
2324		_pktlist_add(pktlist, p, line, file);
2325}
2326
2327/* Remove a packet from the pktlist */
2328static void
2329_pktlist_remove(pktlist_info_t *pktlist, void *pkt)
2330{
2331	uint16 i;
2332	uint16 num = pktlist->count;
2333#ifdef BCMDBG_PTRACE
2334	uint16 *idx = PKTLIST_IDX(pkt);
2335
2336	ASSERT((*idx) < pktlist->count);
2337#endif /* BCMDBG_PTRACE */
2338
2339	/* find the index where pkt exists */
2340	for (i = 0; i < num; i++) {
2341		/* check for the existence of pkt in the list */
2342		if (pktlist->list[i].pkt == pkt) {
2343#ifdef BCMDBG_PTRACE
2344			ASSERT((*idx) == i);
2345#endif /* BCMDBG_PTRACE */
2346			/* replace with the last element */
2347			pktlist->list[i].pkt = pktlist->list[num-1].pkt;
2348			pktlist->list[i].line = pktlist->list[num-1].line;
2349			pktlist->list[i].file = pktlist->list[num-1].file;
2350#ifdef BCMDBG_PTRACE
2351			memcpy(pktlist->list[i].pkt_trace, pktlist->list[num-1].pkt_trace,
2352				PKTTRACE_MAX_BYTES);
2353			idx = PKTLIST_IDX(pktlist->list[i].pkt);
2354			*idx = i;
2355#endif /* BCMDBG_PTRACE */
2356			pktlist->count--;
2357			return;
2358		}
2359	}
2360	ASSERT(0);
2361}
2362
2363void
2364pktlist_remove(pktlist_info_t *pktlist, void *pkt)
2365{
2366	void *p;
2367	for (p = pkt; p != NULL; p = PKTCLINK(p))
2368		_pktlist_remove(pktlist, p);
2369}
2370
2371#ifdef BCMDBG_PTRACE
2372static void
2373_pktlist_trace(pktlist_info_t *pktlist, void *pkt, uint16 bit)
2374{
2375	uint16 *idx = PKTLIST_IDX(pkt);
2376
2377	ASSERT(((*idx) < pktlist->count) && (bit < PKTTRACE_MAX_BITS));
2378	ASSERT(pktlist->list[(*idx)].pkt == pkt);
2379
2380	pktlist->list[(*idx)].pkt_trace[bit/NBBY] |= (1 << ((bit)%NBBY));
2381
2382}
2383void
2384pktlist_trace(pktlist_info_t *pktlist, void *pkt, uint16 bit)
2385{
2386	void *p;
2387	for (p = pkt; p != NULL; p = PKTCLINK(p))
2388		_pktlist_trace(pktlist, p, bit);
2389}
2390#endif /* BCMDBG_PTRACE */
2391
2392/* Dump the pktlist (and the contents of each packet if 'data'
2393 * is set). 'buf' should be large enough
2394 */
2395
2396char *
2397pktlist_dump(pktlist_info_t *pktlist, char *buf)
2398{
2399	char *obuf = buf;
2400	uint16 i;
2401
2402	if (buf != NULL)
2403		buf += sprintf(buf, "Packet list dump:\n");
2404	else
2405		printf("Packet list dump:\n");
2406
2407	for (i = 0; i < (pktlist->count); i++) {
2408		if (buf != NULL)
2409			buf += sprintf(buf, "Pkt_addr: 0x%p Line: %d File: %s\t",
2410				pktlist->list[i].pkt, pktlist->list[i].line,
2411				pktlist->list[i].file);
2412		else
2413			printf("Pkt_addr: 0x%p Line: %d File: %s\t", pktlist->list[i].pkt,
2414				pktlist->list[i].line, pktlist->list[i].file);
2415
2416/* #ifdef NOTDEF  Remove this ifdef to print pkttag and pktdata */
2417		if (buf != NULL) {
2418			if (PKTTAG(pktlist->list[i].pkt)) {
2419				/* Print pkttag */
2420				buf += sprintf(buf, "Pkttag(in hex): ");
2421				buf += bcm_format_hex(buf, PKTTAG(pktlist->list[i].pkt),
2422					OSL_PKTTAG_SZ);
2423			}
2424			buf += sprintf(buf, "Pktdata(in hex): ");
2425			buf += bcm_format_hex(buf, PKTDATA(NULL, pktlist->list[i].pkt),
2426			                      PKTLEN(NULL, pktlist->list[i].pkt));
2427		} else {
2428			void *pkt = pktlist->list[i].pkt, *npkt;
2429
2430			printf("Pkt[%d] Dump:\n", i);
2431			while (pkt) {
2432				int hroom, pktlen;
2433				uchar *src;
2434#ifdef BCMDBG_PTRACE
2435				uint16 *idx = PKTLIST_IDX(pkt);
2436
2437				ASSERT((*idx) < pktlist->count);
2438				prhex("Pkt Trace (in hex):", pktlist->list[(*idx)].pkt_trace,
2439					PKTTRACE_MAX_BYTES);
2440#endif /* BCMDBG_PTRACE */
2441				npkt = (void *)PKTNEXT(NULL, pkt);
2442				PKTSETNEXT(NULL, pkt, NULL);
2443
2444				src = (uchar *)(PKTTAG(pkt));
2445				pktlen = PKTLEN(NULL, pkt);
2446				hroom = PKTHEADROOM(NULL, pkt);
2447
2448				printf("Pkttag_addr: %p\n", src);
2449				if (src)
2450					prhex("Pkttag(in hex): ", src, OSL_PKTTAG_SZ);
2451				src = (uchar *) (PKTDATA(NULL, pkt));
2452				printf("Pkthead_addr: %p len: %d\n", src - hroom, hroom);
2453				prhex("Pkt headroom content(in hex): ", src - hroom, hroom);
2454				printf("Pktdata_addr: %p len: %d\n", src, pktlen);
2455				prhex("Pktdata(in hex): ", src, pktlen);
2456
2457				pkt = npkt;
2458			}
2459		}
2460/* #endif  NOTDEF */
2461
2462		if (buf != NULL)
2463			buf += sprintf(buf, "\n");
2464		else
2465			printf("\n");
2466	}
2467	return obuf;
2468}
2469#endif  /* BCMDBG_PKT */
2470
2471/* iovar table lookup */
2472const bcm_iovar_t*
2473bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
2474{
2475	const bcm_iovar_t *vi;
2476	const char *lookup_name;
2477
2478	/* skip any ':' delimited option prefixes */
2479	lookup_name = strrchr(name, ':');
2480	if (lookup_name != NULL)
2481		lookup_name++;
2482	else
2483		lookup_name = name;
2484
2485	ASSERT(table != NULL);
2486
2487	for (vi = table; vi->name; vi++) {
2488		if (!strcmp(vi->name, lookup_name))
2489			return vi;
2490	}
2491	/* ran to end of table */
2492
2493	return NULL; /* var name not found */
2494}
2495
2496int
2497bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
2498{
2499	int bcmerror = 0;
2500
2501	/* length check on io buf */
2502	switch (vi->type) {
2503	case IOVT_BOOL:
2504	case IOVT_INT8:
2505	case IOVT_INT16:
2506	case IOVT_INT32:
2507	case IOVT_UINT8:
2508	case IOVT_UINT16:
2509	case IOVT_UINT32:
2510		/* all integers are int32 sized args at the ioctl interface */
2511		if (len < (int)sizeof(int)) {
2512			bcmerror = BCME_BUFTOOSHORT;
2513		}
2514		break;
2515
2516	case IOVT_BUFFER:
2517		/* buffer must meet minimum length requirement */
2518		if (len < vi->minlen) {
2519			bcmerror = BCME_BUFTOOSHORT;
2520		}
2521		break;
2522
2523	case IOVT_VOID:
2524		if (!set) {
2525			/* Cannot return nil... */
2526			bcmerror = BCME_UNSUPPORTED;
2527		} else if (len) {
2528			/* Set is an action w/o parameters */
2529			bcmerror = BCME_BUFTOOLONG;
2530		}
2531		break;
2532
2533	default:
2534		/* unknown type for length check in iovar info */
2535		ASSERT(0);
2536		bcmerror = BCME_UNSUPPORTED;
2537	}
2538
2539	return bcmerror;
2540}
2541
2542#endif	/* BCMDRIVER */
2543
2544
2545/*******************************************************************************
2546 * crc8
2547 *
2548 * Computes a crc8 over the input data using the polynomial:
2549 *
2550 *       x^8 + x^7 +x^6 + x^4 + x^2 + 1
2551 *
2552 * The caller provides the initial value (either CRC8_INIT_VALUE
2553 * or the previous returned value) to allow for processing of
2554 * discontiguous blocks of data.  When generating the CRC the
2555 * caller is responsible for complementing the final return value
2556 * and inserting it into the byte stream.  When checking, a final
2557 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
2558 *
2559 * Reference: Dallas Semiconductor Application Note 27
2560 *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2561 *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2562 *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2563 *
2564 * ****************************************************************************
2565 */
2566
2567static const uint8 crc8_table[256] = {
2568    0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
2569    0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
2570    0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
2571    0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
2572    0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
2573    0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
2574    0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
2575    0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
2576    0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
2577    0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
2578    0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
2579    0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
2580    0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
2581    0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
2582    0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
2583    0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
2584    0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
2585    0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
2586    0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
2587    0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
2588    0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
2589    0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
2590    0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
2591    0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
2592    0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
2593    0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
2594    0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
2595    0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
2596    0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
2597    0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
2598    0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
2599    0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
2600};
2601
2602#define CRC_INNER_LOOP(n, c, x) \
2603	(c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
2604
2605uint8
2606BCMROMFN(hndcrc8)(
2607	uint8 *pdata,	/* pointer to array of data to process */
2608	uint  nbytes,	/* number of input data bytes to process */
2609	uint8 crc	/* either CRC8_INIT_VALUE or previous return value */
2610)
2611{
2612	/* hard code the crc loop instead of using CRC_INNER_LOOP macro
2613	 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
2614	 */
2615	while (nbytes-- > 0)
2616		crc = crc8_table[(crc ^ *pdata++) & 0xff];
2617
2618	return crc;
2619}
2620
2621/*******************************************************************************
2622 * crc16
2623 *
2624 * Computes a crc16 over the input data using the polynomial:
2625 *
2626 *       x^16 + x^12 +x^5 + 1
2627 *
2628 * The caller provides the initial value (either CRC16_INIT_VALUE
2629 * or the previous returned value) to allow for processing of
2630 * discontiguous blocks of data.  When generating the CRC the
2631 * caller is responsible for complementing the final return value
2632 * and inserting it into the byte stream.  When checking, a final
2633 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
2634 *
2635 * Reference: Dallas Semiconductor Application Note 27
2636 *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2637 *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2638 *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2639 *
2640 * ****************************************************************************
2641 */
2642
2643static const uint16 crc16_table[256] = {
2644    0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
2645    0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
2646    0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
2647    0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
2648    0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
2649    0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
2650    0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
2651    0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
2652    0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
2653    0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
2654    0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
2655    0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
2656    0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
2657    0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
2658    0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
2659    0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
2660    0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
2661    0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
2662    0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
2663    0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
2664    0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
2665    0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
2666    0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
2667    0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
2668    0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
2669    0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
2670    0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
2671    0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
2672    0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
2673    0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
2674    0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
2675    0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
2676};
2677
2678uint16
2679BCMROMFN(hndcrc16)(
2680    uint8 *pdata,  /* pointer to array of data to process */
2681    uint nbytes, /* number of input data bytes to process */
2682    uint16 crc     /* either CRC16_INIT_VALUE or previous return value */
2683)
2684{
2685	while (nbytes-- > 0)
2686		CRC_INNER_LOOP(16, crc, *pdata++);
2687	return crc;
2688}
2689
2690static const uint32 crc32_table[256] = {
2691    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
2692    0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
2693    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
2694    0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
2695    0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
2696    0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
2697    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
2698    0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
2699    0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
2700    0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
2701    0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
2702    0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
2703    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
2704    0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
2705    0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
2706    0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
2707    0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
2708    0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
2709    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
2710    0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
2711    0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
2712    0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
2713    0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
2714    0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
2715    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
2716    0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
2717    0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
2718    0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
2719    0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
2720    0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
2721    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
2722    0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
2723    0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
2724    0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
2725    0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
2726    0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
2727    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
2728    0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
2729    0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
2730    0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
2731    0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
2732    0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
2733    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
2734    0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
2735    0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
2736    0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
2737    0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
2738    0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
2739    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
2740    0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
2741    0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
2742    0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
2743    0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
2744    0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
2745    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
2746    0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
2747    0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
2748    0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
2749    0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
2750    0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
2751    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
2752    0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
2753    0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
2754    0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
2755};
2756
2757/*
2758 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
2759 * accumulating over multiple pieces.
2760 */
2761uint32
2762BCMROMFN(hndcrc32)(uint8 *pdata, uint nbytes, uint32 crc)
2763{
2764	uint8 *pend;
2765#ifdef __mips__
2766	uint8 tmp[4];
2767	ulong *tptr = (ulong *)tmp;
2768
2769	if (nbytes > 3) {
2770		/* in case the beginning of the buffer isn't aligned */
2771		pend = (uint8 *)((uint)(pdata + 3) & ~0x3);
2772		nbytes -= (pend - pdata);
2773		while (pdata < pend)
2774			CRC_INNER_LOOP(32, crc, *pdata++);
2775	}
2776
2777	if (nbytes > 3) {
2778		/* handle bulk of data as 32-bit words */
2779		pend = pdata + (nbytes & ~0x3);
2780		while (pdata < pend) {
2781			*tptr = *(ulong *)pdata;
2782			pdata += sizeof(ulong *);
2783			CRC_INNER_LOOP(32, crc, tmp[0]);
2784			CRC_INNER_LOOP(32, crc, tmp[1]);
2785			CRC_INNER_LOOP(32, crc, tmp[2]);
2786			CRC_INNER_LOOP(32, crc, tmp[3]);
2787		}
2788	}
2789
2790	/* 1-3 bytes at end of buffer */
2791	pend = pdata + (nbytes & 0x03);
2792	while (pdata < pend)
2793		CRC_INNER_LOOP(32, crc, *pdata++);
2794#else
2795	pend = pdata + nbytes;
2796	while (pdata < pend)
2797		CRC_INNER_LOOP(32, crc, *pdata++);
2798#endif /* __mips__ */
2799
2800	return crc;
2801}
2802
2803#ifdef notdef
2804#define CLEN 	1499 	/*  CRC Length */
2805#define CBUFSIZ 	(CLEN+4)
2806#define CNBUFS		5 /* # of bufs */
2807
2808void
2809testcrc32(void)
2810{
2811	uint j, k, l;
2812	uint8 *buf;
2813	uint len[CNBUFS];
2814	uint32 crcr;
2815	uint32 crc32tv[CNBUFS] =
2816		{0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
2817
2818	ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
2819
2820	/* step through all possible alignments */
2821	for (l = 0; l <= 4; l++) {
2822		for (j = 0; j < CNBUFS; j++) {
2823			len[j] = CLEN;
2824			for (k = 0; k < len[j]; k++)
2825				*(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
2826		}
2827
2828		for (j = 0; j < CNBUFS; j++) {
2829			crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
2830			ASSERT(crcr == crc32tv[j]);
2831		}
2832	}
2833
2834	MFREE(buf, CBUFSIZ*CNBUFS);
2835	return;
2836}
2837#endif /* notdef */
2838
2839/*
2840 * Advance from the current 1-byte tag/1-byte length/variable-length value
2841 * triple, to the next, returning a pointer to the next.
2842 * If the current or next TLV is invalid (does not fit in given buffer length),
2843 * NULL is returned.
2844 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
2845 * by the TLV parameter's length if it is valid.
2846 */
2847bcm_tlv_t *
2848BCMROMFN(bcm_next_tlv)(bcm_tlv_t *elt, int *buflen)
2849{
2850	int len;
2851
2852	/* validate current elt */
2853	if (!bcm_valid_tlv(elt, *buflen))
2854		return NULL;
2855
2856	/* advance to next elt */
2857	len = elt->len;
2858	elt = (bcm_tlv_t*)(elt->data + len);
2859	*buflen -= (TLV_HDR_LEN + len);
2860
2861	/* validate next elt */
2862	if (!bcm_valid_tlv(elt, *buflen))
2863		return NULL;
2864
2865	return elt;
2866}
2867
2868/*
2869 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2870 * triples, returning a pointer to the substring whose first element
2871 * matches tag
2872 */
2873bcm_tlv_t *
2874BCMROMFN(bcm_parse_tlvs)(void *buf, int buflen, uint key)
2875{
2876	bcm_tlv_t *elt;
2877	int totlen;
2878
2879	elt = (bcm_tlv_t*)buf;
2880	totlen = buflen;
2881
2882	/* find tagged parameter */
2883	while (totlen >= TLV_HDR_LEN) {
2884		int len = elt->len;
2885
2886		/* validate remaining totlen */
2887		if ((elt->id == key) &&
2888		    (totlen >= (len + TLV_HDR_LEN)))
2889			return (elt);
2890
2891		elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
2892		totlen -= (len + TLV_HDR_LEN);
2893	}
2894
2895	return NULL;
2896}
2897
2898/*
2899 * Traverse a string of 1-byte tag/1-byte length/variable-length value
2900 * triples, returning a pointer to the substring whose first element
2901 * matches tag.  Stop parsing when we see an element whose ID is greater
2902 * than the target key.
2903 */
2904bcm_tlv_t *
2905BCMROMFN(bcm_parse_ordered_tlvs)(void *buf, int buflen, uint key)
2906{
2907	bcm_tlv_t *elt;
2908	int totlen;
2909
2910	elt = (bcm_tlv_t*)buf;
2911	totlen = buflen;
2912
2913	/* find tagged parameter */
2914	while (totlen >= TLV_HDR_LEN) {
2915		uint id = elt->id;
2916		int len = elt->len;
2917
2918		/* Punt if we start seeing IDs > than target key */
2919		if (id > key)
2920			return (NULL);
2921
2922		/* validate remaining totlen */
2923		if ((id == key) &&
2924		    (totlen >= (len + TLV_HDR_LEN)))
2925			return (elt);
2926
2927		elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
2928		totlen -= (len + TLV_HDR_LEN);
2929	}
2930	return NULL;
2931}
2932
2933#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
2934	defined(BCMDBG_DUMP) || defined(DHD_DEBUG)
2935int
2936bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len)
2937{
2938	int i, slen = 0;
2939	uint32 bit, mask;
2940	const char *name;
2941	mask = bd->mask;
2942	if (len < 2 || !buf)
2943		return 0;
2944
2945	buf[0] = '\0';
2946
2947	for (i = 0;  (name = bd->bitfield[i].name) != NULL; i++) {
2948		bit = bd->bitfield[i].bit;
2949		if ((flags & mask) == bit) {
2950			if (len > (int)strlen(name)) {
2951				slen = strlen(name);
2952				strncpy(buf, name, slen+1);
2953			}
2954			break;
2955		}
2956	}
2957	return slen;
2958}
2959
2960int
2961bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
2962{
2963	int i;
2964	char* p = buf;
2965	char hexstr[16];
2966	int slen = 0, nlen = 0;
2967	uint32 bit;
2968	const char* name;
2969
2970	if (len < 2 || !buf)
2971		return 0;
2972
2973	buf[0] = '\0';
2974
2975	for (i = 0; flags != 0; i++) {
2976		bit = bd[i].bit;
2977		name = bd[i].name;
2978		if (bit == 0 && flags != 0) {
2979			/* print any unnamed bits */
2980			snprintf(hexstr, 16, "0x%X", flags);
2981			name = hexstr;
2982			flags = 0;	/* exit loop */
2983		} else if ((flags & bit) == 0)
2984			continue;
2985		flags &= ~bit;
2986		nlen = strlen(name);
2987		slen += nlen;
2988		/* count btwn flag space */
2989		if (flags != 0)
2990			slen += 1;
2991		/* need NULL char as well */
2992		if (len <= slen)
2993			break;
2994		/* copy NULL char but don't count it */
2995		strncpy(p, name, nlen + 1);
2996		p += nlen;
2997		/* copy btwn flag space and NULL char */
2998		if (flags != 0)
2999			p += snprintf(p, 2, " ");
3000	}
3001
3002	/* indicate the str was too short */
3003	if (flags != 0) {
3004		if (len < 2)
3005			p -= 2 - len;	/* overwrite last char */
3006		p += snprintf(p, 2, ">");
3007	}
3008
3009	return (int)(p - buf);
3010}
3011
3012/* print bytes formatted as hex to a string. return the resulting string length */
3013int
3014bcm_format_hex(char *str, const void *bytes, int len)
3015{
3016	int i;
3017	char *p = str;
3018	const uint8 *src = (const uint8*)bytes;
3019
3020	for (i = 0; i < len; i++) {
3021		p += snprintf(p, 3, "%02X", *src);
3022		src++;
3023	}
3024	return (int)(p - str);
3025}
3026#endif
3027
3028/* pretty hex print a contiguous buffer */
3029void
3030prhex(const char *msg, uchar *buf, uint nbytes)
3031{
3032	char line[128], *p;
3033	int len = sizeof(line);
3034	int nchar;
3035	uint i;
3036
3037	if (msg && (msg[0] != '\0'))
3038		printf("%s:\n", msg);
3039
3040	p = line;
3041	for (i = 0; i < nbytes; i++) {
3042		if (i % 16 == 0) {
3043			nchar = snprintf(p, len, "  %04d: ", i);	/* line prefix */
3044			p += nchar;
3045			len -= nchar;
3046		}
3047		if (len > 0) {
3048			nchar = snprintf(p, len, "%02x ", buf[i]);
3049			p += nchar;
3050			len -= nchar;
3051		}
3052
3053		if (i % 16 == 15) {
3054			printf("%s\n", line);		/* flush line */
3055			p = line;
3056			len = sizeof(line);
3057		}
3058	}
3059
3060	/* flush last partial line */
3061	if (p != line)
3062		printf("%s\n", line);
3063}
3064
3065static const char *crypto_algo_names[] = {
3066	"NONE",
3067	"WEP1",
3068	"TKIP",
3069	"WEP128",
3070	"AES_CCM",
3071	"AES_OCB_MSDU",
3072	"AES_OCB_MPDU",
3073	"NALG"
3074	"UNDEF",
3075	"UNDEF",
3076	"UNDEF",
3077	"UNDEF"
3078};
3079
3080const char *
3081bcm_crypto_algo_name(uint algo)
3082{
3083	return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
3084}
3085
3086
3087char *
3088bcm_chipname(uint chipid, char *buf, uint len)
3089{
3090	const char *fmt;
3091
3092	fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
3093	snprintf(buf, len, fmt, chipid);
3094	return buf;
3095}
3096
3097/* Produce a human-readable string for boardrev */
3098char *
3099bcm_brev_str(uint32 brev, char *buf)
3100{
3101	if (brev < 0x100)
3102		snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
3103	else
3104		snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
3105
3106	return (buf);
3107}
3108
3109#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
3110
3111/* dump large strings to console */
3112void
3113printbig(char *buf)
3114{
3115	uint len, max_len;
3116	char c;
3117
3118	len = strlen(buf);
3119
3120	max_len = BUFSIZE_TODUMP_ATONCE;
3121
3122	while (len > max_len) {
3123		c = buf[max_len];
3124		buf[max_len] = '\0';
3125		printf("%s", buf);
3126		buf[max_len] = c;
3127
3128		buf += max_len;
3129		len -= max_len;
3130	}
3131	/* print the remaining string */
3132	printf("%s\n", buf);
3133	return;
3134}
3135
3136/* routine to dump fields in a fileddesc structure */
3137uint
3138bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
3139	char *buf, uint32 bufsize)
3140{
3141	uint  filled_len;
3142	int len;
3143	struct fielddesc *cur_ptr;
3144
3145	filled_len = 0;
3146	cur_ptr = fielddesc_array;
3147
3148	while (bufsize > 1) {
3149		if (cur_ptr->nameandfmt == NULL)
3150			break;
3151		len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
3152		               read_rtn(arg0, arg1, cur_ptr->offset));
3153		/* check for snprintf overflow or error */
3154		if (len < 0 || (uint32)len >= bufsize)
3155			len = bufsize - 1;
3156		buf += len;
3157		bufsize -= len;
3158		filled_len += len;
3159		cur_ptr++;
3160	}
3161	return filled_len;
3162}
3163
3164uint
3165bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
3166{
3167	uint len;
3168
3169	len = strlen(name) + 1;
3170
3171	if ((len + datalen) > buflen)
3172		return 0;
3173
3174	strncpy(buf, name, buflen);
3175
3176	/* append data onto the end of the name string */
3177	memcpy(&buf[len], data, datalen);
3178	len += datalen;
3179
3180	return len;
3181}
3182
3183/* Quarter dBm units to mW
3184 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
3185 * Table is offset so the last entry is largest mW value that fits in
3186 * a uint16.
3187 */
3188
3189#define QDBM_OFFSET 153		/* Offset for first entry */
3190#define QDBM_TABLE_LEN 40	/* Table size */
3191
3192/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
3193 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
3194 */
3195#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
3196
3197/* Largest mW value that will round down to the last table entry,
3198 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
3199 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
3200 */
3201#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
3202
3203static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
3204/* qdBm: 	+0 	+1 	+2 	+3 	+4 	+5 	+6 	+7 */
3205/* 153: */      6683,	7079,	7499,	7943,	8414,	8913,	9441,	10000,
3206/* 161: */      10593,	11220,	11885,	12589,	13335,	14125,	14962,	15849,
3207/* 169: */      16788,	17783,	18836,	19953,	21135,	22387,	23714,	25119,
3208/* 177: */      26607,	28184,	29854,	31623,	33497,	35481,	37584,	39811,
3209/* 185: */      42170,	44668,	47315,	50119,	53088,	56234,	59566,	63096
3210};
3211
3212uint16
3213BCMROMFN(bcm_qdbm_to_mw)(uint8 qdbm)
3214{
3215	uint factor = 1;
3216	int idx = qdbm - QDBM_OFFSET;
3217
3218	if (idx >= QDBM_TABLE_LEN) {
3219		/* clamp to max uint16 mW value */
3220		return 0xFFFF;
3221	}
3222
3223	/* scale the qdBm index up to the range of the table 0-40
3224	 * where an offset of 40 qdBm equals a factor of 10 mW.
3225	 */
3226	while (idx < 0) {
3227		idx += 40;
3228		factor *= 10;
3229	}
3230
3231	/* return the mW value scaled down to the correct factor of 10,
3232	 * adding in factor/2 to get proper rounding.
3233	 */
3234	return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
3235}
3236
3237uint8
3238BCMROMFN(bcm_mw_to_qdbm)(uint16 mw)
3239{
3240	uint8 qdbm;
3241	int offset;
3242	uint mw_uint = mw;
3243	uint boundary;
3244
3245	/* handle boundary case */
3246	if (mw_uint <= 1)
3247		return 0;
3248
3249	offset = QDBM_OFFSET;
3250
3251	/* move mw into the range of the table */
3252	while (mw_uint < QDBM_TABLE_LOW_BOUND) {
3253		mw_uint *= 10;
3254		offset -= 40;
3255	}
3256
3257	for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
3258		boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
3259		                                    nqdBm_to_mW_map[qdbm])/2;
3260		if (mw_uint < boundary) break;
3261	}
3262
3263	qdbm += (uint8)offset;
3264
3265	return (qdbm);
3266}
3267
3268
3269uint
3270BCMROMFN(bcm_bitcount)(uint8 *bitmap, uint length)
3271{
3272	uint bitcount = 0, i;
3273	uint8 tmp;
3274	for (i = 0; i < length; i++) {
3275		tmp = bitmap[i];
3276		while (tmp) {
3277			bitcount++;
3278			tmp &= (tmp - 1);
3279		}
3280	}
3281	return bitcount;
3282}
3283
3284#ifdef BCMDRIVER
3285
3286/* Initialization of bcmstrbuf structure */
3287void
3288bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
3289{
3290	b->origsize = b->size = size;
3291	b->origbuf = b->buf = buf;
3292}
3293
3294/* Buffer sprintf wrapper to guard against buffer overflow */
3295int
3296bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
3297{
3298	va_list ap;
3299	int r;
3300
3301	va_start(ap, fmt);
3302
3303	r = vsnprintf(b->buf, b->size, fmt, ap);
3304
3305	/* Non Ansi C99 compliant returns -1,
3306	 * Ansi compliant return r >= b->size,
3307	 * bcmstdlib returns 0, handle all
3308	 */
3309	/* r == 0 is also the case when strlen(fmt) is zero.
3310	 * typically the case when "" is passed as argument.
3311	 */
3312	if ((r == -1) || (r >= (int)b->size)) {
3313		b->size = 0;
3314	} else {
3315		b->size -= r;
3316		b->buf += r;
3317	}
3318
3319	va_end(ap);
3320
3321	return r;
3322}
3323
3324void
3325bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len)
3326{
3327	int i;
3328
3329	if (msg != NULL && msg[0] != '\0')
3330		bcm_bprintf(b, "%s", msg);
3331	for (i = 0; i < len; i ++)
3332		bcm_bprintf(b, "%02X", buf[i]);
3333	if (newline)
3334		bcm_bprintf(b, "\n");
3335}
3336
3337void
3338bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
3339{
3340	int i;
3341
3342	for (i = 0; i < num_bytes; i++) {
3343		num[i] += amount;
3344		if (num[i] >= amount)
3345			break;
3346		amount = 1;
3347	}
3348}
3349
3350int
3351bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes)
3352{
3353	int i;
3354
3355	for (i = nbytes - 1; i >= 0; i--) {
3356		if (arg1[i] != arg2[i])
3357			return (arg1[i] - arg2[i]);
3358	}
3359	return 0;
3360}
3361
3362void
3363bcm_print_bytes(const char *name, const uchar *data, int len)
3364{
3365	int i;
3366	int per_line = 0;
3367
3368	printf("%s: %d \n", name ? name : "", len);
3369	for (i = 0; i < len; i++) {
3370		printf("%02x ", *data++);
3371		per_line++;
3372		if (per_line == 16) {
3373			per_line = 0;
3374			printf("\n");
3375		}
3376	}
3377	printf("\n");
3378}
3379#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
3380	defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
3381#define SSID_FMT_BUF_LEN	((4 * DOT11_MAX_SSID_LEN) + 1)
3382
3383int
3384bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
3385{
3386	uint i, c;
3387	char *p = buf;
3388	char *endp = buf + SSID_FMT_BUF_LEN;
3389
3390	if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
3391
3392	for (i = 0; i < ssid_len; i++) {
3393		c = (uint)ssid[i];
3394		if (c == '\\') {
3395			*p++ = '\\';
3396			*p++ = '\\';
3397		} else if (bcm_isprint((uchar)c)) {
3398			*p++ = (char)c;
3399		} else {
3400			p += snprintf(p, (endp - p), "\\x%02X", c);
3401		}
3402	}
3403	*p = '\0';
3404	ASSERT(p < endp);
3405
3406	return (int)(p - buf);
3407}
3408#endif
3409
3410#endif /* BCMDRIVER */
3411
3412/*
3413 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
3414 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
3415 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
3416 * Shortens buffer as needed and pads with NULs.  End of buffer is marked by two NULs.
3417*/
3418
3419unsigned int
3420process_nvram_vars(char *varbuf, unsigned int len)
3421{
3422	char *dp;
3423	bool findNewline;
3424	int column;
3425	unsigned int buf_len, n;
3426	unsigned int pad = 0;
3427
3428	dp = varbuf;
3429
3430	findNewline = FALSE;
3431	column = 0;
3432
3433	for (n = 0; n < len; n++) {
3434		if (varbuf[n] == '\r')
3435			continue;
3436		if (findNewline && varbuf[n] != '\n')
3437			continue;
3438		findNewline = FALSE;
3439		if (varbuf[n] == '#') {
3440			findNewline = TRUE;
3441			continue;
3442		}
3443		if (varbuf[n] == '\n') {
3444			if (column == 0)
3445				continue;
3446			*dp++ = 0;
3447			column = 0;
3448			continue;
3449		}
3450		*dp++ = varbuf[n];
3451		column++;
3452	}
3453	buf_len = (unsigned int)(dp - varbuf);
3454	if (buf_len % 4) {
3455		pad = 4 - buf_len % 4;
3456		if (pad && (buf_len + pad <= len)) {
3457			buf_len += pad;
3458		}
3459	}
3460
3461	while (dp < varbuf + n)
3462		*dp++ = 0;
3463
3464	return buf_len;
3465}
3466
3467/* calculate a * b + c */
3468void
3469bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c)
3470{
3471#define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;}
3472	uint32 r1, r0;
3473	uint32 a1, a0, b1, b0, t, cc = 0;
3474
3475	a1 = a >> 16;
3476	a0 = a & 0xffff;
3477	b1 = b >> 16;
3478	b0 = b & 0xffff;
3479
3480	r0 = a0 * b0;
3481	FORMALIZE(r0);
3482
3483	t = (a1 * b0) << 16;
3484	FORMALIZE(t);
3485
3486	r0 += t;
3487	FORMALIZE(r0);
3488
3489	t = (a0 * b1) << 16;
3490	FORMALIZE(t);
3491
3492	r0 += t;
3493	FORMALIZE(r0);
3494
3495	FORMALIZE(c);
3496
3497	r0 += c;
3498	FORMALIZE(r0);
3499
3500	r0 |= (cc % 2) ? 0x80000000 : 0;
3501	r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2);
3502
3503	*r_high = r1;
3504	*r_low = r0;
3505}
3506
3507/* calculate a / b */
3508void
3509bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
3510{
3511	uint32 a1 = a_high, a0 = a_low, r0 = 0;
3512
3513	if (b < 2)
3514		return;
3515
3516	while (a1 != 0) {
3517		r0 += (0xffffffff / b) * a1;
3518		bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0);
3519	}
3520
3521	r0 += a0 / b;
3522	*r = r0;
3523}
3524
3525/* calculate a >> b; and returns only lower 32 bits */
3526void
3527bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b)
3528{
3529	uint32 a1 = a_high, a0 = a_low, r0 = 0;
3530
3531	if (b == 0) {
3532		r0 = a_low;
3533		*r = r0;
3534		return;
3535	}
3536
3537	if (b < 32) {
3538		a0 = a0 >> b;
3539		a1 = a1 & ((1 << b) - 1);
3540		a1 = a1 << (32 - b);
3541		r0 = a0 | a1;
3542		*r = r0;
3543		return;
3544	} else {
3545		r0 = a1 >> (b - 32);
3546		*r = r0;
3547		return;
3548	}
3549
3550}
3551