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