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