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