1/* 2 * Driver O/S-independent utility routines 3 * 4 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved. 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 * $Id: bcmutils.c 401759 2013-05-13 16:08:08Z $ 18 */ 19 20#include <bcm_cfg.h> 21#include <typedefs.h> 22#include <bcmdefs.h> 23#if defined(__FreeBSD__) || defined(__NetBSD__) 24#include <sys/param.h> 25#if __NetBSD_Version__ >= 500000003 26#include <sys/stdarg.h> 27#else 28#include <machine/stdarg.h> 29#endif 30#else 31#include <stdarg.h> 32#endif /* NetBSD */ 33#ifdef BCMDRIVER 34 35#include <osl.h> 36#include <bcmutils.h> 37#include <siutils.h> 38#include <bcmnvram.h> 39 40#else /* !BCMDRIVER */ 41 42#include <stdio.h> 43#include <string.h> 44#include <bcmutils.h> 45 46#if defined(BCMEXTSUP) 47#include <bcm_osl.h> 48#endif 49 50 51#endif /* !BCMDRIVER */ 52 53#if defined(_WIN32) || defined(NDIS) || defined(__vxworks) || defined(_CFE_) 54#include <bcmstdlib.h> 55#endif 56#include <bcmendian.h> 57#include <bcmdevs.h> 58#include <proto/ethernet.h> 59#include <proto/vlan.h> 60#include <proto/bcmip.h> 61#include <proto/802.1d.h> 62#include <proto/802.11.h> 63#ifdef BCMPERFSTATS 64#include <bcmperf.h> 65#endif 66#include <proto/bcmipv6.h> 67void *_bcmutils_dummy_fn = NULL; 68 69#ifdef BCMDRIVER 70 71#ifdef WLC_LOW 72/* nvram vars cache */ 73static char *nvram_vars = NULL; 74static int vars_len = -1; 75#endif /* WLC_LOW */ 76 77int 78BCMATTACHFN(pktpool_init)(osl_t *osh, pktpool_t *pktp, int *pplen, int plen, bool istx) 79{ 80 int i, err = BCME_OK; 81 void *p; 82 int pktplen; 83 84 ASSERT(pktp != NULL); 85 ASSERT(osh != NULL); 86 ASSERT(pplen != NULL); 87 88 pktplen = *pplen; 89 90 bzero(pktp, sizeof(pktpool_t)); 91 pktp->inited = TRUE; 92 pktp->istx = istx ? TRUE : FALSE; 93 pktp->plen = (uint16)plen; 94 *pplen = 0; 95 96 pktp->maxlen = PKTPOOL_LEN_MAX; 97 if (pktplen > pktp->maxlen) 98 pktplen = pktp->maxlen; 99 100 for (i = 0; i < pktplen; i++) { 101 p = PKTGET(osh, plen, pktp->istx); 102 if (p == NULL) { 103 /* Not able to allocate all requested pkts 104 * so just return what was actually allocated 105 * We can add to the pool later 106 */ 107 if (pktp->w == 0) 108 err = BCME_NOMEM; 109 110 goto exit; 111 } 112 113 PKTSETPOOL(osh, p, TRUE, pktp); 114 pktp->q[i] = p; 115 pktp->w++; 116 pktp->len++; 117#ifdef BCMDBG_POOL 118 pktp->dbg_q[pktp->dbg_qlen++].p = p; 119#endif 120 } 121 122exit: 123 *pplen = pktp->w; 124 pktp->len++; /* Add one for end */ 125 return err; 126} 127 128int 129BCMATTACHFN(pktpool_deinit)(osl_t *osh, pktpool_t *pktp) 130{ 131 int i; 132 int cnt; 133 134 ASSERT(osh != NULL); 135 ASSERT(pktp != NULL); 136 137 cnt = pktp->len; 138 for (i = 0; i < cnt; i++) { 139 if (pktp->q[i] != NULL) { 140 PKTSETPOOL(osh, pktp->q[i], FALSE, NULL); 141 PKTFREE(osh, pktp->q[i], pktp->istx); 142 pktp->q[i] = NULL; 143 pktp->len--; 144 } 145#ifdef BCMDBG_POOL 146 if (pktp->dbg_q[i].p != NULL) 147 pktp->dbg_q[i].p = NULL; 148#endif 149 } 150 pktp->inited = FALSE; 151 152 /* Are there still pending pkts? */ 153 ASSERT(pktpool_len(pktp) == 0); 154 155 return 0; 156} 157 158int 159pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal) 160{ 161 void *p; 162 int err = 0; 163 int len, psize, maxlen; 164 165 ASSERT(pktpool_plen(pktp) != 0); 166 167 maxlen = pktpool_maxlen(pktp); 168 psize = minimal ? (maxlen >> 2) : maxlen; 169 len = pktpool_len(pktp); 170 for (; len < psize; len++) { 171 p = PKTGET(osh, pktpool_plen(pktp), FALSE); 172 if (p == NULL) { 173 err = BCME_NOMEM; 174 break; 175 } 176 177 if (pktpool_add(pktp, p) != BCME_OK) { 178 PKTFREE(osh, p, FALSE); 179 err = BCME_ERROR; 180 break; 181 } 182 } 183 184 return err; 185} 186 187uint16 188pktpool_avail(pktpool_t *pktp) 189{ 190 if (pktp->w == pktp->r) 191 return 0; 192 193 return (pktp->w > pktp->r) ? (pktp->w - pktp->r) : ((pktp->len) - (pktp->r - pktp->w)); 194} 195 196static void * 197pktpool_deq(pktpool_t *pktp) 198{ 199 void *p; 200 201 if (pktp->r == pktp->w) 202 return NULL; 203 204 p = pktp->q[pktp->r]; 205 ASSERT(p != NULL); 206 207 pktp->q[pktp->r++] = NULL; 208 pktp->r %= (pktp->len); 209 210 return p; 211} 212 213static void 214pktpool_enq(pktpool_t *pktp, void *p) 215{ 216 uint16 next; 217 218 ASSERT(p != NULL); 219 220 next = (pktp->w + 1) % (pktp->len); 221 if (next == pktp->r) { 222 /* Should not happen; otherwise pkt leak */ 223 ASSERT(0); 224 return; 225 } 226 227 ASSERT(pktp->q[pktp->w] == NULL); 228 229#ifdef BCMDBG_ASSERT 230 if (pktpool_avail(pktp)) { 231 int prev = (pktp->w == 0) ? (pktp->len - 1) : (pktp->w - 1); 232 ASSERT(pktp->q[prev] != p); 233 } 234#endif 235 pktp->q[pktp->w] = p; 236 pktp->w = next; 237} 238 239int 240BCMATTACHFN(pktpool_avail_register)(pktpool_t *pktp, pktpool_cb_t cb, void *arg) 241{ 242 int i; 243 244 ASSERT(cb != NULL); 245 246 i = pktp->cbcnt; 247 if (i == PKTPOOL_CB_MAX) 248 return BCME_ERROR; 249 250 ASSERT(pktp->cbs[i].cb == NULL); 251 pktp->cbs[i].cb = cb; 252 pktp->cbs[i].arg = arg; 253 pktp->cbcnt++; 254 255 return 0; 256} 257 258int 259BCMATTACHFN(pktpool_empty_register)(pktpool_t *pktp, pktpool_cb_t cb, void *arg) 260{ 261 int i; 262 263 ASSERT(cb != NULL); 264 265 i = pktp->ecbcnt; 266 if (i == PKTPOOL_CB_MAX) 267 return BCME_ERROR; 268 269 ASSERT(pktp->ecbs[i].cb == NULL); 270 pktp->ecbs[i].cb = cb; 271 pktp->ecbs[i].arg = arg; 272 pktp->ecbcnt++; 273 274 return 0; 275} 276 277static int 278pktpool_empty_notify(pktpool_t *pktp) 279{ 280 int i; 281 282 pktp->empty = TRUE; 283 for (i = 0; i < pktp->ecbcnt; i++) { 284 ASSERT(pktp->ecbs[i].cb != NULL); 285 pktp->ecbs[i].cb(pktp, pktp->ecbs[i].arg); 286 } 287 pktp->empty = FALSE; 288 289 return 0; 290} 291 292#ifdef BCMDBG_POOL 293int 294pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg) 295{ 296 int i; 297 298 ASSERT(cb); 299 300 i = pktp->dbg_cbcnt; 301 if (i == PKTPOOL_CB_MAX) 302 return BCME_ERROR; 303 304 ASSERT(pktp->dbg_cbs[i].cb == NULL); 305 pktp->dbg_cbs[i].cb = cb; 306 pktp->dbg_cbs[i].arg = arg; 307 pktp->dbg_cbcnt++; 308 309 return 0; 310} 311 312int pktpool_dbg_notify(pktpool_t *pktp); 313 314int 315pktpool_dbg_notify(pktpool_t *pktp) 316{ 317 int i; 318 319 for (i = 0; i < pktp->dbg_cbcnt; i++) { 320 ASSERT(pktp->dbg_cbs[i].cb); 321 pktp->dbg_cbs[i].cb(pktp, pktp->dbg_cbs[i].arg); 322 } 323 324 return 0; 325} 326 327int 328pktpool_dbg_dump(pktpool_t *pktp) 329{ 330 int i; 331 332 printf("pool len=%d maxlen=%d\n", pktp->dbg_qlen, pktp->maxlen); 333 for (i = 0; i < pktp->dbg_qlen; i++) { 334 ASSERT(pktp->dbg_q[i].p); 335 printf("%d, p: 0x%x dur:%lu us state:%d\n", i, 336 pktp->dbg_q[i].p, pktp->dbg_q[i].dur/100, PKTPOOLSTATE(pktp->dbg_q[i].p)); 337 } 338 339 return 0; 340} 341 342int 343pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats) 344{ 345 int i; 346 int state; 347 348 bzero(stats, sizeof(pktpool_stats_t)); 349 for (i = 0; i < pktp->dbg_qlen; i++) { 350 ASSERT(pktp->dbg_q[i].p != NULL); 351 352 state = PKTPOOLSTATE(pktp->dbg_q[i].p); 353 switch (state) { 354 case POOL_TXENQ: 355 stats->enq++; break; 356 case POOL_TXDH: 357 stats->txdh++; break; 358 case POOL_TXD11: 359 stats->txd11++; break; 360 case POOL_RXDH: 361 stats->rxdh++; break; 362 case POOL_RXD11: 363 stats->rxd11++; break; 364 case POOL_RXFILL: 365 stats->rxfill++; break; 366 case POOL_IDLE: 367 stats->idle++; break; 368 } 369 } 370 371 return 0; 372} 373 374int 375pktpool_start_trigger(pktpool_t *pktp, void *p) 376{ 377 uint32 cycles, i; 378 379 if (!PKTPOOL(NULL, p)) 380 return 0; 381 382 OSL_GETCYCLES(cycles); 383 384 for (i = 0; i < pktp->dbg_qlen; i++) { 385 ASSERT(pktp->dbg_q[i].p != NULL); 386 387 if (pktp->dbg_q[i].p == p) { 388 pktp->dbg_q[i].cycles = cycles; 389 break; 390 } 391 } 392 393 return 0; 394} 395 396int pktpool_stop_trigger(pktpool_t *pktp, void *p); 397int 398pktpool_stop_trigger(pktpool_t *pktp, void *p) 399{ 400 uint32 cycles, i; 401 402 if (!PKTPOOL(NULL, p)) 403 return 0; 404 405 OSL_GETCYCLES(cycles); 406 407 for (i = 0; i < pktp->dbg_qlen; i++) { 408 ASSERT(pktp->dbg_q[i].p != NULL); 409 410 if (pktp->dbg_q[i].p == p) { 411 if (pktp->dbg_q[i].cycles == 0) 412 break; 413 414 if (cycles >= pktp->dbg_q[i].cycles) 415 pktp->dbg_q[i].dur = cycles - pktp->dbg_q[i].cycles; 416 else 417 pktp->dbg_q[i].dur = 418 (((uint32)-1) - pktp->dbg_q[i].cycles) + cycles + 1; 419 420 pktp->dbg_q[i].cycles = 0; 421 break; 422 } 423 } 424 425 return 0; 426} 427#endif /* BCMDBG_POOL */ 428 429int 430pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp) 431{ 432 ASSERT(pktp); 433 pktp->availcb_excl = NULL; 434 return 0; 435} 436 437int 438pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb) 439{ 440 int i; 441 442 ASSERT(pktp); 443 ASSERT(pktp->availcb_excl == NULL); 444 for (i = 0; i < pktp->cbcnt; i++) { 445 if (cb == pktp->cbs[i].cb) { 446 pktp->availcb_excl = &pktp->cbs[i]; 447 break; 448 } 449 } 450 451 if (pktp->availcb_excl == NULL) 452 return BCME_ERROR; 453 else 454 return 0; 455} 456 457static int 458pktpool_avail_notify(pktpool_t *pktp) 459{ 460 int i, k, idx; 461 int avail; 462 463 ASSERT(pktp); 464 if (pktp->availcb_excl != NULL) { 465 pktp->availcb_excl->cb(pktp, pktp->availcb_excl->arg); 466 return 0; 467 } 468 469 k = pktp->cbcnt - 1; 470 for (i = 0; i < pktp->cbcnt; i++) { 471 avail = pktpool_avail(pktp); 472 473 if (avail) { 474 if (pktp->cbtoggle) 475 idx = i; 476 else 477 idx = k--; 478 479 ASSERT(pktp->cbs[idx].cb != NULL); 480 pktp->cbs[idx].cb(pktp, pktp->cbs[idx].arg); 481 } 482 } 483 484 /* Alternate between filling from head or tail 485 */ 486 pktp->cbtoggle ^= 1; 487 488 return 0; 489} 490 491void * 492pktpool_get(pktpool_t *pktp) 493{ 494 void *p; 495 496 p = pktpool_deq(pktp); 497 498 if (p == NULL) { 499 /* Notify and try to reclaim tx pkts */ 500 if (pktp->ecbcnt) 501 pktpool_empty_notify(pktp); 502 503 p = pktpool_deq(pktp); 504 } 505 506 return p; 507} 508 509void 510pktpool_free(pktpool_t *pktp, void *p) 511{ 512 ASSERT(p != NULL); 513 514#ifdef BCMDBG_POOL 515 /* pktpool_stop_trigger(pktp, p); */ 516#endif 517 518 pktpool_enq(pktp, p); 519 520 if (pktp->emptycb_disable) 521 return; 522 523 if (pktp->cbcnt) { 524 if (pktp->empty == FALSE) 525 pktpool_avail_notify(pktp); 526 } 527} 528 529int 530pktpool_add(pktpool_t *pktp, void *p) 531{ 532 ASSERT(p != NULL); 533 534 if (pktpool_len(pktp) == pktp->maxlen) 535 return BCME_RANGE; 536 537 ASSERT(pktpool_plen(pktp) == PKTLEN(NULL, p)); /* pkts in pool have same length */ 538 PKTSETPOOL(NULL, p, TRUE, pktp); 539 540 pktp->len++; 541 if (pktp->r > pktp->w) { 542 /* Add to tail */ 543 ASSERT(pktp->q[pktp->len - 1] == NULL); 544 pktp->q[pktp->len - 1] = p; 545 } else 546 pktpool_enq(pktp, p); 547 548#ifdef BCMDBG_POOL 549 pktp->dbg_q[pktp->dbg_qlen++].p = p; 550#endif 551 552 return 0; 553} 554 555int 556pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen) 557{ 558 if (maxlen > PKTPOOL_LEN_MAX) 559 maxlen = PKTPOOL_LEN_MAX; 560 561 /* if pool is already beyond maxlen, then just cap it 562 * since we currently do not reduce the pool len 563 * already allocated 564 */ 565 pktp->maxlen = (pktpool_len(pktp) > maxlen) ? pktpool_len(pktp) : maxlen; 566 567 return pktp->maxlen; 568} 569 570void 571pktpool_emptycb_disable(pktpool_t *pktp, bool disable) 572{ 573 ASSERT(pktp); 574 575 pktp->emptycb_disable = disable; 576} 577 578bool 579pktpool_emptycb_disabled(pktpool_t *pktp) 580{ 581 ASSERT(pktp); 582 return pktp->emptycb_disable; 583} 584 585/* copy a pkt buffer chain into a buffer */ 586uint 587pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) 588{ 589 uint n, ret = 0; 590 591 if (len < 0) 592 len = 4096; /* "infinite" */ 593 594 /* skip 'offset' bytes */ 595 for (; p && offset; p = PKTNEXT(osh, p)) { 596 if (offset < (uint)PKTLEN(osh, p)) 597 break; 598 offset -= PKTLEN(osh, p); 599 } 600 601 if (!p) 602 return 0; 603 604 /* copy the data */ 605 for (; p && len; p = PKTNEXT(osh, p)) { 606 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); 607 bcopy(PKTDATA(osh, p) + offset, buf, n); 608 buf += n; 609 len -= n; 610 ret += n; 611 offset = 0; 612 } 613 614 return ret; 615} 616 617/* copy a buffer into a pkt buffer chain */ 618uint 619pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf) 620{ 621 uint n, ret = 0; 622 623 /* skip 'offset' bytes */ 624 for (; p && offset; p = PKTNEXT(osh, p)) { 625 if (offset < (uint)PKTLEN(osh, p)) 626 break; 627 offset -= PKTLEN(osh, p); 628 } 629 630 if (!p) 631 return 0; 632 633 /* copy the data */ 634 for (; p && len; p = PKTNEXT(osh, p)) { 635 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); 636 bcopy(buf, PKTDATA(osh, p) + offset, n); 637 buf += n; 638 len -= n; 639 ret += n; 640 offset = 0; 641 } 642 643 return ret; 644} 645 646#ifdef NOTYET 647/* copy data from one pkt buffer (chain) to another */ 648uint 649pkt2pktcopy(osl_t *osh, void *p1, uint offs1, void *p2, uint offs2, int maxlen) 650{ 651 uint8 *dp1, *dp2; 652 uint len1, len2, copylen, totallen; 653 654 for (; p1 && offs; p1 = PKTNEXT(osh, p1)) { 655 if (offs1 < (uint)PKTLEN(osh, p1)) 656 break; 657 offs1 -= PKTLEN(osh, p1); 658 } 659 for (; p2 && offs; p2 = PKTNEXT(osh, p2)) { 660 if (offs2 < (uint)PKTLEN(osh, p2)) 661 break; 662 offs2 -= PKTLEN(osh, p2); 663 } 664 665 /* Heck w/it, only need the above for now */ 666} 667#endif /* NOTYET */ 668 669 670/* return total length of buffer chain */ 671uint BCMFASTPATH 672pkttotlen(osl_t *osh, void *p) 673{ 674 uint total; 675 int len; 676 677 total = 0; 678 for (; p; p = PKTNEXT(osh, p)) { 679 len = PKTLEN(osh, p); 680#ifdef MACOSX 681 if (len < 0) { 682 /* Bad packet length, just drop and exit */ 683 printf("wl: pkttotlen bad (%p,%d)\n", p, len); 684 break; 685 } 686#endif /* MACOSX */ 687 total += len; 688 } 689 690 return (total); 691} 692 693/* return the last buffer of chained pkt */ 694void * 695pktlast(osl_t *osh, void *p) 696{ 697 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p)) 698 ; 699 700 return (p); 701} 702 703/* count segments of a chained packet */ 704uint BCMFASTPATH 705pktsegcnt(osl_t *osh, void *p) 706{ 707 uint cnt; 708 709 for (cnt = 0; p; p = PKTNEXT(osh, p)) 710 cnt++; 711 712 return cnt; 713} 714 715 716/* count segments of a chained packet */ 717uint BCMFASTPATH 718pktsegcnt_war(osl_t *osh, void *p) 719{ 720 uint cnt; 721 uint8 *pktdata; 722 uint len, remain, align64; 723 724 for (cnt = 0; p; p = PKTNEXT(osh, p)) { 725 cnt++; 726 len = PKTLEN(osh, p); 727 if (len > 128) { 728 pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */ 729 /* Check for page boundary straddle (2048B) */ 730 if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff)) 731 cnt++; 732 733 align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */ 734 align64 = (64 - align64) & 0x3f; 735 len -= align64; /* bytes from aligned 64B to end */ 736 /* if aligned to 128B, check for MOD 128 between 1 to 4B */ 737 remain = len % 128; 738 if (remain > 0 && remain <= 4) 739 cnt++; /* add extra seg */ 740 } 741 } 742 743 return cnt; 744} 745 746uint8 * BCMFASTPATH 747pktdataoffset(osl_t *osh, void *p, uint offset) 748{ 749 uint total = pkttotlen(osh, p); 750 uint pkt_off = 0, len = 0; 751 uint8 *pdata = (uint8 *) PKTDATA(osh, p); 752 753 if (offset > total) 754 return NULL; 755 756 for (; p; p = PKTNEXT(osh, p)) { 757 pdata = (uint8 *) PKTDATA(osh, p); 758 pkt_off = offset - len; 759 len += PKTLEN(osh, p); 760 if (len > offset) 761 break; 762 } 763 return (uint8*) (pdata+pkt_off); 764} 765 766 767/* given a offset in pdata, find the pkt seg hdr */ 768void * 769pktoffset(osl_t *osh, void *p, uint offset) 770{ 771 uint total = pkttotlen(osh, p); 772 uint len = 0; 773 774 if (offset > total) 775 return NULL; 776 777 for (; p; p = PKTNEXT(osh, p)) { 778 len += PKTLEN(osh, p); 779 if (len > offset) 780 break; 781 } 782 return p; 783} 784 785/* 786 * osl multiple-precedence packet queue 787 * hi_prec is always >= the number of the highest non-empty precedence 788 */ 789void * BCMFASTPATH 790pktq_penq(struct pktq *pq, int prec, void *p) 791{ 792 struct pktq_prec *q; 793 794 ASSERT(prec >= 0 && prec < pq->num_prec); 795 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ 796 797 ASSERT(!pktq_full(pq)); 798 ASSERT(!pktq_pfull(pq, prec)); 799 800 q = &pq->q[prec]; 801 802 if (q->head) 803 PKTSETLINK(q->tail, p); 804 else 805 q->head = p; 806 807 q->tail = p; 808 q->len++; 809 810 pq->len++; 811 812 if (pq->hi_prec < prec) 813 pq->hi_prec = (uint8)prec; 814 815 return p; 816} 817 818void * BCMFASTPATH 819pktq_penq_head(struct pktq *pq, int prec, void *p) 820{ 821 struct pktq_prec *q; 822 823 ASSERT(prec >= 0 && prec < pq->num_prec); 824 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ 825 826 ASSERT(!pktq_full(pq)); 827 ASSERT(!pktq_pfull(pq, prec)); 828 829 q = &pq->q[prec]; 830 831 if (q->head == NULL) 832 q->tail = p; 833 834 PKTSETLINK(p, q->head); 835 q->head = p; 836 q->len++; 837 838 pq->len++; 839 840 if (pq->hi_prec < prec) 841 pq->hi_prec = (uint8)prec; 842 843 return p; 844} 845 846void * BCMFASTPATH 847pktq_pdeq(struct pktq *pq, int prec) 848{ 849 struct pktq_prec *q; 850 void *p; 851 852 ASSERT(prec >= 0 && prec < pq->num_prec); 853 854 q = &pq->q[prec]; 855 856 if ((p = q->head) == NULL) 857 return NULL; 858 859 if ((q->head = PKTLINK(p)) == NULL) 860 q->tail = NULL; 861 862 q->len--; 863 864 pq->len--; 865 866 PKTSETLINK(p, NULL); 867 868 return p; 869} 870 871void * BCMFASTPATH 872pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p) 873{ 874 struct pktq_prec *q; 875 void *p; 876 877 ASSERT(prec >= 0 && prec < pq->num_prec); 878 879 q = &pq->q[prec]; 880 881 if (prev_p == NULL) 882 return NULL; 883 884 if ((p = PKTLINK(prev_p)) == NULL) 885 return NULL; 886 887 if (q->tail == p) 888 q->tail = prev_p; 889 890 q->len--; 891 892 pq->len--; 893 894 PKTSETLINK(prev_p, PKTLINK(p)); 895 PKTSETLINK(p, NULL); 896 897 return p; 898} 899 900void * BCMFASTPATH 901pktq_pdeq_tail(struct pktq *pq, int prec) 902{ 903 struct pktq_prec *q; 904 void *p, *prev; 905 906 ASSERT(prec >= 0 && prec < pq->num_prec); 907 908 q = &pq->q[prec]; 909 910 if ((p = q->head) == NULL) 911 return NULL; 912 913 for (prev = NULL; p != q->tail; p = PKTLINK(p)) 914 prev = p; 915 916 if (prev) 917 PKTSETLINK(prev, NULL); 918 else 919 q->head = NULL; 920 921 q->tail = prev; 922 q->len--; 923 924 pq->len--; 925 926 return p; 927} 928 929void 930pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg) 931{ 932 struct pktq_prec *q; 933 void *p, *prev = NULL; 934 935 q = &pq->q[prec]; 936 p = q->head; 937 while (p) { 938 if (fn == NULL || (*fn)(p, arg)) { 939 bool head = (p == q->head); 940 if (head) 941 q->head = PKTLINK(p); 942 else 943 PKTSETLINK(prev, PKTLINK(p)); 944 PKTSETLINK(p, NULL); 945 PKTFREE(osh, p, dir); 946 q->len--; 947 pq->len--; 948 p = (head ? q->head : PKTLINK(prev)); 949 } else { 950 prev = p; 951 p = PKTLINK(p); 952 } 953 } 954 955 if (q->head == NULL) { 956 ASSERT(q->len == 0); 957 q->tail = NULL; 958 } 959} 960 961bool BCMFASTPATH 962pktq_pdel(struct pktq *pq, void *pktbuf, int prec) 963{ 964 struct pktq_prec *q; 965 void *p; 966 967 ASSERT(prec >= 0 && prec < pq->num_prec); 968 969 if (!pktbuf) 970 return FALSE; 971 972 q = &pq->q[prec]; 973 974 if (q->head == pktbuf) { 975 if ((q->head = PKTLINK(pktbuf)) == NULL) 976 q->tail = NULL; 977 } else { 978 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p)) 979 ; 980 if (p == NULL) 981 return FALSE; 982 983 PKTSETLINK(p, PKTLINK(pktbuf)); 984 if (q->tail == pktbuf) 985 q->tail = p; 986 } 987 988 q->len--; 989 pq->len--; 990 PKTSETLINK(pktbuf, NULL); 991 return TRUE; 992} 993 994void 995pktq_init(struct pktq *pq, int num_prec, int max_len) 996{ 997 int prec; 998 999 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); 1000 1001 /* pq is variable size; only zero out what's requested */ 1002 bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec)); 1003 1004 pq->num_prec = (uint16)num_prec; 1005 1006 pq->max = (uint16)max_len; 1007 1008 for (prec = 0; prec < num_prec; prec++) 1009 pq->q[prec].max = pq->max; 1010} 1011 1012void 1013pktq_set_max_plen(struct pktq *pq, int prec, int max_len) 1014{ 1015 ASSERT(prec >= 0 && prec < pq->num_prec); 1016 1017 if (prec < pq->num_prec) 1018 pq->q[prec].max = (uint16)max_len; 1019} 1020 1021void * BCMFASTPATH 1022pktq_deq(struct pktq *pq, int *prec_out) 1023{ 1024 struct pktq_prec *q; 1025 void *p; 1026 int prec; 1027 1028 if (pq->len == 0) 1029 return NULL; 1030 1031 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) 1032 pq->hi_prec--; 1033 1034 q = &pq->q[prec]; 1035 1036 if ((p = q->head) == NULL) 1037 return NULL; 1038 1039 if ((q->head = PKTLINK(p)) == NULL) 1040 q->tail = NULL; 1041 1042 q->len--; 1043 1044 pq->len--; 1045 1046 if (prec_out) 1047 *prec_out = prec; 1048 1049 PKTSETLINK(p, NULL); 1050 1051 return p; 1052} 1053 1054void * BCMFASTPATH 1055pktq_deq_tail(struct pktq *pq, int *prec_out) 1056{ 1057 struct pktq_prec *q; 1058 void *p, *prev; 1059 int prec; 1060 1061 if (pq->len == 0) 1062 return NULL; 1063 1064 for (prec = 0; prec < pq->hi_prec; prec++) 1065 if (pq->q[prec].head) 1066 break; 1067 1068 q = &pq->q[prec]; 1069 1070 if ((p = q->head) == NULL) 1071 return NULL; 1072 1073 for (prev = NULL; p != q->tail; p = PKTLINK(p)) 1074 prev = p; 1075 1076 if (prev) 1077 PKTSETLINK(prev, NULL); 1078 else 1079 q->head = NULL; 1080 1081 q->tail = prev; 1082 q->len--; 1083 1084 pq->len--; 1085 1086 if (prec_out) 1087 *prec_out = prec; 1088 1089 PKTSETLINK(p, NULL); 1090 1091 return p; 1092} 1093 1094void * 1095pktq_peek(struct pktq *pq, int *prec_out) 1096{ 1097 int prec; 1098 1099 if (pq->len == 0) 1100 return NULL; 1101 1102 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) 1103 pq->hi_prec--; 1104 1105 if (prec_out) 1106 *prec_out = prec; 1107 1108 return (pq->q[prec].head); 1109} 1110 1111void * 1112pktq_peek_tail(struct pktq *pq, int *prec_out) 1113{ 1114 int prec; 1115 1116 if (pq->len == 0) 1117 return NULL; 1118 1119 for (prec = 0; prec < pq->hi_prec; prec++) 1120 if (pq->q[prec].head) 1121 break; 1122 1123 if (prec_out) 1124 *prec_out = prec; 1125 1126 return (pq->q[prec].tail); 1127} 1128 1129void 1130pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg) 1131{ 1132 int prec; 1133 1134 /* Optimize flush, if pktq len = 0, just return. 1135 * pktq len of 0 means pktq's prec q's are all empty. 1136 */ 1137 if (pq->len == 0) { 1138 return; 1139 } 1140 1141 for (prec = 0; prec < pq->num_prec; prec++) 1142 pktq_pflush(osh, pq, prec, dir, fn, arg); 1143 if (fn == NULL) 1144 ASSERT(pq->len == 0); 1145} 1146 1147/* Return sum of lengths of a specific set of precedences */ 1148int 1149pktq_mlen(struct pktq *pq, uint prec_bmp) 1150{ 1151 int prec, len; 1152 1153 len = 0; 1154 1155 for (prec = 0; prec <= pq->hi_prec; prec++) 1156 if (prec_bmp & (1 << prec)) 1157 len += pq->q[prec].len; 1158 1159 return len; 1160} 1161 1162/* Priority peek from a specific set of precedences */ 1163void * BCMFASTPATH 1164pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out) 1165{ 1166 struct pktq_prec *q; 1167 void *p; 1168 int prec; 1169 1170 if (pq->len == 0) 1171 { 1172 return NULL; 1173 } 1174 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) 1175 pq->hi_prec--; 1176 1177 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL) 1178 if (prec-- == 0) 1179 return NULL; 1180 1181 q = &pq->q[prec]; 1182 1183 if ((p = q->head) == NULL) 1184 return NULL; 1185 1186 if (prec_out) 1187 *prec_out = prec; 1188 1189 return p; 1190} 1191/* Priority dequeue from a specific set of precedences */ 1192void * BCMFASTPATH 1193pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) 1194{ 1195 struct pktq_prec *q; 1196 void *p; 1197 int prec; 1198 1199 if (pq->len == 0) 1200 return NULL; 1201 1202 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) 1203 pq->hi_prec--; 1204 1205 while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0)) 1206 if (prec-- == 0) 1207 return NULL; 1208 1209 q = &pq->q[prec]; 1210 1211 if ((p = q->head) == NULL) 1212 return NULL; 1213 1214 if ((q->head = PKTLINK(p)) == NULL) 1215 q->tail = NULL; 1216 1217 q->len--; 1218 1219 if (prec_out) 1220 *prec_out = prec; 1221 1222 pq->len--; 1223 1224 PKTSETLINK(p, NULL); 1225 1226 return p; 1227} 1228 1229#endif /* BCMDRIVER */ 1230 1231#if defined(BCMROMBUILD) 1232const unsigned char BCMROMDATA(bcm_ctype)[] = { 1233#else 1234const unsigned char bcm_ctype[] = { 1235#endif 1236 1237 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */ 1238 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C, 1239 _BCM_C, /* 8-15 */ 1240 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */ 1241 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */ 1242 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */ 1243 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */ 1244 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */ 1245 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */ 1246 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, 1247 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */ 1248 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */ 1249 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */ 1250 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */ 1251 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, 1252 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */ 1253 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */ 1254 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */ 1255 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */ 1256 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */ 1257 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */ 1258 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, 1259 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */ 1260 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, 1261 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */ 1262 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, 1263 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */ 1264 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U, 1265 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */ 1266 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, 1267 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */ 1268 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L, 1269 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */ 1270}; 1271 1272ulong 1273BCMROMFN(bcm_strtoul)(const char *cp, char **endp, uint base) 1274{ 1275 ulong result, last_result = 0, value; 1276 bool minus; 1277 1278 minus = FALSE; 1279 1280 while (bcm_isspace(*cp)) 1281 cp++; 1282 1283 if (cp[0] == '+') 1284 cp++; 1285 else if (cp[0] == '-') { 1286 minus = TRUE; 1287 cp++; 1288 } 1289 1290 if (base == 0) { 1291 if (cp[0] == '0') { 1292 if ((cp[1] == 'x') || (cp[1] == 'X')) { 1293 base = 16; 1294 cp = &cp[2]; 1295 } else { 1296 base = 8; 1297 cp = &cp[1]; 1298 } 1299 } else 1300 base = 10; 1301 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { 1302 cp = &cp[2]; 1303 } 1304 1305 result = 0; 1306 1307 while (bcm_isxdigit(*cp) && 1308 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) { 1309 result = result*base + value; 1310 /* Detected overflow */ 1311 if (result < last_result && !minus) 1312 return (ulong)-1; 1313 last_result = result; 1314 cp++; 1315 } 1316 1317 if (minus) 1318 result = (ulong)(-(long)result); 1319 1320 if (endp) 1321 *endp = DISCARD_QUAL(cp, char); 1322 1323 return (result); 1324} 1325 1326int 1327BCMROMFN(bcm_atoi)(const char *s) 1328{ 1329 return (int)bcm_strtoul(s, NULL, 10); 1330} 1331 1332/* return pointer to location of substring 'needle' in 'haystack' */ 1333char * 1334BCMROMFN(bcmstrstr)(const char *haystack, const char *needle) 1335{ 1336 int len, nlen; 1337 int i; 1338 1339 if ((haystack == NULL) || (needle == NULL)) 1340 return DISCARD_QUAL(haystack, char); 1341 1342 nlen = strlen(needle); 1343 len = strlen(haystack) - nlen + 1; 1344 1345 for (i = 0; i < len; i++) 1346 if (memcmp(needle, &haystack[i], nlen) == 0) 1347 return DISCARD_QUAL(&haystack[i], char); 1348 return (NULL); 1349} 1350 1351char * 1352BCMROMFN(bcmstrcat)(char *dest, const char *src) 1353{ 1354 char *p; 1355 1356 p = dest + strlen(dest); 1357 1358 while ((*p++ = *src++) != '\0') 1359 ; 1360 1361 return (dest); 1362} 1363 1364char * 1365BCMROMFN(bcmstrncat)(char *dest, const char *src, uint size) 1366{ 1367 char *endp; 1368 char *p; 1369 1370 p = dest + strlen(dest); 1371 endp = p + size; 1372 1373 while (p != endp && (*p++ = *src++) != '\0') 1374 ; 1375 1376 return (dest); 1377} 1378 1379 1380/**************************************************************************** 1381* Function: bcmstrtok 1382* 1383* Purpose: 1384* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(), 1385* but allows strToken() to be used by different strings or callers at the same 1386* time. Each call modifies '*string' by substituting a NULL character for the 1387* first delimiter that is encountered, and updates 'string' to point to the char 1388* after the delimiter. Leading delimiters are skipped. 1389* 1390* Parameters: 1391* string (mod) Ptr to string ptr, updated by token. 1392* delimiters (in) Set of delimiter characters. 1393* tokdelim (out) Character that delimits the returned token. (May 1394* be set to NULL if token delimiter is not required). 1395* 1396* Returns: Pointer to the next token found. NULL when no more tokens are found. 1397***************************************************************************** 1398*/ 1399char * 1400bcmstrtok(char **string, const char *delimiters, char *tokdelim) 1401{ 1402 unsigned char *str; 1403 unsigned long map[8]; 1404 int count; 1405 char *nextoken; 1406 1407 if (tokdelim != NULL) { 1408 /* Prime the token delimiter */ 1409 *tokdelim = '\0'; 1410 } 1411 1412 /* Clear control map */ 1413 for (count = 0; count < 8; count++) { 1414 map[count] = 0; 1415 } 1416 1417 /* Set bits in delimiter table */ 1418 do { 1419 map[*delimiters >> 5] |= (1 << (*delimiters & 31)); 1420 } 1421 while (*delimiters++); 1422 1423 str = (unsigned char*)*string; 1424 1425 /* Find beginning of token (skip over leading delimiters). Note that 1426 * there is no token iff this loop sets str to point to the terminal 1427 * null (*str == '\0') 1428 */ 1429 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) { 1430 str++; 1431 } 1432 1433 nextoken = (char*)str; 1434 1435 /* Find the end of the token. If it is not the end of the string, 1436 * put a null there. 1437 */ 1438 for (; *str; str++) { 1439 if (map[*str >> 5] & (1 << (*str & 31))) { 1440 if (tokdelim != NULL) { 1441 *tokdelim = *str; 1442 } 1443 1444 *str++ = '\0'; 1445 break; 1446 } 1447 } 1448 1449 *string = (char*)str; 1450 1451 /* Determine if a token has been found. */ 1452 if (nextoken == (char *) str) { 1453 return NULL; 1454 } 1455 else { 1456 return nextoken; 1457 } 1458} 1459 1460 1461#define xToLower(C) \ 1462 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C) 1463 1464 1465/**************************************************************************** 1466* Function: bcmstricmp 1467* 1468* Purpose: Compare to strings case insensitively. 1469* 1470* Parameters: s1 (in) First string to compare. 1471* s2 (in) Second string to compare. 1472* 1473* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if 1474* t1 > t2, when ignoring case sensitivity. 1475***************************************************************************** 1476*/ 1477int 1478bcmstricmp(const char *s1, const char *s2) 1479{ 1480 char dc, sc; 1481 1482 while (*s2 && *s1) { 1483 dc = xToLower(*s1); 1484 sc = xToLower(*s2); 1485 if (dc < sc) return -1; 1486 if (dc > sc) return 1; 1487 s1++; 1488 s2++; 1489 } 1490 1491 if (*s1 && !*s2) return 1; 1492 if (!*s1 && *s2) return -1; 1493 return 0; 1494} 1495 1496 1497/**************************************************************************** 1498* Function: bcmstrnicmp 1499* 1500* Purpose: Compare to strings case insensitively, upto a max of 'cnt' 1501* characters. 1502* 1503* Parameters: s1 (in) First string to compare. 1504* s2 (in) Second string to compare. 1505* cnt (in) Max characters to compare. 1506* 1507* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if 1508* t1 > t2, when ignoring case sensitivity. 1509***************************************************************************** 1510*/ 1511int 1512bcmstrnicmp(const char* s1, const char* s2, int cnt) 1513{ 1514 char dc, sc; 1515 1516 while (*s2 && *s1 && cnt) { 1517 dc = xToLower(*s1); 1518 sc = xToLower(*s2); 1519 if (dc < sc) return -1; 1520 if (dc > sc) return 1; 1521 s1++; 1522 s2++; 1523 cnt--; 1524 } 1525 1526 if (!cnt) return 0; 1527 if (*s1 && !*s2) return 1; 1528 if (!*s1 && *s2) return -1; 1529 return 0; 1530} 1531 1532/* parse a xx:xx:xx:xx:xx:xx format ethernet address */ 1533int 1534BCMROMFN(bcm_ether_atoe)(const char *p, struct ether_addr *ea) 1535{ 1536 int i = 0; 1537 char *ep; 1538 1539 for (;;) { 1540 ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16); 1541 p = ep; 1542 if (!*p++ || i == 6) 1543 break; 1544 } 1545 1546 return (i == 6); 1547} 1548 1549#ifdef _HNDRTE_ 1550 1551const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; 1552const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; 1553const struct ether_addr ether_ipv6_mcast = {{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}}; 1554 1555int 1556ether_isbcast(const void *ea) 1557{ 1558 return (memcmp(ea, ðer_bcast, sizeof(struct ether_addr)) == 0); 1559} 1560 1561int 1562ether_isnulladdr(const void *ea) 1563{ 1564 return (memcmp(ea, ðer_null, sizeof(struct ether_addr)) == 0); 1565} 1566 1567#endif /* _HNDRTE_ */ 1568 1569#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER) 1570/* registry routine buffer preparation utility functions: 1571 * parameter order is like strncpy, but returns count 1572 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2) 1573 */ 1574ulong 1575wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen) 1576{ 1577 ulong copyct = 1; 1578 ushort i; 1579 1580 if (abuflen == 0) 1581 return 0; 1582 1583 /* wbuflen is in bytes */ 1584 wbuflen /= sizeof(ushort); 1585 1586 for (i = 0; i < wbuflen; ++i) { 1587 if (--abuflen == 0) 1588 break; 1589 *abuf++ = (char) *wbuf++; 1590 ++copyct; 1591 } 1592 *abuf = '\0'; 1593 1594 return copyct; 1595} 1596#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */ 1597 1598char * 1599bcm_ether_ntoa(const struct ether_addr *ea, char *buf) 1600{ 1601 static const char hex[] = 1602 { 1603 '0', '1', '2', '3', '4', '5', '6', '7', 1604 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' 1605 }; 1606 const uint8 *octet = ea->octet; 1607 char *p = buf; 1608 int i; 1609 1610 for (i = 0; i < 6; i++, octet++) { 1611 *p++ = hex[(*octet >> 4) & 0xf]; 1612 *p++ = hex[*octet & 0xf]; 1613 *p++ = ':'; 1614 } 1615 1616 *(p-1) = '\0'; 1617 1618 return (buf); 1619} 1620 1621char * 1622bcm_ip_ntoa(struct ipv4_addr *ia, char *buf) 1623{ 1624 snprintf(buf, 16, "%d.%d.%d.%d", 1625 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); 1626 return (buf); 1627} 1628 1629char * 1630bcm_ipv6_ntoa(void *ipv6, char *buf) 1631{ 1632 /* Implementing RFC 5952 Sections 4 + 5 */ 1633 /* Not thoroughly tested */ 1634 uint16 *a = (uint16 *)ipv6; 1635 char *p = buf; 1636 int i, i_max = -1, cnt = 0, cnt_max = 1; 1637 uint8 *a4 = NULL; 1638 1639 for (i = 0; i < IPV6_ADDR_LEN/2; i++) { 1640 if (a[i]) { 1641 if (cnt > cnt_max) { 1642 cnt_max = cnt; 1643 i_max = i - cnt; 1644 } 1645 cnt = 0; 1646 } else 1647 cnt++; 1648 } 1649 if (cnt > cnt_max) { 1650 cnt_max = cnt; 1651 i_max = i - cnt; 1652 } 1653 if (i_max == 0 && 1654 /* IPv4-translated: ::ffff:0:a.b.c.d */ 1655 ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) || 1656 /* IPv4-mapped: ::ffff:a.b.c.d */ 1657 (cnt_max == 5 && a[5] == 0xffff))) 1658 a4 = (uint8*) (a + 6); 1659 1660 for (i = 0; i < IPV6_ADDR_LEN/2; i++) { 1661 if ((uint8*) (a + i) == a4) { 1662 snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]); 1663 break; 1664 } else if (i == i_max) { 1665 *p++ = ':'; 1666 i += cnt_max - 1; 1667 p[0] = ':'; 1668 p[1] = '\0'; 1669 } else { 1670 if (i) 1671 *p++ = ':'; 1672 p += snprintf(p, 8, "%x", ntoh16(a[i])); 1673 } 1674 } 1675 1676 return buf; 1677} 1678 1679#ifdef BCMDRIVER 1680 1681void 1682bcm_mdelay(uint ms) 1683{ 1684 uint i; 1685 1686 for (i = 0; i < ms; i++) { 1687 OSL_DELAY(1000); 1688 } 1689} 1690 1691/* 1692 * Search the name=value vars for a specific one and return its value. 1693 * Returns NULL if not found. 1694 */ 1695char * 1696getvar(char *vars, const char *name) 1697{ 1698#ifdef _MINOSL_ 1699 return NULL; 1700#else 1701 char *s; 1702 int len; 1703 1704 if (!name) 1705 return NULL; 1706 1707 len = strlen(name); 1708 if (len == 0) 1709 return NULL; 1710 1711 /* first look in vars[] */ 1712 for (s = vars; s && *s;) { 1713 if ((bcmp(s, name, len) == 0) && (s[len] == '=')) 1714 return (&s[len+1]); 1715 1716 while (*s++) 1717 ; 1718 } 1719 1720 /* then query nvram */ 1721 return (nvram_get(name)); 1722#endif /* defined(_MINOSL_) */ 1723} 1724 1725/* 1726 * Search the vars for a specific one and return its value as 1727 * an integer. Returns 0 if not found. 1728 */ 1729int 1730getintvar(char *vars, const char *name) 1731{ 1732#ifdef _MINOSL_ 1733 return 0; 1734#else 1735 char *val; 1736 1737 if ((val = getvar(vars, name)) == NULL) 1738 return (0); 1739 1740 return (bcm_strtoul(val, NULL, 0)); 1741#endif /* _MINOSL_ */ 1742} 1743 1744int 1745getintvararray(char *vars, const char *name, int index) 1746{ 1747#ifdef _MINOSL_ 1748 return 0; 1749#else 1750 char *buf, *endp; 1751 int i = 0; 1752 int val = 0; 1753 1754 if ((buf = getvar(vars, name)) == NULL) { 1755 return (0); 1756 } 1757 1758 /* table values are always separated by "," or " " */ 1759 while (*buf != '\0') { 1760 val = bcm_strtoul(buf, &endp, 0); 1761 if (i == index) { 1762 return val; 1763 } 1764 buf = endp; 1765 /* delimiter is ',' */ 1766 if (*buf == ',') 1767 buf++; 1768 i++; 1769 } 1770 return 0; 1771#endif /* _MINOSL_ */ 1772} 1773 1774int 1775getintvararraysize(char *vars, const char *name) 1776{ 1777#ifdef _MINOSL_ 1778 return 0; 1779#else 1780 char *buf, *endp; 1781 int count = 0; 1782 int val = 0; 1783 1784 if ((buf = getvar(vars, name)) == NULL) { 1785 return (0); 1786 } 1787 1788 /* table values are always separated by "," or " " */ 1789 while (*buf != '\0') { 1790 val = bcm_strtoul(buf, &endp, 0); 1791 buf = endp; 1792 /* delimiter is ',' */ 1793 if (*buf == ',') 1794 buf++; 1795 count++; 1796 } 1797 BCM_REFERENCE(val); 1798 return count; 1799#endif /* _MINOSL_ */ 1800} 1801 1802/* Search for token in comma separated token-string */ 1803static int 1804findmatch(const char *string, const char *name) 1805{ 1806 uint len; 1807 char *c; 1808 1809 len = strlen(name); 1810 while ((c = strchr(string, ',')) != NULL) { 1811 if (len == (uint)(c - string) && !strncmp(string, name, len)) 1812 return 1; 1813 string = c + 1; 1814 } 1815 1816 return (!strcmp(string, name)); 1817} 1818 1819/* Return gpio pin number assigned to the named pin 1820 * 1821 * Variable should be in format: 1822 * 1823 * gpio<N>=pin_name,pin_name 1824 * 1825 * This format allows multiple features to share the gpio with mutual 1826 * understanding. 1827 * 1828 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality 1829 * and if def_pin is not used by others. 1830 */ 1831uint 1832getgpiopin(char *vars, char *pin_name, uint def_pin) 1833{ 1834 char name[] = "gpioXXXX"; 1835 char *val; 1836 uint pin; 1837 1838 /* Go thru all possibilities till a match in pin name */ 1839 for (pin = 0; pin < GPIO_NUMPINS; pin ++) { 1840 snprintf(name, sizeof(name), "gpio%d", pin); 1841 val = getvar(vars, name); 1842 if (val && findmatch(val, pin_name)) 1843 return pin; 1844 } 1845 1846 if (def_pin != GPIO_PIN_NOTDEFINED) { 1847 /* make sure the default pin is not used by someone else */ 1848 snprintf(name, sizeof(name), "gpio%d", def_pin); 1849 if (getvar(vars, name)) { 1850 def_pin = GPIO_PIN_NOTDEFINED; 1851 } 1852 } 1853 return def_pin; 1854} 1855 1856#if defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS) 1857 1858#define LOGSIZE 256 /* should be power of 2 to avoid div below */ 1859static struct { 1860 uint cycles; 1861 char *fmt; 1862 uint a1; 1863 uint a2; 1864} logtab[LOGSIZE]; 1865 1866/* last entry logged */ 1867static uint logi = 0; 1868/* next entry to read */ 1869static uint readi = 0; 1870#endif /* defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS) */ 1871 1872#ifdef BCMPERFSTATS 1873void 1874bcm_perf_enable() 1875{ 1876 BCMPERF_ENABLE_INSTRCOUNT(); 1877 BCMPERF_ENABLE_ICACHE_MISS(); 1878 BCMPERF_ENABLE_ICACHE_HIT(); 1879} 1880 1881/* WARNING: This routine uses OSL_GETCYCLES(), which can give unexpected results on 1882 * modern speed stepping CPUs. Use bcmtslog() instead in combination with TSF counter. 1883 */ 1884void 1885bcmlog(char *fmt, uint a1, uint a2) 1886{ 1887 static uint last = 0; 1888 uint cycles, i; 1889 OSL_GETCYCLES(cycles); 1890 1891 i = logi; 1892 1893 logtab[i].cycles = cycles - last; 1894 logtab[i].fmt = fmt; 1895 logtab[i].a1 = a1; 1896 logtab[i].a2 = a2; 1897 1898 logi = (i + 1) % LOGSIZE; 1899 last = cycles; 1900} 1901 1902 1903void 1904bcmstats(char *fmt) 1905{ 1906 static uint last = 0; 1907 static uint32 ic_miss = 0; 1908 static uint32 instr_count = 0; 1909 uint32 ic_miss_cur; 1910 uint32 instr_count_cur; 1911 uint cycles, i; 1912 1913 OSL_GETCYCLES(cycles); 1914 BCMPERF_GETICACHE_MISS(ic_miss_cur); 1915 BCMPERF_GETINSTRCOUNT(instr_count_cur); 1916 1917 i = logi; 1918 1919 logtab[i].cycles = cycles - last; 1920 logtab[i].a1 = ic_miss_cur - ic_miss; 1921 logtab[i].a2 = instr_count_cur - instr_count; 1922 logtab[i].fmt = fmt; 1923 1924 logi = (i + 1) % LOGSIZE; 1925 1926 last = cycles; 1927 instr_count = instr_count_cur; 1928 ic_miss = ic_miss_cur; 1929} 1930 1931 1932void 1933bcmdumplog(char *buf, int size) 1934{ 1935 char *limit; 1936 int j = 0; 1937 int num; 1938 1939 limit = buf + size - 80; 1940 *buf = '\0'; 1941 1942 num = logi - readi; 1943 1944 if (num < 0) 1945 num += LOGSIZE; 1946 1947 /* print in chronological order */ 1948 1949 for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) { 1950 if (logtab[readi].fmt == NULL) 1951 continue; 1952 buf += snprintf(buf, (limit - buf), "%d\t", logtab[readi].cycles); 1953 buf += snprintf(buf, (limit - buf), logtab[readi].fmt, logtab[readi].a1, 1954 logtab[readi].a2); 1955 buf += snprintf(buf, (limit - buf), "\n"); 1956 } 1957 1958} 1959 1960 1961/* 1962 * Dump one log entry at a time. 1963 * Return index of next entry or -1 when no more . 1964 */ 1965int 1966bcmdumplogent(char *buf, uint i) 1967{ 1968 bool hit; 1969 1970 /* 1971 * If buf is NULL, return the starting index, 1972 * interpreting i as the indicator of last 'i' entries to dump. 1973 */ 1974 if (buf == NULL) { 1975 i = ((i > 0) && (i < (LOGSIZE - 1))) ? i : (LOGSIZE - 1); 1976 return ((logi - i) % LOGSIZE); 1977 } 1978 1979 *buf = '\0'; 1980 1981 ASSERT(i < LOGSIZE); 1982 1983 if (i == logi) 1984 return (-1); 1985 1986 hit = FALSE; 1987 for (; (i != logi) && !hit; i = (i + 1) % LOGSIZE) { 1988 if (logtab[i].fmt == NULL) 1989 continue; 1990 buf += sprintf(buf, "%d: %d\t", i, logtab[i].cycles); 1991 buf += sprintf(buf, logtab[i].fmt, logtab[i].a1, logtab[i].a2); 1992 buf += sprintf(buf, "\n"); 1993 hit = TRUE; 1994 } 1995 1996 return (i); 1997} 1998 1999#endif /* BCMPERFSTATS */ 2000 2001#if defined(BCMTSTAMPEDLOGS) 2002/* Store a TSF timestamp and a log line in the log buffer */ 2003void 2004bcmtslog(uint32 tstamp, char *fmt, uint a1, uint a2) 2005{ 2006 uint i = logi; 2007 bool use_delta = FALSE; 2008 static uint32 last = 0; /* used only when use_delta is true */ 2009 2010 logtab[i].cycles = tstamp; 2011 if (use_delta) 2012 logtab[i].cycles -= last; 2013 2014 logtab[i].fmt = fmt; 2015 logtab[i].a1 = a1; 2016 logtab[i].a2 = a2; 2017 2018 if (use_delta) 2019 last = tstamp; 2020 logi = (i + 1) % LOGSIZE; 2021} 2022 2023/* Print out a microsecond timestamp as "sec.ms.us " */ 2024void 2025bcmprinttstamp(uint32 ticks) 2026{ 2027 uint us, ms, sec; 2028 2029 us = (ticks % TSF_TICKS_PER_MS) * 1000 / TSF_TICKS_PER_MS; 2030 ms = ticks / TSF_TICKS_PER_MS; 2031 sec = ms / 1000; 2032 ms -= sec * 1000; 2033 printf("%04u.%03u.%03u ", sec, ms, us); 2034} 2035 2036/* Print out the log buffer with timestamps */ 2037void 2038bcmprinttslogs(void) 2039{ 2040 int j = 0; 2041 int num; 2042 2043 num = logi - readi; 2044 if (num < 0) 2045 num += LOGSIZE; 2046 2047 /* Format and print the log entries directly in chronological order */ 2048 for (j = 0; j < num; readi = (readi + 1) % LOGSIZE, j++) { 2049 if (logtab[readi].fmt == NULL) 2050 continue; 2051 bcmprinttstamp(logtab[readi].cycles); 2052 printf(logtab[readi].fmt, logtab[readi].a1, logtab[readi].a2); 2053 printf("\n"); 2054 } 2055} 2056 2057void 2058bcmdumptslog(char *buf, int size) 2059{ 2060 char *limit; 2061 int j = 0; 2062 int num; 2063 uint us, ms, sec; 2064 2065 limit = buf + size - 80; 2066 *buf = '\0'; 2067 2068 num = logi - readi; 2069 2070 if (num < 0) 2071 num += LOGSIZE; 2072 2073 /* print in chronological order */ 2074 for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) { 2075 if (logtab[readi].fmt == NULL) 2076 continue; 2077 us = (logtab[readi].cycles % TSF_TICKS_PER_MS) * 1000 / TSF_TICKS_PER_MS; 2078 ms = logtab[readi].cycles / TSF_TICKS_PER_MS; 2079 sec = ms / 1000; 2080 ms -= sec * 1000; 2081 2082 buf += snprintf(buf, (limit - buf), "%04u.%03u.%03u ", sec, ms, us); 2083 /* buf += snprintf(buf, (limit - buf), "%d\t", logtab[readi].cycles); */ 2084 buf += snprintf(buf, (limit - buf), logtab[readi].fmt, logtab[readi].a1, 2085 logtab[readi].a2); 2086 buf += snprintf(buf, (limit - buf), "\n"); 2087 } 2088} 2089 2090#endif /* BCMTSTAMPEDLOGS */ 2091 2092#if defined(DHD_DEBUG) 2093/* pretty hex print a pkt buffer chain */ 2094void 2095prpkt(const char *msg, osl_t *osh, void *p0) 2096{ 2097 void *p; 2098 2099 if (msg && (msg[0] != '\0')) 2100 printf("%s:\n", msg); 2101 2102 for (p = p0; p; p = PKTNEXT(osh, p)) 2103 prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p)); 2104} 2105#endif 2106 2107/* Takes an Ethernet frame and sets out-of-bound PKTPRIO. 2108 * Also updates the inplace vlan tag if requested. 2109 * For debugging, it returns an indication of what it did. 2110 */ 2111uint BCMFASTPATH 2112pktsetprio(void *pkt, bool update_vtag) 2113{ 2114 struct ether_header *eh; 2115 struct ethervlan_header *evh; 2116 uint8 *pktdata; 2117 int priority = 0; 2118 int rc = 0; 2119 2120 pktdata = (uint8 *)PKTDATA(NULL, pkt); 2121 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); 2122 2123 eh = (struct ether_header *) pktdata; 2124 2125 if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) { 2126 uint16 vlan_tag; 2127 int vlan_prio, dscp_prio = 0; 2128 2129 evh = (struct ethervlan_header *)eh; 2130 2131 vlan_tag = ntoh16(evh->vlan_tag); 2132 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; 2133 2134 if (evh->ether_type == hton16(ETHER_TYPE_IP)) { 2135 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); 2136 uint8 tos_tc = IP_TOS46(ip_body); 2137 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); 2138 } 2139 2140 /* DSCP priority gets precedence over 802.1P (vlan tag) */ 2141 if (dscp_prio != 0) { 2142 priority = dscp_prio; 2143 rc |= PKTPRIO_VDSCP; 2144 } else { 2145 priority = vlan_prio; 2146 rc |= PKTPRIO_VLAN; 2147 } 2148 /* 2149 * If the DSCP priority is not the same as the VLAN priority, 2150 * then overwrite the priority field in the vlan tag, with the 2151 * DSCP priority value. This is required for Linux APs because 2152 * the VLAN driver on Linux, overwrites the skb->priority field 2153 * with the priority value in the vlan tag 2154 */ 2155 if (update_vtag && (priority != vlan_prio)) { 2156 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); 2157 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; 2158 evh->vlan_tag = hton16(vlan_tag); 2159 rc |= PKTPRIO_UPD; 2160 } 2161 } else if (eh->ether_type == hton16(ETHER_TYPE_IP)) { 2162 uint8 *ip_body = pktdata + sizeof(struct ether_header); 2163 uint8 tos_tc = IP_TOS46(ip_body); 2164 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); 2165 rc |= PKTPRIO_DSCP; 2166 } 2167 2168 ASSERT(priority >= 0 && priority <= MAXPRIO); 2169 PKTSETPRIO(pkt, priority); 2170 return (rc | priority); 2171} 2172 2173#ifndef BCM_BOOTLOADER 2174 2175static char bcm_undeferrstr[32]; 2176static const char *const bcmerrorstrtable[] = BCMERRSTRINGTABLE; 2177 2178/* Convert the error codes into related error strings */ 2179const char * 2180bcmerrorstr(int bcmerror) 2181{ 2182 /* check if someone added a bcmerror code but forgot to add errorstring */ 2183 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); 2184 2185 if (bcmerror > 0 || bcmerror < BCME_LAST) { 2186 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror); 2187 return bcm_undeferrstr; 2188 } 2189 2190 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN); 2191 2192 return bcmerrorstrtable[-bcmerror]; 2193} 2194 2195#endif /* !BCM_BOOTLOADER */ 2196 2197#ifdef WLC_LOW 2198static void 2199BCMINITFN(bcm_nvram_refresh)(char *flash) 2200{ 2201 int i; 2202 int ret = 0; 2203 2204 ASSERT(flash != NULL); 2205 2206 /* default "empty" vars cache */ 2207 bzero(flash, 2); 2208 2209 if ((ret = nvram_getall(flash, MAX_NVRAM_SPACE))) 2210 return; 2211 2212 /* determine nvram length */ 2213 for (i = 0; i < MAX_NVRAM_SPACE; i++) { 2214 if (flash[i] == '\0' && flash[i+1] == '\0') 2215 break; 2216 } 2217 2218 if (i > 1) 2219 vars_len = i + 2; 2220 else 2221 vars_len = 0; 2222} 2223 2224char * 2225bcm_nvram_vars(uint *length) 2226{ 2227#ifndef BCMNVRAMR 2228 /* cache may be stale if nvram is read/write */ 2229 if (nvram_vars) { 2230 ASSERT(!bcmreclaimed); 2231 bcm_nvram_refresh(nvram_vars); 2232 } 2233#endif 2234 if (length) 2235 *length = vars_len; 2236 return nvram_vars; 2237} 2238 2239/* copy nvram vars into locally-allocated multi-string array */ 2240int 2241BCMINITFN(bcm_nvram_cache)(void *sih) 2242{ 2243 int ret = 0; 2244 void *osh; 2245 char *flash = NULL; 2246 2247 if (vars_len >= 0) { 2248#ifndef BCMNVRAMR 2249 bcm_nvram_refresh(nvram_vars); 2250#endif 2251 return 0; 2252 } 2253 2254 osh = si_osh((si_t *)sih); 2255 2256 /* allocate memory and read in flash */ 2257 if (!(flash = MALLOC(osh, MAX_NVRAM_SPACE))) { 2258 ret = BCME_NOMEM; 2259 goto exit; 2260 } 2261 2262 bcm_nvram_refresh(flash); 2263 2264#ifdef BCMNVRAMR 2265 if (vars_len > 3) { 2266 /* copy into a properly-sized buffer */ 2267 if (!(nvram_vars = MALLOC(osh, vars_len))) { 2268 ret = BCME_NOMEM; 2269 } else 2270 bcopy(flash, nvram_vars, vars_len); 2271 } 2272 MFREE(osh, flash, MAX_NVRAM_SPACE); 2273#else 2274 /* cache must be full size of nvram if read/write */ 2275 nvram_vars = flash; 2276#endif /* BCMNVRAMR */ 2277 2278exit: 2279 return ret; 2280} 2281#endif /* WLC_LOW */ 2282 2283#ifdef BCMDBG_PKT /* pkt logging for debugging */ 2284/* Add a packet to the pktlist */ 2285static void 2286_pktlist_add(pktlist_info_t *pktlist, void *pkt, int line, char *file) 2287{ 2288 uint16 i; 2289 char *basename; 2290#ifdef BCMDBG_PTRACE 2291 uint16 *idx = PKTLIST_IDX(pkt); 2292#endif /* BCMDBG_PTRACE */ 2293 2294 ASSERT(pktlist->count < PKTLIST_SIZE); 2295 2296 /* Verify the packet is not already part of the list */ 2297 for (i = 0; i < pktlist->count; i++) { 2298 if (pktlist->list[i].pkt == pkt) 2299 ASSERT(0); 2300 } 2301 pktlist->list[pktlist->count].pkt = pkt; 2302 pktlist->list[pktlist->count].line = line; 2303 2304 basename = strrchr(file, '/'); 2305 if (basename) 2306 basename++; 2307 else 2308 basename = file; 2309 pktlist->list[pktlist->count].file = basename; 2310#ifdef BCMDBG_PTRACE 2311 *idx = pktlist->count; 2312 bzero(pktlist->list[pktlist->count].pkt_trace, PKTTRACE_MAX_BYTES); 2313#endif /* BCMDBG_PTRACE */ 2314 pktlist->count++; 2315 2316 return; 2317} 2318 2319void 2320pktlist_add(pktlist_info_t *pktlist, void *pkt, int line, char *file) 2321{ 2322 void *p; 2323 for (p = pkt; p != NULL; p = PKTCLINK(p)) 2324 _pktlist_add(pktlist, p, line, file); 2325} 2326 2327/* Remove a packet from the pktlist */ 2328static void 2329_pktlist_remove(pktlist_info_t *pktlist, void *pkt) 2330{ 2331 uint16 i; 2332 uint16 num = pktlist->count; 2333#ifdef BCMDBG_PTRACE 2334 uint16 *idx = PKTLIST_IDX(pkt); 2335 2336 ASSERT((*idx) < pktlist->count); 2337#endif /* BCMDBG_PTRACE */ 2338 2339 /* find the index where pkt exists */ 2340 for (i = 0; i < num; i++) { 2341 /* check for the existence of pkt in the list */ 2342 if (pktlist->list[i].pkt == pkt) { 2343#ifdef BCMDBG_PTRACE 2344 ASSERT((*idx) == i); 2345#endif /* BCMDBG_PTRACE */ 2346 /* replace with the last element */ 2347 pktlist->list[i].pkt = pktlist->list[num-1].pkt; 2348 pktlist->list[i].line = pktlist->list[num-1].line; 2349 pktlist->list[i].file = pktlist->list[num-1].file; 2350#ifdef BCMDBG_PTRACE 2351 memcpy(pktlist->list[i].pkt_trace, pktlist->list[num-1].pkt_trace, 2352 PKTTRACE_MAX_BYTES); 2353 idx = PKTLIST_IDX(pktlist->list[i].pkt); 2354 *idx = i; 2355#endif /* BCMDBG_PTRACE */ 2356 pktlist->count--; 2357 return; 2358 } 2359 } 2360 ASSERT(0); 2361} 2362 2363void 2364pktlist_remove(pktlist_info_t *pktlist, void *pkt) 2365{ 2366 void *p; 2367 for (p = pkt; p != NULL; p = PKTCLINK(p)) 2368 _pktlist_remove(pktlist, p); 2369} 2370 2371#ifdef BCMDBG_PTRACE 2372static void 2373_pktlist_trace(pktlist_info_t *pktlist, void *pkt, uint16 bit) 2374{ 2375 uint16 *idx = PKTLIST_IDX(pkt); 2376 2377 ASSERT(((*idx) < pktlist->count) && (bit < PKTTRACE_MAX_BITS)); 2378 ASSERT(pktlist->list[(*idx)].pkt == pkt); 2379 2380 pktlist->list[(*idx)].pkt_trace[bit/NBBY] |= (1 << ((bit)%NBBY)); 2381 2382} 2383void 2384pktlist_trace(pktlist_info_t *pktlist, void *pkt, uint16 bit) 2385{ 2386 void *p; 2387 for (p = pkt; p != NULL; p = PKTCLINK(p)) 2388 _pktlist_trace(pktlist, p, bit); 2389} 2390#endif /* BCMDBG_PTRACE */ 2391 2392/* Dump the pktlist (and the contents of each packet if 'data' 2393 * is set). 'buf' should be large enough 2394 */ 2395 2396char * 2397pktlist_dump(pktlist_info_t *pktlist, char *buf) 2398{ 2399 char *obuf = buf; 2400 uint16 i; 2401 2402 if (buf != NULL) 2403 buf += sprintf(buf, "Packet list dump:\n"); 2404 else 2405 printf("Packet list dump:\n"); 2406 2407 for (i = 0; i < (pktlist->count); i++) { 2408 if (buf != NULL) 2409 buf += sprintf(buf, "Pkt_addr: 0x%p Line: %d File: %s\t", 2410 pktlist->list[i].pkt, pktlist->list[i].line, 2411 pktlist->list[i].file); 2412 else 2413 printf("Pkt_addr: 0x%p Line: %d File: %s\t", pktlist->list[i].pkt, 2414 pktlist->list[i].line, pktlist->list[i].file); 2415 2416/* #ifdef NOTDEF Remove this ifdef to print pkttag and pktdata */ 2417 if (buf != NULL) { 2418 if (PKTTAG(pktlist->list[i].pkt)) { 2419 /* Print pkttag */ 2420 buf += sprintf(buf, "Pkttag(in hex): "); 2421 buf += bcm_format_hex(buf, PKTTAG(pktlist->list[i].pkt), 2422 OSL_PKTTAG_SZ); 2423 } 2424 buf += sprintf(buf, "Pktdata(in hex): "); 2425 buf += bcm_format_hex(buf, PKTDATA(NULL, pktlist->list[i].pkt), 2426 PKTLEN(NULL, pktlist->list[i].pkt)); 2427 } else { 2428 void *pkt = pktlist->list[i].pkt, *npkt; 2429 2430 printf("Pkt[%d] Dump:\n", i); 2431 while (pkt) { 2432 int hroom, pktlen; 2433 uchar *src; 2434#ifdef BCMDBG_PTRACE 2435 uint16 *idx = PKTLIST_IDX(pkt); 2436 2437 ASSERT((*idx) < pktlist->count); 2438 prhex("Pkt Trace (in hex):", pktlist->list[(*idx)].pkt_trace, 2439 PKTTRACE_MAX_BYTES); 2440#endif /* BCMDBG_PTRACE */ 2441 npkt = (void *)PKTNEXT(NULL, pkt); 2442 PKTSETNEXT(NULL, pkt, NULL); 2443 2444 src = (uchar *)(PKTTAG(pkt)); 2445 pktlen = PKTLEN(NULL, pkt); 2446 hroom = PKTHEADROOM(NULL, pkt); 2447 2448 printf("Pkttag_addr: %p\n", src); 2449 if (src) 2450 prhex("Pkttag(in hex): ", src, OSL_PKTTAG_SZ); 2451 src = (uchar *) (PKTDATA(NULL, pkt)); 2452 printf("Pkthead_addr: %p len: %d\n", src - hroom, hroom); 2453 prhex("Pkt headroom content(in hex): ", src - hroom, hroom); 2454 printf("Pktdata_addr: %p len: %d\n", src, pktlen); 2455 prhex("Pktdata(in hex): ", src, pktlen); 2456 2457 pkt = npkt; 2458 } 2459 } 2460/* #endif NOTDEF */ 2461 2462 if (buf != NULL) 2463 buf += sprintf(buf, "\n"); 2464 else 2465 printf("\n"); 2466 } 2467 return obuf; 2468} 2469#endif /* BCMDBG_PKT */ 2470 2471/* iovar table lookup */ 2472const bcm_iovar_t* 2473bcm_iovar_lookup(const bcm_iovar_t *table, const char *name) 2474{ 2475 const bcm_iovar_t *vi; 2476 const char *lookup_name; 2477 2478 /* skip any ':' delimited option prefixes */ 2479 lookup_name = strrchr(name, ':'); 2480 if (lookup_name != NULL) 2481 lookup_name++; 2482 else 2483 lookup_name = name; 2484 2485 ASSERT(table != NULL); 2486 2487 for (vi = table; vi->name; vi++) { 2488 if (!strcmp(vi->name, lookup_name)) 2489 return vi; 2490 } 2491 /* ran to end of table */ 2492 2493 return NULL; /* var name not found */ 2494} 2495 2496int 2497bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) 2498{ 2499 int bcmerror = 0; 2500 2501 /* length check on io buf */ 2502 switch (vi->type) { 2503 case IOVT_BOOL: 2504 case IOVT_INT8: 2505 case IOVT_INT16: 2506 case IOVT_INT32: 2507 case IOVT_UINT8: 2508 case IOVT_UINT16: 2509 case IOVT_UINT32: 2510 /* all integers are int32 sized args at the ioctl interface */ 2511 if (len < (int)sizeof(int)) { 2512 bcmerror = BCME_BUFTOOSHORT; 2513 } 2514 break; 2515 2516 case IOVT_BUFFER: 2517 /* buffer must meet minimum length requirement */ 2518 if (len < vi->minlen) { 2519 bcmerror = BCME_BUFTOOSHORT; 2520 } 2521 break; 2522 2523 case IOVT_VOID: 2524 if (!set) { 2525 /* Cannot return nil... */ 2526 bcmerror = BCME_UNSUPPORTED; 2527 } else if (len) { 2528 /* Set is an action w/o parameters */ 2529 bcmerror = BCME_BUFTOOLONG; 2530 } 2531 break; 2532 2533 default: 2534 /* unknown type for length check in iovar info */ 2535 ASSERT(0); 2536 bcmerror = BCME_UNSUPPORTED; 2537 } 2538 2539 return bcmerror; 2540} 2541 2542#endif /* BCMDRIVER */ 2543 2544 2545/******************************************************************************* 2546 * crc8 2547 * 2548 * Computes a crc8 over the input data using the polynomial: 2549 * 2550 * x^8 + x^7 +x^6 + x^4 + x^2 + 1 2551 * 2552 * The caller provides the initial value (either CRC8_INIT_VALUE 2553 * or the previous returned value) to allow for processing of 2554 * discontiguous blocks of data. When generating the CRC the 2555 * caller is responsible for complementing the final return value 2556 * and inserting it into the byte stream. When checking, a final 2557 * return value of CRC8_GOOD_VALUE indicates a valid CRC. 2558 * 2559 * Reference: Dallas Semiconductor Application Note 27 2560 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", 2561 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., 2562 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt 2563 * 2564 * **************************************************************************** 2565 */ 2566 2567static const uint8 crc8_table[256] = { 2568 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, 2569 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, 2570 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, 2571 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, 2572 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, 2573 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, 2574 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, 2575 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, 2576 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, 2577 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, 2578 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, 2579 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, 2580 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, 2581 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, 2582 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, 2583 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, 2584 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, 2585 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, 2586 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, 2587 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, 2588 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, 2589 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, 2590 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, 2591 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, 2592 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, 2593 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, 2594 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, 2595 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, 2596 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, 2597 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, 2598 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, 2599 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F 2600}; 2601 2602#define CRC_INNER_LOOP(n, c, x) \ 2603 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff] 2604 2605uint8 2606BCMROMFN(hndcrc8)( 2607 uint8 *pdata, /* pointer to array of data to process */ 2608 uint nbytes, /* number of input data bytes to process */ 2609 uint8 crc /* either CRC8_INIT_VALUE or previous return value */ 2610) 2611{ 2612 /* hard code the crc loop instead of using CRC_INNER_LOOP macro 2613 * to avoid the undefined and unnecessary (uint8 >> 8) operation. 2614 */ 2615 while (nbytes-- > 0) 2616 crc = crc8_table[(crc ^ *pdata++) & 0xff]; 2617 2618 return crc; 2619} 2620 2621/******************************************************************************* 2622 * crc16 2623 * 2624 * Computes a crc16 over the input data using the polynomial: 2625 * 2626 * x^16 + x^12 +x^5 + 1 2627 * 2628 * The caller provides the initial value (either CRC16_INIT_VALUE 2629 * or the previous returned value) to allow for processing of 2630 * discontiguous blocks of data. When generating the CRC the 2631 * caller is responsible for complementing the final return value 2632 * and inserting it into the byte stream. When checking, a final 2633 * return value of CRC16_GOOD_VALUE indicates a valid CRC. 2634 * 2635 * Reference: Dallas Semiconductor Application Note 27 2636 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", 2637 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., 2638 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt 2639 * 2640 * **************************************************************************** 2641 */ 2642 2643static const uint16 crc16_table[256] = { 2644 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 2645 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, 2646 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, 2647 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, 2648 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, 2649 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, 2650 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, 2651 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, 2652 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, 2653 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, 2654 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, 2655 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, 2656 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, 2657 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, 2658 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, 2659 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, 2660 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, 2661 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, 2662 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, 2663 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, 2664 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, 2665 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, 2666 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, 2667 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, 2668 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, 2669 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, 2670 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, 2671 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, 2672 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, 2673 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, 2674 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, 2675 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 2676}; 2677 2678uint16 2679BCMROMFN(hndcrc16)( 2680 uint8 *pdata, /* pointer to array of data to process */ 2681 uint nbytes, /* number of input data bytes to process */ 2682 uint16 crc /* either CRC16_INIT_VALUE or previous return value */ 2683) 2684{ 2685 while (nbytes-- > 0) 2686 CRC_INNER_LOOP(16, crc, *pdata++); 2687 return crc; 2688} 2689 2690static const uint32 crc32_table[256] = { 2691 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 2692 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 2693 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 2694 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 2695 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 2696 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 2697 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 2698 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 2699 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 2700 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 2701 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 2702 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 2703 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 2704 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 2705 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 2706 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 2707 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 2708 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 2709 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 2710 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 2711 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 2712 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 2713 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 2714 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 2715 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 2716 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 2717 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 2718 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 2719 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 2720 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 2721 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 2722 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 2723 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 2724 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 2725 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 2726 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 2727 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 2728 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 2729 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 2730 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 2731 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 2732 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 2733 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 2734 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 2735 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 2736 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 2737 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 2738 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 2739 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 2740 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 2741 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 2742 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 2743 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 2744 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 2745 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 2746 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 2747 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 2748 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 2749 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 2750 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 2751 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 2752 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 2753 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 2754 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D 2755}; 2756 2757/* 2758 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if 2759 * accumulating over multiple pieces. 2760 */ 2761uint32 2762BCMROMFN(hndcrc32)(uint8 *pdata, uint nbytes, uint32 crc) 2763{ 2764 uint8 *pend; 2765#ifdef __mips__ 2766 uint8 tmp[4]; 2767 ulong *tptr = (ulong *)tmp; 2768 2769 if (nbytes > 3) { 2770 /* in case the beginning of the buffer isn't aligned */ 2771 pend = (uint8 *)((uint)(pdata + 3) & ~0x3); 2772 nbytes -= (pend - pdata); 2773 while (pdata < pend) 2774 CRC_INNER_LOOP(32, crc, *pdata++); 2775 } 2776 2777 if (nbytes > 3) { 2778 /* handle bulk of data as 32-bit words */ 2779 pend = pdata + (nbytes & ~0x3); 2780 while (pdata < pend) { 2781 *tptr = *(ulong *)pdata; 2782 pdata += sizeof(ulong *); 2783 CRC_INNER_LOOP(32, crc, tmp[0]); 2784 CRC_INNER_LOOP(32, crc, tmp[1]); 2785 CRC_INNER_LOOP(32, crc, tmp[2]); 2786 CRC_INNER_LOOP(32, crc, tmp[3]); 2787 } 2788 } 2789 2790 /* 1-3 bytes at end of buffer */ 2791 pend = pdata + (nbytes & 0x03); 2792 while (pdata < pend) 2793 CRC_INNER_LOOP(32, crc, *pdata++); 2794#else 2795 pend = pdata + nbytes; 2796 while (pdata < pend) 2797 CRC_INNER_LOOP(32, crc, *pdata++); 2798#endif /* __mips__ */ 2799 2800 return crc; 2801} 2802 2803#ifdef notdef 2804#define CLEN 1499 /* CRC Length */ 2805#define CBUFSIZ (CLEN+4) 2806#define CNBUFS 5 /* # of bufs */ 2807 2808void 2809testcrc32(void) 2810{ 2811 uint j, k, l; 2812 uint8 *buf; 2813 uint len[CNBUFS]; 2814 uint32 crcr; 2815 uint32 crc32tv[CNBUFS] = 2816 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110}; 2817 2818 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL); 2819 2820 /* step through all possible alignments */ 2821 for (l = 0; l <= 4; l++) { 2822 for (j = 0; j < CNBUFS; j++) { 2823 len[j] = CLEN; 2824 for (k = 0; k < len[j]; k++) 2825 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff; 2826 } 2827 2828 for (j = 0; j < CNBUFS; j++) { 2829 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE); 2830 ASSERT(crcr == crc32tv[j]); 2831 } 2832 } 2833 2834 MFREE(buf, CBUFSIZ*CNBUFS); 2835 return; 2836} 2837#endif /* notdef */ 2838 2839/* 2840 * Advance from the current 1-byte tag/1-byte length/variable-length value 2841 * triple, to the next, returning a pointer to the next. 2842 * If the current or next TLV is invalid (does not fit in given buffer length), 2843 * NULL is returned. 2844 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented 2845 * by the TLV parameter's length if it is valid. 2846 */ 2847bcm_tlv_t * 2848BCMROMFN(bcm_next_tlv)(bcm_tlv_t *elt, int *buflen) 2849{ 2850 int len; 2851 2852 /* validate current elt */ 2853 if (!bcm_valid_tlv(elt, *buflen)) 2854 return NULL; 2855 2856 /* advance to next elt */ 2857 len = elt->len; 2858 elt = (bcm_tlv_t*)(elt->data + len); 2859 *buflen -= (TLV_HDR_LEN + len); 2860 2861 /* validate next elt */ 2862 if (!bcm_valid_tlv(elt, *buflen)) 2863 return NULL; 2864 2865 return elt; 2866} 2867 2868/* 2869 * Traverse a string of 1-byte tag/1-byte length/variable-length value 2870 * triples, returning a pointer to the substring whose first element 2871 * matches tag 2872 */ 2873bcm_tlv_t * 2874BCMROMFN(bcm_parse_tlvs)(void *buf, int buflen, uint key) 2875{ 2876 bcm_tlv_t *elt; 2877 int totlen; 2878 2879 elt = (bcm_tlv_t*)buf; 2880 totlen = buflen; 2881 2882 /* find tagged parameter */ 2883 while (totlen >= TLV_HDR_LEN) { 2884 int len = elt->len; 2885 2886 /* validate remaining totlen */ 2887 if ((elt->id == key) && 2888 (totlen >= (len + TLV_HDR_LEN))) 2889 return (elt); 2890 2891 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); 2892 totlen -= (len + TLV_HDR_LEN); 2893 } 2894 2895 return NULL; 2896} 2897 2898/* 2899 * Traverse a string of 1-byte tag/1-byte length/variable-length value 2900 * triples, returning a pointer to the substring whose first element 2901 * matches tag. Stop parsing when we see an element whose ID is greater 2902 * than the target key. 2903 */ 2904bcm_tlv_t * 2905BCMROMFN(bcm_parse_ordered_tlvs)(void *buf, int buflen, uint key) 2906{ 2907 bcm_tlv_t *elt; 2908 int totlen; 2909 2910 elt = (bcm_tlv_t*)buf; 2911 totlen = buflen; 2912 2913 /* find tagged parameter */ 2914 while (totlen >= TLV_HDR_LEN) { 2915 uint id = elt->id; 2916 int len = elt->len; 2917 2918 /* Punt if we start seeing IDs > than target key */ 2919 if (id > key) 2920 return (NULL); 2921 2922 /* validate remaining totlen */ 2923 if ((id == key) && 2924 (totlen >= (len + TLV_HDR_LEN))) 2925 return (elt); 2926 2927 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); 2928 totlen -= (len + TLV_HDR_LEN); 2929 } 2930 return NULL; 2931} 2932 2933#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \ 2934 defined(BCMDBG_DUMP) || defined(DHD_DEBUG) 2935int 2936bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len) 2937{ 2938 int i, slen = 0; 2939 uint32 bit, mask; 2940 const char *name; 2941 mask = bd->mask; 2942 if (len < 2 || !buf) 2943 return 0; 2944 2945 buf[0] = '\0'; 2946 2947 for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) { 2948 bit = bd->bitfield[i].bit; 2949 if ((flags & mask) == bit) { 2950 if (len > (int)strlen(name)) { 2951 slen = strlen(name); 2952 strncpy(buf, name, slen+1); 2953 } 2954 break; 2955 } 2956 } 2957 return slen; 2958} 2959 2960int 2961bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len) 2962{ 2963 int i; 2964 char* p = buf; 2965 char hexstr[16]; 2966 int slen = 0, nlen = 0; 2967 uint32 bit; 2968 const char* name; 2969 2970 if (len < 2 || !buf) 2971 return 0; 2972 2973 buf[0] = '\0'; 2974 2975 for (i = 0; flags != 0; i++) { 2976 bit = bd[i].bit; 2977 name = bd[i].name; 2978 if (bit == 0 && flags != 0) { 2979 /* print any unnamed bits */ 2980 snprintf(hexstr, 16, "0x%X", flags); 2981 name = hexstr; 2982 flags = 0; /* exit loop */ 2983 } else if ((flags & bit) == 0) 2984 continue; 2985 flags &= ~bit; 2986 nlen = strlen(name); 2987 slen += nlen; 2988 /* count btwn flag space */ 2989 if (flags != 0) 2990 slen += 1; 2991 /* need NULL char as well */ 2992 if (len <= slen) 2993 break; 2994 /* copy NULL char but don't count it */ 2995 strncpy(p, name, nlen + 1); 2996 p += nlen; 2997 /* copy btwn flag space and NULL char */ 2998 if (flags != 0) 2999 p += snprintf(p, 2, " "); 3000 } 3001 3002 /* indicate the str was too short */ 3003 if (flags != 0) { 3004 if (len < 2) 3005 p -= 2 - len; /* overwrite last char */ 3006 p += snprintf(p, 2, ">"); 3007 } 3008 3009 return (int)(p - buf); 3010} 3011 3012/* print bytes formatted as hex to a string. return the resulting string length */ 3013int 3014bcm_format_hex(char *str, const void *bytes, int len) 3015{ 3016 int i; 3017 char *p = str; 3018 const uint8 *src = (const uint8*)bytes; 3019 3020 for (i = 0; i < len; i++) { 3021 p += snprintf(p, 3, "%02X", *src); 3022 src++; 3023 } 3024 return (int)(p - str); 3025} 3026#endif 3027 3028/* pretty hex print a contiguous buffer */ 3029void 3030prhex(const char *msg, uchar *buf, uint nbytes) 3031{ 3032 char line[128], *p; 3033 int len = sizeof(line); 3034 int nchar; 3035 uint i; 3036 3037 if (msg && (msg[0] != '\0')) 3038 printf("%s:\n", msg); 3039 3040 p = line; 3041 for (i = 0; i < nbytes; i++) { 3042 if (i % 16 == 0) { 3043 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */ 3044 p += nchar; 3045 len -= nchar; 3046 } 3047 if (len > 0) { 3048 nchar = snprintf(p, len, "%02x ", buf[i]); 3049 p += nchar; 3050 len -= nchar; 3051 } 3052 3053 if (i % 16 == 15) { 3054 printf("%s\n", line); /* flush line */ 3055 p = line; 3056 len = sizeof(line); 3057 } 3058 } 3059 3060 /* flush last partial line */ 3061 if (p != line) 3062 printf("%s\n", line); 3063} 3064 3065static const char *crypto_algo_names[] = { 3066 "NONE", 3067 "WEP1", 3068 "TKIP", 3069 "WEP128", 3070 "AES_CCM", 3071 "AES_OCB_MSDU", 3072 "AES_OCB_MPDU", 3073 "NALG" 3074 "UNDEF", 3075 "UNDEF", 3076 "UNDEF", 3077 "UNDEF" 3078}; 3079 3080const char * 3081bcm_crypto_algo_name(uint algo) 3082{ 3083 return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR"; 3084} 3085 3086 3087char * 3088bcm_chipname(uint chipid, char *buf, uint len) 3089{ 3090 const char *fmt; 3091 3092 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; 3093 snprintf(buf, len, fmt, chipid); 3094 return buf; 3095} 3096 3097/* Produce a human-readable string for boardrev */ 3098char * 3099bcm_brev_str(uint32 brev, char *buf) 3100{ 3101 if (brev < 0x100) 3102 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); 3103 else 3104 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff); 3105 3106 return (buf); 3107} 3108 3109#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */ 3110 3111/* dump large strings to console */ 3112void 3113printbig(char *buf) 3114{ 3115 uint len, max_len; 3116 char c; 3117 3118 len = strlen(buf); 3119 3120 max_len = BUFSIZE_TODUMP_ATONCE; 3121 3122 while (len > max_len) { 3123 c = buf[max_len]; 3124 buf[max_len] = '\0'; 3125 printf("%s", buf); 3126 buf[max_len] = c; 3127 3128 buf += max_len; 3129 len -= max_len; 3130 } 3131 /* print the remaining string */ 3132 printf("%s\n", buf); 3133 return; 3134} 3135 3136/* routine to dump fields in a fileddesc structure */ 3137uint 3138bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array, 3139 char *buf, uint32 bufsize) 3140{ 3141 uint filled_len; 3142 int len; 3143 struct fielddesc *cur_ptr; 3144 3145 filled_len = 0; 3146 cur_ptr = fielddesc_array; 3147 3148 while (bufsize > 1) { 3149 if (cur_ptr->nameandfmt == NULL) 3150 break; 3151 len = snprintf(buf, bufsize, cur_ptr->nameandfmt, 3152 read_rtn(arg0, arg1, cur_ptr->offset)); 3153 /* check for snprintf overflow or error */ 3154 if (len < 0 || (uint32)len >= bufsize) 3155 len = bufsize - 1; 3156 buf += len; 3157 bufsize -= len; 3158 filled_len += len; 3159 cur_ptr++; 3160 } 3161 return filled_len; 3162} 3163 3164uint 3165bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) 3166{ 3167 uint len; 3168 3169 len = strlen(name) + 1; 3170 3171 if ((len + datalen) > buflen) 3172 return 0; 3173 3174 strncpy(buf, name, buflen); 3175 3176 /* append data onto the end of the name string */ 3177 memcpy(&buf[len], data, datalen); 3178 len += datalen; 3179 3180 return len; 3181} 3182 3183/* Quarter dBm units to mW 3184 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 3185 * Table is offset so the last entry is largest mW value that fits in 3186 * a uint16. 3187 */ 3188 3189#define QDBM_OFFSET 153 /* Offset for first entry */ 3190#define QDBM_TABLE_LEN 40 /* Table size */ 3191 3192/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET. 3193 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2 3194 */ 3195#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */ 3196 3197/* Largest mW value that will round down to the last table entry, 3198 * QDBM_OFFSET + QDBM_TABLE_LEN-1. 3199 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2. 3200 */ 3201#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */ 3202 3203static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = { 3204/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */ 3205/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000, 3206/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849, 3207/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119, 3208/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811, 3209/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096 3210}; 3211 3212uint16 3213BCMROMFN(bcm_qdbm_to_mw)(uint8 qdbm) 3214{ 3215 uint factor = 1; 3216 int idx = qdbm - QDBM_OFFSET; 3217 3218 if (idx >= QDBM_TABLE_LEN) { 3219 /* clamp to max uint16 mW value */ 3220 return 0xFFFF; 3221 } 3222 3223 /* scale the qdBm index up to the range of the table 0-40 3224 * where an offset of 40 qdBm equals a factor of 10 mW. 3225 */ 3226 while (idx < 0) { 3227 idx += 40; 3228 factor *= 10; 3229 } 3230 3231 /* return the mW value scaled down to the correct factor of 10, 3232 * adding in factor/2 to get proper rounding. 3233 */ 3234 return ((nqdBm_to_mW_map[idx] + factor/2) / factor); 3235} 3236 3237uint8 3238BCMROMFN(bcm_mw_to_qdbm)(uint16 mw) 3239{ 3240 uint8 qdbm; 3241 int offset; 3242 uint mw_uint = mw; 3243 uint boundary; 3244 3245 /* handle boundary case */ 3246 if (mw_uint <= 1) 3247 return 0; 3248 3249 offset = QDBM_OFFSET; 3250 3251 /* move mw into the range of the table */ 3252 while (mw_uint < QDBM_TABLE_LOW_BOUND) { 3253 mw_uint *= 10; 3254 offset -= 40; 3255 } 3256 3257 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) { 3258 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] - 3259 nqdBm_to_mW_map[qdbm])/2; 3260 if (mw_uint < boundary) break; 3261 } 3262 3263 qdbm += (uint8)offset; 3264 3265 return (qdbm); 3266} 3267 3268 3269uint 3270BCMROMFN(bcm_bitcount)(uint8 *bitmap, uint length) 3271{ 3272 uint bitcount = 0, i; 3273 uint8 tmp; 3274 for (i = 0; i < length; i++) { 3275 tmp = bitmap[i]; 3276 while (tmp) { 3277 bitcount++; 3278 tmp &= (tmp - 1); 3279 } 3280 } 3281 return bitcount; 3282} 3283 3284#ifdef BCMDRIVER 3285 3286/* Initialization of bcmstrbuf structure */ 3287void 3288bcm_binit(struct bcmstrbuf *b, char *buf, uint size) 3289{ 3290 b->origsize = b->size = size; 3291 b->origbuf = b->buf = buf; 3292} 3293 3294/* Buffer sprintf wrapper to guard against buffer overflow */ 3295int 3296bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) 3297{ 3298 va_list ap; 3299 int r; 3300 3301 va_start(ap, fmt); 3302 3303 r = vsnprintf(b->buf, b->size, fmt, ap); 3304 3305 /* Non Ansi C99 compliant returns -1, 3306 * Ansi compliant return r >= b->size, 3307 * bcmstdlib returns 0, handle all 3308 */ 3309 /* r == 0 is also the case when strlen(fmt) is zero. 3310 * typically the case when "" is passed as argument. 3311 */ 3312 if ((r == -1) || (r >= (int)b->size)) { 3313 b->size = 0; 3314 } else { 3315 b->size -= r; 3316 b->buf += r; 3317 } 3318 3319 va_end(ap); 3320 3321 return r; 3322} 3323 3324void 3325bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len) 3326{ 3327 int i; 3328 3329 if (msg != NULL && msg[0] != '\0') 3330 bcm_bprintf(b, "%s", msg); 3331 for (i = 0; i < len; i ++) 3332 bcm_bprintf(b, "%02X", buf[i]); 3333 if (newline) 3334 bcm_bprintf(b, "\n"); 3335} 3336 3337void 3338bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount) 3339{ 3340 int i; 3341 3342 for (i = 0; i < num_bytes; i++) { 3343 num[i] += amount; 3344 if (num[i] >= amount) 3345 break; 3346 amount = 1; 3347 } 3348} 3349 3350int 3351bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes) 3352{ 3353 int i; 3354 3355 for (i = nbytes - 1; i >= 0; i--) { 3356 if (arg1[i] != arg2[i]) 3357 return (arg1[i] - arg2[i]); 3358 } 3359 return 0; 3360} 3361 3362void 3363bcm_print_bytes(const char *name, const uchar *data, int len) 3364{ 3365 int i; 3366 int per_line = 0; 3367 3368 printf("%s: %d \n", name ? name : "", len); 3369 for (i = 0; i < len; i++) { 3370 printf("%02x ", *data++); 3371 per_line++; 3372 if (per_line == 16) { 3373 per_line = 0; 3374 printf("\n"); 3375 } 3376 } 3377 printf("\n"); 3378} 3379#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ 3380 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) 3381#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) 3382 3383int 3384bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) 3385{ 3386 uint i, c; 3387 char *p = buf; 3388 char *endp = buf + SSID_FMT_BUF_LEN; 3389 3390 if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN; 3391 3392 for (i = 0; i < ssid_len; i++) { 3393 c = (uint)ssid[i]; 3394 if (c == '\\') { 3395 *p++ = '\\'; 3396 *p++ = '\\'; 3397 } else if (bcm_isprint((uchar)c)) { 3398 *p++ = (char)c; 3399 } else { 3400 p += snprintf(p, (endp - p), "\\x%02X", c); 3401 } 3402 } 3403 *p = '\0'; 3404 ASSERT(p < endp); 3405 3406 return (int)(p - buf); 3407} 3408#endif 3409 3410#endif /* BCMDRIVER */ 3411 3412/* 3413 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL. 3414 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0 3415 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs. 3416 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs. 3417*/ 3418 3419unsigned int 3420process_nvram_vars(char *varbuf, unsigned int len) 3421{ 3422 char *dp; 3423 bool findNewline; 3424 int column; 3425 unsigned int buf_len, n; 3426 unsigned int pad = 0; 3427 3428 dp = varbuf; 3429 3430 findNewline = FALSE; 3431 column = 0; 3432 3433 for (n = 0; n < len; n++) { 3434 if (varbuf[n] == '\r') 3435 continue; 3436 if (findNewline && varbuf[n] != '\n') 3437 continue; 3438 findNewline = FALSE; 3439 if (varbuf[n] == '#') { 3440 findNewline = TRUE; 3441 continue; 3442 } 3443 if (varbuf[n] == '\n') { 3444 if (column == 0) 3445 continue; 3446 *dp++ = 0; 3447 column = 0; 3448 continue; 3449 } 3450 *dp++ = varbuf[n]; 3451 column++; 3452 } 3453 buf_len = (unsigned int)(dp - varbuf); 3454 if (buf_len % 4) { 3455 pad = 4 - buf_len % 4; 3456 if (pad && (buf_len + pad <= len)) { 3457 buf_len += pad; 3458 } 3459 } 3460 3461 while (dp < varbuf + n) 3462 *dp++ = 0; 3463 3464 return buf_len; 3465} 3466 3467/* calculate a * b + c */ 3468void 3469bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c) 3470{ 3471#define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;} 3472 uint32 r1, r0; 3473 uint32 a1, a0, b1, b0, t, cc = 0; 3474 3475 a1 = a >> 16; 3476 a0 = a & 0xffff; 3477 b1 = b >> 16; 3478 b0 = b & 0xffff; 3479 3480 r0 = a0 * b0; 3481 FORMALIZE(r0); 3482 3483 t = (a1 * b0) << 16; 3484 FORMALIZE(t); 3485 3486 r0 += t; 3487 FORMALIZE(r0); 3488 3489 t = (a0 * b1) << 16; 3490 FORMALIZE(t); 3491 3492 r0 += t; 3493 FORMALIZE(r0); 3494 3495 FORMALIZE(c); 3496 3497 r0 += c; 3498 FORMALIZE(r0); 3499 3500 r0 |= (cc % 2) ? 0x80000000 : 0; 3501 r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2); 3502 3503 *r_high = r1; 3504 *r_low = r0; 3505} 3506 3507/* calculate a / b */ 3508void 3509bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b) 3510{ 3511 uint32 a1 = a_high, a0 = a_low, r0 = 0; 3512 3513 if (b < 2) 3514 return; 3515 3516 while (a1 != 0) { 3517 r0 += (0xffffffff / b) * a1; 3518 bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0); 3519 } 3520 3521 r0 += a0 / b; 3522 *r = r0; 3523} 3524 3525/* calculate a >> b; and returns only lower 32 bits */ 3526void 3527bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b) 3528{ 3529 uint32 a1 = a_high, a0 = a_low, r0 = 0; 3530 3531 if (b == 0) { 3532 r0 = a_low; 3533 *r = r0; 3534 return; 3535 } 3536 3537 if (b < 32) { 3538 a0 = a0 >> b; 3539 a1 = a1 & ((1 << b) - 1); 3540 a1 = a1 << (32 - b); 3541 r0 = a0 | a1; 3542 *r = r0; 3543 return; 3544 } else { 3545 r0 = a1 >> (b - 32); 3546 *r = r0; 3547 return; 3548 } 3549 3550} 3551