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