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>
50 void *_bcmutils_dummy_fn = NULL;
51 
52 
53 #ifdef BCMDRIVER
54 
55 
56 
57 /* copy a pkt buffer chain into a buffer */
58 uint
pktcopy(osl_t * osh,void * p,uint offset,int len,uchar * buf)59 pktcopy(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 */
90 uint
pktfrombuf(osl_t * osh,void * p,uint offset,int len,uchar * buf)91 pktfrombuf(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 */
121 uint BCMFASTPATH
pkttotlen(osl_t * osh,void * p)122 pkttotlen(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 */
137 void *
pktlast(osl_t * osh,void * p)138 pktlast(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 */
147 uint BCMFASTPATH
pktsegcnt(osl_t * osh,void * p)148 pktsegcnt(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 */
160 uint BCMFASTPATH
pktsegcnt_war(osl_t * osh,void * p)161 pktsegcnt_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 
189 uint8 * BCMFASTPATH
pktdataoffset(osl_t * osh,void * p,uint offset)190 pktdataoffset(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 */
211 void *
pktoffset(osl_t * osh,void * p,uint offset)212 pktoffset(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  */
232 void * BCMFASTPATH
pktq_penq(struct pktq * pq,int prec,void * p)233 pktq_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 
261 void * BCMFASTPATH
pktq_penq_head(struct pktq * pq,int prec,void * p)262 pktq_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 
289 void * BCMFASTPATH
pktq_pdeq(struct pktq * pq,int prec)290 pktq_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 
314 void * BCMFASTPATH
pktq_pdeq_prev(struct pktq * pq,int prec,void * prev_p)315 pktq_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 
340 void * BCMFASTPATH
pktq_pdeq_with_fn(struct pktq * pq,int prec,ifpkt_cb_t fn,int arg)341 pktq_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 
378 void * BCMFASTPATH
pktq_pdeq_tail(struct pktq * pq,int prec)379 pktq_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 
407 void
pktq_pflush(osl_t * osh,struct pktq * pq,int prec,bool dir,ifpkt_cb_t fn,int arg)408 pktq_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 
439 bool BCMFASTPATH
pktq_pdel(struct pktq * pq,void * pktbuf,int prec)440 pktq_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 
472 void
pktq_init(struct pktq * pq,int num_prec,int max_len)473 pktq_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 
490 void
pktq_set_max_plen(struct pktq * pq,int prec,int max_len)491 pktq_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 
499 void * BCMFASTPATH
pktq_deq(struct pktq * pq,int * prec_out)500 pktq_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 
532 void * BCMFASTPATH
pktq_deq_tail(struct pktq * pq,int * prec_out)533 pktq_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 
572 void *
pktq_peek(struct pktq * pq,int * prec_out)573 pktq_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 
589 void *
pktq_peek_tail(struct pktq * pq,int * prec_out)590 pktq_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 
607 void
pktq_flush(osl_t * osh,struct pktq * pq,bool dir,ifpkt_cb_t fn,int arg)608 pktq_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 */
626 int
pktq_mlen(struct pktq * pq,uint prec_bmp)627 pktq_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 */
641 void * BCMFASTPATH
pktq_mpeek(struct pktq * pq,uint prec_bmp,int * prec_out)642 pktq_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 */
670 void * BCMFASTPATH
pktq_mdeq(struct pktq * pq,uint prec_bmp,int * prec_out)671 pktq_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)
710 const 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 
747 ulong
bcm_strtoul(const char * cp,char ** endp,uint base)748 bcm_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 
801 int
bcm_atoi(const char * s)802 bcm_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' */
808 char *
bcmstrstr(const char * haystack,const char * needle)809 bcmstrstr(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 
826 char *
bcmstrcat(char * dest,const char * src)827 bcmstrcat(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 
839 char *
bcmstrncat(char * dest,const char * src,uint size)840 bcmstrncat(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 */
874 char *
bcmstrtok(char ** string,const char * delimiters,char * tokdelim)875 bcmstrtok(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 */
952 int
bcmstricmp(const char * s1,const char * s2)953 bcmstricmp(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 */
986 int
bcmstrnicmp(const char * s1,const char * s2,int cnt)987 bcmstrnicmp(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 */
1008 int
bcm_ether_atoe(const char * p,struct ether_addr * ea)1009 bcm_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  */
1031 ulong
wchar2ascii(char * abuf,ushort * wbuf,ushort wbuflen,ulong abuflen)1032 wchar2ascii(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 
1055 char *
bcm_ether_ntoa(const struct ether_addr * ea,char * buf)1056 bcm_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 
1078 char *
bcm_ip_ntoa(struct ipv4_addr * ia,char * buf)1079 bcm_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 
1088 void
bcm_mdelay(uint ms)1089 bcm_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 */
1104 void
prpkt(const char * msg,osl_t * osh,void * p0)1105 prpkt(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  */
1121 uint BCMFASTPATH
pktsetprio(void * pkt,bool update_vtag)1122 pktsetprio(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 
1184 static char bcm_undeferrstr[32];
1185 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
1186 
1187 /* Convert the error codes into related error strings  */
1188 const char *
bcmerrorstr(int bcmerror)1189 bcmerrorstr(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 */
1207 const bcm_iovar_t*
bcm_iovar_lookup(const bcm_iovar_t * table,const char * name)1208 bcm_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 
1231 int
bcm_iovar_lencheck(const bcm_iovar_t * vi,void * arg,int len,bool set)1232 bcm_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 
1303 static 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 
1341 uint8
hndcrc8(uint8 * pdata,uint nbytes,uint8 crc)1342 hndcrc8(
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 
1379 static 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 
1414 uint16
hndcrc16(uint8 * pdata,uint nbytes,uint16 crc)1415 hndcrc16(
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 
1426 static 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  */
1497 uint32
hndcrc32(uint8 * pdata,uint nbytes,uint32 crc)1498 hndcrc32(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 
1513 void
testcrc32(void)1514 testcrc32(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  */
1552 bcm_tlv_t *
bcm_next_tlv(bcm_tlv_t * elt,int * buflen)1553 bcm_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  */
1578 bcm_tlv_t *
bcm_parse_tlvs(void * buf,int buflen,uint key)1579 bcm_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  */
1609 bcm_tlv_t *
bcm_parse_ordered_tlvs(void * buf,int buflen,uint key)1610 bcm_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)
1641 int
bcm_format_field(const bcm_bit_desc_ex_t * bd,uint32 flags,char * buf,int len)1642 bcm_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 
1666 int
bcm_format_flags(const bcm_bit_desc_t * bd,uint32 flags,char * buf,int len)1667 bcm_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 */
1719 int
bcm_format_hex(char * str,const void * bytes,int len)1720 bcm_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 */
1735 void
prhex(const char * msg,uchar * buf,uint nbytes)1736 prhex(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 
1771 static 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 
1786 const char *
bcm_crypto_algo_name(uint algo)1787 bcm_crypto_algo_name(uint algo)
1788 {
1789 	return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
1790 }
1791 
1792 
1793 char *
bcm_chipname(uint chipid,char * buf,uint len)1794 bcm_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 */
1804 char *
bcm_brev_str(uint32 brev,char * buf)1805 bcm_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 */
1818 void
printbig(char * buf)1819 printbig(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 */
1843 uint
bcmdumpfields(bcmutl_rdreg_rtn read_rtn,void * arg0,uint arg1,struct fielddesc * fielddesc_array,char * buf,uint32 bufsize)1844 bcmdumpfields(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 
1870 uint
bcm_mkiovar(char * name,char * data,uint datalen,char * buf,uint buflen)1871 bcm_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 
1909 static 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 
1918 uint16
bcm_qdbm_to_mw(uint8 qdbm)1919 bcm_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 
1943 uint8
bcm_mw_to_qdbm(uint16 mw)1944 bcm_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 
1975 uint
bcm_bitcount(uint8 * bitmap,uint length)1976 bcm_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 */
1993 void
bcm_binit(struct bcmstrbuf * b,char * buf,uint size)1994 bcm_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 */
2001 int
bcm_bprintf(struct bcmstrbuf * b,const char * fmt,...)2002 bcm_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 
2030 void
bcm_bprhex(struct bcmstrbuf * b,const char * msg,bool newline,uint8 * buf,int len)2031 bcm_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 
2043 void
bcm_inc_bytes(uchar * num,int num_bytes,uint8 amount)2044 bcm_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 
2056 int
bcm_cmp_bytes(const uchar * arg1,const uchar * arg2,uint8 nbytes)2057 bcm_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 
2068 void
bcm_print_bytes(const char * name,const uchar * data,int len)2069 bcm_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 */
2087 bcm_tlv_t *
find_vendor_ie(void * tlvs,int tlvs_len,const char * voui,uint8 * type,int type_len)2088 find_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 
2122 int
bcm_format_ssid(char * buf,const uchar ssid[],uint ssid_len)2123 bcm_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 
2158 unsigned int
process_nvram_vars(char * varbuf,unsigned int len)2159 process_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 */
2207 void
bcm_uint64_multiple_add(uint32 * r_high,uint32 * r_low,uint32 a,uint32 b,uint32 c)2208 bcm_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 */
2247 void
bcm_uint64_divide(uint32 * r,uint32 a_high,uint32 a_low,uint32 b)2248 bcm_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. */
2267 void
setbit(void * array,uint bit)2268 setbit(void *array, uint bit)
2269 {
2270 	((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY);
2271 }
2272 
2273 /* Clear bit in byte array. */
2274 void
clrbit(void * array,uint bit)2275 clrbit(void *array, uint bit)
2276 {
2277 	((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY));
2278 }
2279 
2280 /* Test if bit is set in byte array. */
2281 bool
isset(const void * array,uint bit)2282 isset(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. */
2288 bool
isclr(const void * array,uint bit)2289 isclr(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