PageRenderTime 144ms CodeModel.GetById 42ms app.highlight 87ms RepoModel.GetById 0ms app.codeStats 1ms

/drivers/net/wireless/bcm4329/bcmutils.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t
C | 1838 lines | 1260 code | 330 blank | 248 comment | 321 complexity | ac1fadb9fd973ee1e14c43798345cefa MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
   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.19 2010/04/26 06:05:25 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 */
  55uint
  56pktcopy(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 */
  87uint
  88pktfrombuf(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 */
 118uint
 119pkttotlen(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 */
 130void *
 131pktlast(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 */
 140uint
 141pktsegcnt(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 */
 156void *
 157pktq_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
 185void *
 186pktq_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
 213void *
 214pktq_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
 238void *
 239pktq_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
 267void
 268pktq_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
 287bool
 288pktq_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
 320void
 321pktq_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
 338void *
 339pktq_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
 371void *
 372pktq_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
 411void *
 412pktq_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
 428void *
 429pktq_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
 446void
 447pktq_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 */
 456int
 457pktq_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 */
 471void *
 472pktq_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
 511const 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
 547ulong
 548bcm_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
 601int
 602bcm_atoi(char *s)
 603{
 604	return (int)bcm_strtoul(s, NULL, 10);
 605}
 606
 607/* return pointer to location of substring 'needle' in 'haystack' */
 608char*
 609bcmstrstr(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
 626char*
 627bcmstrcat(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
 639char*
 640bcmstrncat(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*/
 674char *
 675bcmstrtok(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*/
 752int
 753bcmstricmp(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*/
 786int
 787bcmstrnicmp(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 */
 808int
 809bcm_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 */
 828ulong
 829wchar2ascii(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
 852char *
 853bcm_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
 862char *
 863bcm_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
 872void
 873bcm_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 */
 889void
 890prpkt(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 */
 906uint
 907pktsetprio(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
 968static char bcm_undeferrstr[BCME_STRLEN];
 969
 970static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
 971
 972/* Convert the error codes into related error strings  */
 973const char *
 974bcmerrorstr(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 */
 992const bcm_iovar_t*
 993bcm_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
1016int
1017bcm_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@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1081 *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1082 *
1083 * ****************************************************************************
1084 */
1085
1086STATIC 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
1124uint8
1125hndcrc8(
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@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1157 *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1158 *
1159 * ****************************************************************************
1160 */
1161
1162static 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
1197uint16
1198hndcrc16(
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
1209STATIC 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
1276uint32
1277hndcrc32(
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
1323void 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 */
1361bcm_tlv_t *
1362bcm_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 */
1387bcm_tlv_t *
1388bcm_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 */
1417bcm_tlv_t *
1418bcm_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)
1447int
1448bcm_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 */
1495int
1496bcm_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 */
1510void
1511prhex(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 */
1539char *
1540bcm_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 */
1553void
1554printbig(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 */
1578uint
1579bcmdumpfields(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
1605uint
1606bcm_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
1644static 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
1653uint16
1654bcm_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
1678uint8
1679bcm_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
1710uint
1711bcm_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 */
1728void
1729bcm_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 */
1736int
1737bcm_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
1761void
1762bcm_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
1774int
1775bcm_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
1786void
1787bcm_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)
1811int
1812bcm_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 */