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