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