CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
orangepi-xunlong

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

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