1 /*
2 * Driver O/S-independent utility routines
3 *
4 * Copyright (C) 2020, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 *
21 * <<Broadcom-WL-IPTag/Dual:>>
22 */
23
24 #include <typedefs.h>
25 #include <bcmdefs.h>
26 #include <stdarg.h>
27 #ifdef BCMDRIVER
28 #include <osl.h>
29 #include <bcmutils.h>
30 #if !defined(BCMDONGLEHOST) || defined(BCMNVRAM)
31 #include <bcmnvram.h>
32 #endif
33
34 #else /* !BCMDRIVER */
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <bcmutils.h>
39
40 #if defined(BCMEXTSUP)
41 #include <bcm_osl.h>
42 #endif
43
44 #ifndef ASSERT
45 #define ASSERT(exp)
46 #endif
47
48 #endif /* !BCMDRIVER */
49
50 #ifdef WL_UNITTEST
51 /*
52 * Definitions and includes needed during software unit test compilation and execution.
53 */
54 #include <stdio.h>
55 #include <stdlib.h>
56 #ifdef ASSERT
57 #undef ASSERT
58 #endif /* ASSERT */
59 #define ASSERT(exp)
60 #endif /* WL_UNITTEST */
61
62 #if defined(_WIN32) || defined(NDIS)
63 /* Debatable */
64 #include <bcmstdlib.h>
65 #endif
66 #include <bcmstdlib_s.h>
67 #include <bcmendian.h>
68 #include <bcmdevs.h>
69 #include <ethernet.h>
70 #include <vlan.h>
71 #include <bcmip.h>
72 #include <802.1d.h>
73 #include <802.11.h>
74 #include <bcmip.h>
75 #include <bcmipv6.h>
76 #include <bcmtcp.h>
77 #ifdef BCMPERFSTATS
78 #include <bcmperf.h>
79 #endif
80
81 #define NUMBER_OF_BITS_BYTE 8u
82
83 #ifdef CUSTOM_DSCP_TO_PRIO_MAPPING
84 #define CUST_IPV4_TOS_PREC_MASK 0x3F
85 #define DCSP_MAX_VALUE 64
86 extern uint dhd_dscpmap_enable;
87 /* 0:BE,1:BK,2:RESV(BK):,3:EE,:4:CL,5:VI,6:VO,7:NC */
88 int dscp2priomap[DCSP_MAX_VALUE]=
89 {
90 0, 0, 0, 0, 0, 0, 0, 0,
91 0, 0, 0, 0, 0, 0, 0, 0, /* BK->BE */
92 2, 0, 0, 0, 0, 0, 0, 0,
93 3, 0, 0, 0, 0, 0, 0, 0,
94 4, 0, 0, 0, 0, 0, 0, 0,
95 5, 0, 0, 0, 0, 0, 0, 0,
96 6, 0, 0, 0, 0, 0, 0, 0,
97 7, 0, 0, 0, 0, 0, 0, 0
98 };
99 #endif /* CUSTOM_DSCP_TO_PRIO_MAPPING */
100
101 #ifdef PRIVACY_MASK
102 struct ether_addr privacy_addrmask;
103
104 /* RAM accessor function to avoid 'privacy_addrmask' in ROM/RAM shared data section. */
105 static struct ether_addr *
BCMRAMFN(privacy_addrmask_get)106 BCMRAMFN(privacy_addrmask_get)(void)
107 {
108 return &privacy_addrmask;
109 }
110 #endif /* PRIVACY_MASK */
111
112 #ifdef BCMDRIVER
113
114 #ifndef BCM_ARM_BACKTRACE
115 /* function pointers for firmware stack backtrace utility */
116 void (*const print_btrace_int_fn)(int depth, uint32 pc, uint32 lr, uint32 sp) = NULL;
117 void (*const print_btrace_fn)(int depth) = NULL;
118 #else
119 void print_backtrace(int depth);
120 void (*const print_btrace_fn)(int depth) = print_backtrace;
121 void print_backtrace_int(int depth, uint32 pc, uint32 lr, uint32 sp);
122 void (*const print_btrace_int_fn)(int depth, uint32 pc, uint32 lr, uint32 sp) = print_backtrace_int;
123 #endif
124
125 #if !defined(BCMDONGLEHOST)
126 /* Forward declarations */
127 char * getvar_internal(char *vars, const char *name);
128 int getintvar_internal(char *vars, const char *name);
129 int getintvararray_internal(char *vars, const char *name, int index);
130 int getintvararraysize_internal(char *vars, const char *name);
131
132 #ifndef WL_FWSIGN
133 /*
134 * Search the name=value vars for a specific one and return its value.
135 * Returns NULL if not found.
136 */
137 char *
getvar(char * vars,const char * name)138 getvar(char *vars, const char *name)
139 {
140 NVRAM_RECLAIM_CHECK(name);
141 return getvar_internal(vars, name);
142 }
143
144 char *
getvar_internal(char * vars,const char * name)145 getvar_internal(char *vars, const char *name)
146 {
147 char *s;
148 uint len;
149
150 if (!name)
151 return NULL;
152
153 len = strlen(name);
154 if (len == 0u) {
155 return NULL;
156 }
157
158 /* first look in vars[] */
159 for (s = vars; s && *s;) {
160 if ((bcmp(s, name, len) == 0) && (s[len] == '=')) {
161 return (&s[len+1u]);
162 }
163 while (*s++)
164 ;
165 }
166
167 /* then query nvram */
168 return (nvram_get(name));
169 }
170
171 /*
172 * Search the vars for a specific one and return its value as
173 * an integer. Returns 0 if not found.
174 */
175 int
getintvar(char * vars,const char * name)176 getintvar(char *vars, const char *name)
177 {
178 NVRAM_RECLAIM_CHECK(name);
179 return getintvar_internal(vars, name);
180 }
181
182 int
getintvar_internal(char * vars,const char * name)183 getintvar_internal(char *vars, const char *name)
184 {
185 char *val;
186
187 if ((val = getvar_internal(vars, name)) == NULL)
188 return (0);
189
190 return (bcm_strtoul(val, NULL, 0));
191 }
192
193 int
getintvararray(char * vars,const char * name,int index)194 getintvararray(char *vars, const char *name, int index)
195 {
196 NVRAM_RECLAIM_CHECK(name);
197 return getintvararray_internal(vars, name, index);
198 }
199
200 int
getintvararray_internal(char * vars,const char * name,int index)201 getintvararray_internal(char *vars, const char *name, int index)
202 {
203 char *buf, *endp;
204 int i = 0;
205 int val = 0;
206
207 if ((buf = getvar_internal(vars, name)) == NULL) {
208 return (0);
209 }
210
211 /* table values are always separated by "," or " " */
212 while (*buf != '\0') {
213 val = bcm_strtoul(buf, &endp, 0);
214 if (i == index) {
215 return val;
216 }
217 buf = endp;
218 /* delimiter is ',' */
219 if (*buf == ',')
220 buf++;
221 i++;
222 }
223 return (0);
224 }
225
226 int
getintvararraysize(char * vars,const char * name)227 getintvararraysize(char *vars, const char *name)
228 {
229 NVRAM_RECLAIM_CHECK(name);
230 return getintvararraysize_internal(vars, name);
231 }
232
233 int
getintvararraysize_internal(char * vars,const char * name)234 getintvararraysize_internal(char *vars, const char *name)
235 {
236 char *buf, *endp;
237 int count = 0;
238 int val = 0;
239
240 if ((buf = getvar_internal(vars, name)) == NULL) {
241 return (0);
242 }
243
244 /* table values are always separated by "," or " " */
245 while (*buf != '\0') {
246 val = bcm_strtoul(buf, &endp, 0);
247 buf = endp;
248 /* delimiter is ',' */
249 if (*buf == ',')
250 buf++;
251 count++;
252 }
253 BCM_REFERENCE(val);
254 return count;
255 }
256
257 /* Read an array of values from a possibly slice-specific nvram string
258 * Store the values in either the uint8 dest_array1 or in the int16 dest_array2.
259 * Pass in NULL for the dest_array[12] that is not to be used.
260 */
261 static int
BCMATTACHFN(getintvararray_slicespecific)262 BCMATTACHFN(getintvararray_slicespecific)(osl_t *osh, char *vars, char *vars_table_accessor,
263 const char* name, uint8* dest_array1, int16* dest_array2, uint dest_size)
264 {
265 uint i;
266 uint array_size = 0;
267 int err = BCME_OK;
268 uint prefixed_name_sz;
269 char *prefixed_name = NULL;
270 const char *new_name;
271 int val;
272
273 prefixed_name_sz = get_slicespecific_var_name(osh, vars_table_accessor,
274 name, &prefixed_name);
275 if (prefixed_name_sz == 0) {
276 return BCME_NOMEM;
277 }
278
279 new_name = prefixed_name;
280 (void) new_name;
281 if (getvar(vars, new_name) == NULL) {
282 /* Try again without the slice prefix in the name */
283 new_name = name;
284 if (getvar(vars, name) == NULL) {
285 err = BCME_NOTFOUND;
286 goto done;
287 }
288 }
289
290 array_size = (uint)getintvararraysize(vars, new_name);
291 if (array_size > dest_size) {
292 err = BCME_BUFTOOSHORT;
293 ASSERT(array_size <= dest_size);
294 goto done;
295 }
296
297 /* limit the initialization to the size of the nvram array */
298 array_size = MIN(array_size, dest_size);
299
300 /* load the destination array with the nvram array values */
301 for (i = 0; i < array_size; i++) {
302 val = getintvararray(vars, new_name, i);
303 if (dest_array1) {
304 dest_array1[i] = (uint8)val;
305 } else if (dest_array2) {
306 dest_array2[i] = (int16)val;
307 }
308 }
309 done:
310 MFREE(osh, prefixed_name, prefixed_name_sz);
311 return (err < 0) ? err : (int)array_size;
312 }
313
314 int
BCMATTACHFN(get_uint8_vararray_slicespecific)315 BCMATTACHFN(get_uint8_vararray_slicespecific)(osl_t *osh, char *vars, char *vars_table_accessor,
316 const char* name, uint8* dest_array, uint dest_size)
317 {
318 int ret;
319
320 ret = getintvararray_slicespecific(osh, vars, vars_table_accessor,
321 name, dest_array, NULL, dest_size);
322 return ret;
323 }
324
325 int
BCMATTACHFN(get_int16_vararray_slicespecific)326 BCMATTACHFN(get_int16_vararray_slicespecific)(osl_t *osh, char *vars, char *vars_table_accessor,
327 const char* name, int16* dest_array, uint dest_size)
328 {
329 return getintvararray_slicespecific(osh, vars, vars_table_accessor,
330 name, NULL, dest_array, dest_size);
331 }
332
333 /* Prepend a slice-specific accessor to an nvram string name.
334 * Sets name_out to the allocated string. Returns the allocated size of the name string.
335 * Caller is responsible for freeing the resulting name string with MFREE.
336 */
337 uint
BCMATTACHFN(get_slicespecific_var_name)338 BCMATTACHFN(get_slicespecific_var_name)(osl_t *osh, char *vars_table_accessor, const char *name,
339 char **name_out)
340 {
341 char *name_with_prefix = NULL;
342 uint sz;
343 uint max_copy_size;
344
345 sz = strlen(name) + strlen(vars_table_accessor) + 1;
346 name_with_prefix = (char *) MALLOC_NOPERSIST(osh, sz);
347 if (name_with_prefix == NULL) {
348 sz = 0;
349 goto end;
350 }
351 name_with_prefix[0] = 0;
352 name_with_prefix[sz - 1] = 0;
353 max_copy_size = sz - 1;
354
355 /* if accessor contains a "slice/N/" string */
356 if (vars_table_accessor[0] != 0) {
357 /* prepend accessor to the vars-name */
358 bcmstrncat(name_with_prefix, vars_table_accessor, max_copy_size);
359 max_copy_size -= strlen(name_with_prefix);
360 }
361
362 /* Append vars-name */
363 bcmstrncat(name_with_prefix, name, max_copy_size);
364 end:
365 *name_out = name_with_prefix;
366 return sz;
367 }
368 #endif /* WL_FWSIGN */
369
370 /* Search for token in comma separated token-string */
371 static int
findmatch(const char * string,const char * name)372 findmatch(const char *string, const char *name)
373 {
374 uint len;
375 char *c;
376
377 len = strlen(name);
378 while ((c = strchr(string, ',')) != NULL) {
379 if (len == (uint)(c - string) && !strncmp(string, name, len))
380 return 1;
381 string = c + 1;
382 }
383
384 return (!strcmp(string, name));
385 }
386
387 /* Return gpio pin number assigned to the named pin
388 *
389 * Variable should be in format:
390 *
391 * gpio<N>=pin_name,pin_name
392 *
393 * This format allows multiple features to share the gpio with mutual
394 * understanding.
395 *
396 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
397 * and if def_pin is not used by others.
398 */
399 uint
getgpiopin(char * vars,char * pin_name,uint def_pin)400 getgpiopin(char *vars, char *pin_name, uint def_pin)
401 {
402 char name[] = "gpioXXXX";
403 char *val;
404 uint pin;
405
406 /* Go thru all possibilities till a match in pin name */
407 for (pin = 0; pin < GPIO_NUMPINS; pin ++) {
408 snprintf(name, sizeof(name), "gpio%d", pin);
409 val = getvar(vars, name);
410 if (val && findmatch(val, pin_name))
411 return pin;
412 }
413
414 if (def_pin != GPIO_PIN_NOTDEFINED) {
415 /* make sure the default pin is not used by someone else */
416 snprintf(name, sizeof(name), "gpio%d", def_pin);
417 if (getvar(vars, name)) {
418 def_pin = GPIO_PIN_NOTDEFINED;
419 }
420 }
421 return def_pin;
422 }
423 #endif /* !BCMDONGLEHOST */
424
425 /* return total length of buffer chain. In case of CSO, submsdu may have extra tsohdr and if
426 * pktotlen should not include submsdu tso header, use the API pkttotlen_no_sfhtoe_hdr.
427 */
428 uint
BCMFASTPATH(pkttotlen)429 BCMFASTPATH(pkttotlen)(osl_t *osh, void *p)
430 {
431 uint total = 0;
432
433 for (; p; p = PKTNEXT(osh, p)) {
434 total += PKTLEN(osh, p);
435
436 if (BCMLFRAG_ENAB() && PKTISFRAG(osh, p)) {
437 total += PKTFRAGTOTLEN(osh, p);
438 }
439 }
440
441 return (total);
442 }
443
444 #ifdef WLCSO
445 /* return total length of buffer chain, but exclude tso hdr of submsdu if its added */
446 uint
BCMFASTPATH(pkttotlen_no_sfhtoe_hdr)447 BCMFASTPATH(pkttotlen_no_sfhtoe_hdr)(osl_t *osh, void *p, uint toe_hdr_len)
448 {
449 uint total = 0;
450
451 for (; p; p = PKTNEXT(osh, p)) {
452 total += PKTLEN(osh, p);
453
454 /* exclude toe_hdr_len if its part of PKTLEN() */
455 if (PKTISSUBMSDUTOEHDR(osh, p)) {
456 total -= toe_hdr_len;
457 }
458
459 if (BCMLFRAG_ENAB() && PKTISFRAG(osh, p)) {
460 total += PKTFRAGTOTLEN(osh, p);
461 }
462 }
463
464 return (total);
465 }
466 #endif /* WLCSO */
467
468 /* return total length of buffer chain */
469 uint
BCMFASTPATH(pkttotcnt)470 BCMFASTPATH(pkttotcnt)(osl_t *osh, void *p)
471 {
472 uint cnt = 0;
473
474 for (; p; p = PKTNEXT(osh, p)) {
475 cnt++;
476 }
477
478 return (cnt);
479 }
480
481 /* return the last buffer of chained pkt */
482 void *
BCMFASTPATH(pktlast)483 BCMFASTPATH(pktlast)(osl_t *osh, void *p)
484 {
485 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
486 ;
487
488 return (p);
489 }
490
491 /* count segments of a chained packet */
492 uint
BCMFASTPATH(pktsegcnt)493 BCMFASTPATH(pktsegcnt)(osl_t *osh, void *p)
494 {
495 uint cnt;
496
497 for (cnt = 0; p; p = PKTNEXT(osh, p)) {
498 if (PKTLEN(osh, p)) {
499 cnt++;
500 }
501 #ifdef BCMLFRAG
502 if (BCMLFRAG_ENAB() && PKTISFRAG(osh, p)) {
503 cnt += PKTFRAGTOTNUM(osh, p);
504 }
505 #endif /* BCMLFRAG */
506 }
507
508 return cnt;
509 }
510
511 #ifdef DONGLEBUILD
512 /**
513 * Takes in a lbuf/lfrag and no of bytes to be trimmed from tail.
514 * trim bytes could be spread out in below 3 formats
515 * 1. entirely in dongle
516 * 2. entirely in host
517 * 3. split between host-dongle
518 */
519 void
BCMFASTPATH(pktfrag_trim_tailbytes)520 BCMFASTPATH(pktfrag_trim_tailbytes)(osl_t * osh, void* p, uint16 trim_len, uint8 type)
521 {
522 uint16 tcmseg_len = PKTLEN(osh, p); /* TCM segment length */
523 uint16 hostseg_len = PKTFRAGUSEDLEN(osh, p); /* HOST segment length */
524
525 /* return if zero trim length- Nothing to do */
526 if (trim_len == 0)
527 return;
528
529 /* if header conv is on, there is no fcs at the end */
530 /* JIRA:SW4349-318 */
531 if (PKTISHDRCONVTD(osh, p))
532 return;
533
534 /* if pktfetched, then its already trimmed */
535 if (PKTISPKTFETCHED(osh, p))
536 return;
537
538 if (PKTFRAGUSEDLEN(osh, p) >= trim_len) {
539 /* TRIM bytes entirely in host */
540 ASSERT_FP(PKTISRXFRAG(osh, p));
541
542 PKTSETFRAGUSEDLEN(osh, p, (hostseg_len - trim_len));
543 } else {
544 /* trim bytes either in dongle or split between dongle-host */
545 PKTSETLEN(osh, p, (tcmseg_len - (trim_len - hostseg_len)));
546
547 /* No more contents in host; reset length to zero */
548 if (PKTFRAGUSEDLEN(osh, p))
549 PKTSETFRAGUSEDLEN(osh, p, 0);
550 }
551 }
552 #endif /* DONGLEBUILD */
553
554 /* copy a pkt buffer chain into a buffer */
555 uint
pktcopy(osl_t * osh,void * p,uint offset,uint len,uchar * buf)556 pktcopy(osl_t *osh, void *p, uint offset, uint len, uchar *buf)
557 {
558 uint n, ret = 0;
559
560 /* skip 'offset' bytes */
561 for (; p && offset; p = PKTNEXT(osh, p)) {
562 if (offset < PKTLEN(osh, p))
563 break;
564 offset -= PKTLEN(osh, p);
565 }
566
567 if (!p)
568 return 0;
569
570 /* copy the data */
571 for (; p && len; p = PKTNEXT(osh, p)) {
572 n = MIN(PKTLEN(osh, p) - offset, len);
573 bcopy(PKTDATA(osh, p) + offset, buf, n);
574 buf += n;
575 len -= n;
576 ret += n;
577 offset = 0;
578 }
579
580 return ret;
581 }
582
583 /* copy a buffer into a pkt buffer chain */
584 uint
pktfrombuf(osl_t * osh,void * p,uint offset,uint len,uchar * buf)585 pktfrombuf(osl_t *osh, void *p, uint offset, uint len, uchar *buf)
586 {
587 uint n, ret = 0;
588
589 /* skip 'offset' bytes */
590 for (; p && offset; p = PKTNEXT(osh, p)) {
591 if (offset < PKTLEN(osh, p))
592 break;
593 offset -= PKTLEN(osh, p);
594 }
595
596 if (!p)
597 return 0;
598
599 /* copy the data */
600 for (; p && len; p = PKTNEXT(osh, p)) {
601 n = MIN(PKTLEN(osh, p) - offset, len);
602 bcopy(buf, PKTDATA(osh, p) + offset, n);
603 buf += n;
604 len -= n;
605 ret += n;
606 offset = 0;
607 }
608
609 return ret;
610 }
611
612 #ifdef NOT_YET
613 /* copy data from one pkt buffer (chain) to another */
614 uint
pkt2pktcopy(osl_t * osh,void * p1,uint offs1,void * p2,uint offs2,uint maxlen)615 pkt2pktcopy(osl_t *osh, void *p1, uint offs1, void *p2, uint offs2, uint maxlen)
616 {
617 uint8 *dp1, *dp2;
618 uint len1, len2, copylen, totallen;
619
620 for (; p1 && offs; p1 = PKTNEXT(osh, p1)) {
621 if (offs1 < (uint)PKTLEN(osh, p1))
622 break;
623 offs1 -= PKTLEN(osh, p1);
624 }
625 for (; p2 && offs; p2 = PKTNEXT(osh, p2)) {
626 if (offs2 < (uint)PKTLEN(osh, p2))
627 break;
628 offs2 -= PKTLEN(osh, p2);
629 }
630
631 /* Heck w/it, only need the above for now */
632 }
633 #endif /* NOT_YET */
634
635 uint8 *
BCMFASTPATH(pktdataoffset)636 BCMFASTPATH(pktdataoffset)(osl_t *osh, void *p, uint offset)
637 {
638 uint total = pkttotlen(osh, p);
639 uint pkt_off = 0, len = 0;
640 uint8 *pdata = (uint8 *) PKTDATA(osh, p);
641
642 if (offset > total)
643 return NULL;
644
645 for (; p; p = PKTNEXT(osh, p)) {
646 pdata = (uint8 *) PKTDATA(osh, p);
647 pkt_off = offset - len;
648 len += PKTLEN(osh, p);
649 if (len > offset)
650 break;
651 }
652 return (uint8*) (pdata+pkt_off);
653 }
654
655 /* given a offset in pdata, find the pkt seg hdr */
656 void *
pktoffset(osl_t * osh,void * p,uint offset)657 pktoffset(osl_t *osh, void *p, uint offset)
658 {
659 uint total = pkttotlen(osh, p);
660 uint len = 0;
661
662 if (offset > total)
663 return NULL;
664
665 for (; p; p = PKTNEXT(osh, p)) {
666 len += PKTLEN(osh, p);
667 if (len > offset)
668 break;
669 }
670 return p;
671 }
672
673 void
bcm_mdelay(uint ms)674 bcm_mdelay(uint ms)
675 {
676 uint i;
677
678 for (i = 0; i < ms; i++) {
679 OSL_DELAY(1000);
680 }
681 }
682
683 #if defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS)
684
685 #if defined(__ARM_ARCH_7R__)
686 #define BCMLOG_CYCLE_OVERHEAD 54 /* Number of CPU cycle overhead due to bcmlog().
687 * This is to compensate CPU cycle incurred by
688 * added bcmlog() function call for profiling.
689 */
690 #else
691 #define BCMLOG_CYCLE_OVERHEAD 0
692 #endif
693
694 #define LOGSIZE 256 /* should be power of 2 to avoid div below */
695 static struct {
696 uint cycles;
697 const char *fmt;
698 uint a1;
699 uint a2;
700 uchar indent; /* track indent level for nice printing */
701 } logtab[LOGSIZE];
702
703 /* last entry logged */
704 static uint logi = 0;
705 /* next entry to read */
706 static uint volatile readi = 0;
707 #endif /* defined(BCMPERFSTATS) || defined(BCMTSTAMPEDLOGS) */
708
709 #ifdef BCMPERFSTATS
710 /* TODO: make the utility configurable (choose between icache, dcache, hits, misses ...) */
711 void
bcm_perf_enable()712 bcm_perf_enable()
713 {
714 BCMPERF_ENABLE_INSTRCOUNT();
715 BCMPERF_ENABLE_ICACHE_MISS();
716 BCMPERF_ENABLE_ICACHE_HIT();
717 }
718
719 /* WARNING: This routine uses OSL_GETCYCLES(), which can give unexpected results on
720 * modern speed stepping CPUs. Use bcmtslog() instead in combination with TSF counter.
721 */
722 void
bcmlog(char * fmt,uint a1,uint a2)723 bcmlog(char *fmt, uint a1, uint a2)
724 {
725 static uint last = 0;
726 uint cycles, i, elapsed;
727 OSL_GETCYCLES(cycles);
728
729 i = logi;
730
731 elapsed = cycles - last;
732 if (elapsed > BCMLOG_CYCLE_OVERHEAD)
733 logtab[i].cycles = elapsed - BCMLOG_CYCLE_OVERHEAD;
734 else
735 logtab[i].cycles = 0;
736 logtab[i].fmt = fmt;
737 logtab[i].a1 = a1;
738 logtab[i].a2 = a2;
739
740 logi = (i + 1) % LOGSIZE;
741 last = cycles;
742
743 /* if log buffer is overflowing, readi should be advanced.
744 * Otherwise logi and readi will become out of sync.
745 */
746 if (logi == readi) {
747 readi = (readi + 1) % LOGSIZE;
748 } else {
749 /* This redundant else is to make CPU cycles of bcmlog() function to be uniform,
750 * so that the cycle compensation with BCMLOG_CYCLE_OVERHEAD is more accurate.
751 */
752 readi = readi % LOGSIZE;
753 }
754 }
755
756 /* Same as bcmlog but specializes the use of a1 and a2 to
757 * store icache misses and instruction count.
758 * TODO : make this use a configuration array to decide what counter to read.
759 * We are limited to 2 numbers but it seems it is the most we can get anyway
760 * since dcache and icache cannot be enabled at the same time. Recording
761 * both the hits and misses at the same time for a given cache is not that useful either.
762 */
763
764 void
bcmstats(char * fmt)765 bcmstats(char *fmt)
766 {
767 static uint last = 0;
768 static uint32 ic_miss = 0;
769 static uint32 instr_count = 0;
770 uint32 ic_miss_cur;
771 uint32 instr_count_cur;
772 uint cycles, i;
773
774 OSL_GETCYCLES(cycles);
775 BCMPERF_GETICACHE_MISS(ic_miss_cur);
776 BCMPERF_GETINSTRCOUNT(instr_count_cur);
777
778 i = logi;
779
780 logtab[i].cycles = cycles - last;
781 logtab[i].a1 = ic_miss_cur - ic_miss;
782 logtab[i].a2 = instr_count_cur - instr_count;
783 logtab[i].fmt = fmt;
784
785 logi = (i + 1) % LOGSIZE;
786
787 last = cycles;
788 instr_count = instr_count_cur;
789 ic_miss = ic_miss_cur;
790
791 /* if log buffer is overflowing, readi should be advanced.
792 * Otherwise logi and readi will become out of sync.
793 */
794 if (logi == readi) {
795 readi = (readi + 1) % LOGSIZE;
796 } else {
797 /* This redundant else is to make CPU cycles of bcmstats() function to be uniform
798 */
799 readi = readi % LOGSIZE;
800 }
801 }
802
803 /*
804 * TODO (linux version): a "proc" version where the log would be dumped
805 * on the proc file directly.
806 */
807
808 void
bcmdumplog(char * buf,int size)809 bcmdumplog(char *buf, int size)
810 {
811 char *limit;
812 int j = 0;
813 int num;
814
815 limit = buf + size - 80;
816 *buf = '\0';
817
818 num = logi - readi;
819
820 if (num < 0)
821 num += LOGSIZE;
822
823 /* print in chronological order */
824
825 for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++) {
826 if (logtab[readi].fmt == NULL)
827 continue;
828 buf += snprintf(buf, (limit - buf), "%d\t", logtab[readi].cycles);
829 buf += snprintf(buf, (limit - buf), logtab[readi].fmt, logtab[readi].a1,
830 logtab[readi].a2);
831 buf += snprintf(buf, (limit - buf), "\n");
832 }
833
834 }
835
836 /*
837 * Dump one log entry at a time.
838 * Return index of next entry or -1 when no more .
839 */
840 int
bcmdumplogent(char * buf,uint i)841 bcmdumplogent(char *buf, uint i)
842 {
843 bool hit;
844
845 /*
846 * If buf is NULL, return the starting index,
847 * interpreting i as the indicator of last 'i' entries to dump.
848 */
849 if (buf == NULL) {
850 i = ((i > 0) && (i < (LOGSIZE - 1))) ? i : (LOGSIZE - 1);
851 return ((logi - i) % LOGSIZE);
852 }
853
854 *buf = '\0';
855
856 ASSERT(i < LOGSIZE);
857
858 if (i == logi)
859 return (-1);
860
861 hit = FALSE;
862 for (; (i != logi) && !hit; i = (i + 1) % LOGSIZE) {
863 if (logtab[i].fmt == NULL)
864 continue;
865 buf += snprintf(buf, LOGSIZE, "%d: %d\t", i, logtab[i].cycles);
866 buf += snprintf(buf, LOGSIZE, logtab[i].fmt, logtab[i].a1, logtab[i].a2);
867 buf += snprintf(buf, LOGSIZE, "\n");
868 hit = TRUE;
869 }
870
871 return (i);
872 }
873
874 #endif /* BCMPERFSTATS */
875
876 #if defined(BCMTSTAMPEDLOGS)
877 /* Store a TSF timestamp and a log line in the log buffer */
878 /*
879 a1 is used to signify entering/exiting a routine. When entering
880 the indent level is increased. When exiting, the delta since entering
881 is printed and the indent level is bumped back out.
882 Nesting can go up to level MAX_TS_INDENTS deep.
883 */
884 #define MAX_TS_INDENTS 20
885 void
bcmtslog(uint32 tstamp,const char * fmt,uint a1,uint a2)886 bcmtslog(uint32 tstamp, const char *fmt, uint a1, uint a2)
887 {
888 uint i = logi;
889 bool use_delta = TRUE;
890 static uint32 last = 0; /* used only when use_delta is true */
891 static uchar indent = 0;
892 static uint32 indents[MAX_TS_INDENTS];
893
894 logtab[i].cycles = tstamp;
895 if (use_delta)
896 logtab[i].cycles -= last;
897
898 logtab[i].a2 = a2;
899
900 if (a1 == TS_EXIT && indent) {
901 indent--;
902 logtab[i].a2 = tstamp - indents[indent];
903 }
904
905 logtab[i].fmt = fmt;
906 logtab[i].a1 = a1;
907 logtab[i].indent = indent;
908
909 if (a1 == TS_ENTER) {
910 indents[indent] = tstamp;
911 if (indent < MAX_TS_INDENTS - 1)
912 indent++;
913 }
914
915 if (use_delta)
916 last = tstamp;
917 logi = (i + 1) % LOGSIZE;
918 }
919
920 /* Print out a microsecond timestamp as "sec.ms.us " */
921 void
bcmprinttstamp(uint32 ticks)922 bcmprinttstamp(uint32 ticks)
923 {
924 uint us, ms, sec;
925
926 us = (ticks % TSF_TICKS_PER_MS) * 1000 / TSF_TICKS_PER_MS;
927 ms = ticks / TSF_TICKS_PER_MS;
928 sec = ms / 1000;
929 ms -= sec * 1000;
930 printf("%04u.%03u.%03u ", sec, ms, us);
931 }
932
933 /* Print out the log buffer with timestamps */
934 void
bcmprinttslogs(void)935 bcmprinttslogs(void)
936 {
937 int j = 0;
938 int num;
939
940 num = logi - readi;
941 if (num < 0)
942 num += LOGSIZE;
943
944 /* Format and print the log entries directly in chronological order */
945 for (j = 0; j < num; readi = (readi + 1) % LOGSIZE, j++) {
946 if (logtab[readi].fmt == NULL)
947 continue;
948 bcmprinttstamp(logtab[readi].cycles);
949 printf(logtab[readi].fmt, logtab[readi].a1, logtab[readi].a2);
950 printf("\n");
951 }
952 }
953
954 /*
955 Identical to bcmdumplog, but output is based on tsf instead of cycles.
956
957 a1 is used to signify entering/exiting a routine. When entering
958 the indent level is increased. When exiting, the delta since entering
959 is printed and the indent level is bumped back out.
960 */
961 void
bcmdumptslog(struct bcmstrbuf * b)962 bcmdumptslog(struct bcmstrbuf *b)
963 {
964 char *limit;
965 int j = 0;
966 int num;
967 uint us, ms, sec;
968 int skip;
969 char *lines = "| | | | | | | | | | | | | | | | | | | |";
970
971 limit = BCMSTRBUF_BUF(b) + BCMSTRBUF_LEN(b) - 80;
972
973 num = logi - readi;
974
975 if (num < 0)
976 num += LOGSIZE;
977
978 /* print in chronological order */
979 for (j = 0; j < num && (BCMSTRBUF_BUF(b) < limit); readi = (readi + 1) % LOGSIZE, j++) {
980 char *last_buf = BCMSTRBUF_BUF(b);
981 if (logtab[readi].fmt == NULL)
982 continue;
983
984 us = (logtab[readi].cycles % TSF_TICKS_PER_MS) * 1000 / TSF_TICKS_PER_MS;
985 ms = logtab[readi].cycles / TSF_TICKS_PER_MS;
986 sec = ms / 1000;
987 ms -= sec * 1000;
988
989 bcm_bprintf(b, "%04u.%03u.%03u ", sec, ms, us);
990
991 /* 2 spaces for each indent level */
992 bcm_bprintf(b, "%.*s", logtab[readi].indent * 2, lines);
993
994 /*
995 * The following call to snprintf generates a compiler warning
996 * due to -Wformat-security. However, the format string is coming
997 * from internal callers rather than external data input, and is a
998 * useful debugging tool serving a variety of diagnostics. Rather
999 * than expand code size by replicating multiple functions with different
1000 * argument lists, or disabling the warning globally, let's consider
1001 * if we can just disable the warning for this one instance.
1002 */
1003 bcm_bprintf(b, logtab[readi].fmt);
1004
1005 /* If a1 is ENTER or EXIT, print the + or - */
1006 skip = 0;
1007 if (logtab[readi].a1 == TS_ENTER) {
1008 bcm_bprintf(b, " +");
1009 skip++;
1010 }
1011 if (logtab[readi].a1 == TS_EXIT) {
1012 bcm_bprintf(b, " -");
1013 skip++;
1014 }
1015
1016 /* else print the real a1 */
1017 if (logtab[readi].a1 && !skip)
1018 bcm_bprintf(b, " %d", logtab[readi].a1);
1019
1020 /*
1021 If exiting routine, print a nicely formatted delta since entering.
1022 Otherwise, just print a2 normally.
1023 */
1024 if (logtab[readi].a2) {
1025 if (logtab[readi].a1 == TS_EXIT) {
1026 int num_space = 75 - (BCMSTRBUF_BUF(b) - last_buf);
1027 bcm_bprintf(b, "%*.s", num_space, "");
1028 bcm_bprintf(b, "%5d usecs", logtab[readi].a2);
1029 } else
1030 bcm_bprintf(b, " %d", logtab[readi].a2);
1031 }
1032 bcm_bprintf(b, "\n");
1033 last_buf = BCMSTRBUF_BUF(b);
1034 }
1035 }
1036
1037 #endif /* BCMTSTAMPEDLOGS */
1038
1039 #if defined(BCMDBG) || defined(DHD_DEBUG)
1040 /* pretty hex print a pkt buffer chain */
1041 void
prpkt(const char * msg,osl_t * osh,void * p0)1042 prpkt(const char *msg, osl_t *osh, void *p0)
1043 {
1044 void *p;
1045
1046 if (msg && (msg[0] != '\0'))
1047 printf("%s:\n", msg);
1048
1049 for (p = p0; p; p = PKTNEXT(osh, p))
1050 prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
1051 }
1052 #endif /* BCMDBG || DHD_DEBUG */
1053
1054 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
1055 * Also updates the inplace vlan tag if requested.
1056 * For debugging, it returns an indication of what it did.
1057 */
1058 uint
BCMFASTPATH(pktsetprio)1059 BCMFASTPATH(pktsetprio)(void *pkt, bool update_vtag)
1060 {
1061 struct ether_header *eh;
1062 struct ethervlan_header *evh;
1063 uint8 *pktdata;
1064 int priority = 0;
1065 int rc = 0;
1066
1067 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
1068 ASSERT_FP(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
1069
1070 eh = (struct ether_header *) pktdata;
1071
1072 if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) {
1073 uint16 vlan_tag;
1074 int vlan_prio, dscp_prio = 0;
1075
1076 evh = (struct ethervlan_header *)eh;
1077
1078 vlan_tag = ntoh16(evh->vlan_tag);
1079 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
1080
1081 if ((evh->ether_type == hton16(ETHER_TYPE_IP)) ||
1082 (evh->ether_type == hton16(ETHER_TYPE_IPV6))) {
1083 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
1084 uint8 tos_tc = IP_TOS46(ip_body);
1085 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
1086 }
1087
1088 /* DSCP priority gets precedence over 802.1P (vlan tag) */
1089 if (dscp_prio != 0) {
1090 priority = dscp_prio;
1091 rc |= PKTPRIO_VDSCP;
1092 } else {
1093 priority = vlan_prio;
1094 rc |= PKTPRIO_VLAN;
1095 }
1096 /*
1097 * If the DSCP priority is not the same as the VLAN priority,
1098 * then overwrite the priority field in the vlan tag, with the
1099 * DSCP priority value. This is required for Linux APs because
1100 * the VLAN driver on Linux, overwrites the skb->priority field
1101 * with the priority value in the vlan tag
1102 */
1103 if (update_vtag && (priority != vlan_prio)) {
1104 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
1105 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
1106 evh->vlan_tag = hton16(vlan_tag);
1107 rc |= PKTPRIO_UPD;
1108 }
1109 #if defined(EAPOL_PKT_PRIO) || defined(DHD_LOSSLESS_ROAMING)
1110 } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
1111 priority = PRIO_8021D_NC;
1112 rc = PKTPRIO_DSCP;
1113 #endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */
1114 #if defined(WLTDLS)
1115 } else if (eh->ether_type == hton16(ETHER_TYPE_89_0D)) {
1116 /* Bump up the priority for TDLS frames */
1117 priority = PRIO_8021D_VI;
1118 rc = PKTPRIO_DSCP;
1119 #endif /* WLTDLS */
1120 } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) ||
1121 (eh->ether_type == hton16(ETHER_TYPE_IPV6))) {
1122 uint8 *ip_body = pktdata + sizeof(struct ether_header);
1123 uint8 tos_tc = IP_TOS46(ip_body);
1124 uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT;
1125 switch (dscp) {
1126 case DSCP_EF:
1127 case DSCP_VA:
1128 priority = PRIO_8021D_VO;
1129 break;
1130 case DSCP_AF31:
1131 case DSCP_AF32:
1132 case DSCP_AF33:
1133 case DSCP_CS3:
1134 priority = PRIO_8021D_CL;
1135 break;
1136 case DSCP_AF21:
1137 case DSCP_AF22:
1138 case DSCP_AF23:
1139 priority = PRIO_8021D_EE;
1140 break;
1141 case DSCP_AF11:
1142 case DSCP_AF12:
1143 case DSCP_AF13:
1144 case DSCP_CS2:
1145 priority = PRIO_8021D_BE;
1146 break;
1147 case DSCP_CS6:
1148 case DSCP_CS7:
1149 priority = PRIO_8021D_NC;
1150 break;
1151 default:
1152 #ifndef CUSTOM_DSCP_TO_PRIO_MAPPING
1153 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
1154 #else
1155 if (dhd_dscpmap_enable) {
1156 priority = (int)dscp2priomap[((tos_tc >> IPV4_TOS_DSCP_SHIFT)
1157 & CUST_IPV4_TOS_PREC_MASK)];
1158 }
1159 else {
1160 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
1161 }
1162 #endif /* CUSTOM_DSCP_TO_PRIO_MAPPING */
1163 break;
1164 }
1165
1166 rc |= PKTPRIO_DSCP;
1167 }
1168
1169 ASSERT_FP(priority >= 0 && priority <= MAXPRIO);
1170 PKTSETPRIO(pkt, priority);
1171 return (rc | priority);
1172 }
1173
1174 /* lookup user priority for specified DSCP */
1175 static uint8
dscp2up(uint8 * up_table,uint8 dscp)1176 dscp2up(uint8 *up_table, uint8 dscp)
1177 {
1178 uint8 user_priority = 255;
1179
1180 /* lookup up from table if parameters valid */
1181 if (up_table != NULL && dscp < UP_TABLE_MAX) {
1182 user_priority = up_table[dscp];
1183 }
1184
1185 /* 255 is unused value so return up from dscp */
1186 if (user_priority == 255) {
1187 user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT);
1188 }
1189
1190 return user_priority;
1191 }
1192
1193 /* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */
1194 uint
BCMFASTPATH(pktsetprio_qms)1195 BCMFASTPATH(pktsetprio_qms)(void *pkt, uint8* up_table, bool update_vtag)
1196 {
1197 if (up_table) {
1198 uint8 *pktdata;
1199 uint pktlen;
1200 uint8 dscp;
1201 uint user_priority = 0;
1202 uint rc = 0;
1203
1204 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
1205 pktlen = PKTLEN(OSH_NULL, pkt);
1206 if (pktgetdscp(pktdata, pktlen, &dscp)) {
1207 rc = PKTPRIO_DSCP;
1208 user_priority = dscp2up(up_table, dscp);
1209 PKTSETPRIO(pkt, user_priority);
1210 }
1211
1212 return (rc | user_priority);
1213 } else {
1214 return pktsetprio(pkt, update_vtag);
1215 }
1216 }
1217
1218 /* Returns TRUE and DSCP if IP header found, FALSE otherwise.
1219 */
1220 bool
BCMFASTPATH(pktgetdscp)1221 BCMFASTPATH(pktgetdscp)(uint8 *pktdata, uint pktlen, uint8 *dscp)
1222 {
1223 struct ether_header *eh;
1224 struct ethervlan_header *evh;
1225 uint8 *ip_body;
1226 bool rc = FALSE;
1227
1228 /* minimum length is ether header and IP header */
1229 if (pktlen < (sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN)) {
1230 return FALSE;
1231 }
1232
1233 eh = (struct ether_header *) pktdata;
1234
1235 if ((eh->ether_type == HTON16(ETHER_TYPE_IP)) ||
1236 (eh->ether_type == HTON16(ETHER_TYPE_IPV6))) {
1237 ip_body = pktdata + sizeof(struct ether_header);
1238 *dscp = IP_DSCP46(ip_body);
1239 rc = TRUE;
1240 }
1241 else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) {
1242 evh = (struct ethervlan_header *)eh;
1243
1244 /* minimum length is ethervlan header and IP header */
1245 if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN &&
1246 evh->ether_type == HTON16(ETHER_TYPE_IP)) {
1247 ip_body = pktdata + sizeof(struct ethervlan_header);
1248 *dscp = IP_DSCP46(ip_body);
1249 rc = TRUE;
1250 }
1251 }
1252
1253 return rc;
1254 }
1255
1256 /* usr_prio range from low to high with usr_prio value */
1257 static bool
up_table_set(uint8 * up_table,uint8 usr_prio,uint8 low,uint8 high)1258 up_table_set(uint8 *up_table, uint8 usr_prio, uint8 low, uint8 high)
1259 {
1260 int i;
1261
1262 if (usr_prio > 7 || low > high || low >= UP_TABLE_MAX || high >= UP_TABLE_MAX) {
1263 return FALSE;
1264 }
1265
1266 for (i = low; i <= high; i++) {
1267 up_table[i] = usr_prio;
1268 }
1269
1270 return TRUE;
1271 }
1272
1273 /* set user priority table */
1274 int
BCMFASTPATH(wl_set_up_table)1275 BCMFASTPATH(wl_set_up_table)(uint8 *up_table, bcm_tlv_t *qos_map_ie)
1276 {
1277 uint8 len;
1278
1279 if (up_table == NULL || qos_map_ie == NULL) {
1280 return BCME_ERROR;
1281 }
1282
1283 /* clear table to check table was set or not */
1284 memset(up_table, 0xff, UP_TABLE_MAX);
1285
1286 /* length of QoS Map IE must be 16+n*2, n is number of exceptions */
1287 if (qos_map_ie != NULL && qos_map_ie->id == DOT11_MNG_QOS_MAP_ID &&
1288 (len = qos_map_ie->len) >= QOS_MAP_FIXED_LENGTH &&
1289 (len % 2) == 0) {
1290 uint8 *except_ptr = (uint8 *)qos_map_ie->data;
1291 uint8 except_len = len - QOS_MAP_FIXED_LENGTH;
1292 uint8 *range_ptr = except_ptr + except_len;
1293 int i;
1294
1295 /* fill in ranges */
1296 for (i = 0; i < QOS_MAP_FIXED_LENGTH; i += 2) {
1297 uint8 low = range_ptr[i];
1298 uint8 high = range_ptr[i + 1];
1299 if (low == 255 && high == 255) {
1300 continue;
1301 }
1302
1303 if (!up_table_set(up_table, i / 2, low, high)) {
1304 /* clear the table on failure */
1305 memset(up_table, 0xff, UP_TABLE_MAX);
1306 return BCME_ERROR;
1307 }
1308 }
1309
1310 /* update exceptions */
1311 for (i = 0; i < except_len; i += 2) {
1312 uint8 dscp = except_ptr[i];
1313 uint8 usr_prio = except_ptr[i+1];
1314
1315 /* exceptions with invalid dscp/usr_prio are ignored */
1316 up_table_set(up_table, usr_prio, dscp, dscp);
1317 }
1318 }
1319
1320 return BCME_OK;
1321 }
1322
1323 #ifndef BCM_BOOTLOADER
1324 /* The 0.5KB string table is not removed by compiler even though it's unused */
1325
1326 static char bcm_undeferrstr[32];
1327 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
1328
1329 /* Convert the error codes into related error strings */
1330 /* BCMRAMFN for BCME_LAST usage */
1331 const char *
BCMRAMFN(bcmerrorstr)1332 BCMRAMFN(bcmerrorstr)(int bcmerror)
1333 {
1334 /* check if someone added a bcmerror code but forgot to add errorstring */
1335 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
1336
1337 if (bcmerror > 0 || bcmerror < BCME_LAST) {
1338 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
1339 return bcm_undeferrstr;
1340 }
1341
1342 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
1343
1344 return bcmerrorstrtable[-bcmerror];
1345 }
1346
1347 #endif /* !BCM_BOOTLOADER */
1348
1349 #ifdef BCMDBG_PKT /* pkt logging for debugging */
1350 /* Add a packet to the pktlist */
1351 static void
_pktlist_add(pktlist_info_t * pktlist,void * pkt,int line,char * file)1352 _pktlist_add(pktlist_info_t *pktlist, void *pkt, int line, char *file)
1353 {
1354 uint16 i;
1355 char *basename;
1356 #ifdef BCMDBG_PTRACE
1357 uint16 *idx = PKTLIST_IDX(pkt);
1358 #endif /* BCMDBG_PTRACE */
1359
1360 ASSERT(pktlist->count < PKTLIST_SIZE);
1361
1362 /* Verify the packet is not already part of the list */
1363 for (i = 0; i < pktlist->count; i++) {
1364 if (pktlist->list[i].pkt == pkt)
1365 ASSERT(0);
1366 }
1367 pktlist->list[pktlist->count].pkt = pkt;
1368 pktlist->list[pktlist->count].line = line;
1369
1370 basename = strrchr(file, '/');
1371 if (basename)
1372 basename++;
1373 else
1374 basename = file;
1375 pktlist->list[pktlist->count].file = basename;
1376 #ifdef BCMDBG_PTRACE
1377 *idx = pktlist->count;
1378 bzero(pktlist->list[pktlist->count].pkt_trace, PKTTRACE_MAX_BYTES);
1379 #endif /* BCMDBG_PTRACE */
1380 pktlist->count++;
1381
1382 return;
1383 }
1384
1385 void
pktlist_add(pktlist_info_t * pktlist,void * pkt,int line,char * file)1386 pktlist_add(pktlist_info_t *pktlist, void *pkt, int line, char *file)
1387 {
1388 void *p;
1389 for (p = pkt; p != NULL; p = PKTCLINK(p))
1390 _pktlist_add(pktlist, p, line, file);
1391 }
1392
1393 /* Remove a packet from the pktlist */
1394 static void
_pktlist_remove(pktlist_info_t * pktlist,void * pkt)1395 _pktlist_remove(pktlist_info_t *pktlist, void *pkt)
1396 {
1397 uint16 i;
1398 uint16 num = pktlist->count;
1399 #ifdef BCMDBG_PTRACE
1400 uint16 *idx = PKTLIST_IDX(pkt);
1401
1402 ASSERT((*idx) < pktlist->count);
1403 #endif /* BCMDBG_PTRACE */
1404
1405 /* find the index where pkt exists */
1406 for (i = 0; i < num; i++) {
1407 /* check for the existence of pkt in the list */
1408 if (pktlist->list[i].pkt == pkt) {
1409 #ifdef BCMDBG_PTRACE
1410 ASSERT((*idx) == i);
1411 #endif /* BCMDBG_PTRACE */
1412 /* replace with the last element */
1413 pktlist->list[i].pkt = pktlist->list[num-1].pkt;
1414 pktlist->list[i].line = pktlist->list[num-1].line;
1415 pktlist->list[i].file = pktlist->list[num-1].file;
1416 #ifdef BCMDBG_PTRACE
1417 memcpy(pktlist->list[i].pkt_trace, pktlist->list[num-1].pkt_trace,
1418 PKTTRACE_MAX_BYTES);
1419 idx = PKTLIST_IDX(pktlist->list[i].pkt);
1420 *idx = i;
1421 #endif /* BCMDBG_PTRACE */
1422 pktlist->count--;
1423 return;
1424 }
1425 }
1426 ASSERT(0);
1427 }
1428
1429 void
pktlist_remove(pktlist_info_t * pktlist,void * pkt)1430 pktlist_remove(pktlist_info_t *pktlist, void *pkt)
1431 {
1432 void *p;
1433 for (p = pkt; p != NULL; p = PKTCLINK(p))
1434 _pktlist_remove(pktlist, p);
1435 }
1436
1437 #ifdef BCMDBG_PTRACE
1438 static void
_pktlist_trace(pktlist_info_t * pktlist,void * pkt,uint16 bit)1439 _pktlist_trace(pktlist_info_t *pktlist, void *pkt, uint16 bit)
1440 {
1441 uint16 *idx = PKTLIST_IDX(pkt);
1442
1443 ASSERT(((*idx) < pktlist->count) && (bit < PKTTRACE_MAX_BITS));
1444 ASSERT(pktlist->list[(*idx)].pkt == pkt);
1445
1446 pktlist->list[(*idx)].pkt_trace[bit/NBBY] |= (1 << ((bit)%NBBY));
1447
1448 }
1449 void
pktlist_trace(pktlist_info_t * pktlist,void * pkt,uint16 bit)1450 pktlist_trace(pktlist_info_t *pktlist, void *pkt, uint16 bit)
1451 {
1452 void *p;
1453 for (p = pkt; p != NULL; p = PKTCLINK(p))
1454 _pktlist_trace(pktlist, p, bit);
1455 }
1456 #endif /* BCMDBG_PTRACE */
1457
1458 /* Dump the pktlist (and the contents of each packet if 'data'
1459 * is set). 'buf' should be large enough
1460 */
1461
1462 char *
pktlist_dump(pktlist_info_t * pktlist,char * buf)1463 pktlist_dump(pktlist_info_t *pktlist, char *buf)
1464 {
1465 char *obuf = buf;
1466 uint16 i;
1467
1468 if (buf != NULL)
1469 buf += sprintf(buf, "Packet list dump:\n");
1470 else
1471 printf("Packet list dump:\n");
1472
1473 for (i = 0; i < (pktlist->count); i++) {
1474 if (buf != NULL)
1475 buf += sprintf(buf, "Pkt_addr: 0x%p Line: %d File: %s\t",
1476 OSL_OBFUSCATE_BUF(pktlist->list[i].pkt), pktlist->list[i].line,
1477 pktlist->list[i].file);
1478 else
1479 printf("Pkt_addr: 0x%p Line: %d File: %s\t",
1480 OSL_OBFUSCATE_BUF(pktlist->list[i].pkt),
1481 pktlist->list[i].line, pktlist->list[i].file);
1482
1483 /* #ifdef NOTDEF Remove this ifdef to print pkttag and pktdata */
1484 if (buf != NULL) {
1485 if (PKTTAG(pktlist->list[i].pkt)) {
1486 /* Print pkttag */
1487 buf += sprintf(buf, "Pkttag(in hex): ");
1488 buf += bcm_format_hex(buf, PKTTAG(pktlist->list[i].pkt),
1489 OSL_PKTTAG_SZ);
1490 }
1491 buf += sprintf(buf, "Pktdata(in hex): ");
1492 buf += bcm_format_hex(buf, PKTDATA(OSH_NULL, pktlist->list[i].pkt),
1493 PKTLEN(OSH_NULL, pktlist->list[i].pkt));
1494 } else {
1495 void *pkt = pktlist->list[i].pkt, *npkt;
1496
1497 printf("Pkt[%d] Dump:\n", i);
1498 while (pkt) {
1499 int hroom;
1500 uint pktlen;
1501 uchar *src;
1502 #ifdef BCMDBG_PTRACE
1503 uint16 *idx = PKTLIST_IDX(pkt);
1504
1505 ASSERT((*idx) < pktlist->count);
1506 prhex("Pkt Trace (in hex):", pktlist->list[(*idx)].pkt_trace,
1507 PKTTRACE_MAX_BYTES);
1508 #endif /* BCMDBG_PTRACE */
1509 npkt = (void *)PKTNEXT(OSH_NULL, pkt);
1510 PKTSETNEXT(OSH_NULL, pkt, NULL);
1511
1512 src = (uchar *)(PKTTAG(pkt));
1513 pktlen = PKTLEN(OSH_NULL, pkt);
1514 hroom = PKTHEADROOM(OSH_NULL, pkt);
1515
1516 printf("Pkttag_addr: %p\n", OSL_OBFUSCATE_BUF(src));
1517 if (src)
1518 prhex("Pkttag(in hex): ", src, OSL_PKTTAG_SZ);
1519 src = (uchar *) (PKTDATA(OSH_NULL, pkt));
1520 printf("Pkthead_addr: %p len: %d\n",
1521 OSL_OBFUSCATE_BUF(src - hroom), hroom);
1522 prhex("Pkt headroom content(in hex): ", src - hroom, hroom);
1523 printf("Pktdata_addr: %p len: %d\n",
1524 OSL_OBFUSCATE_BUF(src), pktlen);
1525 prhex("Pktdata(in hex): ", src, pktlen);
1526
1527 pkt = npkt;
1528 }
1529 }
1530 /* #endif NOTDEF */
1531
1532 if (buf != NULL)
1533 buf += sprintf(buf, "\n");
1534 else
1535 printf("\n");
1536 }
1537 return obuf;
1538 }
1539 #endif /* BCMDBG_PKT */
1540
1541 /* iovar table lookup */
1542 /* could mandate sorted tables and do a binary search */
1543 const bcm_iovar_t*
bcm_iovar_lookup(const bcm_iovar_t * table,const char * name)1544 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
1545 {
1546 const bcm_iovar_t *vi;
1547 const char *lookup_name;
1548
1549 /* skip any ':' delimited option prefixes */
1550 lookup_name = strrchr(name, ':');
1551 if (lookup_name != NULL)
1552 lookup_name++;
1553 else
1554 lookup_name = name;
1555
1556 ASSERT(table != NULL);
1557
1558 for (vi = table; vi->name; vi++) {
1559 if (!strcmp(vi->name, lookup_name))
1560 return vi;
1561 }
1562 /* ran to end of table */
1563
1564 return NULL; /* var name not found */
1565 }
1566
1567 int
bcm_iovar_lencheck(const bcm_iovar_t * vi,void * arg,uint len,bool set)1568 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, uint len, bool set)
1569 {
1570 int bcmerror = 0;
1571 BCM_REFERENCE(arg);
1572
1573 /* length check on io buf */
1574 switch (vi->type) {
1575 case IOVT_BOOL:
1576 case IOVT_INT8:
1577 case IOVT_INT16:
1578 case IOVT_INT32:
1579 case IOVT_UINT8:
1580 case IOVT_UINT16:
1581 case IOVT_UINT32:
1582 /* all integers are int32 sized args at the ioctl interface */
1583 if (len < sizeof(int)) {
1584 bcmerror = BCME_BUFTOOSHORT;
1585 }
1586 break;
1587
1588 case IOVT_BUFFER:
1589 /* buffer must meet minimum length requirement */
1590 if (len < vi->minlen) {
1591 bcmerror = BCME_BUFTOOSHORT;
1592 }
1593 break;
1594
1595 case IOVT_VOID:
1596 if (!set) {
1597 /* Cannot return nil... */
1598 bcmerror = BCME_UNSUPPORTED;
1599 }
1600 break;
1601
1602 default:
1603 /* unknown type for length check in iovar info */
1604 ASSERT(0);
1605 bcmerror = BCME_UNSUPPORTED;
1606 }
1607
1608 return bcmerror;
1609 }
1610
1611 /*
1612 * Hierarchical Multiword bitmap based small id allocator.
1613 *
1614 * Multilevel hierarchy bitmap. (maximum 2 levels)
1615 * First hierarchy uses a multiword bitmap to identify 32bit words in the
1616 * second hierarchy that have at least a single bit set. Each bit in a word of
1617 * the second hierarchy represents a unique ID that may be allocated.
1618 *
1619 * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed.
1620 * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word
1621 * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs.
1622 * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non
1623 * non-zero bitmap word carrying at least one free ID.
1624 * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations.
1625 * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID
1626 *
1627 * Design Notes:
1628 * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many
1629 * bits are computed each time on allocation and deallocation, requiring 4
1630 * array indexed access and 3 arithmetic operations. When not defined, a runtime
1631 * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed.
1632 * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation.
1633 * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may
1634 * be used by defining BCM_MWBMAP_USE_CNTSETBITS.
1635 *
1636 * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array
1637 * size is fixed. No intention to support larger than 4K indice allocation. ID
1638 * allocators for ranges smaller than 4K will have a wastage of only 12Bytes
1639 * with savings in not having to use an indirect access, had it been dynamically
1640 * allocated.
1641 */
1642 #if defined(DONGLEBUILD)
1643 #define BCM_MWBMAP_USE_CNTSETBITS /* runtime count set bits */
1644 #if defined(PCIEDEV_HOST_PKTID_AUDIT_ENABLED)
1645 #define BCM_MWBMAP_ITEMS_MAX (38 * 1024)
1646 #else /* ! PCIEDEV_HOST_PKTID_AUDIT_ENABLED */
1647 #define BCM_MWBMAP_ITEMS_MAX (7 * 1024)
1648 #endif /* PCIEDEV_HOST_PKTID_AUDIT_ENABLED */
1649 #else /* ! DONGLEBUILD */
1650 #define BCM_MWBMAP_ITEMS_MAX (64 * 1024) /* May increase to 64K */
1651 #endif /* DONGLEBUILD */
1652
1653 #define BCM_MWBMAP_BITS_WORD (NBITS(uint32))
1654 #define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD)
1655 #define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD)
1656 #define BCM_MWBMAP_SHIFT_OP (5)
1657 #define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1))
1658 #define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP)
1659 #define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP)
1660
1661 /* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */
1662 #define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl))
1663 #define BCM_MWBMAP_HDL(ptr) ((void *)(ptr))
1664
1665 #if defined(BCM_MWBMAP_DEBUG)
1666 #define BCM_MWBMAP_AUDIT(mwb) \
1667 do { \
1668 ASSERT((mwb != NULL) && \
1669 (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \
1670 bcm_mwbmap_audit(mwb); \
1671 } while (0)
1672 #define MWBMAP_ASSERT(exp) ASSERT(exp)
1673 #define MWBMAP_DBG(x) printf x
1674 #else /* !BCM_MWBMAP_DEBUG */
1675 #define BCM_MWBMAP_AUDIT(mwb) do {} while (0)
1676 #define MWBMAP_ASSERT(exp) do {} while (0)
1677 #define MWBMAP_DBG(x)
1678 #endif /* !BCM_MWBMAP_DEBUG */
1679
1680 typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */
1681 uint16 wmaps; /* Total number of words in free wd bitmap */
1682 uint16 imaps; /* Total number of words in free id bitmap */
1683 int32 ifree; /* Count of free indices. Used only in audits */
1684 uint16 total; /* Total indices managed by multiword bitmap */
1685
1686 void * magic; /* Audit handle parameter from user */
1687
1688 uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */
1689 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
1690 int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */
1691 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
1692
1693 uint32 id_bitmap[0]; /* Second level bitmap */
1694 } bcm_mwbmap_t;
1695
1696 /* Incarnate a hierarchical multiword bitmap based small index allocator. */
1697 struct bcm_mwbmap *
BCMATTACHFN(bcm_mwbmap_init)1698 BCMATTACHFN(bcm_mwbmap_init)(osl_t *osh, uint32 items_max)
1699 {
1700 struct bcm_mwbmap * mwbmap_p;
1701 uint32 wordix, size, words, extra;
1702
1703 /* Implementation Constraint: Uses 32bit word bitmap */
1704 MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U);
1705 MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U);
1706 MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX));
1707 MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U);
1708
1709 ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX);
1710
1711 /* Determine the number of words needed in the multiword bitmap */
1712 extra = BCM_MWBMAP_MODOP(items_max);
1713 words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U);
1714
1715 /* Allocate runtime state of multiword bitmap */
1716 /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */
1717 size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words);
1718 mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size);
1719 if (mwbmap_p == (bcm_mwbmap_t *)NULL) {
1720 ASSERT(0);
1721 goto error1;
1722 }
1723 memset(mwbmap_p, 0, size);
1724
1725 /* Initialize runtime multiword bitmap state */
1726 mwbmap_p->imaps = (uint16)words;
1727 mwbmap_p->ifree = (int32)items_max;
1728 mwbmap_p->total = (uint16)items_max;
1729
1730 /* Setup magic, for use in audit of handle */
1731 mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p);
1732
1733 /* Setup the second level bitmap of free indices */
1734 /* Mark all indices as available */
1735 for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) {
1736 mwbmap_p->id_bitmap[wordix] = (uint32)(~0U);
1737 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
1738 mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD;
1739 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
1740 }
1741
1742 /* Ensure that extra indices are tagged as un-available */
1743 if (extra) { /* fixup the free ids in last bitmap and wd_count */
1744 uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1];
1745 *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
1746 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
1747 mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */
1748 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
1749 }
1750
1751 /* Setup the first level bitmap hierarchy */
1752 extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps);
1753 words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U);
1754
1755 mwbmap_p->wmaps = (uint16)words;
1756
1757 for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++)
1758 mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U);
1759 if (extra) {
1760 uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1];
1761 *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
1762 }
1763
1764 return mwbmap_p;
1765
1766 error1:
1767 return BCM_MWBMAP_INVALID_HDL;
1768 }
1769
1770 /* Release resources used by multiword bitmap based small index allocator. */
1771 void
BCMATTACHFN(bcm_mwbmap_fini)1772 BCMATTACHFN(bcm_mwbmap_fini)(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl)
1773 {
1774 bcm_mwbmap_t * mwbmap_p;
1775
1776 BCM_MWBMAP_AUDIT(mwbmap_hdl);
1777 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
1778
1779 MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap)
1780 + (sizeof(uint32) * mwbmap_p->imaps));
1781 return;
1782 }
1783
1784 /* Allocate a unique small index using a multiword bitmap index allocator. */
1785 uint32
BCMFASTPATH(bcm_mwbmap_alloc)1786 BCMFASTPATH(bcm_mwbmap_alloc)(struct bcm_mwbmap * mwbmap_hdl)
1787 {
1788 bcm_mwbmap_t * mwbmap_p;
1789 uint32 wordix, bitmap;
1790
1791 BCM_MWBMAP_AUDIT(mwbmap_hdl);
1792 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
1793
1794 /* Start with the first hierarchy */
1795 for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) {
1796
1797 bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */
1798
1799 if (bitmap != 0U) {
1800
1801 uint32 count, bitix, *bitmap_p;
1802
1803 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
1804
1805 /* clear all except trailing 1 */
1806 if (bitmap != (1u << 31u)) {
1807 bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
1808 }
1809 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
1810 bcm_count_leading_zeros(bitmap));
1811 bitix = (BCM_MWBMAP_BITS_WORD - 1)
1812 - bcm_count_leading_zeros(bitmap); /* use asm clz */
1813 wordix = BCM_MWBMAP_MULOP(wordix) + bitix;
1814
1815 /* Clear bit if wd count is 0, without conditional branch */
1816 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
1817 count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1;
1818 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
1819 mwbmap_p->wd_count[wordix]--;
1820 count = mwbmap_p->wd_count[wordix];
1821 MWBMAP_ASSERT(count ==
1822 (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1));
1823 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
1824 MWBMAP_ASSERT(count >= 0);
1825
1826 /* clear wd_bitmap bit if id_map count is 0 */
1827 bitmap = (count == 0) << bitix;
1828
1829 MWBMAP_DBG((
1830 "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
1831 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count));
1832
1833 *bitmap_p ^= bitmap;
1834
1835 /* Use bitix in the second hierarchy */
1836 bitmap_p = &mwbmap_p->id_bitmap[wordix];
1837
1838 bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */
1839 MWBMAP_ASSERT(bitmap != 0U);
1840
1841 /* clear all except trailing 1 */
1842 if (bitmap != (1u << 31u)) {
1843 bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
1844 }
1845 MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
1846 bcm_count_leading_zeros(bitmap));
1847 bitix = BCM_MWBMAP_MULOP(wordix)
1848 + (BCM_MWBMAP_BITS_WORD - 1)
1849 - bcm_count_leading_zeros(bitmap); /* use asm clz */
1850
1851 mwbmap_p->ifree--; /* decrement system wide free count */
1852 MWBMAP_ASSERT(mwbmap_p->ifree >= 0);
1853
1854 MWBMAP_DBG((
1855 "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d",
1856 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
1857 mwbmap_p->ifree));
1858
1859 *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */
1860
1861 return bitix;
1862 }
1863 }
1864
1865 ASSERT(mwbmap_p->ifree == 0);
1866
1867 return BCM_MWBMAP_INVALID_IDX;
1868 }
1869
1870 /* Force an index at a specified position to be in use */
1871 void
bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl,uint32 bitix)1872 bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
1873 {
1874 bcm_mwbmap_t * mwbmap_p;
1875 uint32 count, wordix, bitmap, *bitmap_p;
1876
1877 BCM_MWBMAP_AUDIT(mwbmap_hdl);
1878 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
1879
1880 ASSERT(bitix < mwbmap_p->total);
1881
1882 /* Start with second hierarchy */
1883 wordix = BCM_MWBMAP_DIVOP(bitix);
1884 bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix));
1885 bitmap_p = &mwbmap_p->id_bitmap[wordix];
1886
1887 ASSERT((*bitmap_p & bitmap) == bitmap);
1888
1889 mwbmap_p->ifree--; /* update free count */
1890 ASSERT(mwbmap_p->ifree >= 0);
1891
1892 MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d",
1893 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
1894 mwbmap_p->ifree));
1895
1896 *bitmap_p ^= bitmap; /* mark as in use */
1897
1898 /* Update first hierarchy */
1899 bitix = wordix;
1900
1901 wordix = BCM_MWBMAP_DIVOP(bitix);
1902 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
1903
1904 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
1905 count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
1906 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
1907 mwbmap_p->wd_count[bitix]--;
1908 count = mwbmap_p->wd_count[bitix];
1909 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
1910 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
1911 MWBMAP_ASSERT(count >= 0);
1912
1913 bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix);
1914
1915 MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
1916 BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap,
1917 (*bitmap_p) ^ bitmap, count));
1918
1919 *bitmap_p ^= bitmap; /* mark as in use */
1920
1921 return;
1922 }
1923
1924 /* Free a previously allocated index back into the multiword bitmap allocator */
1925 void
BCMPOSTTRAPFASTPATH(bcm_mwbmap_free)1926 BCMPOSTTRAPFASTPATH(bcm_mwbmap_free)(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
1927 {
1928 bcm_mwbmap_t * mwbmap_p;
1929 uint32 wordix, bitmap, *bitmap_p;
1930
1931 BCM_MWBMAP_AUDIT(mwbmap_hdl);
1932 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
1933
1934 ASSERT_FP(bitix < mwbmap_p->total);
1935
1936 /* Start with second level hierarchy */
1937 wordix = BCM_MWBMAP_DIVOP(bitix);
1938 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
1939 bitmap_p = &mwbmap_p->id_bitmap[wordix];
1940
1941 ASSERT_FP((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */
1942
1943 mwbmap_p->ifree++; /* update free count */
1944 ASSERT_FP(mwbmap_p->ifree <= mwbmap_p->total);
1945
1946 MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d",
1947 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap,
1948 mwbmap_p->ifree));
1949
1950 *bitmap_p |= bitmap; /* mark as available */
1951
1952 /* Now update first level hierarchy */
1953
1954 bitix = wordix;
1955
1956 wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */
1957 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
1958 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
1959
1960 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
1961 mwbmap_p->wd_count[bitix]++;
1962 #endif
1963
1964 #if defined(BCM_MWBMAP_DEBUG)
1965 {
1966 uint32 count;
1967 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
1968 count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
1969 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
1970 count = mwbmap_p->wd_count[bitix];
1971 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
1972 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
1973
1974 MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD);
1975
1976 MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d",
1977 bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count));
1978 }
1979 #endif /* BCM_MWBMAP_DEBUG */
1980
1981 *bitmap_p |= bitmap;
1982
1983 return;
1984 }
1985
1986 /* Fetch the toal number of free indices in the multiword bitmap allocator */
1987 uint32
bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl)1988 bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl)
1989 {
1990 bcm_mwbmap_t * mwbmap_p;
1991
1992 BCM_MWBMAP_AUDIT(mwbmap_hdl);
1993 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
1994
1995 ASSERT(mwbmap_p->ifree >= 0);
1996
1997 return mwbmap_p->ifree;
1998 }
1999
2000 /* Determine whether an index is inuse or free */
2001 bool
bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl,uint32 bitix)2002 bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
2003 {
2004 bcm_mwbmap_t * mwbmap_p;
2005 uint32 wordix, bitmap;
2006
2007 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2008 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2009
2010 ASSERT(bitix < mwbmap_p->total);
2011
2012 wordix = BCM_MWBMAP_DIVOP(bitix);
2013 bitmap = (1U << BCM_MWBMAP_MODOP(bitix));
2014
2015 return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U);
2016 }
2017
2018 /* Debug dump a multiword bitmap allocator */
2019 void
bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl)2020 bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl)
2021 {
2022 uint32 ix, count;
2023 bcm_mwbmap_t * mwbmap_p;
2024
2025 BCM_MWBMAP_AUDIT(mwbmap_hdl);
2026 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2027
2028 printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n",
2029 OSL_OBFUSCATE_BUF((void *)mwbmap_p),
2030 mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total);
2031 for (ix = 0U; ix < mwbmap_p->wmaps; ix++) {
2032 printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]);
2033 bcm_bitprint32(mwbmap_p->wd_bitmap[ix]);
2034 printf("\n");
2035 }
2036 for (ix = 0U; ix < mwbmap_p->imaps; ix++) {
2037 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
2038 count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]);
2039 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
2040 count = mwbmap_p->wd_count[ix];
2041 MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix]));
2042 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2043 printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count);
2044 bcm_bitprint32(mwbmap_p->id_bitmap[ix]);
2045 printf("\n");
2046 }
2047
2048 return;
2049 }
2050
2051 /* Audit a hierarchical multiword bitmap */
2052 void
bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)2053 bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)
2054 {
2055 bcm_mwbmap_t * mwbmap_p;
2056 uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p;
2057
2058 mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
2059
2060 for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) {
2061
2062 bitmap_p = &mwbmap_p->wd_bitmap[wordix];
2063
2064 for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) {
2065 if ((*bitmap_p) & (1 << bitix)) {
2066 idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix;
2067 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
2068 count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]);
2069 #else /* ! BCM_MWBMAP_USE_CNTSETBITS */
2070 count = mwbmap_p->wd_count[idmap_ix];
2071 ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]));
2072 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
2073 ASSERT(count != 0U);
2074 free_cnt += count;
2075 }
2076 }
2077 }
2078
2079 ASSERT((int)free_cnt == mwbmap_p->ifree);
2080 }
2081 /* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
2082
2083 /* Simple 16bit Id allocator using a stack implementation. */
2084 typedef struct id16_map {
2085 uint32 failures; /* count of failures */
2086 void *dbg; /* debug placeholder */
2087 uint16 total; /* total number of ids managed by allocator */
2088 uint16 start; /* start value of 16bit ids to be managed */
2089 int stack_idx; /* index into stack of available ids */
2090 uint16 stack[0]; /* stack of 16 bit ids */
2091 } id16_map_t;
2092
2093 #define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \
2094 (sizeof(uint16) * (items)))
2095
2096 #if defined(BCM_DBG)
2097
2098 /* Uncomment BCM_DBG_ID16 to debug double free */
2099 /* #define BCM_DBG_ID16 */
2100
2101 typedef struct id16_map_dbg {
2102 uint16 total;
2103 bool avail[0];
2104 } id16_map_dbg_t;
2105 #define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \
2106 (sizeof(bool) * (items)))
2107 #define ID16_MAP_MSG(x) print x
2108 #else
2109 #define ID16_MAP_MSG(x)
2110 #endif /* BCM_DBG */
2111
2112 void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */
id16_map_init(osl_t * osh,uint16 total_ids,uint16 start_val16)2113 id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16)
2114 {
2115 uint16 idx, val16;
2116 id16_map_t * id16_map;
2117
2118 ASSERT(total_ids > 0);
2119
2120 /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
2121 * with random values.
2122 */
2123 ASSERT((start_val16 == ID16_UNDEFINED) ||
2124 (start_val16 + total_ids) < ID16_INVALID);
2125
2126 id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids));
2127 if (id16_map == NULL) {
2128 return NULL;
2129 }
2130
2131 id16_map->total = total_ids;
2132 id16_map->start = start_val16;
2133 id16_map->failures = 0;
2134 id16_map->dbg = NULL;
2135
2136 /*
2137 * Populate stack with 16bit id values, commencing with start_val16.
2138 * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map.
2139 */
2140 id16_map->stack_idx = -1;
2141
2142 if (id16_map->start != ID16_UNDEFINED) {
2143 val16 = start_val16;
2144
2145 for (idx = 0; idx < total_ids; idx++, val16++) {
2146 id16_map->stack_idx = idx;
2147 id16_map->stack[id16_map->stack_idx] = val16;
2148 }
2149 }
2150
2151 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
2152 if (id16_map->start != ID16_UNDEFINED) {
2153 id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids));
2154
2155 if (id16_map->dbg) {
2156 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
2157
2158 id16_map_dbg->total = total_ids;
2159 for (idx = 0; idx < total_ids; idx++) {
2160 id16_map_dbg->avail[idx] = TRUE;
2161 }
2162 }
2163 }
2164 #endif /* BCM_DBG && BCM_DBG_ID16 */
2165
2166 return (void *)id16_map;
2167 }
2168
2169 void * /* Destruct an id16 allocator instance */
id16_map_fini(osl_t * osh,void * id16_map_hndl)2170 id16_map_fini(osl_t *osh, void * id16_map_hndl)
2171 {
2172 uint16 total_ids;
2173 id16_map_t * id16_map;
2174
2175 if (id16_map_hndl == NULL)
2176 return NULL;
2177
2178 id16_map = (id16_map_t *)id16_map_hndl;
2179
2180 total_ids = id16_map->total;
2181 ASSERT(total_ids > 0);
2182
2183 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
2184 if (id16_map->dbg) {
2185 MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids));
2186 }
2187 #endif /* BCM_DBG && BCM_DBG_ID16 */
2188
2189 id16_map->total = 0;
2190 MFREE(osh, id16_map, ID16_MAP_SZ(total_ids));
2191
2192 return NULL;
2193 }
2194
2195 void
id16_map_clear(void * id16_map_hndl,uint16 total_ids,uint16 start_val16)2196 id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16)
2197 {
2198 uint16 idx, val16;
2199 id16_map_t * id16_map;
2200
2201 ASSERT(total_ids > 0);
2202 /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
2203 * with random values.
2204 */
2205 ASSERT((start_val16 == ID16_UNDEFINED) ||
2206 (start_val16 + total_ids) < ID16_INVALID);
2207
2208 id16_map = (id16_map_t *)id16_map_hndl;
2209 if (id16_map == NULL) {
2210 return;
2211 }
2212
2213 id16_map->total = total_ids;
2214 id16_map->start = start_val16;
2215 id16_map->failures = 0;
2216
2217 /* Populate stack with 16bit id values, commencing with start_val16 */
2218 id16_map->stack_idx = -1;
2219
2220 if (id16_map->start != ID16_UNDEFINED) {
2221 val16 = start_val16;
2222
2223 for (idx = 0; idx < total_ids; idx++, val16++) {
2224 id16_map->stack_idx = idx;
2225 id16_map->stack[id16_map->stack_idx] = val16;
2226 }
2227 }
2228
2229 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
2230 if (id16_map->start != ID16_UNDEFINED) {
2231 if (id16_map->dbg) {
2232 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
2233
2234 id16_map_dbg->total = total_ids;
2235 for (idx = 0; idx < total_ids; idx++) {
2236 id16_map_dbg->avail[idx] = TRUE;
2237 }
2238 }
2239 }
2240 #endif /* BCM_DBG && BCM_DBG_ID16 */
2241 }
2242
2243 uint16 /* Allocate a unique 16bit id */
BCMFASTPATH(id16_map_alloc)2244 BCMFASTPATH(id16_map_alloc)(void * id16_map_hndl)
2245 {
2246 uint16 val16;
2247 id16_map_t * id16_map;
2248
2249 ASSERT_FP(id16_map_hndl != NULL);
2250
2251 id16_map = (id16_map_t *)id16_map_hndl;
2252
2253 ASSERT_FP(id16_map->total > 0);
2254
2255 if (id16_map->stack_idx < 0) {
2256 id16_map->failures++;
2257 return ID16_INVALID;
2258 }
2259
2260 val16 = id16_map->stack[id16_map->stack_idx];
2261 id16_map->stack_idx--;
2262
2263 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
2264 ASSERT_FP((id16_map->start == ID16_UNDEFINED) ||
2265 (val16 < (id16_map->start + id16_map->total)));
2266
2267 if (id16_map->dbg) { /* Validate val16 */
2268 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
2269
2270 ASSERT_FP(id16_map_dbg->avail[val16 - id16_map->start] == TRUE);
2271 id16_map_dbg->avail[val16 - id16_map->start] = FALSE;
2272 }
2273 #endif /* BCM_DBG && BCM_DBG_ID16 */
2274
2275 return val16;
2276 }
2277
2278 void /* Free a 16bit id value into the id16 allocator */
BCMFASTPATH(id16_map_free)2279 BCMFASTPATH(id16_map_free)(void * id16_map_hndl, uint16 val16)
2280 {
2281 id16_map_t * id16_map;
2282
2283 ASSERT_FP(id16_map_hndl != NULL);
2284
2285 id16_map = (id16_map_t *)id16_map_hndl;
2286
2287 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
2288 ASSERT_FP((id16_map->start == ID16_UNDEFINED) ||
2289 (val16 < (id16_map->start + id16_map->total)));
2290
2291 if (id16_map->dbg) { /* Validate val16 */
2292 id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
2293
2294 ASSERT_FP(id16_map_dbg->avail[val16 - id16_map->start] == FALSE);
2295 id16_map_dbg->avail[val16 - id16_map->start] = TRUE;
2296 }
2297 #endif /* BCM_DBG && BCM_DBG_ID16 */
2298
2299 id16_map->stack_idx++;
2300 id16_map->stack[id16_map->stack_idx] = val16;
2301 }
2302
2303 uint32 /* Returns number of failures to allocate an unique id16 */
id16_map_failures(void * id16_map_hndl)2304 id16_map_failures(void * id16_map_hndl)
2305 {
2306 ASSERT(id16_map_hndl != NULL);
2307 return ((id16_map_t *)id16_map_hndl)->failures;
2308 }
2309
2310 bool
id16_map_audit(void * id16_map_hndl)2311 id16_map_audit(void * id16_map_hndl)
2312 {
2313 int idx;
2314 int insane = 0;
2315 id16_map_t * id16_map;
2316
2317 ASSERT(id16_map_hndl != NULL);
2318
2319 id16_map = (id16_map_t *)id16_map_hndl;
2320
2321 ASSERT(id16_map->stack_idx >= -1);
2322 ASSERT(id16_map->stack_idx < (int)id16_map->total);
2323
2324 if (id16_map->start == ID16_UNDEFINED)
2325 goto done;
2326
2327 for (idx = 0; idx <= id16_map->stack_idx; idx++) {
2328 ASSERT(id16_map->stack[idx] >= id16_map->start);
2329 ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total));
2330
2331 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
2332 if (id16_map->dbg) {
2333 uint16 val16 = id16_map->stack[idx];
2334 if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) {
2335 insane |= 1;
2336 ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n",
2337 OSL_OBFUSATE_BUF(id16_map_hndl), idx, val16));
2338 }
2339 }
2340 #endif /* BCM_DBG && BCM_DBG_ID16 */
2341 }
2342
2343 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
2344 if (id16_map->dbg) {
2345 uint16 avail = 0; /* Audit available ids counts */
2346 for (idx = 0; idx < id16_map_dbg->total; idx++) {
2347 if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE)
2348 avail++;
2349 }
2350 if (avail && (avail != (id16_map->stack_idx + 1))) {
2351 insane |= 1;
2352 ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n",
2353 OSL_OBFUSCATE_BUF(id16_map_hndl),
2354 avail, id16_map->stack_idx));
2355 }
2356 }
2357 #endif /* BCM_DBG && BCM_DBG_ID16 */
2358
2359 done:
2360 /* invoke any other system audits */
2361 return (!!insane);
2362 }
2363 /* END: Simple id16 allocator */
2364
2365 void
BCMATTACHFN(dll_pool_detach)2366 BCMATTACHFN(dll_pool_detach)(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size)
2367 {
2368 uint32 mem_size;
2369 mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
2370 if (pool)
2371 MFREE(osh, pool, mem_size);
2372 }
2373 dll_pool_t *
BCMATTACHFN(dll_pool_init)2374 BCMATTACHFN(dll_pool_init)(void * osh, uint16 elems_max, uint16 elem_size)
2375 {
2376 uint32 mem_size, i;
2377 dll_pool_t * dll_pool_p;
2378 dll_t * elem_p;
2379
2380 ASSERT(elem_size > sizeof(dll_t));
2381
2382 mem_size = sizeof(dll_pool_t) + (elems_max * elem_size);
2383
2384 if ((dll_pool_p = (dll_pool_t *)MALLOCZ(osh, mem_size)) == NULL) {
2385 ASSERT(0);
2386 return dll_pool_p;
2387 }
2388
2389 dll_init(&dll_pool_p->free_list);
2390 dll_pool_p->elems_max = elems_max;
2391 dll_pool_p->elem_size = elem_size;
2392
2393 elem_p = dll_pool_p->elements;
2394 for (i = 0; i < elems_max; i++) {
2395 dll_append(&dll_pool_p->free_list, elem_p);
2396 elem_p = (dll_t *)((uintptr)elem_p + elem_size);
2397 }
2398
2399 dll_pool_p->free_count = elems_max;
2400
2401 return dll_pool_p;
2402 }
2403
2404 void *
dll_pool_alloc(dll_pool_t * dll_pool_p)2405 dll_pool_alloc(dll_pool_t * dll_pool_p)
2406 {
2407 dll_t * elem_p;
2408
2409 if (dll_pool_p->free_count == 0) {
2410 ASSERT(dll_empty(&dll_pool_p->free_list));
2411 return NULL;
2412 }
2413
2414 elem_p = dll_head_p(&dll_pool_p->free_list);
2415 dll_delete(elem_p);
2416 dll_pool_p->free_count -= 1;
2417
2418 return (void *)elem_p;
2419 }
2420
2421 void
BCMPOSTTRAPFN(dll_pool_free)2422 BCMPOSTTRAPFN(dll_pool_free)(dll_pool_t * dll_pool_p, void * elem_p)
2423 {
2424 dll_t * node_p = (dll_t *)elem_p;
2425 dll_prepend(&dll_pool_p->free_list, node_p);
2426 dll_pool_p->free_count += 1;
2427 }
2428
2429 void
dll_pool_free_tail(dll_pool_t * dll_pool_p,void * elem_p)2430 dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p)
2431 {
2432 dll_t * node_p = (dll_t *)elem_p;
2433 dll_append(&dll_pool_p->free_list, node_p);
2434 dll_pool_p->free_count += 1;
2435 }
2436
2437 #ifdef BCMDBG
2438 void
dll_pool_dump(dll_pool_t * dll_pool_p,dll_elem_dump elem_dump)2439 dll_pool_dump(dll_pool_t * dll_pool_p, dll_elem_dump elem_dump)
2440 {
2441 dll_t * elem_p;
2442 dll_t * next_p;
2443 printf("dll_pool<%p> free_count<%u> elems_max<%u> elem_size<%u>\n",
2444 OSL_OBFUSCATE_BUF(dll_pool_p), dll_pool_p->free_count,
2445 dll_pool_p->elems_max, dll_pool_p->elem_size);
2446
2447 for (elem_p = dll_head_p(&dll_pool_p->free_list);
2448 !dll_end(&dll_pool_p->free_list, elem_p); elem_p = next_p) {
2449
2450 next_p = dll_next_p(elem_p);
2451 printf("\telem<%p>\n", OSL_OBFUSCATE_BUF(elem_p));
2452 if (elem_dump != NULL)
2453 elem_dump((void *)elem_p);
2454 }
2455 }
2456 #endif /* BCMDBG */
2457
2458 #endif /* BCMDRIVER */
2459
2460 #if defined(BCMDRIVER) || defined(WL_UNITTEST)
2461
2462 /* triggers bcm_bprintf to print to kernel log */
2463 bool bcm_bprintf_bypass = FALSE;
2464
2465 /* Initialization of bcmstrbuf structure */
2466 void
BCMPOSTTRAPFN(bcm_binit)2467 BCMPOSTTRAPFN(bcm_binit)(struct bcmstrbuf *b, char *buf, uint size)
2468 {
2469 b->origsize = b->size = size;
2470 b->origbuf = b->buf = buf;
2471 if (size > 0) {
2472 buf[0] = '\0';
2473 }
2474 }
2475
2476 /* Buffer sprintf wrapper to guard against buffer overflow */
2477 int
BCMPOSTTRAPFN(bcm_bprintf)2478 BCMPOSTTRAPFN(bcm_bprintf)(struct bcmstrbuf *b, const char *fmt, ...)
2479 {
2480 va_list ap;
2481 int r;
2482
2483 va_start(ap, fmt);
2484
2485 r = vsnprintf(b->buf, b->size, fmt, ap);
2486 if (bcm_bprintf_bypass == TRUE) {
2487 printf("%s", b->buf);
2488 goto exit;
2489 }
2490
2491 /* Non Ansi C99 compliant returns -1,
2492 * Ansi compliant return r >= b->size,
2493 * bcmstdlib returns 0, handle all
2494 */
2495 /* r == 0 is also the case when strlen(fmt) is zero.
2496 * typically the case when "" is passed as argument.
2497 */
2498 if ((r == -1) || (r >= (int)b->size)) {
2499 b->size = 0;
2500 } else {
2501 b->size -= r;
2502 b->buf += r;
2503 }
2504
2505 exit:
2506 va_end(ap);
2507
2508 return r;
2509 }
2510
2511 void
bcm_bprhex(struct bcmstrbuf * b,const char * msg,bool newline,const uint8 * buf,uint len)2512 bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, const uint8 *buf, uint len)
2513 {
2514 uint i;
2515
2516 if (msg != NULL && msg[0] != '\0')
2517 bcm_bprintf(b, "%s", msg);
2518 for (i = 0u; i < len; i ++)
2519 bcm_bprintf(b, "%02X", buf[i]);
2520 if (newline)
2521 bcm_bprintf(b, "\n");
2522 }
2523
2524 void
bcm_inc_bytes(uchar * num,int num_bytes,uint8 amount)2525 bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
2526 {
2527 int i;
2528
2529 for (i = 0; i < num_bytes; i++) {
2530 num[i] += amount;
2531 if (num[i] >= amount)
2532 break;
2533 amount = 1;
2534 }
2535 }
2536
2537 int
bcm_cmp_bytes(const uchar * arg1,const uchar * arg2,uint8 nbytes)2538 bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes)
2539 {
2540 int i;
2541
2542 for (i = nbytes - 1; i >= 0; i--) {
2543 if (arg1[i] != arg2[i])
2544 return (arg1[i] - arg2[i]);
2545 }
2546 return 0;
2547 }
2548
2549 void
bcm_print_bytes(const char * name,const uchar * data,uint len)2550 bcm_print_bytes(const char *name, const uchar *data, uint len)
2551 {
2552 uint i;
2553 int per_line = 0;
2554
2555 printf("%s: %d \n", name ? name : "", len);
2556 for (i = 0u; i < len; i++) {
2557 printf("%02x ", *data++);
2558 per_line++;
2559 if (per_line == 16) {
2560 per_line = 0;
2561 printf("\n");
2562 }
2563 }
2564 printf("\n");
2565 }
2566
2567 /* Search for an IE having a specific tag and an OUI type from a buffer.
2568 * tlvs: buffer to search for IE
2569 * tlvs_len: buffer length
2570 * tag: IE tag
2571 * oui: Specific OUI to match
2572 * oui_len: length of the OUI
2573 * type: OUI type
2574 * Return the matched IE, else return null.
2575 */
2576 bcm_tlv_t *
bcm_find_ie(const uint8 * tlvs,uint tlvs_len,uint8 tag,uint8 oui_len,const char * oui,uint8 type)2577 bcm_find_ie(const uint8* tlvs, uint tlvs_len, uint8 tag, uint8 oui_len,
2578 const char *oui, uint8 type)
2579 {
2580 const bcm_tlv_t *ie;
2581
2582 COV_TAINTED_DATA_SINK(tlvs_len);
2583 COV_NEG_SINK(tlvs_len);
2584
2585 /* Walk through the IEs looking for an OUI match */
2586 while ((ie = bcm_parse_tlvs_advance(&tlvs, &tlvs_len, tag,
2587 BCM_TLV_ADVANCE_TO))) {
2588 if ((ie->len > oui_len) &&
2589 !bcmp(ie->data, oui, oui_len) &&
2590 ie->data[oui_len] == type) {
2591
2592 COV_TAINTED_DATA_ARG(ie);
2593
2594 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2595 return (bcm_tlv_t *)(ie); /* a match */
2596 GCC_DIAGNOSTIC_POP();
2597 }
2598 /* Point to the next IE */
2599 bcm_tlv_buffer_advance_past(ie, &tlvs, &tlvs_len);
2600 }
2601
2602 return NULL;
2603 }
2604
2605 /* Look for vendor-specific IE with specified OUI and optional type */
2606 bcm_tlv_t *
bcm_find_vendor_ie(const void * tlvs,uint tlvs_len,const char * voui,uint8 * type,uint type_len)2607 bcm_find_vendor_ie(const void *tlvs, uint tlvs_len, const char *voui, uint8 *type, uint type_len)
2608 {
2609 const bcm_tlv_t *ie;
2610 uint8 ie_len;
2611
2612 COV_TAINTED_DATA_SINK(tlvs_len);
2613 COV_NEG_SINK(tlvs_len);
2614
2615 ie = (const bcm_tlv_t*)tlvs;
2616
2617 /* make sure we are looking at a valid IE */
2618 if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) {
2619 return NULL;
2620 }
2621
2622 /* Walk through the IEs looking for an OUI match */
2623 do {
2624 ie_len = ie->len;
2625 if ((ie->id == DOT11_MNG_VS_ID) &&
2626 (ie_len >= (DOT11_OUI_LEN + type_len)) &&
2627 !bcmp(ie->data, voui, DOT11_OUI_LEN))
2628 {
2629 /* compare optional type */
2630 if (type_len == 0 ||
2631 !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) {
2632
2633 COV_TAINTED_DATA_ARG(ie);
2634
2635 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2636 return (bcm_tlv_t *)(ie); /* a match */
2637 GCC_DIAGNOSTIC_POP();
2638 }
2639 }
2640 } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL);
2641
2642 return NULL;
2643 }
2644
2645 #if defined(WLTINYDUMP) || defined(BCMDBG) || defined(WLMSG_INFORM) || \
2646 defined(WLMSG_ASSOC) || defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
2647 #define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
2648
2649 int
bcm_format_ssid(char * buf,const uchar ssid[],uint ssid_len)2650 bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
2651 {
2652 uint i, c;
2653 char *p = buf;
2654 char *endp = buf + SSID_FMT_BUF_LEN;
2655
2656 if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
2657
2658 for (i = 0; i < ssid_len; i++) {
2659 c = (uint)ssid[i];
2660 if (c == '\\') {
2661 *p++ = '\\';
2662 *p++ = '\\';
2663 } else if (bcm_isprint((uchar)c)) {
2664 *p++ = (char)c;
2665 } else {
2666 p += snprintf(p, (endp - p), "\\x%02X", c);
2667 }
2668 }
2669 *p = '\0';
2670 ASSERT(p < endp);
2671
2672 return (int)(p - buf);
2673 }
2674 #endif /* WLTINYDUMP || BCMDBG || WLMSG_INFORM || WLMSG_ASSOC || WLMSG_PRPKT */
2675
2676 #endif /* BCMDRIVER || WL_UNITTEST */
2677
2678 /* Masking few bytes of MAC address per customer in all prints/eventlogs. */
2679 int
BCMRAMFN(bcm_addrmask_set)2680 BCMRAMFN(bcm_addrmask_set)(int enable)
2681 {
2682 #ifdef PRIVACY_MASK
2683 struct ether_addr *privacy = privacy_addrmask_get();
2684 if (enable) {
2685 /* apply mask as (For SS)
2686 * orig : 12:34:56:78:90:ab
2687 * masked : 12:xx:xx:xx:x0:ab
2688 */
2689 privacy->octet[1] = privacy->octet[2] =
2690 privacy->octet[3] = 0;
2691 privacy->octet[0] = privacy->octet[5] = 0xff;
2692 privacy->octet[4] = 0x0f;
2693 } else
2694 {
2695 /* No masking. All are 0xff. */
2696 memcpy(privacy, ðer_bcast, sizeof(struct ether_addr));
2697 }
2698
2699 return BCME_OK;
2700 #else
2701 BCM_REFERENCE(enable);
2702 return BCME_UNSUPPORTED;
2703 #endif /* PRIVACY_MASK */
2704
2705 }
2706
2707 int
bcm_addrmask_get(int * val)2708 bcm_addrmask_get(int *val)
2709 {
2710 #ifdef PRIVACY_MASK
2711 struct ether_addr *privacy = privacy_addrmask_get();
2712 if (!eacmp(ðer_bcast, privacy)) {
2713 *val = FALSE;
2714 } else {
2715 *val = TRUE;
2716 }
2717
2718 return BCME_OK;
2719 #else
2720 BCM_REFERENCE(val);
2721 return BCME_UNSUPPORTED;
2722 #endif
2723 }
2724
2725 uint64
BCMRAMFN(bcm_ether_ntou64)2726 BCMRAMFN(bcm_ether_ntou64)(const struct ether_addr *ea)
2727 {
2728 uint64 mac;
2729 struct ether_addr addr;
2730
2731 memcpy(&addr, ea, sizeof(struct ether_addr));
2732
2733 #ifdef PRIVACY_MASK
2734 struct ether_addr *privacy = privacy_addrmask_get();
2735 if (!ETHER_ISMULTI(ea)) {
2736 *(uint32*)(&addr.octet[0]) &= *((uint32*)&privacy->octet[0]);
2737 *(uint16*)(&addr.octet[4]) &= *((uint16*)&privacy->octet[4]);
2738 }
2739 #endif /* PRIVACY_MASK */
2740
2741 mac = ((uint64)HTON16(*((const uint16*)&addr.octet[4]))) << 32 |
2742 HTON32(*((const uint32*)&addr.octet[0]));
2743 return (mac);
2744 }
2745
2746 char *
bcm_ether_ntoa(const struct ether_addr * ea,char * buf)2747 bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
2748 {
2749 static const char hex[] =
2750 {
2751 '0', '1', '2', '3', '4', '5', '6', '7',
2752 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
2753 };
2754 const uint8 *octet = ea->octet;
2755 char *p = buf;
2756 int i;
2757
2758 for (i = 0; i < 6; i++, octet++) {
2759 *p++ = hex[(*octet >> 4) & 0xf];
2760 *p++ = hex[*octet & 0xf];
2761 *p++ = ':';
2762 }
2763
2764 *(p-1) = '\0';
2765
2766 return (buf);
2767 }
2768
2769 /* Find the position of first bit set
2770 * in the given number.
2771 */
2772 int
bcm_find_fsb(uint32 num)2773 bcm_find_fsb(uint32 num)
2774 {
2775 uint8 pos = 0;
2776 if (!num)
2777 return pos;
2778 while (!(num & 1)) {
2779 num >>= 1;
2780 pos++;
2781 }
2782 return (pos+1);
2783 }
2784
2785 /* TODO: need to pass in the buffer length for validation check */
2786 char *
bcm_ip_ntoa(struct ipv4_addr * ia,char * buf)2787 bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
2788 {
2789 snprintf(buf, 16, "%d.%d.%d.%d",
2790 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
2791 return (buf);
2792 }
2793
2794 /* TODO: need to pass in the buffer length for validation check */
2795 char *
bcm_ipv6_ntoa(void * ipv6,char * buf)2796 bcm_ipv6_ntoa(void *ipv6, char *buf)
2797 {
2798 /* Implementing RFC 5952 Sections 4 + 5 */
2799 /* Not thoroughly tested */
2800 uint16 tmp[8];
2801 uint16 *a = &tmp[0];
2802 char *p = buf;
2803 int i, i_max = -1, cnt = 0, cnt_max = 1;
2804 uint8 *a4 = NULL;
2805 memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN);
2806
2807 for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
2808 if (a[i]) {
2809 if (cnt > cnt_max) {
2810 cnt_max = cnt;
2811 i_max = i - cnt;
2812 }
2813 cnt = 0;
2814 } else
2815 cnt++;
2816 }
2817 if (cnt > cnt_max) {
2818 cnt_max = cnt;
2819 i_max = i - cnt;
2820 }
2821 if (i_max == 0 &&
2822 /* IPv4-translated: ::ffff:0:a.b.c.d */
2823 ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) ||
2824 /* IPv4-mapped: ::ffff:a.b.c.d */
2825 (cnt_max == 5 && a[5] == 0xffff)))
2826 a4 = (uint8*) (a + 6);
2827
2828 for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
2829 if ((uint8*) (a + i) == a4) {
2830 snprintf(p, 17, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]);
2831 break;
2832 } else if (i == i_max) {
2833 *p++ = ':';
2834 i += cnt_max - 1;
2835 p[0] = ':';
2836 p[1] = '\0';
2837 } else {
2838 if (i)
2839 *p++ = ':';
2840 p += snprintf(p, 8, "%x", ntoh16(a[i]));
2841 }
2842 }
2843
2844 return buf;
2845 }
2846
2847 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
2848 const unsigned char bcm_ctype[256] = {
2849
2850 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
2851 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
2852 _BCM_C, /* 8-15 */
2853 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
2854 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
2855 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
2856 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
2857 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
2858 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
2859 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
2860 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
2861 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
2862 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
2863 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
2864 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
2865 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
2866 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
2867 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
2868 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
2869 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
2870 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
2871 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
2872 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
2873 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
2874 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
2875 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
2876 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
2877 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
2878 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
2879 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
2880 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
2881 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
2882 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
2883 };
2884
2885 uint64
bcm_strtoull(const char * cp,char ** endp,uint base)2886 bcm_strtoull(const char *cp, char **endp, uint base)
2887 {
2888 uint64 result, last_result = 0, value;
2889 bool minus;
2890
2891 minus = FALSE;
2892
2893 while (bcm_isspace(*cp))
2894 cp++;
2895
2896 if (cp[0] == '+')
2897 cp++;
2898 else if (cp[0] == '-') {
2899 minus = TRUE;
2900 cp++;
2901 }
2902
2903 if (base == 0) {
2904 if (cp[0] == '0') {
2905 if ((cp[1] == 'x') || (cp[1] == 'X')) {
2906 base = 16;
2907 cp = &cp[2];
2908 } else {
2909 base = 8;
2910 cp = &cp[1];
2911 }
2912 } else
2913 base = 10;
2914 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
2915 cp = &cp[2];
2916 }
2917
2918 result = 0;
2919
2920 while (bcm_isxdigit(*cp) &&
2921 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
2922 result = result*base + value;
2923 /* Detected overflow */
2924 if (result < last_result && !minus) {
2925 if (endp) {
2926 /* Go to the end of current number */
2927 while (bcm_isxdigit(*cp)) {
2928 cp++;
2929 }
2930 *endp = DISCARD_QUAL(cp, char);
2931 }
2932 return (ulong)-1;
2933 }
2934 last_result = result;
2935 cp++;
2936 }
2937
2938 if (minus)
2939 result = (ulong)(-(long)result);
2940
2941 if (endp)
2942 *endp = DISCARD_QUAL(cp, char);
2943
2944 return (result);
2945 }
2946
2947 ulong
bcm_strtoul(const char * cp,char ** endp,uint base)2948 bcm_strtoul(const char *cp, char **endp, uint base)
2949 {
2950 return (ulong) bcm_strtoull(cp, endp, base);
2951 }
2952
2953 int
bcm_atoi(const char * s)2954 bcm_atoi(const char *s)
2955 {
2956 return (int)bcm_strtoul(s, NULL, 10);
2957 }
2958
2959 /* return pointer to location of substring 'needle' in 'haystack' */
2960 char *
bcmstrstr(const char * haystack,const char * needle)2961 bcmstrstr(const char *haystack, const char *needle)
2962 {
2963 uint len, nlen;
2964 uint i;
2965
2966 if ((haystack == NULL) || (needle == NULL))
2967 return DISCARD_QUAL(haystack, char);
2968
2969 nlen = (uint)strlen(needle);
2970 if (strlen(haystack) < nlen) {
2971 return NULL;
2972 }
2973 len = (uint)strlen(haystack) - nlen + 1u;
2974
2975 for (i = 0u; i < len; i++)
2976 if (memcmp(needle, &haystack[i], nlen) == 0)
2977 return DISCARD_QUAL(&haystack[i], char);
2978 return (NULL);
2979 }
2980
2981 char *
bcmstrnstr(const char * s,uint s_len,const char * substr,uint substr_len)2982 bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len)
2983 {
2984 for (; s_len >= substr_len; s++, s_len--)
2985 if (strncmp(s, substr, substr_len) == 0)
2986 return DISCARD_QUAL(s, char);
2987
2988 return NULL;
2989 }
2990
2991 char *
bcmstrcat(char * dest,const char * src)2992 bcmstrcat(char *dest, const char *src)
2993 {
2994 char *p;
2995
2996 p = dest + strlen(dest);
2997
2998 while ((*p++ = *src++) != '\0')
2999 ;
3000
3001 return (dest);
3002 }
3003
3004 char *
bcmstrncat(char * dest,const char * src,uint size)3005 bcmstrncat(char *dest, const char *src, uint size)
3006 {
3007 char *endp;
3008 char *p;
3009
3010 p = dest + strlen(dest);
3011 endp = p + size;
3012
3013 while (p != endp && (*p++ = *src++) != '\0')
3014 ;
3015
3016 return (dest);
3017 }
3018
3019 /****************************************************************************
3020 * Function: bcmstrtok
3021 *
3022 * Purpose:
3023 * Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
3024 * but allows strToken() to be used by different strings or callers at the same
3025 * time. Each call modifies '*string' by substituting a NULL character for the
3026 * first delimiter that is encountered, and updates 'string' to point to the char
3027 * after the delimiter. Leading delimiters are skipped.
3028 *
3029 * Parameters:
3030 * string (mod) Ptr to string ptr, updated by token.
3031 * delimiters (in) Set of delimiter characters.
3032 * tokdelim (out) Character that delimits the returned token. (May
3033 * be set to NULL if token delimiter is not required).
3034 *
3035 * Returns: Pointer to the next token found. NULL when no more tokens are found.
3036 *****************************************************************************
3037 */
3038 char *
bcmstrtok(char ** string,const char * delimiters,char * tokdelim)3039 bcmstrtok(char **string, const char *delimiters, char *tokdelim)
3040 {
3041 unsigned char *str;
3042 unsigned long map[8];
3043 int count;
3044 char *nextoken;
3045
3046 if (tokdelim != NULL) {
3047 /* Prime the token delimiter */
3048 *tokdelim = '\0';
3049 }
3050
3051 /* Clear control map */
3052 for (count = 0; count < 8; count++) {
3053 map[count] = 0;
3054 }
3055
3056 /* Set bits in delimiter table */
3057 do {
3058 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
3059 }
3060 while (*delimiters++);
3061
3062 str = (unsigned char*)*string;
3063
3064 /* Find beginning of token (skip over leading delimiters). Note that
3065 * there is no token iff this loop sets str to point to the terminal
3066 * null (*str == '\0')
3067 */
3068 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
3069 str++;
3070 }
3071
3072 nextoken = (char*)str;
3073
3074 /* Find the end of the token. If it is not the end of the string,
3075 * put a null there.
3076 */
3077 for (; *str; str++) {
3078 if (map[*str >> 5] & (1 << (*str & 31))) {
3079 if (tokdelim != NULL) {
3080 *tokdelim = *str;
3081 }
3082
3083 *str++ = '\0';
3084 break;
3085 }
3086 }
3087
3088 *string = (char*)str;
3089
3090 /* Determine if a token has been found. */
3091 if (nextoken == (char *) str) {
3092 return NULL;
3093 }
3094 else {
3095 return nextoken;
3096 }
3097 }
3098
3099 #define xToLower(C) \
3100 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
3101
3102 /****************************************************************************
3103 * Function: bcmstricmp
3104 *
3105 * Purpose: Compare to strings case insensitively.
3106 *
3107 * Parameters: s1 (in) First string to compare.
3108 * s2 (in) Second string to compare.
3109 *
3110 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
3111 * t1 > t2, when ignoring case sensitivity.
3112 *****************************************************************************
3113 */
3114 int
bcmstricmp(const char * s1,const char * s2)3115 bcmstricmp(const char *s1, const char *s2)
3116 {
3117 char dc, sc;
3118
3119 while (*s2 && *s1) {
3120 dc = xToLower(*s1);
3121 sc = xToLower(*s2);
3122 if (dc < sc) return -1;
3123 if (dc > sc) return 1;
3124 s1++;
3125 s2++;
3126 }
3127
3128 if (*s1 && !*s2) return 1;
3129 if (!*s1 && *s2) return -1;
3130 return 0;
3131 }
3132
3133 /****************************************************************************
3134 * Function: bcmstrnicmp
3135 *
3136 * Purpose: Compare to strings case insensitively, upto a max of 'cnt'
3137 * characters.
3138 *
3139 * Parameters: s1 (in) First string to compare.
3140 * s2 (in) Second string to compare.
3141 * cnt (in) Max characters to compare.
3142 *
3143 * Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
3144 * t1 > t2, when ignoring case sensitivity.
3145 *****************************************************************************
3146 */
3147 int
bcmstrnicmp(const char * s1,const char * s2,int cnt)3148 bcmstrnicmp(const char* s1, const char* s2, int cnt)
3149 {
3150 char dc, sc;
3151
3152 while (*s2 && *s1 && cnt) {
3153 dc = xToLower(*s1);
3154 sc = xToLower(*s2);
3155 if (dc < sc) return -1;
3156 if (dc > sc) return 1;
3157 s1++;
3158 s2++;
3159 cnt--;
3160 }
3161
3162 if (!cnt) return 0;
3163 if (*s1 && !*s2) return 1;
3164 if (!*s1 && *s2) return -1;
3165 return 0;
3166 }
3167
3168 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
3169 int
bcm_ether_atoe(const char * p,struct ether_addr * ea)3170 bcm_ether_atoe(const char *p, struct ether_addr *ea)
3171 {
3172 int i = 0;
3173 char *ep;
3174
3175 for (;;) {
3176 ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16);
3177 p = ep;
3178 if (!*p++ || i == 6)
3179 break;
3180 }
3181
3182 return (i == 6);
3183 }
3184
3185 /* parse a nnn.nnn.nnn.nnn format IPV4 address */
3186 int
bcm_atoipv4(const char * p,struct ipv4_addr * ip)3187 bcm_atoipv4(const char *p, struct ipv4_addr *ip)
3188 {
3189
3190 int i = 0;
3191 char *c;
3192 for (;;) {
3193 ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0);
3194 if (*c++ != '.' || i == IPV4_ADDR_LEN)
3195 break;
3196 p = c;
3197 }
3198 return (i == IPV4_ADDR_LEN);
3199 }
3200 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
3201
3202 const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}};
3203 const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}};
3204 const struct ether_addr ether_ipv6_mcast = {{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}};
3205
3206 int
ether_isbcast(const void * ea)3207 ether_isbcast(const void *ea)
3208 {
3209 return (memcmp(ea, ðer_bcast, sizeof(struct ether_addr)) == 0);
3210 }
3211
3212 int
BCMPOSTTRAPFN(ether_isnulladdr)3213 BCMPOSTTRAPFN(ether_isnulladdr)(const void *ea)
3214 {
3215 const uint8 *ea8 = (const uint8 *)ea;
3216 return !(ea8[5] || ea8[4] || ea8[3] || ea8[2] || ea8[1] || ea8[0]);
3217 }
3218
3219 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
3220 /* registry routine buffer preparation utility functions:
3221 * parameter order is like strlcpy, but returns count
3222 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
3223 */
3224 ulong
wchar2ascii(char * abuf,ushort * wbuf,ushort wbuflen,ulong abuflen)3225 wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
3226 {
3227 ulong copyct = 1;
3228 ushort i;
3229
3230 if (abuflen == 0)
3231 return 0;
3232
3233 /* wbuflen is in bytes */
3234 wbuflen /= sizeof(ushort);
3235
3236 for (i = 0; i < wbuflen; ++i) {
3237 if (--abuflen == 0)
3238 break;
3239 *abuf++ = (char) *wbuf++;
3240 ++copyct;
3241 }
3242 *abuf = '\0';
3243
3244 return copyct;
3245 }
3246 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
3247
3248 #ifdef BCM_OBJECT_TRACE
3249
3250 #define BCM_OBJECT_MERGE_SAME_OBJ 0
3251
3252 /* some place may add / remove the object to trace list for Linux: */
3253 /* add: osl_alloc_skb dev_alloc_skb skb_realloc_headroom dhd_start_xmit */
3254 /* remove: osl_pktfree dev_kfree_skb netif_rx */
3255
3256 #if defined(__linux__)
3257 #define BCM_OBJDBG_COUNT (1024 * 100)
3258 static spinlock_t dbgobj_lock;
3259 #define BCM_OBJDBG_LOCK_INIT() spin_lock_init(&dbgobj_lock)
3260 #define BCM_OBJDBG_LOCK_DESTROY()
3261 #define BCM_OBJDBG_LOCK spin_lock_irqsave
3262 #define BCM_OBJDBG_UNLOCK spin_unlock_irqrestore
3263 #else
3264 #define BCM_OBJDBG_COUNT (256)
3265 #define BCM_OBJDBG_LOCK_INIT()
3266 #define BCM_OBJDBG_LOCK_DESTROY()
3267 #define BCM_OBJDBG_LOCK(x, y)
3268 #define BCM_OBJDBG_UNLOCK(x, y)
3269 #endif /* else OS */
3270
3271 #define BCM_OBJDBG_ADDTOHEAD 0
3272 #define BCM_OBJDBG_ADDTOTAIL 1
3273
3274 #define BCM_OBJDBG_CALLER_LEN 32
3275 struct bcm_dbgobj {
3276 struct bcm_dbgobj *prior;
3277 struct bcm_dbgobj *next;
3278 uint32 flag;
3279 void *obj;
3280 uint32 obj_sn;
3281 uint32 obj_state;
3282 uint32 line;
3283 char caller[BCM_OBJDBG_CALLER_LEN];
3284 };
3285
3286 static struct bcm_dbgobj *dbgobj_freehead = NULL;
3287 static struct bcm_dbgobj *dbgobj_freetail = NULL;
3288 static struct bcm_dbgobj *dbgobj_objhead = NULL;
3289 static struct bcm_dbgobj *dbgobj_objtail = NULL;
3290
3291 static uint32 dbgobj_sn = 0;
3292 static int dbgobj_count = 0;
3293 static struct bcm_dbgobj bcm_dbg_objs[BCM_OBJDBG_COUNT];
3294
3295 void
bcm_object_trace_init(void)3296 bcm_object_trace_init(void)
3297 {
3298 int i = 0;
3299 BCM_OBJDBG_LOCK_INIT();
3300 memset(&bcm_dbg_objs, 0x00, sizeof(struct bcm_dbgobj) * BCM_OBJDBG_COUNT);
3301 dbgobj_freehead = &bcm_dbg_objs[0];
3302 dbgobj_freetail = &bcm_dbg_objs[BCM_OBJDBG_COUNT - 1];
3303
3304 for (i = 0; i < BCM_OBJDBG_COUNT; ++i) {
3305 bcm_dbg_objs[i].next = (i == (BCM_OBJDBG_COUNT - 1)) ?
3306 dbgobj_freehead : &bcm_dbg_objs[i + 1];
3307 bcm_dbg_objs[i].prior = (i == 0) ?
3308 dbgobj_freetail : &bcm_dbg_objs[i - 1];
3309 }
3310 }
3311
3312 void
bcm_object_trace_deinit(void)3313 bcm_object_trace_deinit(void)
3314 {
3315 if (dbgobj_objhead || dbgobj_objtail) {
3316 printf("bcm_object_trace_deinit: not all objects are released\n");
3317 ASSERT(0);
3318 }
3319 BCM_OBJDBG_LOCK_DESTROY();
3320 }
3321
3322 static void
bcm_object_rm_list(struct bcm_dbgobj ** head,struct bcm_dbgobj ** tail,struct bcm_dbgobj * dbgobj)3323 bcm_object_rm_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
3324 struct bcm_dbgobj *dbgobj)
3325 {
3326 if ((dbgobj == *head) && (dbgobj == *tail)) {
3327 *head = NULL;
3328 *tail = NULL;
3329 } else if (dbgobj == *head) {
3330 *head = (*head)->next;
3331 } else if (dbgobj == *tail) {
3332 *tail = (*tail)->prior;
3333 }
3334 dbgobj->next->prior = dbgobj->prior;
3335 dbgobj->prior->next = dbgobj->next;
3336 }
3337
3338 static void
bcm_object_add_list(struct bcm_dbgobj ** head,struct bcm_dbgobj ** tail,struct bcm_dbgobj * dbgobj,int addtotail)3339 bcm_object_add_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
3340 struct bcm_dbgobj *dbgobj, int addtotail)
3341 {
3342 if (!(*head) && !(*tail)) {
3343 *head = dbgobj;
3344 *tail = dbgobj;
3345 dbgobj->next = dbgobj;
3346 dbgobj->prior = dbgobj;
3347 } else if ((*head) && (*tail)) {
3348 (*tail)->next = dbgobj;
3349 (*head)->prior = dbgobj;
3350 dbgobj->next = *head;
3351 dbgobj->prior = *tail;
3352 if (addtotail == BCM_OBJDBG_ADDTOTAIL)
3353 *tail = dbgobj;
3354 else
3355 *head = dbgobj;
3356 } else {
3357 ASSERT(0); /* can't be this case */
3358 }
3359 }
3360
3361 static INLINE void
bcm_object_movetoend(struct bcm_dbgobj ** head,struct bcm_dbgobj ** tail,struct bcm_dbgobj * dbgobj,int movetotail)3362 bcm_object_movetoend(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
3363 struct bcm_dbgobj *dbgobj, int movetotail)
3364 {
3365 if ((*head) && (*tail)) {
3366 if (movetotail == BCM_OBJDBG_ADDTOTAIL) {
3367 if (dbgobj != (*tail)) {
3368 bcm_object_rm_list(head, tail, dbgobj);
3369 bcm_object_add_list(head, tail, dbgobj, movetotail);
3370 }
3371 } else {
3372 if (dbgobj != (*head)) {
3373 bcm_object_rm_list(head, tail, dbgobj);
3374 bcm_object_add_list(head, tail, dbgobj, movetotail);
3375 }
3376 }
3377 } else {
3378 ASSERT(0); /* can't be this case */
3379 }
3380 }
3381
3382 void
bcm_object_trace_opr(void * obj,uint32 opt,const char * caller,int line)3383 bcm_object_trace_opr(void *obj, uint32 opt, const char *caller, int line)
3384 {
3385 struct bcm_dbgobj *dbgobj;
3386 unsigned long flags;
3387
3388 BCM_REFERENCE(flags);
3389 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
3390
3391 if (opt == BCM_OBJDBG_ADD_PKT ||
3392 opt == BCM_OBJDBG_ADD) {
3393 dbgobj = dbgobj_objtail;
3394 while (dbgobj) {
3395 if (dbgobj->obj == obj) {
3396 printf("bcm_object_trace_opr: obj %p allocated from %s(%d),"
3397 " allocate again from %s(%d)\n",
3398 dbgobj->obj,
3399 dbgobj->caller, dbgobj->line,
3400 caller, line);
3401 ASSERT(0);
3402 goto EXIT;
3403 }
3404 dbgobj = dbgobj->prior;
3405 if (dbgobj == dbgobj_objtail)
3406 break;
3407 }
3408
3409 #if BCM_OBJECT_MERGE_SAME_OBJ
3410 dbgobj = dbgobj_freetail;
3411 while (dbgobj) {
3412 if (dbgobj->obj == obj) {
3413 goto FREED_ENTRY_FOUND;
3414 }
3415 dbgobj = dbgobj->prior;
3416 if (dbgobj == dbgobj_freetail)
3417 break;
3418 }
3419 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
3420
3421 dbgobj = dbgobj_freehead;
3422 #if BCM_OBJECT_MERGE_SAME_OBJ
3423 FREED_ENTRY_FOUND:
3424 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
3425 if (!dbgobj) {
3426 printf("bcm_object_trace_opr: already got %d objects ?????????????????\n",
3427 BCM_OBJDBG_COUNT);
3428 ASSERT(0);
3429 goto EXIT;
3430 }
3431
3432 bcm_object_rm_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj);
3433 dbgobj->obj = obj;
3434 strlcpy(dbgobj->caller, caller, sizeof(dbgobj->caller));
3435 dbgobj->line = line;
3436 dbgobj->flag = 0;
3437 if (opt == BCM_OBJDBG_ADD_PKT) {
3438 dbgobj->obj_sn = dbgobj_sn++;
3439 dbgobj->obj_state = 0;
3440 /* first 4 bytes is pkt sn */
3441 if (((unsigned long)PKTTAG(obj)) & 0x3)
3442 printf("pkt tag address not aligned by 4: %p\n", PKTTAG(obj));
3443 *(uint32*)PKTTAG(obj) = dbgobj->obj_sn;
3444 }
3445 bcm_object_add_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj,
3446 BCM_OBJDBG_ADDTOTAIL);
3447
3448 dbgobj_count++;
3449
3450 } else if (opt == BCM_OBJDBG_REMOVE) {
3451 dbgobj = dbgobj_objtail;
3452 while (dbgobj) {
3453 if (dbgobj->obj == obj) {
3454 if (dbgobj->flag) {
3455 printf("bcm_object_trace_opr: rm flagged obj %p"
3456 " flag 0x%08x from %s(%d)\n",
3457 obj, dbgobj->flag, caller, line);
3458 }
3459 bcm_object_rm_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj);
3460 bzero(dbgobj->caller, sizeof(dbgobj->caller));
3461 strlcpy(dbgobj->caller, caller, sizeof(dbgobj->caller));
3462 dbgobj->line = line;
3463 bcm_object_add_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj,
3464 BCM_OBJDBG_ADDTOTAIL);
3465 dbgobj_count--;
3466 goto EXIT;
3467 }
3468 dbgobj = dbgobj->prior;
3469 if (dbgobj == dbgobj_objtail)
3470 break;
3471 }
3472
3473 dbgobj = dbgobj_freetail;
3474 while (dbgobj && dbgobj->obj) {
3475 if (dbgobj->obj == obj) {
3476 printf("bcm_object_trace_opr: obj %p already freed"
3477 " from from %s(%d),"
3478 " try free again from %s(%d)\n",
3479 obj,
3480 dbgobj->caller, dbgobj->line,
3481 caller, line);
3482 //ASSERT(0); /* release same obj more than one time? */
3483 goto EXIT;
3484 }
3485 dbgobj = dbgobj->prior;
3486 if (dbgobj == dbgobj_freetail)
3487 break;
3488 }
3489
3490 printf("bcm_object_trace_opr: ################### release none-existing"
3491 " obj %p from %s(%d)\n",
3492 obj, caller, line);
3493 //ASSERT(0); /* release same obj more than one time? */
3494
3495 }
3496
3497 EXIT:
3498 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
3499 return;
3500 }
3501
3502 void
bcm_object_trace_upd(void * obj,void * obj_new)3503 bcm_object_trace_upd(void *obj, void *obj_new)
3504 {
3505 struct bcm_dbgobj *dbgobj;
3506 unsigned long flags;
3507
3508 BCM_REFERENCE(flags);
3509 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
3510
3511 dbgobj = dbgobj_objtail;
3512 while (dbgobj) {
3513 if (dbgobj->obj == obj) {
3514 dbgobj->obj = obj_new;
3515 if (dbgobj != dbgobj_objtail) {
3516 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
3517 dbgobj, BCM_OBJDBG_ADDTOTAIL);
3518 }
3519 goto EXIT;
3520 }
3521 dbgobj = dbgobj->prior;
3522 if (dbgobj == dbgobj_objtail)
3523 break;
3524 }
3525
3526 EXIT:
3527 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
3528 return;
3529 }
3530
3531 void
bcm_object_trace_chk(void * obj,uint32 chksn,uint32 sn,const char * caller,int line)3532 bcm_object_trace_chk(void *obj, uint32 chksn, uint32 sn,
3533 const char *caller, int line)
3534 {
3535 struct bcm_dbgobj *dbgobj;
3536 unsigned long flags;
3537
3538 BCM_REFERENCE(flags);
3539 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
3540
3541 dbgobj = dbgobj_objtail;
3542 while (dbgobj) {
3543 if ((dbgobj->obj == obj) &&
3544 ((!chksn) || (dbgobj->obj_sn == sn))) {
3545 #if 0
3546 printf("bcm_object_trace_chk: (%s:%d) obj %p was allocated from %s(%d)\n",
3547 caller, line,
3548 dbgobj->obj, dbgobj->caller, dbgobj->line);
3549 #endif /* #if 0 */
3550 if (dbgobj != dbgobj_objtail) {
3551 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
3552 dbgobj, BCM_OBJDBG_ADDTOTAIL);
3553 }
3554 goto EXIT;
3555 }
3556 dbgobj = dbgobj->prior;
3557 if (dbgobj == dbgobj_objtail)
3558 break;
3559 }
3560
3561 dbgobj = dbgobj_freetail;
3562 while (dbgobj) {
3563 if ((dbgobj->obj == obj) &&
3564 ((!chksn) || (dbgobj->obj_sn == sn))) {
3565 printf("bcm_object_trace_chk: (%s:%d) obj %p (sn %d state %d)"
3566 " was freed from %s(%d)\n",
3567 caller, line,
3568 dbgobj->obj, dbgobj->obj_sn, dbgobj->obj_state,
3569 dbgobj->caller, dbgobj->line);
3570 goto EXIT;
3571 }
3572 else if (dbgobj->obj == NULL) {
3573 break;
3574 }
3575 dbgobj = dbgobj->prior;
3576 if (dbgobj == dbgobj_freetail)
3577 break;
3578 }
3579
3580 printf("bcm_object_trace_chk: obj %p not found, check from %s(%d), chksn %s, sn %d\n",
3581 obj, caller, line, chksn ? "yes" : "no", sn);
3582 dbgobj = dbgobj_objtail;
3583 while (dbgobj) {
3584 printf("bcm_object_trace_chk: (%s:%d) obj %p sn %d was allocated from %s(%d)\n",
3585 caller, line,
3586 dbgobj->obj, dbgobj->obj_sn, dbgobj->caller, dbgobj->line);
3587 dbgobj = dbgobj->prior;
3588 if (dbgobj == dbgobj_objtail)
3589 break;
3590 }
3591
3592 EXIT:
3593 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
3594 return;
3595 }
3596
3597 void
bcm_object_feature_set(void * obj,uint32 type,uint32 value)3598 bcm_object_feature_set(void *obj, uint32 type, uint32 value)
3599 {
3600 struct bcm_dbgobj *dbgobj;
3601 unsigned long flags;
3602
3603 BCM_REFERENCE(flags);
3604 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
3605
3606 dbgobj = dbgobj_objtail;
3607 while (dbgobj) {
3608 if (dbgobj->obj == obj) {
3609 if (type == BCM_OBJECT_FEATURE_FLAG) {
3610 if (value & BCM_OBJECT_FEATURE_CLEAR)
3611 dbgobj->flag &= ~(value);
3612 else
3613 dbgobj->flag |= (value);
3614 } else if (type == BCM_OBJECT_FEATURE_PKT_STATE) {
3615 dbgobj->obj_state = value;
3616 }
3617 if (dbgobj != dbgobj_objtail) {
3618 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
3619 dbgobj, BCM_OBJDBG_ADDTOTAIL);
3620 }
3621 goto EXIT;
3622 }
3623 dbgobj = dbgobj->prior;
3624 if (dbgobj == dbgobj_objtail)
3625 break;
3626 }
3627
3628 printf("bcm_object_feature_set: obj %p not found in active list\n", obj);
3629 ASSERT(0);
3630
3631 EXIT:
3632 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
3633 return;
3634 }
3635
3636 int
bcm_object_feature_get(void * obj,uint32 type,uint32 value)3637 bcm_object_feature_get(void *obj, uint32 type, uint32 value)
3638 {
3639 int rtn = 0;
3640 struct bcm_dbgobj *dbgobj;
3641 unsigned long flags;
3642
3643 BCM_REFERENCE(flags);
3644 BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
3645
3646 dbgobj = dbgobj_objtail;
3647 while (dbgobj) {
3648 if (dbgobj->obj == obj) {
3649 if (type == BCM_OBJECT_FEATURE_FLAG) {
3650 rtn = (dbgobj->flag & value) & (~BCM_OBJECT_FEATURE_CLEAR);
3651 }
3652 if (dbgobj != dbgobj_objtail) {
3653 bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
3654 dbgobj, BCM_OBJDBG_ADDTOTAIL);
3655 }
3656 goto EXIT;
3657 }
3658 dbgobj = dbgobj->prior;
3659 if (dbgobj == dbgobj_objtail)
3660 break;
3661 }
3662
3663 printf("bcm_object_feature_get: obj %p not found in active list\n", obj);
3664 ASSERT(0);
3665
3666 EXIT:
3667 BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
3668 return rtn;
3669 }
3670
3671 #endif /* BCM_OBJECT_TRACE */
3672
3673 uint8 *
BCMPOSTTRAPFN(bcm_write_tlv)3674 BCMPOSTTRAPFN(bcm_write_tlv)(int type, const void *data, uint datalen, uint8 *dst)
3675 {
3676 uint8 *new_dst = dst;
3677 bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst;
3678
3679 /* dst buffer should always be valid */
3680 ASSERT(dst);
3681
3682 /* data len must be within valid range */
3683 ASSERT((datalen <= BCM_TLV_MAX_DATA_SIZE));
3684
3685 /* source data buffer pointer should be valid, unless datalen is 0
3686 * meaning no data with this TLV
3687 */
3688 ASSERT((data != NULL) || (datalen == 0));
3689
3690 /* only do work if the inputs are valid
3691 * - must have a dst to write to AND
3692 * - datalen must be within range AND
3693 * - the source data pointer must be non-NULL if datalen is non-zero
3694 * (this last condition detects datalen > 0 with a NULL data pointer)
3695 */
3696 if ((dst != NULL) &&
3697 ((datalen <= BCM_TLV_MAX_DATA_SIZE)) &&
3698 ((data != NULL) || (datalen == 0u))) {
3699
3700 /* write type, len fields */
3701 dst_tlv->id = (uint8)type;
3702 dst_tlv->len = (uint8)datalen;
3703
3704 /* if data is present, copy to the output buffer and update
3705 * pointer to output buffer
3706 */
3707 if (datalen > 0u) {
3708
3709 memcpy(dst_tlv->data, data, datalen);
3710 }
3711
3712 /* update the output destination poitner to point past
3713 * the TLV written
3714 */
3715 new_dst = dst + BCM_TLV_HDR_SIZE + datalen;
3716 }
3717
3718 return (new_dst);
3719 }
3720
3721 uint8 *
bcm_write_tlv_ext(uint8 type,uint8 ext,const void * data,uint8 datalen,uint8 * dst)3722 bcm_write_tlv_ext(uint8 type, uint8 ext, const void *data, uint8 datalen, uint8 *dst)
3723 {
3724 uint8 *new_dst = dst;
3725 bcm_tlv_ext_t *dst_tlv = (bcm_tlv_ext_t *)dst;
3726
3727 /* dst buffer should always be valid */
3728 ASSERT(dst);
3729
3730 /* data len must be within valid range */
3731 ASSERT(datalen <= BCM_TLV_EXT_MAX_DATA_SIZE);
3732
3733 /* source data buffer pointer should be valid, unless datalen is 0
3734 * meaning no data with this TLV
3735 */
3736 ASSERT((data != NULL) || (datalen == 0));
3737
3738 /* only do work if the inputs are valid
3739 * - must have a dst to write to AND
3740 * - datalen must be within range AND
3741 * - the source data pointer must be non-NULL if datalen is non-zero
3742 * (this last condition detects datalen > 0 with a NULL data pointer)
3743 */
3744 if ((dst != NULL) &&
3745 (datalen <= BCM_TLV_EXT_MAX_DATA_SIZE) &&
3746 ((data != NULL) || (datalen == 0))) {
3747
3748 /* write type, len fields */
3749 dst_tlv->id = (uint8)type;
3750 dst_tlv->ext = ext;
3751 dst_tlv->len = 1 + (uint8)datalen;
3752
3753 /* if data is present, copy to the output buffer and update
3754 * pointer to output buffer
3755 */
3756 if (datalen > 0) {
3757 memcpy(dst_tlv->data, data, datalen);
3758 }
3759
3760 /* update the output destination poitner to point past
3761 * the TLV written
3762 */
3763 new_dst = dst + BCM_TLV_EXT_HDR_SIZE + datalen;
3764 }
3765
3766 return (new_dst);
3767 }
3768
3769 uint8 *
BCMPOSTTRAPFN(bcm_write_tlv_safe)3770 BCMPOSTTRAPFN(bcm_write_tlv_safe)(int type, const void *data, uint datalen, uint8 *dst,
3771 uint dst_maxlen)
3772 {
3773 uint8 *new_dst = dst;
3774
3775 if ((datalen <= BCM_TLV_MAX_DATA_SIZE)) {
3776
3777 /* if len + tlv hdr len is more than destlen, don't do anything
3778 * just return the buffer untouched
3779 */
3780 if ((datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) {
3781
3782 new_dst = bcm_write_tlv(type, data, datalen, dst);
3783 }
3784 }
3785
3786 return (new_dst);
3787 }
3788
3789 uint8 *
bcm_copy_tlv(const void * src,uint8 * dst)3790 bcm_copy_tlv(const void *src, uint8 *dst)
3791 {
3792 uint8 *new_dst = dst;
3793 const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
3794 uint totlen;
3795
3796 ASSERT(dst && src);
3797 if (dst && src) {
3798
3799 totlen = BCM_TLV_HDR_SIZE + src_tlv->len;
3800 memcpy(dst, src_tlv, totlen);
3801 new_dst = dst + totlen;
3802 }
3803
3804 return (new_dst);
3805 }
3806
3807 uint8 *
bcm_copy_tlv_safe(const void * src,uint8 * dst,uint dst_maxlen)3808 bcm_copy_tlv_safe(const void *src, uint8 *dst, uint dst_maxlen)
3809 {
3810 uint8 *new_dst = dst;
3811 const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
3812
3813 ASSERT(src);
3814 if (bcm_valid_tlv(src_tlv, dst_maxlen)) {
3815 new_dst = bcm_copy_tlv(src, dst);
3816 }
3817
3818 return (new_dst);
3819 }
3820
3821 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
3822 /*******************************************************************************
3823 * crc8
3824 *
3825 * Computes a crc8 over the input data using the polynomial:
3826 *
3827 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
3828 *
3829 * The caller provides the initial value (either CRC8_INIT_VALUE
3830 * or the previous returned value) to allow for processing of
3831 * discontiguous blocks of data. When generating the CRC the
3832 * caller is responsible for complementing the final return value
3833 * and inserting it into the byte stream. When checking, a final
3834 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
3835 *
3836 * Reference: Dallas Semiconductor Application Note 27
3837 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
3838 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
3839 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
3840 *
3841 * ****************************************************************************
3842 */
3843
3844 static const uint8 crc8_table[256] = {
3845 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
3846 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
3847 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
3848 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
3849 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
3850 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
3851 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
3852 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
3853 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
3854 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
3855 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
3856 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
3857 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
3858 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
3859 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
3860 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
3861 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
3862 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
3863 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
3864 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
3865 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
3866 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
3867 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
3868 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
3869 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
3870 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
3871 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
3872 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
3873 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
3874 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
3875 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
3876 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
3877 };
3878
3879 #define CRC_INNER_LOOP(n, c, x) \
3880 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
3881
3882 uint8
hndcrc8(const uint8 * pdata,uint nbytes,uint8 crc)3883 hndcrc8(
3884 const uint8 *pdata, /* pointer to array of data to process */
3885 uint nbytes, /* number of input data bytes to process */
3886 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
3887 )
3888 {
3889 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
3890 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
3891 */
3892 while (nbytes-- > 0)
3893 crc = crc8_table[(crc ^ *pdata++) & 0xff];
3894
3895 return crc;
3896 }
3897
3898 /*******************************************************************************
3899 * crc16
3900 *
3901 * Computes a crc16 over the input data using the polynomial:
3902 *
3903 * x^16 + x^12 +x^5 + 1
3904 *
3905 * The caller provides the initial value (either CRC16_INIT_VALUE
3906 * or the previous returned value) to allow for processing of
3907 * discontiguous blocks of data. When generating the CRC the
3908 * caller is responsible for complementing the final return value
3909 * and inserting it into the byte stream. When checking, a final
3910 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
3911 *
3912 * Reference: Dallas Semiconductor Application Note 27
3913 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
3914 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
3915 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
3916 *
3917 * ****************************************************************************
3918 */
3919
3920 static const uint16 crc16_table[256] = {
3921 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
3922 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
3923 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
3924 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
3925 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
3926 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
3927 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
3928 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
3929 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
3930 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
3931 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
3932 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
3933 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
3934 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
3935 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
3936 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
3937 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
3938 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
3939 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
3940 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
3941 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
3942 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
3943 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
3944 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
3945 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
3946 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
3947 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
3948 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
3949 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
3950 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
3951 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
3952 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
3953 };
3954
3955 uint16
hndcrc16(const uint8 * pdata,uint nbytes,uint16 crc)3956 hndcrc16(
3957 const uint8 *pdata, /* pointer to array of data to process */
3958 uint nbytes, /* number of input data bytes to process */
3959 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
3960 )
3961 {
3962 while (nbytes-- > 0)
3963 CRC_INNER_LOOP(16, crc, *pdata++);
3964 return crc;
3965 }
3966
3967 static const uint32 crc32_table[256] = {
3968 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
3969 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
3970 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
3971 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
3972 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
3973 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
3974 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
3975 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
3976 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
3977 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
3978 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
3979 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
3980 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
3981 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
3982 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
3983 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
3984 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
3985 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
3986 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
3987 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
3988 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
3989 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
3990 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
3991 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
3992 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
3993 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
3994 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
3995 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
3996 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
3997 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
3998 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
3999 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
4000 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
4001 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
4002 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
4003 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
4004 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
4005 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
4006 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
4007 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
4008 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
4009 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
4010 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
4011 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
4012 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
4013 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
4014 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
4015 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
4016 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
4017 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
4018 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
4019 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
4020 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
4021 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
4022 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
4023 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
4024 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
4025 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
4026 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
4027 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
4028 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
4029 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
4030 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
4031 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
4032 };
4033
4034 /*
4035 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
4036 * accumulating over multiple pieces.
4037 */
4038 uint32
hndcrc32(const uint8 * pdata,uint nbytes,uint32 crc)4039 hndcrc32(const uint8 *pdata, uint nbytes, uint32 crc)
4040 {
4041 const uint8 *pend;
4042 pend = pdata + nbytes;
4043 while (pdata < pend)
4044 CRC_INNER_LOOP(32, crc, *pdata++);
4045
4046 return crc;
4047 }
4048
4049 #ifdef NOT_YET
4050 #define CLEN 1499 /* CRC Length */
4051 #define CBUFSIZ (CLEN+4)
4052 #define CNBUFS 5 /* # of bufs */
4053
4054 void
testcrc32(void)4055 testcrc32(void)
4056 {
4057 uint j, k, l;
4058 uint8 *buf;
4059 uint len[CNBUFS];
4060 uint32 crcr;
4061 uint32 crc32tv[CNBUFS] =
4062 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
4063
4064 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
4065
4066 /* step through all possible alignments */
4067 for (l = 0; l <= 4; l++) {
4068 for (j = 0; j < CNBUFS; j++) {
4069 len[j] = CLEN;
4070 for (k = 0; k < len[j]; k++)
4071 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
4072 }
4073
4074 for (j = 0; j < CNBUFS; j++) {
4075 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
4076 ASSERT(crcr == crc32tv[j]);
4077 }
4078 }
4079
4080 MFREE(buf, CBUFSIZ*CNBUFS);
4081 return;
4082 }
4083 #endif /* NOT_YET */
4084
4085 /*
4086 * Advance from the current 1-byte tag/1-byte length/variable-length value
4087 * triple, to the next, returning a pointer to the next.
4088 * If the current or next TLV is invalid (does not fit in given buffer length),
4089 * NULL is returned.
4090 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
4091 * by the TLV parameter's length if it is valid.
4092 */
4093 bcm_tlv_t *
bcm_next_tlv(const bcm_tlv_t * elt,uint * buflen)4094 bcm_next_tlv(const bcm_tlv_t *elt, uint *buflen)
4095 {
4096 uint len;
4097
4098 COV_TAINTED_DATA_SINK(buflen);
4099 COV_NEG_SINK(buflen);
4100
4101 /* validate current elt */
4102 if (!bcm_valid_tlv(elt, *buflen)) {
4103 return NULL;
4104 }
4105
4106 /* advance to next elt */
4107 len = TLV_HDR_LEN + elt->len;
4108 elt = (const bcm_tlv_t*)((const uint8 *)elt + len);
4109
4110 #if defined(__COVERITY__)
4111 /* The 'len' value is tainted in Coverity because it is read from the tainted data pointed
4112 * to by 'elt'. However, bcm_valid_tlv() verifies that the elt pointer is a valid element,
4113 * so its length, len = (TLV_HDR_LEN + elt->len), is in the bounds of the buffer.
4114 * Clearing the tainted attribute of 'len' for Coverity.
4115 */
4116 __coverity_tainted_data_sanitize__(len);
4117 if (len > *buflen) {
4118 return NULL;
4119 }
4120 #endif /* __COVERITY__ */
4121
4122 *buflen -= len;
4123
4124 /* validate next elt */
4125 if (!bcm_valid_tlv(elt, *buflen)) {
4126 return NULL;
4127 }
4128
4129 COV_TAINTED_DATA_ARG(elt);
4130
4131 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4132 return (bcm_tlv_t *)(elt);
4133 GCC_DIAGNOSTIC_POP();
4134 }
4135
4136 /**
4137 * Advance a const tlv buffer pointer and length up to the given tlv element pointer
4138 * 'elt'. The function checks that elt is a valid tlv; the elt pointer and data
4139 * are all in the range of the buffer/length.
4140 *
4141 * @param elt pointer to a valid bcm_tlv_t in the buffer
4142 * @param buffer pointer to a tlv buffer
4143 * @param buflen length of the buffer in bytes
4144 *
4145 * On return, if elt is not a tlv in the buffer bounds, the *buffer parameter
4146 * will be set to NULL and *buflen parameter will be set to zero. Otherwise,
4147 * *buffer will point to elt, and *buflen will have been adjusted by the the
4148 * difference between *buffer and elt.
4149 */
4150 void
bcm_tlv_buffer_advance_to(const bcm_tlv_t * elt,const uint8 ** buffer,uint * buflen)4151 bcm_tlv_buffer_advance_to(const bcm_tlv_t *elt, const uint8 **buffer, uint *buflen)
4152 {
4153 uint new_buflen;
4154 const uint8 *new_buffer;
4155
4156 /* model the input length value as a tainted and negative sink so
4157 * Coverity will complain about unvalidated or possibly length values
4158 */
4159 COV_TAINTED_DATA_SINK(*buflen);
4160 COV_NEG_SINK(*buflen);
4161
4162 new_buffer = (const uint8*)elt;
4163
4164 /* make sure the input buffer pointer is non-null, that (buffer + buflen) does not wrap,
4165 * and that the elt pointer is in the range of [buffer, buffer + buflen]
4166 */
4167 if ((*buffer != NULL) &&
4168 ((uintptr)*buffer < ((uintptr)*buffer + *buflen)) &&
4169 (new_buffer >= *buffer) &&
4170 (new_buffer < (*buffer + *buflen))) {
4171 /* delta between buffer and new_buffer is <= *buflen, so truncating cast to uint
4172 * from ptrdiff is ok
4173 */
4174 uint delta = (uint)(new_buffer - *buffer);
4175
4176 /* New buffer length is old len minus the delta from the buffer start to elt.
4177 * The check just above guarantees that the subtractions does not underflow.
4178 */
4179 new_buflen = *buflen - delta;
4180
4181 /* validate current elt */
4182 if (bcm_valid_tlv(elt, new_buflen)) {
4183 /* All good, so update the input/output parameters */
4184 *buffer = new_buffer;
4185 *buflen = new_buflen;
4186 return;
4187 }
4188 }
4189
4190 /* something did not check out, clear out the buffer info */
4191 *buffer = NULL;
4192 *buflen = 0;
4193
4194 return;
4195 }
4196
4197 /**
4198 * Advance a const tlv buffer pointer and length past the given tlv element pointer
4199 * 'elt'. The function checks that elt is a valid tlv; the elt pointer and data
4200 * are all in the range of the buffer/length. The function also checks that the
4201 * remaining buffer starts with a valid tlv.
4202 *
4203 * @param elt pointer to a valid bcm_tlv_t in the buffer
4204 * @param buffer pointer to a tlv buffer
4205 * @param buflen length of the buffer in bytes
4206 *
4207 * On return, if elt is not a tlv in the buffer bounds, or the remaining buffer
4208 * following the elt does not begin with a tlv in the buffer bounds, the *buffer
4209 * parameter will be set to NULL and *buflen parameter will be set to zero.
4210 * Otherwise, *buffer will point to the first byte past elt, and *buflen will
4211 * have the remaining buffer length.
4212 */
4213 void
bcm_tlv_buffer_advance_past(const bcm_tlv_t * elt,const uint8 ** buffer,uint * buflen)4214 bcm_tlv_buffer_advance_past(const bcm_tlv_t *elt, const uint8 **buffer, uint *buflen)
4215 {
4216 /* Start by advancing the buffer up to the given elt */
4217 bcm_tlv_buffer_advance_to(elt, buffer, buflen);
4218
4219 /* if that did not work, bail out */
4220 if (*buflen == 0) {
4221 return;
4222 }
4223
4224 #if defined(__COVERITY__)
4225 /* The elt has been verified by bcm_tlv_buffer_advance_to() to be a valid element,
4226 * so its elt->len is in the bounds of the buffer. The following check prevents
4227 * Coverity from flagging the (elt->data + elt->len) statement below as using a
4228 * tainted elt->len to index into array 'elt->data'.
4229 */
4230 if (elt->len > *buflen) {
4231 return;
4232 }
4233 #endif /* __COVERITY__ */
4234
4235 /* We know we are advanced up to a good tlv.
4236 * Now just advance to the following tlv.
4237 */
4238 elt = (const bcm_tlv_t*)(elt->data + elt->len);
4239
4240 bcm_tlv_buffer_advance_to(elt, buffer, buflen);
4241
4242 return;
4243 }
4244
4245 /*
4246 * Traverse a string of 1-byte tag/1-byte length/variable-length value
4247 * triples, returning a pointer to the substring whose first element
4248 * matches tag
4249 */
4250 bcm_tlv_t *
bcm_parse_tlvs(const void * buf,uint buflen,uint key)4251 bcm_parse_tlvs(const void *buf, uint buflen, uint key)
4252 {
4253 const bcm_tlv_t *elt;
4254 uint totlen;
4255
4256 COV_TAINTED_DATA_SINK(buflen);
4257 COV_NEG_SINK(buflen);
4258
4259 if ((elt = (const bcm_tlv_t*)buf) == NULL) {
4260 return NULL;
4261 }
4262 totlen = buflen;
4263
4264 /* find tagged parameter */
4265 while (totlen >= TLV_HDR_LEN) {
4266 uint len = elt->len;
4267
4268 /* check if elt overruns buffer */
4269 if (totlen < (len + TLV_HDR_LEN)) {
4270 break;
4271 }
4272 /* did we find the ID? */
4273 if ((elt->id == key)) {
4274 COV_TAINTED_DATA_ARG(elt);
4275
4276 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4277 return (bcm_tlv_t *)(elt);
4278 GCC_DIAGNOSTIC_POP();
4279 }
4280 elt = (const bcm_tlv_t*)((const uint8*)elt + (len + TLV_HDR_LEN));
4281 totlen -= (len + TLV_HDR_LEN);
4282 }
4283
4284 return NULL;
4285 }
4286
4287 /*
4288 * Traverse a string of 1-byte tag/1-byte length/variable-length value
4289 * triples, returning a pointer to the substring whose first element
4290 * matches tag.
4291 * The 'advance' parmeter specifies what to do to the parse buf/buflen values if a
4292 * matching tlv is found:
4293 * BCM_TLV_ADVANCE_NONE - do nothing
4294 * BCM_TLV_ADVANCE_TO - move the buf up to the discovered tlv, and adjust buflen.
4295 * BCM_TLV_ADVANCE_PAST - move the buf past the discovered tlb, and adjust buflen.
4296 * If a tlv is not found, no changes are made to buf/buflen
4297 *
4298 */
4299 const bcm_tlv_t *
bcm_parse_tlvs_advance(const uint8 ** buf,uint * buflen,uint key,bcm_tlv_advance_mode_t advance)4300 bcm_parse_tlvs_advance(const uint8 **buf, uint *buflen, uint key, bcm_tlv_advance_mode_t advance)
4301 {
4302 const bcm_tlv_t *elt;
4303
4304 elt = bcm_parse_tlvs(*buf, *buflen, key);
4305
4306 if (elt == NULL) {
4307 return elt;
4308 }
4309
4310 if (advance == BCM_TLV_ADVANCE_TO) {
4311 bcm_tlv_buffer_advance_to(elt, buf, buflen);
4312 } else if (advance == BCM_TLV_ADVANCE_PAST) {
4313 bcm_tlv_buffer_advance_past(elt, buf, buflen);
4314 } else if (advance == BCM_TLV_ADVANCE_NONE) {
4315 /* nothing to do */
4316 } else {
4317 /* there are only 3 modes, but just in case, zero the parse buffer pointer and
4318 * length to prevent infinite loops in callers that expect progress.
4319 */
4320 ASSERT(0);
4321 *buf = NULL;
4322 *buflen = 0;
4323 }
4324
4325 return elt;
4326 }
4327
4328 bcm_tlv_t *
bcm_parse_tlvs_dot11(const void * buf,uint buflen,uint key,bool id_ext)4329 bcm_parse_tlvs_dot11(const void *buf, uint buflen, uint key, bool id_ext)
4330 {
4331 bcm_tlv_t *elt;
4332 uint totlen;
4333
4334 COV_TAINTED_DATA_SINK(buflen);
4335 COV_NEG_SINK(buflen);
4336
4337 /*
4338 ideally, we don't want to do that, but returning a const pointer
4339 from these parse function spreads casting everywhere in the code
4340 */
4341 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4342 elt = (bcm_tlv_t*)buf;
4343 GCC_DIAGNOSTIC_POP();
4344
4345 totlen = buflen;
4346
4347 /* find tagged parameter */
4348 while (totlen >= TLV_HDR_LEN) {
4349 uint len = elt->len;
4350
4351 /* validate remaining totlen */
4352 if (totlen < (len + TLV_HDR_LEN)) {
4353 break;
4354 }
4355
4356 do {
4357 if (id_ext) {
4358 if (!DOT11_MNG_IE_ID_EXT_MATCH(elt, key))
4359 break;
4360 } else if (elt->id != key) {
4361 break;
4362 }
4363
4364 COV_TAINTED_DATA_ARG(elt);
4365
4366 return (bcm_tlv_t *)(elt); /* a match */
4367 } while (0);
4368
4369 elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
4370 totlen -= (len + TLV_HDR_LEN);
4371 }
4372
4373 return NULL;
4374 }
4375
4376 /*
4377 * Traverse a string of 1-byte tag/1-byte length/variable-length value
4378 * triples, returning a pointer to the substring whose first element
4379 * matches tag
4380 * return NULL if not found or length field < min_varlen
4381 */
4382 bcm_tlv_t *
bcm_parse_tlvs_min_bodylen(const void * buf,uint buflen,uint key,uint min_bodylen)4383 bcm_parse_tlvs_min_bodylen(const void *buf, uint buflen, uint key, uint min_bodylen)
4384 {
4385 bcm_tlv_t * ret;
4386 ret = bcm_parse_tlvs(buf, buflen, key);
4387 if (ret == NULL || ret->len < min_bodylen) {
4388 return NULL;
4389 }
4390 return ret;
4391 }
4392
4393 /*
4394 * Traverse a string of 1-byte tag/1-byte length/variable-length value
4395 * triples, returning a pointer to the substring whose first element
4396 * matches tag
4397 * return NULL if not found or tlv size > max_len or < min_len
4398 */
4399 bcm_tlv_t *
bcm_parse_tlvs_minmax_len(const void * buf,uint buflen,uint key,uint min_len,uint max_len)4400 bcm_parse_tlvs_minmax_len(const void *buf, uint buflen, uint key,
4401 uint min_len, uint max_len)
4402 {
4403 bcm_tlv_t * ret;
4404 ret = bcm_parse_tlvs(buf, buflen, key);
4405 if (ret == NULL ||
4406 (BCM_TLV_SIZE(ret) > max_len) ||
4407 (BCM_TLV_SIZE(ret) < min_len)) {
4408 return NULL;
4409 }
4410 return ret;
4411 }
4412
4413 /*
4414 * Traverse a string of 1-byte tag/1-byte length/variable-length value
4415 * triples, returning a pointer to the substring whose first element
4416 * matches tag. Stop parsing when we see an element whose ID is greater
4417 * than the target key.
4418 */
4419 const bcm_tlv_t *
bcm_parse_ordered_tlvs(const void * buf,uint buflen,uint key)4420 bcm_parse_ordered_tlvs(const void *buf, uint buflen, uint key)
4421 {
4422 const bcm_tlv_t *elt;
4423 uint totlen;
4424
4425 COV_TAINTED_DATA_SINK(buflen);
4426 COV_NEG_SINK(buflen);
4427
4428 elt = (const bcm_tlv_t*)buf;
4429 totlen = buflen;
4430
4431 /* find tagged parameter */
4432 while (totlen >= TLV_HDR_LEN) {
4433 uint id = elt->id;
4434 uint len = elt->len;
4435
4436 /* Punt if we start seeing IDs > than target key */
4437 if (id > key) {
4438 return (NULL);
4439 }
4440
4441 /* validate remaining totlen */
4442 if (totlen < (len + TLV_HDR_LEN)) {
4443 break;
4444 }
4445 if (id == key) {
4446 COV_TAINTED_DATA_ARG(elt);
4447 return (elt);
4448 }
4449
4450 elt = (const bcm_tlv_t*)((const uint8*)elt + (len + TLV_HDR_LEN));
4451 totlen -= (len + TLV_HDR_LEN);
4452 }
4453 return NULL;
4454 }
4455 #endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
4456
4457 uint
bcm_format_field(const bcm_bit_desc_ex_t * bd,uint32 flags,char * buf,uint len)4458 bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, uint len)
4459 {
4460 uint i, slen = 0;
4461 uint32 bit, mask;
4462 const char *name;
4463 mask = bd->mask;
4464 if (len < 2 || !buf)
4465 return 0;
4466
4467 buf[0] = '\0';
4468
4469 for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) {
4470 bit = bd->bitfield[i].bit;
4471 if ((flags & mask) == bit) {
4472 slen = (int)strlen(name);
4473 if (memcpy_s(buf, len, name, slen + 1) != BCME_OK) {
4474 slen = 0;
4475 }
4476 break;
4477 }
4478 }
4479 return slen;
4480 }
4481
4482 int
bcm_format_flags(const bcm_bit_desc_t * bd,uint32 flags,char * buf,uint len)4483 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, uint len)
4484 {
4485 uint i;
4486 char *p = buf;
4487 char *end = (buf + len);
4488 char hexstr[16];
4489 uint32 bit;
4490 const char* name;
4491 bool err = FALSE;
4492
4493 if (len < 2 || !buf)
4494 return 0;
4495
4496 buf[0] = '\0';
4497
4498 for (i = 0; flags != 0; i++) {
4499 bit = bd[i].bit;
4500 name = bd[i].name;
4501 if (bit == 0 && flags != 0) {
4502 /* print any unnamed bits */
4503 snprintf(hexstr, sizeof(hexstr), "0x%X", flags);
4504 name = hexstr;
4505 flags = 0; /* exit loop */
4506 } else if ((flags & bit) == 0) {
4507 continue;
4508 }
4509 flags &= ~bit;
4510
4511 /* Print named bit. */
4512 p += strlcpy(p, name, (end - p));
4513 if (p == end) {
4514 /* Truncation error. */
4515 err = TRUE;
4516 break;
4517 }
4518
4519 /* Add space delimiter if there are more bits. */
4520 if (flags != 0) {
4521 p += strlcpy(p, " ", (end - p));
4522 if (p == end) {
4523 /* Truncation error. */
4524 err = TRUE;
4525 break;
4526 }
4527 }
4528 }
4529
4530 /* indicate the str was too short */
4531 if (err) {
4532 ASSERT(len >= 2u);
4533 buf[len - 2u] = '>';
4534 }
4535
4536 return (int)(p - buf);
4537 }
4538
4539 /* print out whcih bits in octet array 'addr' are set. bcm_bit_desc_t:bit is a bit offset. */
4540 int
bcm_format_octets(const bcm_bit_desc_t * bd,uint bdsz,const uint8 * addr,uint size,char * buf,uint len)4541 bcm_format_octets(const bcm_bit_desc_t *bd, uint bdsz,
4542 const uint8 *addr, uint size, char *buf, uint len)
4543 {
4544 uint i;
4545 char *p = buf;
4546 uint slen = 0, nlen = 0;
4547 uint32 bit;
4548 const char* name;
4549 bool more = FALSE;
4550
4551 BCM_REFERENCE(size);
4552
4553 if (len < 2 || !buf)
4554 return 0;
4555
4556 buf[0] = '\0';
4557
4558 for (i = 0; i < bdsz; i++) {
4559 bit = bd[i].bit;
4560 name = bd[i].name;
4561 if (isset(addr, bit)) {
4562 nlen = (int)strlen(name);
4563 slen += nlen;
4564 /* need SPACE - for simplicity */
4565 slen += 1;
4566 /* need NULL as well */
4567 if (len < slen + 1) {
4568 more = TRUE;
4569 break;
4570 }
4571 memcpy(p, name, nlen);
4572 p += nlen;
4573 p[0] = ' ';
4574 p += 1;
4575 p[0] = '\0';
4576 }
4577 }
4578
4579 if (more) {
4580 p[0] = '>';
4581 p += 1;
4582 p[0] = '\0';
4583 }
4584
4585 return (int)(p - buf);
4586 }
4587
4588 /* Transform an hexadecimal string into binary.
4589 * Output is limited to 64K.
4590 * hex : string
4591 * hex_len : string length
4592 * buf : allocated output buffer
4593 * buf_len : allocated size
4594 * return : copied length, if successfull, 0 if error.
4595 */
4596 uint16
bcmhex2bin(const uint8 * hex,uint hex_len,uint8 * buf,uint buf_len)4597 bcmhex2bin(const uint8* hex, uint hex_len, uint8 *buf, uint buf_len)
4598 {
4599 uint i = 0;
4600 uint16 out_len;
4601 char tmp[] = "XX";
4602 if (hex_len % 2) {
4603 /* hex_len not even */
4604 return 0;
4605 }
4606 /* check for hex radix */
4607 if ((hex[0] == '0') && ((hex[1] == 'x') || (hex[1] == 'X'))) {
4608 hex += 2;
4609 hex_len -= 2;
4610 }
4611 if (hex_len/2 > 0xFFFF) {
4612 /* exceed 64K buffer capacity */
4613 return 0;
4614 }
4615 if ((out_len = hex_len/2) > buf_len) {
4616 /* buf too short */
4617 return 0;
4618 }
4619 do {
4620 tmp[0] = *hex++;
4621 tmp[1] = *hex++;
4622 if (!bcm_isxdigit(tmp[0]) || !bcm_isxdigit(tmp[1])) {
4623 /* char is not a 256-bit hex number */
4624 return 0;
4625 }
4626 /* okay so far; make this piece a number */
4627 buf[i] = (uint8) bcm_strtoul(tmp, NULL, 16);
4628 } while (++i < out_len);
4629 return out_len;
4630 }
4631
4632 /* print bytes formatted as hex to a string. return the resulting string length */
4633 int
bcm_format_hex(char * str,const void * bytes,uint len)4634 bcm_format_hex(char *str, const void *bytes, uint len)
4635 {
4636 uint i;
4637 char *p = str;
4638 const uint8 *src = (const uint8*)bytes;
4639
4640 for (i = 0; i < len; i++) {
4641 p += snprintf(p, 3, "%02X", *src);
4642 src++;
4643 }
4644 return (int)(p - str);
4645 }
4646
4647 /* pretty hex print a contiguous buffer */
4648 void
prhex(const char * msg,const uchar * buf,uint nbytes)4649 prhex(const char *msg, const uchar *buf, uint nbytes)
4650 {
4651 char line[128], *p;
4652 uint len = sizeof(line);
4653 int nchar;
4654 uint i;
4655
4656 if (msg && (msg[0] != '\0'))
4657 printf("%s:\n", msg);
4658
4659 p = line;
4660 for (i = 0; i < nbytes; i++) {
4661 if (i % 16 == 0) {
4662 nchar = snprintf(p, len, " %04x: ", i); /* line prefix */
4663 p += nchar;
4664 len -= nchar;
4665 }
4666 if (len > 0) {
4667 nchar = snprintf(p, len, "%02x ", buf[i]);
4668 p += nchar;
4669 len -= nchar;
4670 }
4671
4672 if (i % 16 == 15) {
4673 printf("%s\n", line); /* flush line */
4674 p = line;
4675 len = sizeof(line);
4676 }
4677 }
4678
4679 /* flush last partial line */
4680 if (p != line)
4681 printf("%s\n", line);
4682 }
4683
4684 static const char *crypto_algo_names[] = {
4685 "NONE",
4686 "WEP1",
4687 "TKIP",
4688 "WEP128",
4689 "AES_CCM",
4690 "AES_OCB_MSDU",
4691 "AES_OCB_MPDU",
4692 "NALG",
4693 "UNDEF",
4694 "UNDEF",
4695 "UNDEF",
4696
4697 #ifdef BCMWAPI_WAI
4698 "WAPI",
4699 #endif /* BCMWAPI_WAI */
4700
4701 #ifndef BCMWAPI_WAI
4702 "UNDEF",
4703 #endif
4704 "PMK",
4705 "BIP",
4706 "AES_GCM",
4707 "AES_CCM256",
4708 "AES_GCM256",
4709 "BIP_CMAC256",
4710 "BIP_GMAC",
4711 "BIP_GMAC256",
4712 "UNDEF"
4713 };
4714
4715 const char *
bcm_crypto_algo_name(uint algo)4716 bcm_crypto_algo_name(uint algo)
4717 {
4718 return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
4719 }
4720
4721 #ifdef BCMDBG
4722 void
deadbeef(void * p,uint len)4723 deadbeef(void *p, uint len)
4724 {
4725 static uint8 meat[] = { 0xde, 0xad, 0xbe, 0xef };
4726
4727 while (len-- > 0) {
4728 *(uint8*)p = meat[((uintptr)p) & 3];
4729 p = (uint8*)p + 1;
4730 }
4731 }
4732 #endif /* BCMDBG */
4733
4734 char *
bcm_chipname(uint chipid,char * buf,uint len)4735 bcm_chipname(uint chipid, char *buf, uint len)
4736 {
4737 const char *fmt;
4738
4739 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
4740 snprintf(buf, len, fmt, chipid);
4741 return buf;
4742 }
4743
4744 /* Produce a human-readable string for boardrev */
4745 char *
bcm_brev_str(uint32 brev,char * buf)4746 bcm_brev_str(uint32 brev, char *buf)
4747 {
4748 if (brev < 0x100)
4749 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
4750 else
4751 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
4752
4753 return (buf);
4754 }
4755
4756 #define BUFSIZE_TODUMP_ATONCE 128 /* Buffer size */
4757
4758 /* dump large strings to console */
4759 void
printbig(char * buf)4760 printbig(char *buf)
4761 {
4762 uint len, max_len;
4763 char c;
4764
4765 len = (uint)strlen(buf);
4766
4767 max_len = BUFSIZE_TODUMP_ATONCE;
4768
4769 while (len > max_len) {
4770 c = buf[max_len];
4771 buf[max_len] = '\0';
4772 printf("%s", buf);
4773 buf[max_len] = c;
4774
4775 buf += max_len;
4776 len -= max_len;
4777 }
4778 /* print the remaining string */
4779 printf("%s\n", buf);
4780 return;
4781 }
4782
4783 /* routine to dump fields in a fileddesc structure */
4784 uint
bcmdumpfields(bcmutl_rdreg_rtn read_rtn,void * arg0,uint arg1,struct fielddesc * fielddesc_array,char * buf,uint32 bufsize)4785 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
4786 char *buf, uint32 bufsize)
4787 {
4788 uint filled_len;
4789 int len;
4790 struct fielddesc *cur_ptr;
4791
4792 filled_len = 0;
4793 cur_ptr = fielddesc_array;
4794
4795 while (bufsize > 1) {
4796 if (cur_ptr->nameandfmt == NULL)
4797 break;
4798 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
4799 read_rtn(arg0, arg1, cur_ptr->offset));
4800 /* check for snprintf overflow or error */
4801 if (len < 0 || (uint32)len >= bufsize)
4802 len = bufsize - 1;
4803 buf += len;
4804 bufsize -= len;
4805 filled_len += len;
4806 cur_ptr++;
4807 }
4808 return filled_len;
4809 }
4810
4811 uint
bcm_mkiovar(const char * name,const char * data,uint datalen,char * buf,uint buflen)4812 bcm_mkiovar(const char *name, const char *data, uint datalen, char *buf, uint buflen)
4813 {
4814 uint len;
4815
4816 len = (uint)strlen(name) + 1;
4817
4818 if ((len + datalen) > buflen)
4819 return 0;
4820
4821 strlcpy(buf, name, buflen);
4822
4823 /* append data onto the end of the name string */
4824 if (data && datalen != 0) {
4825 memcpy(&buf[len], data, datalen);
4826 len += datalen;
4827 }
4828
4829 return len;
4830 }
4831
4832 /* Quarter dBm units to mW
4833 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
4834 * Table is offset so the last entry is largest mW value that fits in
4835 * a uint16.
4836 */
4837
4838 #define QDBM_OFFSET 153 /* Offset for first entry */
4839 #define QDBM_TABLE_LEN 40 /* Table size */
4840
4841 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
4842 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
4843 */
4844 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
4845
4846 /* Largest mW value that will round down to the last table entry,
4847 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
4848 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
4849 */
4850 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
4851
4852 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
4853 /* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
4854 /* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
4855 /* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
4856 /* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
4857 /* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
4858 /* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
4859 };
4860
4861 uint16
bcm_qdbm_to_mw(uint8 qdbm)4862 bcm_qdbm_to_mw(uint8 qdbm)
4863 {
4864 uint factor = 1;
4865 int idx = qdbm - QDBM_OFFSET;
4866
4867 if (idx >= QDBM_TABLE_LEN) {
4868 /* clamp to max uint16 mW value */
4869 return 0xFFFF;
4870 }
4871
4872 /* scale the qdBm index up to the range of the table 0-40
4873 * where an offset of 40 qdBm equals a factor of 10 mW.
4874 */
4875 while (idx < 0) {
4876 idx += 40;
4877 factor *= 10;
4878 }
4879
4880 /* return the mW value scaled down to the correct factor of 10,
4881 * adding in factor/2 to get proper rounding.
4882 */
4883 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
4884 }
4885
4886 uint8
bcm_mw_to_qdbm(uint16 mw)4887 bcm_mw_to_qdbm(uint16 mw)
4888 {
4889 uint8 qdbm;
4890 int offset;
4891 uint mw_uint = mw;
4892 uint boundary;
4893
4894 /* handle boundary case */
4895 if (mw_uint <= 1)
4896 return 0;
4897
4898 offset = QDBM_OFFSET;
4899
4900 /* move mw into the range of the table */
4901 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
4902 mw_uint *= 10;
4903 offset -= 40;
4904 }
4905
4906 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
4907 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
4908 nqdBm_to_mW_map[qdbm])/2;
4909 if (mw_uint < boundary) break;
4910 }
4911
4912 qdbm += (uint8)offset;
4913
4914 return (qdbm);
4915 }
4916
4917 uint
BCMPOSTTRAPFN(bcm_bitcount)4918 BCMPOSTTRAPFN(bcm_bitcount)(const uint8 *bitmap, uint length)
4919 {
4920 uint bitcount = 0, i;
4921 uint8 tmp;
4922 for (i = 0; i < length; i++) {
4923 tmp = bitmap[i];
4924 while (tmp) {
4925 bitcount++;
4926 tmp &= (tmp - 1);
4927 }
4928 }
4929 return bitcount;
4930 }
4931
4932 /*
4933 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
4934 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
4935 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
4936 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
4937 */
4938
4939 unsigned int
process_nvram_vars(char * varbuf,unsigned int len)4940 process_nvram_vars(char *varbuf, unsigned int len)
4941 {
4942 char *dp;
4943 bool findNewline;
4944 int column;
4945 unsigned int buf_len, n;
4946 unsigned int pad = 0;
4947 char nv_ver[128];
4948
4949 dp = varbuf;
4950
4951 findNewline = FALSE;
4952 column = 0;
4953
4954 // terence 20130914: print out NVRAM version
4955 if (varbuf[0] == '#') {
4956 memset(nv_ver, 0x00, sizeof(nv_ver));
4957 for (n=1; n<len && n<(sizeof(nv_ver)-1); n++) {
4958 if (varbuf[n] == '\n')
4959 break;
4960 nv_ver[n-1] = varbuf[n];
4961 }
4962 printf("NVRAM version: %s\n", nv_ver);
4963 }
4964
4965 for (n = 0; n < len; n++) {
4966 if (varbuf[n] == '\r')
4967 continue;
4968 if (findNewline && varbuf[n] != '\n')
4969 continue;
4970 findNewline = FALSE;
4971 if (varbuf[n] == '#') {
4972 findNewline = TRUE;
4973 continue;
4974 }
4975 if (varbuf[n] == '\n') {
4976 if (column == 0)
4977 continue;
4978 *dp++ = 0;
4979 column = 0;
4980 continue;
4981 }
4982 *dp++ = varbuf[n];
4983 column++;
4984 }
4985 buf_len = (unsigned int)(dp - varbuf);
4986 if (buf_len % 4) {
4987 pad = 4 - buf_len % 4;
4988 if (pad && (buf_len + pad <= len)) {
4989 buf_len += pad;
4990 }
4991 }
4992
4993 while (dp < varbuf + n)
4994 *dp++ = 0;
4995
4996 return buf_len;
4997 }
4998
4999 #ifndef setbit /* As in the header file */
5000 #ifdef BCMUTILS_BIT_MACROS_USE_FUNCS
5001 /* Set bit in byte array. */
5002 void
setbit(void * array,uint bit)5003 setbit(void *array, uint bit)
5004 {
5005 ((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY);
5006 }
5007
5008 /* Clear bit in byte array. */
5009 void
clrbit(void * array,uint bit)5010 clrbit(void *array, uint bit)
5011 {
5012 ((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY));
5013 }
5014
5015 /* Test if bit is set in byte array. */
5016 bool
isset(const void * array,uint bit)5017 isset(const void *array, uint bit)
5018 {
5019 return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY)));
5020 }
5021
5022 /* Test if bit is clear in byte array. */
5023 bool
isclr(const void * array,uint bit)5024 isclr(const void *array, uint bit)
5025 {
5026 return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0);
5027 }
5028 #endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */
5029 #endif /* setbit */
5030
5031 void
BCMPOSTTRAPFN(set_bitrange)5032 BCMPOSTTRAPFN(set_bitrange)(void *array, uint start, uint end, uint maxbit)
5033 {
5034 uint startbyte = start/NBBY;
5035 uint endbyte = end/NBBY;
5036 uint i, startbytelastbit, endbytestartbit;
5037
5038 if (end >= start) {
5039 if (endbyte - startbyte > 1) {
5040 startbytelastbit = ((startbyte + 1) * NBBY) - 1;
5041 endbytestartbit = endbyte * NBBY;
5042 for (i = startbyte + 1; i < endbyte; i++)
5043 ((uint8 *)array)[i] = 0xFF;
5044 for (i = start; i <= startbytelastbit; i++)
5045 setbit(array, i);
5046 for (i = endbytestartbit; i <= end; i++)
5047 setbit(array, i);
5048 } else {
5049 for (i = start; i <= end; i++)
5050 setbit(array, i);
5051 }
5052 } else {
5053 set_bitrange(array, start, maxbit, maxbit);
5054 set_bitrange(array, 0, end, maxbit);
5055 }
5056 }
5057
5058 void
clr_bitrange(void * array,uint start,uint end,uint maxbit)5059 clr_bitrange(void *array, uint start, uint end, uint maxbit)
5060 {
5061 uint startbyte = start/NBBY;
5062 uint endbyte = end/NBBY;
5063 uint i, startbytelastbit, endbytestartbit;
5064
5065 if (end >= start) {
5066 if (endbyte - startbyte > 1) {
5067 startbytelastbit = ((startbyte + 1) * NBBY) - 1;
5068 endbytestartbit = endbyte * NBBY;
5069 for (i = startbyte + 1; i < endbyte; i++)
5070 ((uint8 *)array)[i] = 0x0;
5071 for (i = start; i <= startbytelastbit; i++)
5072 clrbit(array, i);
5073 for (i = endbytestartbit; i <= end; i++)
5074 clrbit(array, i);
5075 } else {
5076 for (i = start; i <= end; i++)
5077 clrbit(array, i);
5078 }
5079 } else {
5080 clr_bitrange(array, start, maxbit, maxbit);
5081 clr_bitrange(array, 0, end, maxbit);
5082 }
5083 }
5084
5085 /*
5086 * This api (set_bitrange_int_access) as same as set_bitrange but uses int32 operation
5087 * This api can be used in the place of set_bitrange but array should be word (32bit) alligned.
5088 * This api has to be used when the memory being accessed has restrictions of
5089 * not using them in 8bit (byte) mode and needing 32bit (word) mode.
5090 */
5091 void
set_bitrange_u32(void * array,uint start,uint end,uint maxbit)5092 set_bitrange_u32(void *array, uint start, uint end, uint maxbit)
5093 {
5094 uint startword = start/SIZE_BITS32(uint32);
5095 uint endword = end/SIZE_BITS32(uint32);
5096 uint startwordstartbit = start % SIZE_BITS32(uint32);
5097 uint endwordlastbit = end % SIZE_BITS32(uint32);
5098 /* Used to caluculate bit number from MSB */
5099 uint u32msbnum = SIZE_BITS32(uint32) - 1U;
5100 uint i;
5101 uint32 setbitsword;
5102 uint32 u32max = ~0U;
5103
5104 ASSERT(ISALIGNED(array, sizeof(uint32))); /* array should be alligned for this API */
5105
5106 if (start > end) {
5107 set_bitrange_u32(array, start, maxbit, maxbit);
5108 set_bitrange_u32(array, 0U, end, maxbit);
5109 return;
5110 }
5111
5112 if (endword - startword) {
5113 /* Setting MSB bits including startwordstartbit */
5114 setbitsword = u32max << startwordstartbit;
5115 ((uint32 *)array)[startword] |= setbitsword;
5116
5117 /* Setting all bits in 'startword + 1' to 'endword - 1' */
5118 for (i = startword + 1U; i <= endword - 1U; i++) {
5119 ((uint32 *)array)[i] = u32max;
5120 }
5121
5122 /* Setting LSB bits including endwordlastbit */
5123 setbitsword = u32max >> (u32msbnum - endwordlastbit);
5124 ((uint32 *)array)[endword] |= setbitsword;
5125 } else { /* start and end are in same word */
5126 /* Setting start bit to end bit including start and end bits */
5127 setbitsword =
5128 (u32max << startwordstartbit) & (u32max >> (u32msbnum - endwordlastbit));
5129 ((uint32 *)array)[startword] |= setbitsword;
5130 }
5131 }
5132
5133 /*
5134 * This api (clr_bitrange_u32) as same as clr_bitrange but uses int32 operation
5135 * This api can be used in the place of clr_bitrange but array should be word (32bit) alligned.
5136 * This api has to be used when the memory being accessed has restrictions of
5137 * not using them in 8bit (byte) mode and needing 32bit (word) mode.
5138 */
5139 void
clr_bitrange_u32(void * array,uint start,uint end,uint maxbit)5140 clr_bitrange_u32(void *array, uint start, uint end, uint maxbit)
5141 {
5142 uint startword = start/SIZE_BITS32(uint32);
5143 uint endword = end/SIZE_BITS32(uint32);
5144 uint startwordstartbit = start % SIZE_BITS32(uint32);
5145 uint endwordlastbit = end % SIZE_BITS32(uint32);
5146 /* Used to caluculate bit number from MSB */
5147 uint u32msbnum = SIZE_BITS32(uint32) - 1U;
5148 uint i;
5149 uint32 clrbitsword;
5150 uint32 u32max = ~0U;
5151
5152 ASSERT(ISALIGNED(array, sizeof(uint32))); /* array should be alligned for this API */
5153
5154 if (start > end) {
5155 clr_bitrange_u32(array, start, maxbit, maxbit);
5156 clr_bitrange_u32(array, 0U, end, maxbit);
5157 return;
5158 }
5159
5160 if (endword - startword) {
5161 /* Clearing MSB bits including startwordstartbit */
5162 clrbitsword = ~(u32max << startwordstartbit);
5163 ((uint32 *)array)[startword] &= clrbitsword;
5164
5165 /* Clearing all bits in 'startword + 1' to 'endword - 1' */
5166 for (i = startword + 1U; i <= endword - 1U; i++) {
5167 ((uint32 *)array)[i] = 0U;
5168 }
5169
5170 /* Clearing LSB bits including endwordlastbit */
5171 clrbitsword = ~(u32max >> (u32msbnum - endwordlastbit));
5172 ((uint32 *)array)[endword] &= clrbitsword;
5173 } else { /* start and end are in same word */
5174 /* Clearing start bit to end bit including start and end bits */
5175 clrbitsword =
5176 ~(u32max << startwordstartbit) | ~(u32max >> (u32msbnum - endwordlastbit));
5177 ((uint32 *)array)[startword] &= clrbitsword;
5178 }
5179 }
5180
5181 void
bcm_bitprint32(const uint32 u32arg)5182 bcm_bitprint32(const uint32 u32arg)
5183 {
5184 int i;
5185 for (i = NBITS(uint32) - 1; i >= 0; i--) {
5186 if (isbitset(u32arg, i)) {
5187 printf("1");
5188 } else {
5189 printf("0");
5190 }
5191
5192 if ((i % NBBY) == 0) printf(" ");
5193 }
5194 printf("\n");
5195 }
5196
5197 /* calculate checksum for ip header, tcp / udp header / data */
5198 uint16
bcm_ip_cksum(uint8 * buf,uint32 len,uint32 sum)5199 bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum)
5200 {
5201 while (len > 1) {
5202 sum += (buf[0] << 8) | buf[1];
5203 buf += 2;
5204 len -= 2;
5205 }
5206
5207 if (len > 0) {
5208 sum += (*buf) << 8;
5209 }
5210
5211 while (sum >> 16) {
5212 sum = (sum & 0xffff) + (sum >> 16);
5213 }
5214
5215 return ((uint16)~sum);
5216 }
5217
5218 /* calculate a + b where a is a 64 bit number and b is a 32 bit number */
5219 void
bcm_add_64(uint32 * r_hi,uint32 * r_lo,uint32 offset)5220 bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset)
5221 {
5222 uint32 r1_lo = *r_lo;
5223 (*r_lo) += offset;
5224 if (*r_lo < r1_lo)
5225 (*r_hi) ++;
5226 }
5227
5228 /* calculate a - b where a is a 64 bit number and b is a 32 bit number */
5229 void
bcm_sub_64(uint32 * r_hi,uint32 * r_lo,uint32 offset)5230 bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset)
5231 {
5232 uint32 r1_lo = *r_lo;
5233 (*r_lo) -= offset;
5234 if (*r_lo > r1_lo)
5235 (*r_hi) --;
5236 }
5237
5238 int
BCMRAMFN(valid_bcmerror)5239 BCMRAMFN(valid_bcmerror)(int e)
5240 {
5241 return ((e <= 0) && (e >= BCME_LAST));
5242 }
5243
5244 #ifdef DEBUG_COUNTER
5245 #if (OSL_SYSUPTIME_SUPPORT == TRUE)
counter_printlog(counter_tbl_t * ctr_tbl)5246 void counter_printlog(counter_tbl_t *ctr_tbl)
5247 {
5248 uint32 now;
5249
5250 if (!ctr_tbl->enabled)
5251 return;
5252
5253 now = OSL_SYSUPTIME();
5254
5255 if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) {
5256 uint8 i = 0;
5257 printf("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print);
5258
5259 for (i = 0; i < ctr_tbl->needed_cnt; i++) {
5260 printf(" %u", ctr_tbl->cnt[i]);
5261 }
5262 printf("\n");
5263
5264 ctr_tbl->prev_log_print = now;
5265 bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint));
5266 }
5267 }
5268 #else
5269 /* OSL_SYSUPTIME is not supported so no way to get time */
5270 #define counter_printlog(a) do {} while (0)
5271 #endif /* OSL_SYSUPTIME_SUPPORT == TRUE */
5272 #endif /* DEBUG_COUNTER */
5273
5274 /* calculate partial checksum */
5275 static uint32
ip_cksum_partial(uint32 sum,uint8 * val8,uint32 count)5276 ip_cksum_partial(uint32 sum, uint8 *val8, uint32 count)
5277 {
5278 uint32 i;
5279 uint16 *val16 = (uint16 *)val8;
5280
5281 ASSERT(val8 != NULL);
5282 /* partial chksum calculated on 16-bit values */
5283 ASSERT((count % 2) == 0);
5284
5285 count /= 2;
5286
5287 for (i = 0; i < count; i++) {
5288 sum += *val16++;
5289 }
5290 return sum;
5291 }
5292
5293 /* calculate IP checksum */
5294 static uint16
ip_cksum(uint32 sum,uint8 * val8,uint32 count)5295 ip_cksum(uint32 sum, uint8 *val8, uint32 count)
5296 {
5297 uint16 *val16 = (uint16 *)val8;
5298
5299 ASSERT(val8 != NULL);
5300
5301 while (count > 1) {
5302 sum += *val16++;
5303 count -= 2;
5304 }
5305 /* add left-over byte, if any */
5306 if (count > 0) {
5307 sum += (*(uint8 *)val16);
5308 }
5309
5310 /* fold 32-bit sum to 16 bits */
5311 sum = (sum >> 16) + (sum & 0xffff);
5312 sum += (sum >> 16);
5313 return ((uint16)~sum);
5314 }
5315
5316 /* calculate IPv4 header checksum
5317 * - input ip points to IP header in network order
5318 * - output cksum is in network order
5319 */
5320 uint16
ipv4_hdr_cksum(uint8 * ip,uint ip_len)5321 ipv4_hdr_cksum(uint8 *ip, uint ip_len)
5322 {
5323 uint32 sum = 0;
5324 uint8 *ptr = ip;
5325
5326 ASSERT(ip != NULL);
5327 ASSERT(ip_len >= IPV4_MIN_HEADER_LEN);
5328
5329 if (ip_len < IPV4_MIN_HEADER_LEN) {
5330 return 0;
5331 }
5332
5333 /* partial cksum skipping the hdr_chksum field */
5334 sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct ipv4_hdr, hdr_chksum));
5335 ptr += OFFSETOF(struct ipv4_hdr, hdr_chksum) + 2;
5336
5337 /* return calculated chksum */
5338 return ip_cksum(sum, ptr, ip_len - OFFSETOF(struct ipv4_hdr, src_ip));
5339 }
5340
5341 /* calculate TCP header checksum using partial sum */
5342 static uint16
tcp_hdr_chksum(uint32 sum,uint8 * tcp_hdr,uint16 tcp_len)5343 tcp_hdr_chksum(uint32 sum, uint8 *tcp_hdr, uint16 tcp_len)
5344 {
5345 uint8 *ptr = tcp_hdr;
5346
5347 ASSERT(tcp_hdr != NULL);
5348 ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
5349
5350 /* partial TCP cksum skipping the chksum field */
5351 sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct bcmtcp_hdr, chksum));
5352 ptr += OFFSETOF(struct bcmtcp_hdr, chksum) + 2;
5353
5354 /* return calculated chksum */
5355 return ip_cksum(sum, ptr, tcp_len - OFFSETOF(struct bcmtcp_hdr, urg_ptr));
5356 }
5357
5358 struct tcp_pseudo_hdr {
5359 uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */
5360 uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */
5361 uint8 zero;
5362 uint8 prot;
5363 uint16 tcp_size;
5364 };
5365
5366 /* calculate IPv4 TCP header checksum
5367 * - input ip and tcp points to IP and TCP header in network order
5368 * - output cksum is in network order
5369 */
5370 uint16
ipv4_tcp_hdr_cksum(uint8 * ip,uint8 * tcp,uint16 tcp_len)5371 ipv4_tcp_hdr_cksum(uint8 *ip, uint8 *tcp, uint16 tcp_len)
5372 {
5373 struct ipv4_hdr *ip_hdr = (struct ipv4_hdr *)ip;
5374 struct tcp_pseudo_hdr tcp_ps;
5375 uint32 sum = 0;
5376
5377 ASSERT(ip != NULL);
5378 ASSERT(tcp != NULL);
5379 ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
5380
5381 /* pseudo header cksum */
5382 memset(&tcp_ps, 0, sizeof(tcp_ps));
5383 memcpy(&tcp_ps.dst_ip, ip_hdr->dst_ip, IPV4_ADDR_LEN);
5384 memcpy(&tcp_ps.src_ip, ip_hdr->src_ip, IPV4_ADDR_LEN);
5385 tcp_ps.zero = 0;
5386 tcp_ps.prot = ip_hdr->prot;
5387 tcp_ps.tcp_size = hton16(tcp_len);
5388 sum = ip_cksum_partial(sum, (uint8 *)&tcp_ps, sizeof(tcp_ps));
5389
5390 /* return calculated TCP header chksum */
5391 return tcp_hdr_chksum(sum, tcp, tcp_len);
5392 }
5393
5394 struct ipv6_pseudo_hdr {
5395 uint8 saddr[IPV6_ADDR_LEN];
5396 uint8 daddr[IPV6_ADDR_LEN];
5397 uint16 payload_len;
5398 uint8 zero;
5399 uint8 next_hdr;
5400 };
5401
5402 /* calculate IPv6 TCP header checksum
5403 * - input ipv6 and tcp points to IPv6 and TCP header in network order
5404 * - output cksum is in network order
5405 */
5406 uint16
ipv6_tcp_hdr_cksum(uint8 * ipv6,uint8 * tcp,uint16 tcp_len)5407 ipv6_tcp_hdr_cksum(uint8 *ipv6, uint8 *tcp, uint16 tcp_len)
5408 {
5409 struct ipv6_hdr *ipv6_hdr = (struct ipv6_hdr *)ipv6;
5410 struct ipv6_pseudo_hdr ipv6_pseudo;
5411 uint32 sum = 0;
5412
5413 ASSERT(ipv6 != NULL);
5414 ASSERT(tcp != NULL);
5415 ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
5416
5417 /* pseudo header cksum */
5418 memset((char *)&ipv6_pseudo, 0, sizeof(ipv6_pseudo));
5419 memcpy((char *)ipv6_pseudo.saddr, (char *)ipv6_hdr->saddr.addr,
5420 sizeof(ipv6_pseudo.saddr));
5421 memcpy((char *)ipv6_pseudo.daddr, (char *)ipv6_hdr->daddr.addr,
5422 sizeof(ipv6_pseudo.daddr));
5423 ipv6_pseudo.payload_len = ipv6_hdr->payload_len;
5424 ipv6_pseudo.next_hdr = ipv6_hdr->nexthdr;
5425 sum = ip_cksum_partial(sum, (uint8 *)&ipv6_pseudo, sizeof(ipv6_pseudo));
5426
5427 /* return calculated TCP header chksum */
5428 return tcp_hdr_chksum(sum, tcp, tcp_len);
5429 }
5430
5431 void *_bcmutils_dummy_fn = NULL;
5432
5433 /* GROUP 1 --- start
5434 * These function under GROUP 1 are general purpose functions to do complex number
5435 * calculations and square root calculation.
5436 */
5437
sqrt_int(uint32 value)5438 uint32 sqrt_int(uint32 value)
5439 {
5440 uint32 root = 0, shift = 0;
5441
5442 /* Compute integer nearest to square root of input integer value */
5443 for (shift = 0; shift < 32; shift += 2) {
5444 if (((0x40000000 >> shift) + root) <= value) {
5445 value -= ((0x40000000 >> shift) + root);
5446 root = (root >> 1) | (0x40000000 >> shift);
5447 }
5448 else {
5449 root = root >> 1;
5450 }
5451 }
5452
5453 /* round to the nearest integer */
5454 if (root < value) ++root;
5455
5456 return root;
5457 }
5458 /* GROUP 1 --- end */
5459
5460 /* read/write field in a consecutive bits in an octet array.
5461 * 'addr' is the octet array's start byte address
5462 * 'size' is the octet array's byte size
5463 * 'stbit' is the value's start bit offset
5464 * 'nbits' is the value's bit size
5465 * This set of utilities are for convenience. Don't use them
5466 * in time critical/data path as there's a great overhead in them.
5467 */
5468 void
setbits(uint8 * addr,uint size,uint stbit,uint nbits,uint32 val)5469 setbits(uint8 *addr, uint size, uint stbit, uint nbits, uint32 val)
5470 {
5471 uint fbyte = stbit >> 3; /* first byte */
5472 uint lbyte = (stbit + nbits - 1) >> 3; /* last byte */
5473 uint fbit = stbit & 7; /* first bit in the first byte */
5474 uint rbits = (nbits > 8 - fbit ?
5475 nbits - (8 - fbit) :
5476 0) & 7; /* remaining bits of the last byte when not 0 */
5477 uint8 mask;
5478 uint byte;
5479
5480 BCM_REFERENCE(size);
5481
5482 ASSERT(fbyte < size);
5483 ASSERT(lbyte < size);
5484 ASSERT(nbits <= (sizeof(val) << 3));
5485
5486 /* all bits are in the same byte */
5487 if (fbyte == lbyte) {
5488 mask = ((1 << nbits) - 1) << fbit;
5489 addr[fbyte] &= ~mask;
5490 addr[fbyte] |= (uint8)(val << fbit);
5491 return;
5492 }
5493
5494 /* first partial byte */
5495 if (fbit > 0) {
5496 mask = (0xff << fbit);
5497 addr[fbyte] &= ~mask;
5498 addr[fbyte] |= (uint8)(val << fbit);
5499 val >>= (8 - fbit);
5500 nbits -= (8 - fbit);
5501 fbyte ++; /* first full byte */
5502 }
5503
5504 /* last partial byte */
5505 if (rbits > 0) {
5506 mask = (1 << rbits) - 1;
5507 addr[lbyte] &= ~mask;
5508 addr[lbyte] |= (uint8)(val >> (nbits - rbits));
5509 lbyte --; /* last full byte */
5510 }
5511
5512 /* remaining full byte(s) */
5513 for (byte = fbyte; byte <= lbyte; byte ++) {
5514 addr[byte] = (uint8)val;
5515 val >>= 8;
5516 }
5517 }
5518
5519 uint32
getbits(const uint8 * addr,uint size,uint stbit,uint nbits)5520 getbits(const uint8 *addr, uint size, uint stbit, uint nbits)
5521 {
5522 uint fbyte = stbit >> 3; /* first byte */
5523 uint lbyte = (stbit + nbits - 1) >> 3; /* last byte */
5524 uint fbit = stbit & 7; /* first bit in the first byte */
5525 uint rbits = (nbits > 8 - fbit ?
5526 nbits - (8 - fbit) :
5527 0) & 7; /* remaining bits of the last byte when not 0 */
5528 uint32 val = 0;
5529 uint bits = 0; /* bits in first partial byte */
5530 uint8 mask;
5531 uint byte;
5532
5533 BCM_REFERENCE(size);
5534
5535 ASSERT(fbyte < size);
5536 ASSERT(lbyte < size);
5537 ASSERT(nbits <= (sizeof(val) << 3));
5538
5539 /* all bits are in the same byte */
5540 if (fbyte == lbyte) {
5541 mask = ((1 << nbits) - 1) << fbit;
5542 val = (addr[fbyte] & mask) >> fbit;
5543 return val;
5544 }
5545
5546 /* first partial byte */
5547 if (fbit > 0) {
5548 bits = 8 - fbit;
5549 mask = (0xff << fbit);
5550 val |= (addr[fbyte] & mask) >> fbit;
5551 fbyte ++; /* first full byte */
5552 }
5553
5554 /* last partial byte */
5555 if (rbits > 0) {
5556 mask = (1 << rbits) - 1;
5557 val |= (addr[lbyte] & mask) << (nbits - rbits);
5558 lbyte --; /* last full byte */
5559 }
5560
5561 /* remaining full byte(s) */
5562 for (byte = fbyte; byte <= lbyte; byte ++) {
5563 val |= (addr[byte] << (((byte - fbyte) << 3) + bits));
5564 }
5565
5566 return val;
5567 }
5568
5569 #if defined(BCMDBG) || defined(WLMSG_ASSOC)
5570 /* support for getting 802.11 frame type/name based on frame kind */
5571 #define FK_NAME_DECL(x) {FC_##x, #x}
5572 static const struct {
5573 uint fk;
5574 const char *name;
5575 } bcm_80211_fk_names[] = {
5576 FK_NAME_DECL(ASSOC_REQ),
5577 FK_NAME_DECL(ASSOC_RESP),
5578 FK_NAME_DECL(REASSOC_REQ),
5579 FK_NAME_DECL(REASSOC_RESP),
5580 FK_NAME_DECL(PROBE_REQ),
5581 FK_NAME_DECL(PROBE_RESP),
5582 FK_NAME_DECL(BEACON),
5583 FK_NAME_DECL(ATIM),
5584 FK_NAME_DECL(DISASSOC),
5585 FK_NAME_DECL(AUTH),
5586 FK_NAME_DECL(DEAUTH),
5587 FK_NAME_DECL(ACTION),
5588 FK_NAME_DECL(ACTION_NOACK),
5589 FK_NAME_DECL(CTL_TRIGGER),
5590 FK_NAME_DECL(CTL_WRAPPER),
5591 FK_NAME_DECL(BLOCKACK_REQ),
5592 FK_NAME_DECL(BLOCKACK),
5593 FK_NAME_DECL(PS_POLL),
5594 FK_NAME_DECL(RTS),
5595 FK_NAME_DECL(CTS),
5596 FK_NAME_DECL(ACK),
5597 FK_NAME_DECL(CF_END),
5598 FK_NAME_DECL(CF_END_ACK),
5599 FK_NAME_DECL(DATA),
5600 FK_NAME_DECL(NULL_DATA),
5601 FK_NAME_DECL(DATA_CF_ACK),
5602 FK_NAME_DECL(QOS_DATA),
5603 FK_NAME_DECL(QOS_NULL)
5604 };
5605 static const uint n_bcm_80211_fk_names = ARRAYSIZE(bcm_80211_fk_names);
5606
bcm_80211_fk_name(uint fk)5607 const char *bcm_80211_fk_name(uint fk)
5608 {
5609 uint i;
5610 for (i = 0; i < n_bcm_80211_fk_names; ++i) {
5611 if (bcm_80211_fk_names[i].fk == fk) {
5612 return bcm_80211_fk_names[i].name;
5613 }
5614 }
5615 return "unknown";
5616 }
5617 #endif /* BCMDBG || WLMSG_ASSOC */
5618
5619 #ifdef BCMDRIVER
5620
5621 /** allocate variable sized data with 'size' bytes. note: vld should NOT be null.
5622 */
5623 int
bcm_vdata_alloc(osl_t * osh,var_len_data_t * vld,uint32 size)5624 bcm_vdata_alloc(osl_t *osh, var_len_data_t *vld, uint32 size)
5625 {
5626 int ret = BCME_ERROR;
5627 uint8 *dat = NULL;
5628
5629 if (vld == NULL) {
5630 ASSERT(0);
5631 goto done;
5632 }
5633
5634 /* trying to allocate twice? */
5635 if (vld->vdata != NULL) {
5636 ASSERT(0);
5637 goto done;
5638 }
5639
5640 /* trying to allocate 0 size? */
5641 if (size == 0) {
5642 ASSERT(0);
5643 ret = BCME_BADARG;
5644 goto done;
5645 }
5646
5647 dat = MALLOCZ(osh, size);
5648 if (dat == NULL) {
5649 ret = BCME_NOMEM;
5650 goto done;
5651 }
5652 vld->vlen = size;
5653 vld->vdata = dat;
5654 ret = BCME_OK;
5655 done:
5656 return ret;
5657 }
5658
5659 /** free memory associated with variable sized data. note: vld should NOT be null.
5660 */
5661 int
bcm_vdata_free(osl_t * osh,var_len_data_t * vld)5662 bcm_vdata_free(osl_t *osh, var_len_data_t *vld)
5663 {
5664 int ret = BCME_ERROR;
5665
5666 if (vld == NULL) {
5667 ASSERT(0);
5668 goto done;
5669 }
5670
5671 if (vld->vdata) {
5672 MFREE(osh, vld->vdata, vld->vlen);
5673 vld->vlen = 0;
5674 ret = BCME_OK;
5675 }
5676 done:
5677 return ret;
5678 }
5679
5680 /* return TRUE if :
5681 * - both buffers are of length 0
5682 * OR
5683 * - both buffers are NULL
5684 * OR
5685 * lengths and contents are the same.
5686 */
5687 bool
bcm_match_buffers(const uint8 * b1,uint b1_len,const uint8 * b2,uint b2_len)5688 bcm_match_buffers(const uint8 *b1, uint b1_len, const uint8 *b2, uint b2_len)
5689
5690 {
5691 if (b1_len == 0 && b2_len == 0) {
5692 return TRUE;
5693 }
5694
5695 if (b1 == NULL && b2 == NULL) {
5696 return TRUE;
5697 }
5698
5699 /* If they are not both NULL, neither can be */
5700 if (b1 == NULL || b2 == NULL) {
5701 return FALSE;
5702 }
5703
5704 if ((b1_len == b2_len) && !memcmp(b1, b2, b1_len)) {
5705 return TRUE;
5706 }
5707 return FALSE;
5708 }
5709
5710 #ifdef PRIVACY_MASK
5711 /* applies privacy mask on the input address itself */
5712 void
BCMRAMFN(bcm_ether_privacy_mask)5713 BCMRAMFN(bcm_ether_privacy_mask)(struct ether_addr *addr)
5714 {
5715 struct ether_addr *privacy = privacy_addrmask_get();
5716 if (addr && !ETHER_ISMULTI(addr)) {
5717 *(uint32*)(&(addr->octet[0])) &= *((uint32*)&privacy->octet[0]);
5718 *(uint16*)(&(addr->octet[4])) &= *((uint16*)&privacy->octet[4]);
5719 }
5720 }
5721 #endif /* PRIVACY_MASK */
5722 #endif /* BCMDRIVER */
5723
5724 /* Count the number of elements not matching a given value in a null terminated array */
5725 int
BCMATTACHFN(array_value_mismatch_count)5726 BCMATTACHFN(array_value_mismatch_count)(uint8 value, uint8 *array, int array_size)
5727 {
5728 int i;
5729 int count = 0;
5730
5731 for (i = 0; i < array_size; i++) {
5732 /* exit if a null terminator is found */
5733 if (array[i] == 0) {
5734 break;
5735 }
5736 if (array[i] != value) {
5737 count++;
5738 }
5739 }
5740 return count;
5741 }
5742
5743 /* Count the number of non-zero elements in an uint8 array */
5744 int
BCMATTACHFN(array_nonzero_count)5745 BCMATTACHFN(array_nonzero_count)(uint8 *array, int array_size)
5746 {
5747 return array_value_mismatch_count(0, array, array_size);
5748 }
5749
5750 /* Count the number of non-zero elements in an int16 array */
5751 int
BCMATTACHFN(array_nonzero_count_int16)5752 BCMATTACHFN(array_nonzero_count_int16)(int16 *array, int array_size)
5753 {
5754 int i;
5755 int count = 0;
5756
5757 for (i = 0; i < array_size; i++) {
5758 if (array[i] != 0) {
5759 count++;
5760 }
5761 }
5762 return count;
5763 }
5764
5765 /* Count the number of zero elements in an uint8 array */
5766 int
BCMATTACHFN(array_zero_count)5767 BCMATTACHFN(array_zero_count)(uint8 *array, int array_size)
5768 {
5769 int i;
5770 int count = 0;
5771
5772 for (i = 0; i < array_size; i++) {
5773 if (array[i] == 0) {
5774 count++;
5775 }
5776 }
5777 return count;
5778 }
5779
5780 /* Validate an array that can be 1 of 2 data types.
5781 * One of array1 or array2 should be non-NULL. The other should be NULL.
5782 */
5783 static int
BCMATTACHFN(verify_ordered_array)5784 BCMATTACHFN(verify_ordered_array)(uint8 *array1, int16 *array2, int array_size,
5785 int range_lo, int range_hi, bool err_if_no_zero_term, bool is_ordered)
5786 {
5787 int ret;
5788 int i;
5789 int val = 0;
5790 int prev_val = 0;
5791
5792 ret = err_if_no_zero_term ? BCME_NOTFOUND : BCME_OK;
5793
5794 /* Check that:
5795 * - values are in descending order.
5796 * - values are within the valid range.
5797 */
5798 for (i = 0; i < array_size; i++) {
5799 if (array1) {
5800 val = (int)array1[i];
5801 } else if (array2) {
5802 val = (int)array2[i];
5803 } else {
5804 /* both array parameters are NULL */
5805 return BCME_NOTFOUND;
5806 }
5807 if (val == 0) {
5808 /* array is zero-terminated */
5809 ret = BCME_OK;
5810 break;
5811 }
5812
5813 if (is_ordered && i > 0 && val > prev_val) {
5814 /* array is not in descending order */
5815 ret = BCME_BADOPTION;
5816 break;
5817 }
5818 prev_val = val;
5819
5820 if (val < range_lo || val > range_hi) {
5821 /* array value out of range */
5822 ret = BCME_RANGE;
5823 break;
5824 }
5825 }
5826
5827 return ret;
5828 }
5829
5830 /* Validate an ordered uint8 configuration array */
5831 int
BCMATTACHFN(verify_ordered_array_uint8)5832 BCMATTACHFN(verify_ordered_array_uint8)(uint8 *array, int array_size,
5833 uint8 range_lo, uint8 range_hi)
5834 {
5835 return verify_ordered_array(array, NULL, array_size, (int)range_lo, (int)range_hi,
5836 TRUE, TRUE);
5837 }
5838
5839 /* Validate an ordered int16 non-zero-terminated configuration array */
5840 int
BCMATTACHFN(verify_ordered_array_int16)5841 BCMATTACHFN(verify_ordered_array_int16)(int16 *array, int array_size,
5842 int16 range_lo, int16 range_hi)
5843 {
5844 return verify_ordered_array(NULL, array, array_size, (int)range_lo, (int)range_hi,
5845 FALSE, TRUE);
5846 }
5847
5848 /* Validate all values in an array are in range */
5849 int
BCMATTACHFN(verify_array_values)5850 BCMATTACHFN(verify_array_values)(uint8 *array, int array_size,
5851 int range_lo, int range_hi, bool zero_terminated)
5852 {
5853 int ret = BCME_OK;
5854 int i;
5855 int val = 0;
5856
5857 /* Check that:
5858 * - values are in strict descending order.
5859 * - values are within the valid range.
5860 */
5861 for (i = 0; i < array_size; i++) {
5862 val = (int)array[i];
5863 if (val == 0 && zero_terminated) {
5864 ret = BCME_OK;
5865 break;
5866 }
5867 if (val < range_lo || val > range_hi) {
5868 /* array value out of range */
5869 ret = BCME_RANGE;
5870 break;
5871 }
5872 }
5873 return ret;
5874 }
5875
5876 /* Adds/replaces NVRAM variable with given value
5877 * varbuf[in,out] - Buffer with NVRAM variables (sequence of zero-terminated 'name=value' records,
5878 * terminated with additional zero)
5879 * buflen[in] - Length of buffer (may, even should, have some unused space)
5880 * variable[in] - Variable to add/replace in 'name=value' form
5881 * datalen[out,opt] - Optional output parameter - resulting length of data in buffer
5882 * Returns TRUE on success, FALSE if buffer too short or variable specified incorrectly
5883 */
5884 bool
replace_nvram_variable(char * varbuf,unsigned int buflen,const char * variable,unsigned int * datalen)5885 replace_nvram_variable(char *varbuf, unsigned int buflen, const char *variable,
5886 unsigned int *datalen)
5887 {
5888 char *p;
5889 int variable_heading_len, record_len, variable_record_len = (int)strlen(variable) + 1;
5890 char *buf_end = varbuf + buflen;
5891 p = strchr(variable, '=');
5892 if (!p) {
5893 return FALSE;
5894 }
5895 /* Length of given variable name, followed by '=' */
5896 variable_heading_len = (int)((const char *)(p + 1) - variable);
5897 /* Scanning NVRAM, record by record up to trailing 0 */
5898 for (p = varbuf; *p; p += strlen(p) + 1) {
5899 /* If given variable found - remove it */
5900 if (!strncmp(p, variable, variable_heading_len)) {
5901 record_len = (int)strlen(p) + 1;
5902 memmove_s(p, buf_end - p, p + record_len, buf_end - (p + record_len));
5903 }
5904 }
5905 /* If buffer does not have space for given variable - return FALSE */
5906 if ((p + variable_record_len + 1) > buf_end) {
5907 return FALSE;
5908 }
5909 /* Copy given variable to end of buffer */
5910 memmove_s(p, buf_end - p, variable, variable_record_len);
5911 /* Adding trailing 0 */
5912 p[variable_record_len] = 0;
5913 /* Setting optional output parameter - length of data in buffer */
5914 if (datalen) {
5915 *datalen = (unsigned int)(p + variable_record_len + 1 - varbuf);
5916 }
5917 return TRUE;
5918 }
5919
5920 /*
5921 * Gets the ceil bit set to the nearest power of 2
5922 * val[in] - value for which nearest power of 2 bit set to be returned
5923 * bitpos[out] - the position of the nearest power of 2 bit set
5924 */
5925 uint8
bcm_get_ceil_pow_2(uint val)5926 bcm_get_ceil_pow_2(uint val)
5927 {
5928 uint8 bitpos = 0;
5929 ASSERT(val);
5930 if (val & (val-1)) {
5931 /* val is not powers of 2.
5932 * pad it, so that allocation will be aligned to
5933 * next immediate powers of 2.
5934 */
5935 bitpos = 1;
5936 }
5937 while (val >>= 1) {
5938 bitpos ++;
5939 }
5940 return (bitpos);
5941 }
5942
5943 #if !defined(BCMDONGLEHOST)
5944 /** Initialization of varbuf structure */
5945 void
BCMATTACHFN(varbuf_init)5946 BCMATTACHFN(varbuf_init)(varbuf_t *b, char *buf, uint size)
5947 {
5948 b->size = size;
5949 b->base = b->buf = buf;
5950 }
5951
5952 /** append a null terminated var=value string */
5953 int
BCMATTACHFN(varbuf_append)5954 BCMATTACHFN(varbuf_append)(varbuf_t *b, const char *fmt, ...)
5955 {
5956 va_list ap;
5957 int r;
5958 size_t len;
5959 char *s;
5960
5961 if (b->size < 2)
5962 return 0;
5963
5964 va_start(ap, fmt);
5965 r = vsnprintf(b->buf, b->size, fmt, ap);
5966 va_end(ap);
5967
5968 /* C99 snprintf behavior returns r >= size on overflow,
5969 * others return -1 on overflow.
5970 * All return -1 on format error.
5971 * We need to leave room for 2 null terminations, one for the current var
5972 * string, and one for final null of the var table. So check that the
5973 * strlen written, r, leaves room for 2 chars.
5974 */
5975 if ((r == -1) || (r > (int)(b->size - 2))) {
5976 b->size = 0;
5977 return 0;
5978 }
5979
5980 /* Remove any earlier occurrence of the same variable */
5981 if ((s = strchr(b->buf, '=')) != NULL) {
5982 len = (size_t)(s - b->buf);
5983 for (s = b->base; s < b->buf;) {
5984 if ((memcmp(s, b->buf, len) == 0) && s[len] == '=') {
5985 len = strlen(s) + 1;
5986 memmove(s, (s + len), ((b->buf + r + 1) - (s + len)));
5987 b->buf -= len;
5988 b->size += (unsigned int)len;
5989 break;
5990 }
5991
5992 while (*s++)
5993 ;
5994 }
5995 }
5996
5997 /* skip over this string's null termination */
5998 r++;
5999 b->size -= r;
6000 b->buf += r;
6001
6002 return r;
6003 }
6004
6005 #if defined(BCMDRIVER)
6006 /**
6007 * Create variable table from memory.
6008 * Return 0 on success, nonzero on error.
6009 */
6010 int
BCMATTACHFN(initvars_table)6011 BCMATTACHFN(initvars_table)(osl_t *osh, char *start, char *end, char **vars,
6012 uint *count)
6013 {
6014 int c = (int)(end - start);
6015
6016 /* do it only when there is more than just the null string */
6017 if (c > 1) {
6018 char *vp = MALLOC(osh, c);
6019 ASSERT(vp != NULL);
6020 if (!vp)
6021 return BCME_NOMEM;
6022 bcopy(start, vp, c);
6023 *vars = vp;
6024 *count = c;
6025 }
6026 else {
6027 *vars = NULL;
6028 *count = 0;
6029 }
6030
6031 return 0;
6032 }
6033 #endif /* BCMDRIVER */
6034
6035 #endif /* !BCMDONGLEHOST */
6036
6037 /* bit shift operation in serialized buffer taking input bits % 8 */
buf_shift_right(uint8 * buf,uint16 len,uint8 bits)6038 int buf_shift_right(uint8 *buf, uint16 len, uint8 bits)
6039 {
6040 uint16 i;
6041
6042 if (len == 0 || (bits == 0) || (bits >= NBBY)) {
6043 return BCME_BADARG;
6044 }
6045
6046 for (i = len - 1u; i > 0; i--) {
6047 buf[i] = (buf[i - 1u] << (NBBY - bits)) | (buf[i] >> bits);
6048 }
6049 buf[0] >>= bits;
6050
6051 return BCME_OK;
6052 }
6053
6054 /* print the content of the 'buf' in hex string format */
6055 void
prhexstr(const char * prefix,const uint8 * buf,uint len,bool newline)6056 prhexstr(const char *prefix, const uint8 *buf, uint len, bool newline)
6057 {
6058 if (len > 0) {
6059 uint i;
6060
6061 if (prefix != NULL) {
6062 printf("%s", prefix);
6063 }
6064 for (i = 0; i < len; i ++) {
6065 printf("%02X", buf[i]);
6066 }
6067 if (newline) {
6068 printf("\n");
6069 }
6070 }
6071 }
6072
6073 /* Add to adjust the 802.1x priority */
6074 void
pktset8021xprio(void * pkt,int prio)6075 pktset8021xprio(void *pkt, int prio)
6076 {
6077 struct ether_header *eh;
6078 uint8 *pktdata;
6079 if(prio == PKTPRIO(pkt))
6080 return;
6081 pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
6082 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
6083 eh = (struct ether_header *) pktdata;
6084 if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
6085 ASSERT(prio >= 0 && prio <= MAXPRIO);
6086 PKTSETPRIO(pkt, prio);
6087 }
6088 }
6089