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