Root/package/broadcom-wl/src/driver/bcmutils.c

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

Archive Download this file



interactive