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