xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/bcmutils.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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, &ether_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(&ether_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, &ether_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