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