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 */ 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