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