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