linux/drivers/staging/brcm80211/util/bcmutils.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2010 Broadcom Corporation
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#include <linux/ctype.h>
  18#include <linux/kernel.h>
  19#include <linux/string.h>
  20#include <bcmdefs.h>
  21#include <stdarg.h>
  22#include <linux/module.h>
  23#include <linux/pci.h>
  24#include <linux/netdevice.h>
  25#include <osl.h>
  26#include <bcmutils.h>
  27#include <siutils.h>
  28#include <bcmnvram.h>
  29#include <bcmendian.h>
  30#include <bcmdevs.h>
  31#include <proto/ethernet.h>
  32#include <proto/802.1d.h>
  33#include <proto/802.11.h>
  34
  35/* copy a buffer into a pkt buffer chain */
  36uint pktfrombuf(struct osl_info *osh, struct sk_buff *p, uint offset, int len,
  37                unsigned char *buf)
  38{
  39        uint n, ret = 0;
  40
  41        /* skip 'offset' bytes */
  42        for (; p && offset; p = p->next) {
  43                if (offset < (uint) (p->len))
  44                        break;
  45                offset -= p->len;
  46        }
  47
  48        if (!p)
  49                return 0;
  50
  51        /* copy the data */
  52        for (; p && len; p = p->next) {
  53                n = min((uint) (p->len) - offset, (uint) len);
  54                bcopy(buf, p->data + offset, n);
  55                buf += n;
  56                len -= n;
  57                ret += n;
  58                offset = 0;
  59        }
  60
  61        return ret;
  62}
  63/* return total length of buffer chain */
  64uint BCMFASTPATH pkttotlen(struct osl_info *osh, struct sk_buff *p)
  65{
  66        uint total;
  67
  68        total = 0;
  69        for (; p; p = p->next)
  70                total += p->len;
  71        return total;
  72}
  73
  74/*
  75 * osl multiple-precedence packet queue
  76 * hi_prec is always >= the number of the highest non-empty precedence
  77 */
  78struct sk_buff *BCMFASTPATH pktq_penq(struct pktq *pq, int prec,
  79                                      struct sk_buff *p)
  80{
  81        struct pktq_prec *q;
  82
  83        ASSERT(prec >= 0 && prec < pq->num_prec);
  84        ASSERT(p->prev == NULL);        /* queueing chains not allowed */
  85
  86        ASSERT(!pktq_full(pq));
  87        ASSERT(!pktq_pfull(pq, prec));
  88
  89        q = &pq->q[prec];
  90
  91        if (q->head)
  92                q->tail->prev = p;
  93        else
  94                q->head = p;
  95
  96        q->tail = p;
  97        q->len++;
  98
  99        pq->len++;
 100
 101        if (pq->hi_prec < prec)
 102                pq->hi_prec = (u8) prec;
 103
 104        return p;
 105}
 106
 107struct sk_buff *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec,
 108                                           struct sk_buff *p)
 109{
 110        struct pktq_prec *q;
 111
 112        ASSERT(prec >= 0 && prec < pq->num_prec);
 113        ASSERT(p->prev == NULL);        /* queueing chains not allowed */
 114
 115        ASSERT(!pktq_full(pq));
 116        ASSERT(!pktq_pfull(pq, prec));
 117
 118        q = &pq->q[prec];
 119
 120        if (q->head == NULL)
 121                q->tail = p;
 122
 123        p->prev = q->head;
 124        q->head = p;
 125        q->len++;
 126
 127        pq->len++;
 128
 129        if (pq->hi_prec < prec)
 130                pq->hi_prec = (u8) prec;
 131
 132        return p;
 133}
 134
 135struct sk_buff *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec)
 136{
 137        struct pktq_prec *q;
 138        struct sk_buff *p;
 139
 140        ASSERT(prec >= 0 && prec < pq->num_prec);
 141
 142        q = &pq->q[prec];
 143
 144        p = q->head;
 145        if (p == NULL)
 146                return NULL;
 147
 148        q->head = p->prev;
 149        if (q->head == NULL)
 150                q->tail = NULL;
 151
 152        q->len--;
 153
 154        pq->len--;
 155
 156        p->prev = NULL;
 157
 158        return p;
 159}
 160
 161struct sk_buff *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec)
 162{
 163        struct pktq_prec *q;
 164        struct sk_buff *p, *prev;
 165
 166        ASSERT(prec >= 0 && prec < pq->num_prec);
 167
 168        q = &pq->q[prec];
 169
 170        p = q->head;
 171        if (p == NULL)
 172                return NULL;
 173
 174        for (prev = NULL; p != q->tail; p = p->prev)
 175                prev = p;
 176
 177        if (prev)
 178                prev->prev = NULL;
 179        else
 180                q->head = NULL;
 181
 182        q->tail = prev;
 183        q->len--;
 184
 185        pq->len--;
 186
 187        return p;
 188}
 189
 190#ifdef BRCM_FULLMAC
 191void pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir)
 192{
 193        struct pktq_prec *q;
 194        struct sk_buff *p;
 195
 196        q = &pq->q[prec];
 197        p = q->head;
 198        while (p) {
 199                q->head = p->prev;
 200                p->prev = NULL;
 201                pkt_buf_free_skb(osh, p, dir);
 202                q->len--;
 203                pq->len--;
 204                p = q->head;
 205        }
 206        ASSERT(q->len == 0);
 207        q->tail = NULL;
 208}
 209
 210void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir)
 211{
 212        int prec;
 213        for (prec = 0; prec < pq->num_prec; prec++)
 214                pktq_pflush(osh, pq, prec, dir);
 215        ASSERT(pq->len == 0);
 216}
 217#else /* !BRCM_FULLMAC */
 218void
 219pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir,
 220            ifpkt_cb_t fn, int arg)
 221{
 222        struct pktq_prec *q;
 223        struct sk_buff *p, *prev = NULL;
 224
 225        q = &pq->q[prec];
 226        p = q->head;
 227        while (p) {
 228                if (fn == NULL || (*fn) (p, arg)) {
 229                        bool head = (p == q->head);
 230                        if (head)
 231                                q->head = p->prev;
 232                        else
 233                                prev->prev = p->prev;
 234                        p->prev = NULL;
 235                        pkt_buf_free_skb(osh, p, dir);
 236                        q->len--;
 237                        pq->len--;
 238                        p = (head ? q->head : prev->prev);
 239                } else {
 240                        prev = p;
 241                        p = p->prev;
 242                }
 243        }
 244
 245        if (q->head == NULL) {
 246                ASSERT(q->len == 0);
 247                q->tail = NULL;
 248        }
 249}
 250
 251void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir,
 252                ifpkt_cb_t fn, int arg)
 253{
 254        int prec;
 255        for (prec = 0; prec < pq->num_prec; prec++)
 256                pktq_pflush(osh, pq, prec, dir, fn, arg);
 257        if (fn == NULL)
 258                ASSERT(pq->len == 0);
 259}
 260#endif /* BRCM_FULLMAC */
 261
 262void pktq_init(struct pktq *pq, int num_prec, int max_len)
 263{
 264        int prec;
 265
 266        ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
 267
 268        /* pq is variable size; only zero out what's requested */
 269        memset(pq, 0,
 270              offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
 271
 272        pq->num_prec = (u16) num_prec;
 273
 274        pq->max = (u16) max_len;
 275
 276        for (prec = 0; prec < num_prec; prec++)
 277                pq->q[prec].max = pq->max;
 278}
 279
 280struct sk_buff *pktq_peek_tail(struct pktq *pq, int *prec_out)
 281{
 282        int prec;
 283
 284        if (pq->len == 0)
 285                return NULL;
 286
 287        for (prec = 0; prec < pq->hi_prec; prec++)
 288                if (pq->q[prec].head)
 289                        break;
 290
 291        if (prec_out)
 292                *prec_out = prec;
 293
 294        return pq->q[prec].tail;
 295}
 296
 297/* Return sum of lengths of a specific set of precedences */
 298int pktq_mlen(struct pktq *pq, uint prec_bmp)
 299{
 300        int prec, len;
 301
 302        len = 0;
 303
 304        for (prec = 0; prec <= pq->hi_prec; prec++)
 305                if (prec_bmp & (1 << prec))
 306                        len += pq->q[prec].len;
 307
 308        return len;
 309}
 310/* Priority dequeue from a specific set of precedences */
 311struct sk_buff *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp,
 312                                      int *prec_out)
 313{
 314        struct pktq_prec *q;
 315        struct sk_buff *p;
 316        int prec;
 317
 318        if (pq->len == 0)
 319                return NULL;
 320
 321        while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
 322                pq->hi_prec--;
 323
 324        while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
 325                if (prec-- == 0)
 326                        return NULL;
 327
 328        q = &pq->q[prec];
 329
 330        p = q->head;
 331        if (p == NULL)
 332                return NULL;
 333
 334        q->head = p->prev;
 335        if (q->head == NULL)
 336                q->tail = NULL;
 337
 338        q->len--;
 339
 340        if (prec_out)
 341                *prec_out = prec;
 342
 343        pq->len--;
 344
 345        p->prev = NULL;
 346
 347        return p;
 348}
 349
 350/* parse a xx:xx:xx:xx:xx:xx format ethernet address */
 351int bcm_ether_atoe(char *p, struct ether_addr *ea)
 352{
 353        int i = 0;
 354
 355        for (;;) {
 356                ea->octet[i++] = (char)simple_strtoul(p, &p, 16);
 357                if (!*p++ || i == 6)
 358                        break;
 359        }
 360
 361        return i == 6;
 362}
 363
 364/*
 365 * Search the name=value vars for a specific one and return its value.
 366 * Returns NULL if not found.
 367 */
 368char *getvar(char *vars, const char *name)
 369{
 370        char *s;
 371        int len;
 372
 373        if (!name)
 374                return NULL;
 375
 376        len = strlen(name);
 377        if (len == 0)
 378                return NULL;
 379
 380        /* first look in vars[] */
 381        for (s = vars; s && *s;) {
 382                if ((memcmp(s, name, len) == 0) && (s[len] == '='))
 383                        return &s[len + 1];
 384
 385                while (*s++)
 386                        ;
 387        }
 388#ifdef BRCM_FULLMAC
 389        return NULL;
 390#else
 391        /* then query nvram */
 392        return nvram_get(name);
 393#endif
 394}
 395
 396/*
 397 * Search the vars for a specific one and return its value as
 398 * an integer. Returns 0 if not found.
 399 */
 400int getintvar(char *vars, const char *name)
 401{
 402        char *val;
 403
 404        val = getvar(vars, name);
 405        if (val == NULL)
 406                return 0;
 407
 408        return simple_strtoul(val, NULL, 0);
 409}
 410
 411#if defined(BCMDBG)
 412/* pretty hex print a pkt buffer chain */
 413void prpkt(const char *msg, struct osl_info *osh, struct sk_buff *p0)
 414{
 415        struct sk_buff *p;
 416
 417        if (msg && (msg[0] != '\0'))
 418                printf("%s:\n", msg);
 419
 420        for (p = p0; p; p = p->next)
 421                prhex(NULL, p->data, p->len);
 422}
 423#endif                          /* defined(BCMDBG) */
 424
 425static char bcm_undeferrstr[BCME_STRLEN];
 426
 427static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
 428
 429/* Convert the error codes into related error strings  */
 430const char *bcmerrorstr(int bcmerror)
 431{
 432        /* check if someone added a bcmerror code but
 433                 forgot to add errorstring */
 434        ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(bcmerrorstrtable) - 1));
 435
 436        if (bcmerror > 0 || bcmerror < BCME_LAST) {
 437                snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d",
 438                         bcmerror);
 439                return bcm_undeferrstr;
 440        }
 441
 442        ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
 443
 444        return bcmerrorstrtable[-bcmerror];
 445}
 446
 447/* iovar table lookup */
 448const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
 449{
 450        const bcm_iovar_t *vi;
 451        const char *lookup_name;
 452
 453        /* skip any ':' delimited option prefixes */
 454        lookup_name = strrchr(name, ':');
 455        if (lookup_name != NULL)
 456                lookup_name++;
 457        else
 458                lookup_name = name;
 459
 460        ASSERT(table != NULL);
 461
 462        for (vi = table; vi->name; vi++) {
 463                if (!strcmp(vi->name, lookup_name))
 464                        return vi;
 465        }
 466        /* ran to end of table */
 467
 468        return NULL;            /* var name not found */
 469}
 470
 471int bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
 472{
 473        int bcmerror = 0;
 474
 475        /* length check on io buf */
 476        switch (vi->type) {
 477        case IOVT_BOOL:
 478        case IOVT_INT8:
 479        case IOVT_INT16:
 480        case IOVT_INT32:
 481        case IOVT_UINT8:
 482        case IOVT_UINT16:
 483        case IOVT_UINT32:
 484                /* all integers are s32 sized args at the ioctl interface */
 485                if (len < (int)sizeof(int)) {
 486                        bcmerror = BCME_BUFTOOSHORT;
 487                }
 488                break;
 489
 490        case IOVT_BUFFER:
 491                /* buffer must meet minimum length requirement */
 492                if (len < vi->minlen) {
 493                        bcmerror = BCME_BUFTOOSHORT;
 494                }
 495                break;
 496
 497        case IOVT_VOID:
 498                if (!set) {
 499                        /* Cannot return nil... */
 500                        bcmerror = BCME_UNSUPPORTED;
 501                } else if (len) {
 502                        /* Set is an action w/o parameters */
 503                        bcmerror = BCME_BUFTOOLONG;
 504                }
 505                break;
 506
 507        default:
 508                /* unknown type for length check in iovar info */
 509                ASSERT(0);
 510                bcmerror = BCME_UNSUPPORTED;
 511        }
 512
 513        return bcmerror;
 514}
 515
 516/*******************************************************************************
 517 * crc8
 518 *
 519 * Computes a crc8 over the input data using the polynomial:
 520 *
 521 *       x^8 + x^7 +x^6 + x^4 + x^2 + 1
 522 *
 523 * The caller provides the initial value (either CRC8_INIT_VALUE
 524 * or the previous returned value) to allow for processing of
 525 * discontiguous blocks of data.  When generating the CRC the
 526 * caller is responsible for complementing the final return value
 527 * and inserting it into the byte stream.  When checking, a final
 528 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
 529 *
 530 * Reference: Dallas Semiconductor Application Note 27
 531 *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
 532 *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
 533 *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
 534 *
 535 * ****************************************************************************
 536 */
 537
 538static const u8 crc8_table[256] = {
 539        0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
 540        0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
 541        0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
 542        0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
 543        0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
 544        0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
 545        0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
 546        0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
 547        0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
 548        0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
 549        0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
 550        0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
 551        0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
 552        0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
 553        0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
 554        0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
 555        0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
 556        0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
 557        0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
 558        0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
 559        0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
 560        0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
 561        0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
 562        0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
 563        0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
 564        0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
 565        0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
 566        0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
 567        0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
 568        0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
 569        0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
 570        0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
 571};
 572
 573#define CRC_INNER_LOOP(n, c, x) \
 574        ((c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff])
 575
 576u8 hndcrc8(u8 *pdata,   /* pointer to array of data to process */
 577                         uint nbytes,   /* number of input data bytes to process */
 578                         u8 crc /* either CRC8_INIT_VALUE or previous return value */
 579    ) {
 580        /* hard code the crc loop instead of using CRC_INNER_LOOP macro
 581         * to avoid the undefined and unnecessary (u8 >> 8) operation.
 582         */
 583        while (nbytes-- > 0)
 584                crc = crc8_table[(crc ^ *pdata++) & 0xff];
 585
 586        return crc;
 587}
 588
 589/*******************************************************************************
 590 * crc16
 591 *
 592 * Computes a crc16 over the input data using the polynomial:
 593 *
 594 *       x^16 + x^12 +x^5 + 1
 595 *
 596 * The caller provides the initial value (either CRC16_INIT_VALUE
 597 * or the previous returned value) to allow for processing of
 598 * discontiguous blocks of data.  When generating the CRC the
 599 * caller is responsible for complementing the final return value
 600 * and inserting it into the byte stream.  When checking, a final
 601 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
 602 *
 603 * Reference: Dallas Semiconductor Application Note 27
 604 *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
 605 *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
 606 *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
 607 *
 608 * ****************************************************************************
 609 */
 610
 611static const u16 crc16_table[256] = {
 612        0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
 613        0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
 614        0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
 615        0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
 616        0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
 617        0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
 618        0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
 619        0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
 620        0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
 621        0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
 622        0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
 623        0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
 624        0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
 625        0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
 626        0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
 627        0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
 628        0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
 629        0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
 630        0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
 631        0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
 632        0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
 633        0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
 634        0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
 635        0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
 636        0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
 637        0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
 638        0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
 639        0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
 640        0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
 641        0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
 642        0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
 643        0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
 644};
 645
 646u16 hndcrc16(u8 *pdata, /* pointer to array of data to process */
 647        uint nbytes,    /* number of input data bytes to process */
 648        u16 crc /* either CRC16_INIT_VALUE or previous return value */
 649    ) {
 650        while (nbytes-- > 0)
 651                CRC_INNER_LOOP(16, crc, *pdata++);
 652        return crc;
 653}
 654
 655static const u32 crc32_table[256] = {
 656        0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
 657        0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
 658        0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
 659        0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
 660        0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
 661        0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
 662        0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
 663        0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
 664        0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
 665        0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
 666        0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
 667        0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
 668        0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
 669        0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
 670        0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
 671        0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
 672        0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
 673        0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
 674        0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
 675        0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
 676        0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
 677        0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
 678        0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
 679        0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
 680        0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
 681        0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
 682        0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
 683        0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
 684        0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
 685        0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
 686        0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
 687        0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
 688        0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
 689        0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
 690        0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
 691        0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
 692        0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
 693        0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
 694        0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
 695        0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
 696        0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
 697        0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
 698        0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
 699        0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
 700        0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
 701        0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
 702        0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
 703        0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
 704        0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
 705        0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
 706        0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
 707        0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
 708        0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
 709        0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
 710        0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
 711        0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
 712        0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
 713        0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
 714        0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
 715        0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
 716        0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
 717        0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
 718        0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
 719        0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
 720};
 721
 722u32 hndcrc32(u8 *pdata, /* pointer to array of data to process */
 723                uint nbytes,    /* number of input data bytes to process */
 724                u32 crc /* either CRC32_INIT_VALUE or previous
 725                                         return value */
 726)
 727{
 728        u8 *pend;
 729#ifdef __mips__
 730        u8 tmp[4];
 731        unsigned long *tptr = (unsigned long *) tmp;
 732
 733        /* in case the beginning of the buffer isn't aligned */
 734        pend = (u8 *) ((uint) (pdata + 3) & 0xfffffffc);
 735        nbytes -= (pend - pdata);
 736        while (pdata < pend)
 737                CRC_INNER_LOOP(32, crc, *pdata++);
 738
 739        /* handle bulk of data as 32-bit words */
 740        pend = pdata + (nbytes & 0xfffffffc);
 741        while (pdata < pend) {
 742                *tptr = *(unsigned long *) pdata;
 743                pdata += sizeof(unsigned long *);
 744                CRC_INNER_LOOP(32, crc, tmp[0]);
 745                CRC_INNER_LOOP(32, crc, tmp[1]);
 746                CRC_INNER_LOOP(32, crc, tmp[2]);
 747                CRC_INNER_LOOP(32, crc, tmp[3]);
 748        }
 749
 750        /* 1-3 bytes at end of buffer */
 751        pend = pdata + (nbytes & 0x03);
 752        while (pdata < pend)
 753                CRC_INNER_LOOP(32, crc, *pdata++);
 754#else
 755        pend = pdata + nbytes;
 756        while (pdata < pend)
 757                CRC_INNER_LOOP(32, crc, *pdata++);
 758#endif                          /* __mips__ */
 759
 760        return crc;
 761}
 762/*
 763 * Traverse a string of 1-byte tag/1-byte length/variable-length value
 764 * triples, returning a pointer to the substring whose first element
 765 * matches tag
 766 */
 767bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key)
 768{
 769        bcm_tlv_t *elt;
 770        int totlen;
 771
 772        elt = (bcm_tlv_t *) buf;
 773        totlen = buflen;
 774
 775        /* find tagged parameter */
 776        while (totlen >= 2) {
 777                int len = elt->len;
 778
 779                /* validate remaining totlen */
 780                if ((elt->id == key) && (totlen >= (len + 2)))
 781                        return elt;
 782
 783                elt = (bcm_tlv_t *) ((u8 *) elt + (len + 2));
 784                totlen -= (len + 2);
 785        }
 786
 787        return NULL;
 788}
 789
 790
 791#if defined(BCMDBG)
 792int
 793bcm_format_flags(const bcm_bit_desc_t *bd, u32 flags, char *buf, int len)
 794{
 795        int i;
 796        char *p = buf;
 797        char hexstr[16];
 798        int slen = 0, nlen = 0;
 799        u32 bit;
 800        const char *name;
 801
 802        if (len < 2 || !buf)
 803                return 0;
 804
 805        buf[0] = '\0';
 806
 807        for (i = 0; flags != 0; i++) {
 808                bit = bd[i].bit;
 809                name = bd[i].name;
 810                if (bit == 0 && flags != 0) {
 811                        /* print any unnamed bits */
 812                        snprintf(hexstr, 16, "0x%X", flags);
 813                        name = hexstr;
 814                        flags = 0;      /* exit loop */
 815                } else if ((flags & bit) == 0)
 816                        continue;
 817                flags &= ~bit;
 818                nlen = strlen(name);
 819                slen += nlen;
 820                /* count btwn flag space */
 821                if (flags != 0)
 822                        slen += 1;
 823                /* need NULL char as well */
 824                if (len <= slen)
 825                        break;
 826                /* copy NULL char but don't count it */
 827                strncpy(p, name, nlen + 1);
 828                p += nlen;
 829                /* copy btwn flag space and NULL char */
 830                if (flags != 0)
 831                        p += snprintf(p, 2, " ");
 832                len -= slen;
 833        }
 834
 835        /* indicate the str was too short */
 836        if (flags != 0) {
 837                if (len < 2)
 838                        p -= 2 - len;   /* overwrite last char */
 839                p += snprintf(p, 2, ">");
 840        }
 841
 842        return (int)(p - buf);
 843}
 844
 845/* print bytes formatted as hex to a string. return the resulting string length */
 846int bcm_format_hex(char *str, const void *bytes, int len)
 847{
 848        int i;
 849        char *p = str;
 850        const u8 *src = (const u8 *)bytes;
 851
 852        for (i = 0; i < len; i++) {
 853                p += snprintf(p, 3, "%02X", *src);
 854                src++;
 855        }
 856        return (int)(p - str);
 857}
 858#endif                          /* defined(BCMDBG) */
 859
 860/* pretty hex print a contiguous buffer */
 861void prhex(const char *msg, unsigned char *buf, uint nbytes)
 862{
 863        char line[128], *p;
 864        int len = sizeof(line);
 865        int nchar;
 866        uint i;
 867
 868        if (msg && (msg[0] != '\0'))
 869                printf("%s:\n", msg);
 870
 871        p = line;
 872        for (i = 0; i < nbytes; i++) {
 873                if (i % 16 == 0) {
 874                        nchar = snprintf(p, len, "  %04d: ", i);        /* line prefix */
 875                        p += nchar;
 876                        len -= nchar;
 877                }
 878                if (len > 0) {
 879                        nchar = snprintf(p, len, "%02x ", buf[i]);
 880                        p += nchar;
 881                        len -= nchar;
 882                }
 883
 884                if (i % 16 == 15) {
 885                        printf("%s\n", line);   /* flush line */
 886                        p = line;
 887                        len = sizeof(line);
 888                }
 889        }
 890
 891        /* flush last partial line */
 892        if (p != line)
 893                printf("%s\n", line);
 894}
 895
 896char *bcm_chipname(uint chipid, char *buf, uint len)
 897{
 898        const char *fmt;
 899
 900        fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
 901        snprintf(buf, len, fmt, chipid);
 902        return buf;
 903}
 904
 905uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
 906{
 907        uint len;
 908
 909        len = strlen(name) + 1;
 910
 911        if ((len + datalen) > buflen)
 912                return 0;
 913
 914        strncpy(buf, name, buflen);
 915
 916        /* append data onto the end of the name string */
 917        memcpy(&buf[len], data, datalen);
 918        len += datalen;
 919
 920        return len;
 921}
 922
 923/* Quarter dBm units to mW
 924 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
 925 * Table is offset so the last entry is largest mW value that fits in
 926 * a u16.
 927 */
 928
 929#define QDBM_OFFSET 153         /* Offset for first entry */
 930#define QDBM_TABLE_LEN 40       /* Table size */
 931
 932/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
 933 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
 934 */
 935#define QDBM_TABLE_LOW_BOUND 6493       /* Low bound */
 936
 937/* Largest mW value that will round down to the last table entry,
 938 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
 939 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
 940 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
 941 */
 942#define QDBM_TABLE_HIGH_BOUND 64938     /* High bound */
 943
 944static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
 945/* qdBm:        +0      +1      +2      +3      +4      +5      +6      +7 */
 946/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
 947/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
 948/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
 949/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
 950/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
 951};
 952
 953u16 bcm_qdbm_to_mw(u8 qdbm)
 954{
 955        uint factor = 1;
 956        int idx = qdbm - QDBM_OFFSET;
 957
 958        if (idx >= QDBM_TABLE_LEN) {
 959                /* clamp to max u16 mW value */
 960                return 0xFFFF;
 961        }
 962
 963        /* scale the qdBm index up to the range of the table 0-40
 964         * where an offset of 40 qdBm equals a factor of 10 mW.
 965         */
 966        while (idx < 0) {
 967                idx += 40;
 968                factor *= 10;
 969        }
 970
 971        /* return the mW value scaled down to the correct factor of 10,
 972         * adding in factor/2 to get proper rounding.
 973         */
 974        return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
 975}
 976u8 bcm_mw_to_qdbm(u16 mw)
 977{
 978        u8 qdbm;
 979        int offset;
 980        uint mw_uint = mw;
 981        uint boundary;
 982
 983        /* handle boundary case */
 984        if (mw_uint <= 1)
 985                return 0;
 986
 987        offset = QDBM_OFFSET;
 988
 989        /* move mw into the range of the table */
 990        while (mw_uint < QDBM_TABLE_LOW_BOUND) {
 991                mw_uint *= 10;
 992                offset -= 40;
 993        }
 994
 995        for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
 996                boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
 997                                                    nqdBm_to_mW_map[qdbm]) / 2;
 998                if (mw_uint < boundary)
 999                        break;
1000        }
1001
1002        qdbm += (u8) offset;
1003
1004        return qdbm;
1005}
1006uint bcm_bitcount(u8 *bitmap, uint length)
1007{
1008        uint bitcount = 0, i;
1009        u8 tmp;
1010        for (i = 0; i < length; i++) {
1011                tmp = bitmap[i];
1012                while (tmp) {
1013                        bitcount++;
1014                        tmp &= (tmp - 1);
1015                }
1016        }
1017        return bitcount;
1018}
1019/* Initialization of bcmstrbuf structure */
1020void bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1021{
1022        b->origsize = b->size = size;
1023        b->origbuf = b->buf = buf;
1024}
1025
1026/* Buffer sprintf wrapper to guard against buffer overflow */
1027int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1028{
1029        va_list ap;
1030        int r;
1031
1032        va_start(ap, fmt);
1033        r = vsnprintf(b->buf, b->size, fmt, ap);
1034
1035        /* Non Ansi C99 compliant returns -1,
1036         * Ansi compliant return r >= b->size,
1037         * bcmstdlib returns 0, handle all
1038         */
1039        if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1040                b->size = 0;
1041        } else {
1042                b->size -= r;
1043                b->buf += r;
1044        }
1045
1046        va_end(ap);
1047
1048        return r;
1049}
1050
1051