• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Driver O/S-independent utility routines
4  *
5  * Copyright (C) 1999-2019, Broadcom.
6  *
7  *      Unless you and Broadcom execute a separate written software license
8  * agreement governing use of this software, this software is licensed to you
9  * under the terms of the GNU General Public License version 2 (the "GPL"),
10  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11  * following added to such license:
12  *
13  *      As a special exception, the copyright holders of this software give you
14  * permission to link this software with independent modules, and to copy and
15  * distribute the resulting executable under terms of your choice, provided that
16  * you also meet, for each linked independent module, the terms and conditions of
17  * the license of that module.  An independent module is a module which is not
18  * derived from this software.  The special exception does not apply to any
19  * modifications of the software.
20  *
21  *      Notwithstanding the above, under no circumstances may you combine this
22  * software in any way with any other Broadcom software provided under a license
23  * other than the GPL, without Broadcom's express prior written consent.
24  *
25  *
26  * <<Broadcom-WL-IPTag/Open:>>
27  *
28  * $Id: bcmutils.c 813798 2019-04-08 10:20:21Z $
29  */
30 
31 #include <bcm_cfg.h>
32 #include <typedefs.h>
33 #include <bcmdefs.h>
34 #include <stdarg.h>
35 #ifdef BCMDRIVER
36 #include <osl.h>
37 #include <bcmutils.h>
38 
39 #else /* !BCMDRIVER */
40 
41 #include <stdio.h>
42 #include <string.h>
43 #include <bcm_math.h>
44 #include <bcmutils.h>
45 
46 #if defined(BCMEXTSUP)
47 #include <bcm_osl.h>
48 #endif // endif
49 
50 #ifndef ASSERT
51 #define ASSERT(exp)
52 #endif // endif
53 
54 #endif /* !BCMDRIVER */
55 
56 #ifdef WL_UNITTEST
57 #ifdef ASSERT
58 #undef ASSERT
59 #endif /* ASSERT */
60 #define ASSERT(exp)
61 #endif /* WL_UNITTEST */
62 
63 #include <bcmstdlib_s.h>
64 #include <bcmendian.h>
65 #include <bcmdevs.h>
66 #include <ethernet.h>
67 #include <vlan.h>
68 #include <bcmip.h>
69 #include <802.1d.h>
70 #include <802.11.h>
71 #include <bcmip.h>
72 #include <bcmipv6.h>
73 #include <bcmtcp.h>
74 
75 #ifdef BCMDRIVER
76 
77 /* return total length of buffer chain */
78 uint BCMFASTPATH
pkttotlen(osl_t * osh,void * p)79 pkttotlen(osl_t *osh, void *p)
80 {
81 	uint total;
82 	int len;
83 
84 	total = 0;
85 	for (; p; p = PKTNEXT(osh, p)) {
86 		len = PKTLEN(osh, p);
87 		total += (uint)len;
88 #ifdef BCMLFRAG
89 		if (BCMLFRAG_ENAB()) {
90 			if (PKTISFRAG(osh, p)) {
91 				total += PKTFRAGTOTLEN(osh, p);
92 			}
93 		}
94 #endif // endif
95 	}
96 
97 	return (total);
98 }
99 
100 /* return the last buffer of chained pkt */
101 void *
pktlast(osl_t * osh,void * p)102 pktlast(osl_t *osh, void *p)
103 {
104 	for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
105 		;
106 
107 	return (p);
108 }
109 
110 /* count segments of a chained packet */
111 uint BCMFASTPATH
pktsegcnt(osl_t * osh,void * p)112 pktsegcnt(osl_t *osh, void *p)
113 {
114 	uint cnt;
115 
116 	for (cnt = 0; p; p = PKTNEXT(osh, p)) {
117 		cnt++;
118 #ifdef BCMLFRAG
119 		if (BCMLFRAG_ENAB()) {
120 			if (PKTISFRAG(osh, p)) {
121 				cnt += PKTFRAGTOTNUM(osh, p);
122 			}
123 		}
124 #endif // endif
125 	}
126 
127 	return cnt;
128 }
129 
130 /* copy a pkt buffer chain into a buffer */
131 uint
pktcopy(osl_t * osh,void * p,uint offset,int len,uchar * buf)132 pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
133 {
134 	uint n, ret = 0;
135 
136 	if (len < 0)
137 		len = 4096;	/* "infinite" */
138 
139 	/* skip 'offset' bytes */
140 	for (; p && offset; p = PKTNEXT(osh, p)) {
141 		if (offset < (uint)PKTLEN(osh, p))
142 			break;
143 		offset -= (uint)PKTLEN(osh, p);
144 	}
145 
146 	if (!p)
147 		return 0;
148 
149 	/* copy the data */
150 	for (; p && len; p = PKTNEXT(osh, p)) {
151 		n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
152 		bcopy(PKTDATA(osh, p) + offset, buf, n);
153 		buf += n;
154 		len -= n;
155 		ret += n;
156 		offset = 0;
157 	}
158 
159 	return ret;
160 }
161 
162 /* copy a buffer into a pkt buffer chain */
163 uint
pktfrombuf(osl_t * osh,void * p,uint offset,int len,uchar * buf)164 pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
165 {
166 	uint n, ret = 0;
167 
168 	/* skip 'offset' bytes */
169 	for (; p && offset; p = PKTNEXT(osh, p)) {
170 		if (offset < (uint)PKTLEN(osh, p))
171 			break;
172 		offset -= (uint)PKTLEN(osh, p);
173 	}
174 
175 	if (!p)
176 		return 0;
177 
178 	/* copy the data */
179 	for (; p && len; p = PKTNEXT(osh, p)) {
180 		n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
181 		bcopy(buf, PKTDATA(osh, p) + offset, n);
182 		buf += n;
183 		len -= n;
184 		ret += n;
185 		offset = 0;
186 	}
187 
188 	return ret;
189 }
190 
191 uint8 * BCMFASTPATH
pktdataoffset(osl_t * osh,void * p,uint offset)192 pktdataoffset(osl_t *osh, void *p,  uint offset)
193 {
194 	uint total = pkttotlen(osh, p);
195 	uint pkt_off = 0, len = 0;
196 	uint8 *pdata = (uint8 *) PKTDATA(osh, p);
197 
198 	if (offset > total)
199 		return NULL;
200 
201 	for (; p; p = PKTNEXT(osh, p)) {
202 		pdata = (uint8 *) PKTDATA(osh, p);
203 		pkt_off = offset - len;
204 		len += (uint)PKTLEN(osh, p);
205 		if (len > offset)
206 			break;
207 	}
208 	return (uint8*) (pdata+pkt_off);
209 }
210 
211 /* given a offset in pdata, find the pkt seg hdr */
212 void *
pktoffset(osl_t * osh,void * p,uint offset)213 pktoffset(osl_t *osh, void *p,  uint offset)
214 {
215 	uint total = pkttotlen(osh, p);
216 	uint len = 0;
217 
218 	if (offset > total)
219 		return NULL;
220 
221 	for (; p; p = PKTNEXT(osh, p)) {
222 		len += (uint)PKTLEN(osh, p);
223 		if (len > offset)
224 			break;
225 	}
226 	return p;
227 }
228 
229 void
bcm_mdelay(uint ms)230 bcm_mdelay(uint ms)
231 {
232 	uint i;
233 
234 	for (i = 0; i < ms; i++) {
235 		OSL_DELAY(1000);
236 	}
237 }
238 
239 #if defined(DHD_DEBUG)
240 /* pretty hex print a pkt buffer chain */
241 void
prpkt(const char * msg,osl_t * osh,void * p0)242 prpkt(const char *msg, osl_t *osh, void *p0)
243 {
244 	void *p;
245 
246 	if (msg && (msg[0] != '\0'))
247 		printf("%s:\n", msg);
248 
249 	for (p = p0; p; p = PKTNEXT(osh, p))
250 		prhex(NULL, PKTDATA(osh, p), (uint)PKTLEN(osh, p));
251 }
252 #endif // endif
253 
254 /* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
255  * Also updates the inplace vlan tag if requested.
256  * For debugging, it returns an indication of what it did.
257  */
258 uint BCMFASTPATH
pktsetprio(void * pkt,bool update_vtag)259 pktsetprio(void *pkt, bool update_vtag)
260 {
261 	struct ether_header *eh;
262 	struct ethervlan_header *evh;
263 	uint8 *pktdata;
264 	uint priority = 0;
265 	uint rc = 0;
266 
267 	pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
268 	ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
269 
270 	eh = (struct ether_header *) pktdata;
271 
272 	if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) {
273 		uint16 vlan_tag;
274 		uint vlan_prio, dscp_prio = 0;
275 
276 		evh = (struct ethervlan_header *)eh;
277 
278 		vlan_tag = ntoh16(evh->vlan_tag);
279 		vlan_prio = (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
280 
281 		if ((evh->ether_type == hton16(ETHER_TYPE_IP)) ||
282 			(evh->ether_type == hton16(ETHER_TYPE_IPV6))) {
283 			uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
284 			uint8 tos_tc = (uint8)IP_TOS46(ip_body);
285 			dscp_prio = tos_tc >> IPV4_TOS_PREC_SHIFT;
286 		}
287 
288 		/* DSCP priority gets precedence over 802.1P (vlan tag) */
289 		if (dscp_prio != 0) {
290 			priority = dscp_prio;
291 			rc |= PKTPRIO_VDSCP;
292 		} else {
293 			priority = vlan_prio;
294 			rc |= PKTPRIO_VLAN;
295 		}
296 		/*
297 		 * If the DSCP priority is not the same as the VLAN priority,
298 		 * then overwrite the priority field in the vlan tag, with the
299 		 * DSCP priority value. This is required for Linux APs because
300 		 * the VLAN driver on Linux, overwrites the skb->priority field
301 		 * with the priority value in the vlan tag
302 		 */
303 		if (update_vtag && (priority != vlan_prio)) {
304 			vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
305 			vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
306 			evh->vlan_tag = hton16(vlan_tag);
307 			rc |= PKTPRIO_UPD;
308 		}
309 #if defined(EAPOL_PKT_PRIO) || defined(DHD_LOSSLESS_ROAMING)
310 	} else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
311 		priority = PRIO_8021D_NC;
312 		rc = PKTPRIO_DSCP;
313 #endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */
314 	} else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) ||
315 		(eh->ether_type == hton16(ETHER_TYPE_IPV6))) {
316 		uint8 *ip_body = pktdata + sizeof(struct ether_header);
317 		uint8 tos_tc = (uint8)IP_TOS46(ip_body);
318 		uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT;
319 		switch (dscp) {
320 		case DSCP_EF:
321 		case DSCP_VA:
322 			priority = PRIO_8021D_VO;
323 			break;
324 		case DSCP_AF31:
325 		case DSCP_AF32:
326 		case DSCP_AF33:
327 		case DSCP_CS3:
328 			priority = PRIO_8021D_CL;
329 			break;
330 		case DSCP_AF21:
331 		case DSCP_AF22:
332 		case DSCP_AF23:
333 			priority = PRIO_8021D_EE;
334 			break;
335 		case DSCP_AF11:
336 		case DSCP_AF12:
337 		case DSCP_AF13:
338 		case DSCP_CS2:
339 			priority = PRIO_8021D_BE;
340 			break;
341 		case DSCP_CS6:
342 		case DSCP_CS7:
343 			priority = PRIO_8021D_NC;
344 			break;
345 		default:
346 			priority = tos_tc >> IPV4_TOS_PREC_SHIFT;
347 			break;
348 		}
349 
350 		rc |= PKTPRIO_DSCP;
351 	}
352 
353 	ASSERT(priority <= MAXPRIO);
354 	PKTSETPRIO(pkt, (int)priority);
355 	return (rc | priority);
356 }
357 
358 /* lookup user priority for specified DSCP */
359 static uint8
dscp2up(uint8 * up_table,uint8 dscp)360 dscp2up(uint8 *up_table, uint8 dscp)
361 {
362 	uint8 user_priority = 255;
363 
364 	/* lookup up from table if parameters valid */
365 	if (up_table != NULL && dscp < UP_TABLE_MAX) {
366 		user_priority = up_table[dscp];
367 	}
368 
369 	/* 255 is unused value so return up from dscp */
370 	if (user_priority == 255) {
371 		user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT);
372 	}
373 
374 	return user_priority;
375 }
376 
377 /* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */
378 uint BCMFASTPATH
pktsetprio_qms(void * pkt,uint8 * up_table,bool update_vtag)379 pktsetprio_qms(void *pkt, uint8* up_table, bool update_vtag)
380 {
381 	if (up_table) {
382 		uint8 *pktdata;
383 		uint pktlen;
384 		uint8 dscp;
385 		uint user_priority = 0;
386 		uint rc = 0;
387 
388 		pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
389 		pktlen = (uint)PKTLEN(OSH_NULL, pkt);
390 
391 		if (pktgetdscp(pktdata, pktlen, &dscp)) {
392 			rc = PKTPRIO_DSCP;
393 			user_priority = dscp2up(up_table, dscp);
394 			PKTSETPRIO(pkt, (int)user_priority);
395 		}
396 
397 		return (rc | user_priority);
398 	} else {
399 		return pktsetprio(pkt, update_vtag);
400 	}
401 }
402 
403 /* Returns TRUE and DSCP if IP header found, FALSE otherwise.
404  */
405 bool BCMFASTPATH
pktgetdscp(uint8 * pktdata,uint pktlen,uint8 * dscp)406 pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp)
407 {
408 	struct ether_header *eh;
409 	struct ethervlan_header *evh;
410 	uint8 *ip_body;
411 	bool rc = FALSE;
412 
413 	/* minimum length is ether header and IP header */
414 	if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN)
415 		return FALSE;
416 
417 	eh = (struct ether_header *) pktdata;
418 
419 	if (eh->ether_type == HTON16(ETHER_TYPE_IP)) {
420 		ip_body = pktdata + sizeof(struct ether_header);
421 		*dscp = (uint8)IP_DSCP46(ip_body);
422 		rc = TRUE;
423 	}
424 	else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) {
425 		evh = (struct ethervlan_header *)eh;
426 
427 		/* minimum length is ethervlan header and IP header */
428 		if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN &&
429 			evh->ether_type == HTON16(ETHER_TYPE_IP)) {
430 			ip_body = pktdata + sizeof(struct ethervlan_header);
431 			*dscp = (uint8)IP_DSCP46(ip_body);
432 			rc = TRUE;
433 		}
434 	}
435 
436 	return rc;
437 }
438 
439 /* usr_prio range from low to high with usr_prio value */
440 static bool
up_table_set(uint8 * up_table,uint8 usr_prio,uint8 low,uint8 high)441 up_table_set(uint8 *up_table, uint8 usr_prio, uint8 low, uint8 high)
442 {
443 	int i;
444 
445 	if (usr_prio > 7 || low > high || low >= UP_TABLE_MAX || high >= UP_TABLE_MAX) {
446 		return FALSE;
447 	}
448 
449 	for (i = low; i <= high; i++) {
450 		up_table[i] = usr_prio;
451 	}
452 
453 	return TRUE;
454 }
455 
456 /* set user priority table */
457 int BCMFASTPATH
wl_set_up_table(uint8 * up_table,bcm_tlv_t * qos_map_ie)458 wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie)
459 {
460 	uint8 len;
461 
462 	if (up_table == NULL || qos_map_ie == NULL) {
463 		return BCME_ERROR;
464 	}
465 
466 	/* clear table to check table was set or not */
467 	memset(up_table, 0xff, UP_TABLE_MAX);
468 
469 	/* length of QoS Map IE must be 16+n*2, n is number of exceptions */
470 	if (qos_map_ie != NULL && qos_map_ie->id == DOT11_MNG_QOS_MAP_ID &&
471 			(len = qos_map_ie->len) >= QOS_MAP_FIXED_LENGTH &&
472 			(len % 2) == 0) {
473 		uint8 *except_ptr = (uint8 *)qos_map_ie->data;
474 		uint8 except_len = len - QOS_MAP_FIXED_LENGTH;
475 		uint8 *range_ptr = except_ptr + except_len;
476 		uint8 i;
477 
478 		/* fill in ranges */
479 		for (i = 0; i < QOS_MAP_FIXED_LENGTH; i += 2) {
480 			uint8 low = range_ptr[i];
481 			uint8 high = range_ptr[i + 1];
482 			if (low == 255 && high == 255) {
483 				continue;
484 			}
485 
486 			if (!up_table_set(up_table, i / 2, low, high)) {
487 				/* clear the table on failure */
488 				memset(up_table, 0xff, UP_TABLE_MAX);
489 				return BCME_ERROR;
490 			}
491 		}
492 
493 		/* update exceptions */
494 		for (i = 0; i < except_len; i += 2) {
495 			uint8 dscp = except_ptr[i];
496 			uint8 usr_prio = except_ptr[i+1];
497 
498 			/* exceptions with invalid dscp/usr_prio are ignored */
499 			up_table_set(up_table, usr_prio, dscp, dscp);
500 		}
501 	}
502 
503 	return BCME_OK;
504 }
505 
506 /* The 0.5KB string table is not removed by compiler even though it's unused */
507 
508 static char bcm_undeferrstr[32];
509 static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
510 
511 /* Convert the error codes into related error strings  */
512 const char *
BCMRAMFN(bcmerrorstr)513 BCMRAMFN(bcmerrorstr)(int bcmerror)
514 {
515 	/* check if someone added a bcmerror code but forgot to add errorstring */
516 	ASSERT((uint)ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
517 
518 	if (bcmerror > 0 || bcmerror < BCME_LAST) {
519 		snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
520 		return bcm_undeferrstr;
521 	}
522 
523 	ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
524 
525 	return bcmerrorstrtable[-bcmerror];
526 }
527 
528 /* iovar table lookup */
529 /* could mandate sorted tables and do a binary search */
530 const bcm_iovar_t*
bcm_iovar_lookup(const bcm_iovar_t * table,const char * name)531 bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
532 {
533 	const bcm_iovar_t *vi;
534 	const char *lookup_name;
535 
536 	/* skip any ':' delimited option prefixes */
537 	lookup_name = strrchr(name, ':');
538 	if (lookup_name != NULL)
539 		lookup_name++;
540 	else
541 		lookup_name = name;
542 
543 	ASSERT(table != NULL);
544 
545 	for (vi = table; vi->name; vi++) {
546 		if (!strcmp(vi->name, lookup_name))
547 			return vi;
548 	}
549 	/* ran to end of table */
550 
551 	return NULL; /* var name not found */
552 }
553 
554 int
bcm_iovar_lencheck(const bcm_iovar_t * vi,void * arg,int len,bool set)555 bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
556 {
557 	int bcmerror = 0;
558 	BCM_REFERENCE(arg);
559 
560 	/* length check on io buf */
561 	switch (vi->type) {
562 	case IOVT_BOOL:
563 	case IOVT_INT8:
564 	case IOVT_INT16:
565 	case IOVT_INT32:
566 	case IOVT_UINT8:
567 	case IOVT_UINT16:
568 	case IOVT_UINT32:
569 		/* all integers are int32 sized args at the ioctl interface */
570 		if (len < (int)sizeof(int)) {
571 			bcmerror = BCME_BUFTOOSHORT;
572 		}
573 		break;
574 
575 	case IOVT_BUFFER:
576 		/* buffer must meet minimum length requirement */
577 		if (len < vi->minlen) {
578 			bcmerror = BCME_BUFTOOSHORT;
579 		}
580 		break;
581 
582 	case IOVT_VOID:
583 		if (!set) {
584 			/* Cannot return nil... */
585 			bcmerror = BCME_UNSUPPORTED;
586 		}
587 		break;
588 
589 	default:
590 		/* unknown type for length check in iovar info */
591 		ASSERT(0);
592 		bcmerror = BCME_UNSUPPORTED;
593 	}
594 
595 	return bcmerror;
596 }
597 
598 #if !defined(_CFEZ_)
599 /*
600  * Hierarchical Multiword bitmap based small id allocator.
601  *
602  * Multilevel hierarchy bitmap. (maximum 2 levels)
603  * First hierarchy uses a multiword bitmap to identify 32bit words in the
604  * second hierarchy that have at least a single bit set. Each bit in a word of
605  * the second hierarchy represents a unique ID that may be allocated.
606  *
607  * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed.
608  * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word
609  * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs.
610  * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non
611  *                       non-zero bitmap word carrying at least one free ID.
612  * BCM_MWBMAP_SHIFT_OP:  Used in MOD, DIV and MUL operations.
613  * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID
614  *
615  * Design Notes:
616  * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many
617  * bits are computed each time on allocation and deallocation, requiring 4
618  * array indexed access and 3 arithmetic operations. When not defined, a runtime
619  * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed.
620  * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation.
621  * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may
622  * be used by defining BCM_MWBMAP_USE_CNTSETBITS.
623  *
624  * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array
625  * size is fixed. No intention to support larger than 4K indice allocation. ID
626  * allocators for ranges smaller than 4K will have a wastage of only 12Bytes
627  * with savings in not having to use an indirect access, had it been dynamically
628  * allocated.
629  */
630 #define BCM_MWBMAP_ITEMS_MAX    (64 * 1024)  /* May increase to 64K */
631 
632 #define BCM_MWBMAP_BITS_WORD    (NBITS(uint32))
633 #define BCM_MWBMAP_WORDS_MAX    (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD)
634 #define BCM_MWBMAP_WDMAP_MAX    (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD)
635 #define BCM_MWBMAP_SHIFT_OP     (5)
636 #define BCM_MWBMAP_MODOP(ix)    ((ix) & (BCM_MWBMAP_BITS_WORD - 1))
637 #define BCM_MWBMAP_DIVOP(ix)    ((ix) >> BCM_MWBMAP_SHIFT_OP)
638 #define BCM_MWBMAP_MULOP(ix)    ((ix) << BCM_MWBMAP_SHIFT_OP)
639 
640 /* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */
641 #define BCM_MWBMAP_PTR(hdl)		((struct bcm_mwbmap *)(hdl))
642 #define BCM_MWBMAP_HDL(ptr)		((void *)(ptr))
643 
644 #if defined(BCM_MWBMAP_DEBUG)
645 #define BCM_MWBMAP_AUDIT(mwb) \
646 	do { \
647 		ASSERT((mwb != NULL) && \
648 		       (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \
649 		bcm_mwbmap_audit(mwb); \
650 	} while (0)
651 #define MWBMAP_ASSERT(exp)		ASSERT(exp)
652 #define MWBMAP_DBG(x)           printf x
653 #else   /* !BCM_MWBMAP_DEBUG */
654 #define BCM_MWBMAP_AUDIT(mwb)   do {} while (0)
655 #define MWBMAP_ASSERT(exp)		do {} while (0)
656 #define MWBMAP_DBG(x)
657 #endif  /* !BCM_MWBMAP_DEBUG */
658 
659 typedef struct bcm_mwbmap {     /* Hierarchical multiword bitmap allocator    */
660 	uint16 wmaps;               /* Total number of words in free wd bitmap    */
661 	uint16 imaps;               /* Total number of words in free id bitmap    */
662 	int32  ifree;               /* Count of free indices. Used only in audits */
663 	uint16 total;               /* Total indices managed by multiword bitmap  */
664 
665 	void * magic;               /* Audit handle parameter from user           */
666 
667 	uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of            */
668 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
669 	int8   wd_count[BCM_MWBMAP_WORDS_MAX];  /* free id running count, 1st lvl */
670 #endif /*  ! BCM_MWBMAP_USE_CNTSETBITS */
671 
672 	uint32 id_bitmap[0];        /* Second level bitmap                        */
673 } bcm_mwbmap_t;
674 
675 /* Incarnate a hierarchical multiword bitmap based small index allocator. */
676 struct bcm_mwbmap *
bcm_mwbmap_init(osl_t * osh,uint32 items_max)677 bcm_mwbmap_init(osl_t *osh, uint32 items_max)
678 {
679 	struct bcm_mwbmap * mwbmap_p;
680 	uint32 wordix, size, words, extra;
681 
682 	/* Implementation Constraint: Uses 32bit word bitmap */
683 	MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U);
684 	MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U);
685 	MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX));
686 	MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U);
687 
688 	ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX);
689 
690 	/* Determine the number of words needed in the multiword bitmap */
691 	extra = BCM_MWBMAP_MODOP(items_max);
692 	words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U);
693 
694 	/* Allocate runtime state of multiword bitmap */
695 	/* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */
696 	size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words);
697 	mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size);
698 	if (mwbmap_p == (bcm_mwbmap_t *)NULL) {
699 		ASSERT(0);
700 		goto error1;
701 	}
702 	memset(mwbmap_p, 0, size);
703 
704 	/* Initialize runtime multiword bitmap state */
705 	mwbmap_p->imaps = (uint16)words;
706 	mwbmap_p->ifree = (int32)items_max;
707 	mwbmap_p->total = (uint16)items_max;
708 
709 	/* Setup magic, for use in audit of handle */
710 	mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p);
711 
712 	/* Setup the second level bitmap of free indices */
713 	/* Mark all indices as available */
714 	for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) {
715 		mwbmap_p->id_bitmap[wordix] = (uint32)(~0U);
716 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
717 		mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD;
718 #endif /*  ! BCM_MWBMAP_USE_CNTSETBITS */
719 	}
720 
721 	/* Ensure that extra indices are tagged as un-available */
722 	if (extra) { /* fixup the free ids in last bitmap and wd_count */
723 		uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1];
724 		*bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
725 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
726 		mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */
727 #endif /*  ! BCM_MWBMAP_USE_CNTSETBITS */
728 	}
729 
730 	/* Setup the first level bitmap hierarchy */
731 	extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps);
732 	words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U);
733 
734 	mwbmap_p->wmaps = (uint16)words;
735 
736 	for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++)
737 		mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U);
738 	if (extra) {
739 		uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1];
740 		*bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */
741 	}
742 
743 	return mwbmap_p;
744 
745 error1:
746 	return BCM_MWBMAP_INVALID_HDL;
747 }
748 
749 /* Release resources used by multiword bitmap based small index allocator. */
750 void
bcm_mwbmap_fini(osl_t * osh,struct bcm_mwbmap * mwbmap_hdl)751 bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl)
752 {
753 	bcm_mwbmap_t * mwbmap_p;
754 
755 	BCM_MWBMAP_AUDIT(mwbmap_hdl);
756 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
757 
758 	MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap)
759 			     + (sizeof(uint32) * mwbmap_p->imaps));
760 	return;
761 }
762 
763 /* Allocate a unique small index using a multiword bitmap index allocator.    */
764 uint32 BCMFASTPATH
bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl)765 bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl)
766 {
767 	bcm_mwbmap_t * mwbmap_p;
768 	uint32 wordix, bitmap;
769 
770 	BCM_MWBMAP_AUDIT(mwbmap_hdl);
771 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
772 
773 	/* Start with the first hierarchy */
774 	for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) {
775 
776 		bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */
777 
778 		if (bitmap != 0U) {
779 
780 			uint32 count, bitix, *bitmap_p;
781 
782 			bitmap_p = &mwbmap_p->wd_bitmap[wordix];
783 
784 			/* clear all except trailing 1 */
785 			bitmap   = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
786 			MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
787 			              bcm_count_leading_zeros(bitmap));
788 			bitix    = (BCM_MWBMAP_BITS_WORD - 1)
789 				 - (uint32)bcm_count_leading_zeros(bitmap); /* use asm clz */
790 			wordix   = BCM_MWBMAP_MULOP(wordix) + bitix;
791 
792 			/* Clear bit if wd count is 0, without conditional branch */
793 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
794 			count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1;
795 #else  /* ! BCM_MWBMAP_USE_CNTSETBITS */
796 			mwbmap_p->wd_count[wordix]--;
797 			count = (uint32)mwbmap_p->wd_count[wordix];
798 			MWBMAP_ASSERT(count ==
799 			              (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1));
800 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
801 			MWBMAP_ASSERT(count >= 0);
802 
803 			/* clear wd_bitmap bit if id_map count is 0 */
804 			bitmap = ((uint32)(count == 0)) << BCM_MWBMAP_MODOP(bitix);
805 
806 			MWBMAP_DBG((
807 			    "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
808 			    bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count));
809 
810 			*bitmap_p ^= bitmap;
811 
812 			/* Use bitix in the second hierarchy */
813 			bitmap_p = &mwbmap_p->id_bitmap[wordix];
814 
815 			bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */
816 			MWBMAP_ASSERT(bitmap != 0U);
817 
818 			/* clear all except trailing 1 */
819 			bitmap   = (uint32)(((int)(bitmap)) & (-((int)(bitmap))));
820 			MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) ==
821 			              bcm_count_leading_zeros(bitmap));
822 			bitix    = BCM_MWBMAP_MULOP(wordix)
823 				 + (BCM_MWBMAP_BITS_WORD - 1)
824 				 - (uint32)bcm_count_leading_zeros(bitmap); /* use asm clz */
825 
826 			mwbmap_p->ifree--; /* decrement system wide free count */
827 			MWBMAP_ASSERT(mwbmap_p->ifree >= 0);
828 
829 			MWBMAP_DBG((
830 			    "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d",
831 			    bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
832 			    mwbmap_p->ifree));
833 
834 			*bitmap_p ^= bitmap; /* mark as allocated = 1b0 */
835 
836 			return bitix;
837 		}
838 	}
839 
840 	ASSERT(mwbmap_p->ifree == 0);
841 
842 	return BCM_MWBMAP_INVALID_IDX;
843 }
844 
845 /* Force an index at a specified position to be in use */
846 void
bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl,uint32 bitix)847 bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
848 {
849 	bcm_mwbmap_t * mwbmap_p;
850 	uint32 count, wordix, bitmap, *bitmap_p;
851 
852 	BCM_MWBMAP_AUDIT(mwbmap_hdl);
853 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
854 
855 	ASSERT(bitix < mwbmap_p->total);
856 
857 	/* Start with second hierarchy */
858 	wordix   = BCM_MWBMAP_DIVOP(bitix);
859 	bitmap   = (uint32)(1U << BCM_MWBMAP_MODOP(bitix));
860 	bitmap_p = &mwbmap_p->id_bitmap[wordix];
861 
862 	ASSERT((*bitmap_p & bitmap) == bitmap);
863 
864 	mwbmap_p->ifree--; /* update free count */
865 	ASSERT(mwbmap_p->ifree >= 0);
866 
867 	MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d",
868 	            bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap,
869 	            mwbmap_p->ifree));
870 
871 	*bitmap_p ^= bitmap; /* mark as in use */
872 
873 	/* Update first hierarchy */
874 	bitix    = wordix;
875 
876 	wordix   = BCM_MWBMAP_DIVOP(bitix);
877 	bitmap_p = &mwbmap_p->wd_bitmap[wordix];
878 
879 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
880 	count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
881 #else  /* ! BCM_MWBMAP_USE_CNTSETBITS */
882 	mwbmap_p->wd_count[bitix]--;
883 	count = (uint32)mwbmap_p->wd_count[bitix];
884 	MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
885 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
886 	MWBMAP_ASSERT(count >= 0);
887 
888 	bitmap   = (uint32)(count == 0) << BCM_MWBMAP_MODOP(bitix);
889 
890 	MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d",
891 	            BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap,
892 	            (*bitmap_p) ^ bitmap, count));
893 
894 	*bitmap_p ^= bitmap; /* mark as in use */
895 
896 	return;
897 }
898 
899 /* Free a previously allocated index back into the multiword bitmap allocator */
900 void BCMFASTPATH
bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl,uint32 bitix)901 bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
902 {
903 	bcm_mwbmap_t * mwbmap_p;
904 	uint32 wordix, bitmap, *bitmap_p;
905 
906 	BCM_MWBMAP_AUDIT(mwbmap_hdl);
907 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
908 
909 	ASSERT(bitix < mwbmap_p->total);
910 
911 	/* Start with second level hierarchy */
912 	wordix   = BCM_MWBMAP_DIVOP(bitix);
913 	bitmap   = (1U << BCM_MWBMAP_MODOP(bitix));
914 	bitmap_p = &mwbmap_p->id_bitmap[wordix];
915 
916 	ASSERT((*bitmap_p & bitmap) == 0U);	/* ASSERT not a double free */
917 
918 	mwbmap_p->ifree++; /* update free count */
919 	ASSERT(mwbmap_p->ifree <= mwbmap_p->total);
920 
921 	MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d",
922 	            bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap,
923 	            mwbmap_p->ifree));
924 
925 	*bitmap_p |= bitmap; /* mark as available */
926 
927 	/* Now update first level hierarchy */
928 
929 	bitix    = wordix;
930 
931 	wordix   = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */
932 	bitmap   = (1U << BCM_MWBMAP_MODOP(bitix));
933 	bitmap_p = &mwbmap_p->wd_bitmap[wordix];
934 
935 #if !defined(BCM_MWBMAP_USE_CNTSETBITS)
936 	mwbmap_p->wd_count[bitix]++;
937 #endif // endif
938 
939 #if defined(BCM_MWBMAP_DEBUG)
940 	{
941 		uint32 count;
942 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
943 		count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]);
944 #else  /*  ! BCM_MWBMAP_USE_CNTSETBITS */
945 		count = mwbmap_p->wd_count[bitix];
946 		MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]));
947 #endif /*  ! BCM_MWBMAP_USE_CNTSETBITS */
948 
949 		MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD);
950 
951 		MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d",
952 		            bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count));
953 	}
954 #endif /* BCM_MWBMAP_DEBUG */
955 
956 	*bitmap_p |= bitmap;
957 
958 	return;
959 }
960 
961 /* Fetch the toal number of free indices in the multiword bitmap allocator */
962 uint32
bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl)963 bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl)
964 {
965 	bcm_mwbmap_t * mwbmap_p;
966 
967 	BCM_MWBMAP_AUDIT(mwbmap_hdl);
968 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
969 
970 	ASSERT(mwbmap_p->ifree >= 0);
971 
972 	return (uint32)mwbmap_p->ifree;
973 }
974 
975 /* Determine whether an index is inuse or free */
976 bool
bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl,uint32 bitix)977 bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix)
978 {
979 	bcm_mwbmap_t * mwbmap_p;
980 	uint32 wordix, bitmap;
981 
982 	BCM_MWBMAP_AUDIT(mwbmap_hdl);
983 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
984 
985 	ASSERT(bitix < mwbmap_p->total);
986 
987 	wordix   = BCM_MWBMAP_DIVOP(bitix);
988 	bitmap   = (1U << BCM_MWBMAP_MODOP(bitix));
989 
990 	return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U);
991 }
992 
993 /* Debug dump a multiword bitmap allocator */
994 void
bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl)995 bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl)
996 {
997 	uint32 ix, count;
998 	bcm_mwbmap_t * mwbmap_p;
999 
1000 	BCM_MWBMAP_AUDIT(mwbmap_hdl);
1001 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
1002 
1003 	printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n",
1004 		OSL_OBFUSCATE_BUF((void *)mwbmap_p),
1005 	       mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total);
1006 	for (ix = 0U; ix < mwbmap_p->wmaps; ix++) {
1007 		printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]);
1008 		bcm_bitprint32(mwbmap_p->wd_bitmap[ix]);
1009 		printf("\n");
1010 	}
1011 	for (ix = 0U; ix < mwbmap_p->imaps; ix++) {
1012 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
1013 		count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]);
1014 #else  /* ! BCM_MWBMAP_USE_CNTSETBITS */
1015 		count = (uint32)mwbmap_p->wd_count[ix];
1016 		MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix]));
1017 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
1018 		printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count);
1019 		bcm_bitprint32(mwbmap_p->id_bitmap[ix]);
1020 		printf("\n");
1021 	}
1022 
1023 	return;
1024 }
1025 
1026 /* Audit a hierarchical multiword bitmap */
1027 void
bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)1028 bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl)
1029 {
1030 	bcm_mwbmap_t * mwbmap_p;
1031 	uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p;
1032 
1033 	mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl);
1034 
1035 	for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) {
1036 
1037 		bitmap_p = &mwbmap_p->wd_bitmap[wordix];
1038 
1039 		for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) {
1040 			if ((*bitmap_p) & (1 << bitix)) {
1041 				idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix;
1042 #if defined(BCM_MWBMAP_USE_CNTSETBITS)
1043 				count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]);
1044 #else  /* ! BCM_MWBMAP_USE_CNTSETBITS */
1045 				count = (uint32)mwbmap_p->wd_count[idmap_ix];
1046 				ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]));
1047 #endif /* ! BCM_MWBMAP_USE_CNTSETBITS */
1048 				ASSERT(count != 0U);
1049 				free_cnt += count;
1050 			}
1051 		}
1052 	}
1053 
1054 	ASSERT((int)free_cnt == mwbmap_p->ifree);
1055 }
1056 /* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
1057 
1058 /* Simple 16bit Id allocator using a stack implementation. */
1059 typedef struct id16_map {
1060 	uint32  failures;  /* count of failures */
1061 	void    *dbg;      /* debug placeholder */
1062 	uint16  total;     /* total number of ids managed by allocator */
1063 	uint16  start;     /* start value of 16bit ids to be managed */
1064 	int     stack_idx; /* index into stack of available ids */
1065 	uint16  stack[0];  /* stack of 16 bit ids */
1066 } id16_map_t;
1067 
1068 #define ID16_MAP_SZ(items)      (sizeof(id16_map_t) + \
1069 				     (sizeof(uint16) * (items)))
1070 
1071 #if defined(BCM_DBG)
1072 
1073 /* Uncomment BCM_DBG_ID16 to debug double free */
1074 /* #define BCM_DBG_ID16 */
1075 
1076 typedef struct id16_map_dbg {
1077 	uint16  total;
1078 	bool    avail[0];
1079 } id16_map_dbg_t;
1080 #define ID16_MAP_DBG_SZ(items)  (sizeof(id16_map_dbg_t) + \
1081 				     (sizeof(bool) * (items)))
1082 #define ID16_MAP_MSG(x)         print x
1083 #else
1084 #define ID16_MAP_MSG(x)
1085 #endif /* BCM_DBG */
1086 
1087 void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */
id16_map_init(osl_t * osh,uint16 total_ids,uint16 start_val16)1088 id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16)
1089 {
1090 	uint16 idx, val16;
1091 	id16_map_t * id16_map;
1092 
1093 	ASSERT(total_ids > 0);
1094 
1095 	/* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
1096 	 * with random values.
1097 	 */
1098 	ASSERT((start_val16 == ID16_UNDEFINED) ||
1099 	       (start_val16 + total_ids) < ID16_INVALID);
1100 
1101 	id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids));
1102 	if (id16_map == NULL) {
1103 		return NULL;
1104 	}
1105 
1106 	id16_map->total = total_ids;
1107 	id16_map->start = start_val16;
1108 	id16_map->failures = 0;
1109 	id16_map->dbg = NULL;
1110 
1111 	/*
1112 	 * Populate stack with 16bit id values, commencing with start_val16.
1113 	 * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map.
1114 	 */
1115 	id16_map->stack_idx = -1;
1116 
1117 	if (id16_map->start != ID16_UNDEFINED) {
1118 		val16 = start_val16;
1119 
1120 		for (idx = 0; idx < total_ids; idx++, val16++) {
1121 			id16_map->stack_idx = idx;
1122 			id16_map->stack[id16_map->stack_idx] = val16;
1123 		}
1124 	}
1125 
1126 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1127 	if (id16_map->start != ID16_UNDEFINED) {
1128 		id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids));
1129 
1130 		if (id16_map->dbg) {
1131 			id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
1132 
1133 			id16_map_dbg->total = total_ids;
1134 			for (idx = 0; idx < total_ids; idx++) {
1135 				id16_map_dbg->avail[idx] = TRUE;
1136 			}
1137 		}
1138 	}
1139 #endif /* BCM_DBG && BCM_DBG_ID16 */
1140 
1141 	return (void *)id16_map;
1142 }
1143 
1144 void * /* Destruct an id16 allocator instance */
id16_map_fini(osl_t * osh,void * id16_map_hndl)1145 id16_map_fini(osl_t *osh, void * id16_map_hndl)
1146 {
1147 	uint16 total_ids;
1148 	id16_map_t * id16_map;
1149 
1150 	if (id16_map_hndl == NULL)
1151 		return NULL;
1152 
1153 	id16_map = (id16_map_t *)id16_map_hndl;
1154 
1155 	total_ids = id16_map->total;
1156 	ASSERT(total_ids > 0);
1157 
1158 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1159 	if (id16_map->dbg) {
1160 		MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids));
1161 		id16_map->dbg = NULL;
1162 	}
1163 #endif /* BCM_DBG && BCM_DBG_ID16 */
1164 
1165 	id16_map->total = 0;
1166 	MFREE(osh, id16_map, ID16_MAP_SZ(total_ids));
1167 
1168 	return NULL;
1169 }
1170 
1171 void
id16_map_clear(void * id16_map_hndl,uint16 total_ids,uint16 start_val16)1172 id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16)
1173 {
1174 	uint16 idx, val16;
1175 	id16_map_t * id16_map;
1176 
1177 	ASSERT(total_ids > 0);
1178 	/* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map
1179 	 * with random values.
1180 	 */
1181 	ASSERT((start_val16 == ID16_UNDEFINED) ||
1182 	       (start_val16 + total_ids) < ID16_INVALID);
1183 
1184 	id16_map = (id16_map_t *)id16_map_hndl;
1185 	if (id16_map == NULL) {
1186 		return;
1187 	}
1188 
1189 	id16_map->total = total_ids;
1190 	id16_map->start = start_val16;
1191 	id16_map->failures = 0;
1192 
1193 	/* Populate stack with 16bit id values, commencing with start_val16 */
1194 	id16_map->stack_idx = -1;
1195 
1196 	if (id16_map->start != ID16_UNDEFINED) {
1197 		val16 = start_val16;
1198 
1199 		for (idx = 0; idx < total_ids; idx++, val16++) {
1200 			id16_map->stack_idx = idx;
1201 			id16_map->stack[id16_map->stack_idx] = val16;
1202 		}
1203 	}
1204 
1205 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1206 	if (id16_map->start != ID16_UNDEFINED) {
1207 		if (id16_map->dbg) {
1208 			id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
1209 
1210 			id16_map_dbg->total = total_ids;
1211 			for (idx = 0; idx < total_ids; idx++) {
1212 				id16_map_dbg->avail[idx] = TRUE;
1213 			}
1214 		}
1215 	}
1216 #endif /* BCM_DBG && BCM_DBG_ID16 */
1217 }
1218 
1219 uint16 BCMFASTPATH /* Allocate a unique 16bit id */
id16_map_alloc(void * id16_map_hndl)1220 id16_map_alloc(void * id16_map_hndl)
1221 {
1222 	uint16 val16;
1223 	id16_map_t * id16_map;
1224 
1225 	ASSERT(id16_map_hndl != NULL);
1226 	if (!id16_map_hndl) {
1227 		return ID16_INVALID;
1228 	}
1229 	id16_map = (id16_map_t *)id16_map_hndl;
1230 
1231 	ASSERT(id16_map->total > 0);
1232 
1233 	if (id16_map->stack_idx < 0) {
1234 		id16_map->failures++;
1235 		return ID16_INVALID;
1236 	}
1237 
1238 	val16 = id16_map->stack[id16_map->stack_idx];
1239 	id16_map->stack_idx--;
1240 
1241 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1242 	ASSERT((id16_map->start == ID16_UNDEFINED) ||
1243 	       (val16 < (id16_map->start + id16_map->total)));
1244 
1245 	if (id16_map->dbg) { /* Validate val16 */
1246 		id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
1247 
1248 		ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE);
1249 		id16_map_dbg->avail[val16 - id16_map->start] = FALSE;
1250 	}
1251 #endif /* BCM_DBG && BCM_DBG_ID16 */
1252 
1253 	return val16;
1254 }
1255 
1256 void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */
id16_map_free(void * id16_map_hndl,uint16 val16)1257 id16_map_free(void * id16_map_hndl, uint16 val16)
1258 {
1259 	id16_map_t * id16_map;
1260 
1261 	ASSERT(id16_map_hndl != NULL);
1262 
1263 	id16_map = (id16_map_t *)id16_map_hndl;
1264 
1265 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1266 	ASSERT((id16_map->start == ID16_UNDEFINED) ||
1267 	       (val16 < (id16_map->start + id16_map->total)));
1268 
1269 	if (id16_map->dbg) { /* Validate val16 */
1270 		id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
1271 
1272 		ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE);
1273 		id16_map_dbg->avail[val16 - id16_map->start] = TRUE;
1274 	}
1275 #endif /* BCM_DBG && BCM_DBG_ID16 */
1276 
1277 	id16_map->stack_idx++;
1278 	id16_map->stack[id16_map->stack_idx] = val16;
1279 }
1280 
1281 uint32 /* Returns number of failures to allocate an unique id16 */
id16_map_failures(void * id16_map_hndl)1282 id16_map_failures(void * id16_map_hndl)
1283 {
1284 	ASSERT(id16_map_hndl != NULL);
1285 	return ((id16_map_t *)id16_map_hndl)->failures;
1286 }
1287 
1288 bool
id16_map_audit(void * id16_map_hndl)1289 id16_map_audit(void * id16_map_hndl)
1290 {
1291 	int idx;
1292 	int insane = 0;
1293 	id16_map_t * id16_map;
1294 
1295 	ASSERT(id16_map_hndl != NULL);
1296 	if (!id16_map_hndl) {
1297 		goto done;
1298 	}
1299 	id16_map = (id16_map_t *)id16_map_hndl;
1300 
1301 	ASSERT(id16_map->stack_idx >= -1);
1302 	ASSERT(id16_map->stack_idx < (int)id16_map->total);
1303 
1304 	if (id16_map->start == ID16_UNDEFINED)
1305 		goto done;
1306 
1307 	for (idx = 0; idx <= id16_map->stack_idx; idx++) {
1308 		ASSERT(id16_map->stack[idx] >= id16_map->start);
1309 		ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total));
1310 
1311 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1312 		if (id16_map->dbg) {
1313 			uint16 val16 = id16_map->stack[idx];
1314 			if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) {
1315 				insane |= 1;
1316 				ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n",
1317 				              OSL_OBFUSATE_BUF(id16_map_hndl), idx, val16));
1318 			}
1319 		}
1320 #endif /* BCM_DBG && BCM_DBG_ID16 */
1321 	}
1322 
1323 #if defined(BCM_DBG) && defined(BCM_DBG_ID16)
1324 	if (id16_map->dbg) {
1325 		uint16 avail = 0; /* Audit available ids counts */
1326 		for (idx = 0; idx < id16_map_dbg->total; idx++) {
1327 			if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE)
1328 				avail++;
1329 		}
1330 		if (avail && (avail != (id16_map->stack_idx + 1))) {
1331 			insane |= 1;
1332 			ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n",
1333 			              OSL_OBFUSCATE_BUF(id16_map_hndl),
1334 			              avail, id16_map->stack_idx));
1335 		}
1336 	}
1337 #endif /* BCM_DBG && BCM_DBG_ID16 */
1338 
1339 done:
1340 	/* invoke any other system audits */
1341 	return (!!insane);
1342 }
1343 /* END: Simple id16 allocator */
1344 
1345 void
dll_pool_detach(void * osh,dll_pool_t * pool,uint16 elems_max,uint16 elem_size)1346 dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size)
1347 {
1348 	uint32 memsize;
1349 	memsize = sizeof(dll_pool_t) + (elems_max * elem_size);
1350 	if (pool)
1351 		MFREE(osh, pool, memsize);
1352 }
1353 dll_pool_t *
dll_pool_init(void * osh,uint16 elems_max,uint16 elem_size)1354 dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size)
1355 {
1356 	uint32 memsize, i;
1357 	dll_pool_t * dll_pool_p;
1358 	dll_t * elem_p;
1359 
1360 	ASSERT(elem_size > sizeof(dll_t));
1361 
1362 	memsize = sizeof(dll_pool_t) + (elems_max * elem_size);
1363 
1364 	if ((dll_pool_p = (dll_pool_t *)MALLOCZ(osh, memsize)) == NULL) {
1365 		printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n",
1366 			elems_max, elem_size);
1367 		ASSERT(0);
1368 		return dll_pool_p;
1369 	}
1370 
1371 	dll_init(&dll_pool_p->free_list);
1372 	dll_pool_p->elems_max = elems_max;
1373 	dll_pool_p->elem_size = elem_size;
1374 
1375 	elem_p = dll_pool_p->elements;
1376 	for (i = 0; i < elems_max; i++) {
1377 		dll_append(&dll_pool_p->free_list, elem_p);
1378 		elem_p = (dll_t *)((uintptr)elem_p + elem_size);
1379 	}
1380 
1381 	dll_pool_p->free_count = elems_max;
1382 
1383 	return dll_pool_p;
1384 }
1385 
1386 void *
dll_pool_alloc(dll_pool_t * dll_pool_p)1387 dll_pool_alloc(dll_pool_t * dll_pool_p)
1388 {
1389 	dll_t * elem_p;
1390 
1391 	if (dll_pool_p->free_count == 0) {
1392 		ASSERT(dll_empty(&dll_pool_p->free_list));
1393 		return NULL;
1394 	}
1395 
1396 	elem_p = dll_head_p(&dll_pool_p->free_list);
1397 	dll_delete(elem_p);
1398 	dll_pool_p->free_count -= 1;
1399 
1400 	return (void *)elem_p;
1401 }
1402 
1403 void
dll_pool_free(dll_pool_t * dll_pool_p,void * elem_p)1404 dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p)
1405 {
1406 	dll_t * node_p = (dll_t *)elem_p;
1407 	dll_prepend(&dll_pool_p->free_list, node_p);
1408 	dll_pool_p->free_count += 1;
1409 }
1410 
1411 void
dll_pool_free_tail(dll_pool_t * dll_pool_p,void * elem_p)1412 dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p)
1413 {
1414 	dll_t * node_p = (dll_t *)elem_p;
1415 	dll_append(&dll_pool_p->free_list, node_p);
1416 	dll_pool_p->free_count += 1;
1417 }
1418 
1419 #endif // endif
1420 
1421 #endif /* BCMDRIVER */
1422 
1423 #if defined(BCMDRIVER) || defined(WL_UNITTEST)
1424 
1425 /* triggers bcm_bprintf to print to kernel log */
1426 bool bcm_bprintf_bypass = FALSE;
1427 
1428 /* Initialization of bcmstrbuf structure */
1429 void
bcm_binit(struct bcmstrbuf * b,char * buf,uint size)1430 bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1431 {
1432 	b->origsize = b->size = size;
1433 	b->origbuf = b->buf = buf;
1434 	if (size > 0) {
1435 		buf[0] = '\0';
1436 	}
1437 }
1438 
1439 /* Buffer sprintf wrapper to guard against buffer overflow */
1440 int
bcm_bprintf(struct bcmstrbuf * b,const char * fmt,...)1441 bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1442 {
1443 	va_list ap;
1444 	int r;
1445 
1446 	va_start(ap, fmt);
1447 
1448 	r = vsnprintf(b->buf, b->size, fmt, ap);
1449 	if (bcm_bprintf_bypass == TRUE) {
1450 		printf("%s", b->buf);
1451 		goto exit;
1452 	}
1453 
1454 	/* Non Ansi C99 compliant returns -1,
1455 	 * Ansi compliant return r >= b->size,
1456 	 * bcmstdlib returns 0, handle all
1457 	 */
1458 	/* r == 0 is also the case when strlen(fmt) is zero.
1459 	 * typically the case when "" is passed as argument.
1460 	 */
1461 	if ((r == -1) || (r >= (int)b->size)) {
1462 		b->size = 0;
1463 	} else {
1464 		b->size -= (uint)r;
1465 		b->buf += r;
1466 	}
1467 
1468 exit:
1469 	va_end(ap);
1470 
1471 	return r;
1472 }
1473 
1474 void
bcm_bprhex(struct bcmstrbuf * b,const char * msg,bool newline,const uint8 * buf,int len)1475 bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, const uint8 *buf, int len)
1476 {
1477 	int i;
1478 
1479 	if (msg != NULL && msg[0] != '\0')
1480 		bcm_bprintf(b, "%s", msg);
1481 	for (i = 0; i < len; i ++)
1482 		bcm_bprintf(b, "%02X", buf[i]);
1483 	if (newline)
1484 		bcm_bprintf(b, "\n");
1485 }
1486 
1487 void
bcm_inc_bytes(uchar * num,int num_bytes,uint8 amount)1488 bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
1489 {
1490 	int i;
1491 
1492 	for (i = 0; i < num_bytes; i++) {
1493 		num[i] += amount;
1494 		if (num[i] >= amount)
1495 			break;
1496 		amount = 1;
1497 	}
1498 }
1499 
1500 int
bcm_cmp_bytes(const uchar * arg1,const uchar * arg2,uint8 nbytes)1501 bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes)
1502 {
1503 	int i;
1504 
1505 	for (i = nbytes - 1; i >= 0; i--) {
1506 		if (arg1[i] != arg2[i])
1507 			return (arg1[i] - arg2[i]);
1508 	}
1509 	return 0;
1510 }
1511 
1512 void
bcm_print_bytes(const char * name,const uchar * data,int len)1513 bcm_print_bytes(const char *name, const uchar *data, int len)
1514 {
1515 	int i;
1516 	int per_line = 0;
1517 
1518 	printf("%s: %d \n", name ? name : "", len);
1519 	for (i = 0; i < len; i++) {
1520 		printf("%02x ", *data++);
1521 		per_line++;
1522 		if (per_line == 16) {
1523 			per_line = 0;
1524 			printf("\n");
1525 		}
1526 	}
1527 	printf("\n");
1528 }
1529 
1530 /* Look for vendor-specific IE with specified OUI and optional type */
1531 bcm_tlv_t *
bcm_find_vendor_ie(const void * tlvs,uint tlvs_len,const char * voui,uint8 * type,uint type_len)1532 bcm_find_vendor_ie(const  void *tlvs, uint tlvs_len, const char *voui, uint8 *type, uint type_len)
1533 {
1534 	const  bcm_tlv_t *ie;
1535 	uint8 ie_len;
1536 
1537 	ie = (const  bcm_tlv_t*)tlvs;
1538 
1539 	/* make sure we are looking at a valid IE */
1540 	if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) {
1541 		return NULL;
1542 	}
1543 
1544 	/* Walk through the IEs looking for an OUI match */
1545 	do {
1546 		ie_len = ie->len;
1547 		if ((ie->id == DOT11_MNG_VS_ID) &&
1548 		    (ie_len >= (DOT11_OUI_LEN + type_len)) &&
1549 		    !bcmp(ie->data, voui, DOT11_OUI_LEN))
1550 		{
1551 			/* compare optional type */
1552 			if (type_len == 0 ||
1553 			    !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) {
1554 				GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1555 				return (bcm_tlv_t *)(ie);		/* a match */
1556 				GCC_DIAGNOSTIC_POP();
1557 			}
1558 		}
1559 	} while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL);
1560 
1561 	return NULL;
1562 }
1563 
1564 #if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
1565 	defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
1566 #define SSID_FMT_BUF_LEN	((4 * DOT11_MAX_SSID_LEN) + 1)
1567 
1568 int
bcm_format_ssid(char * buf,const uchar ssid[],uint ssid_len)1569 bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
1570 {
1571 	uint i, c;
1572 	char *p = buf;
1573 	char *endp = buf + SSID_FMT_BUF_LEN;
1574 
1575 	if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
1576 
1577 	for (i = 0; i < ssid_len; i++) {
1578 		c = (uint)ssid[i];
1579 		if (c == '\\') {
1580 			*p++ = '\\';
1581 			*p++ = '\\';
1582 		} else if (bcm_isprint((uchar)c)) {
1583 			*p++ = (char)c;
1584 		} else {
1585 			p += snprintf(p, (size_t)(endp - p), "\\x%02X", c);
1586 		}
1587 	}
1588 	*p = '\0';
1589 	ASSERT(p < endp);
1590 
1591 	return (int)(p - buf);
1592 }
1593 #endif // endif
1594 
1595 #endif /* BCMDRIVER || WL_UNITTEST */
1596 
1597 char *
bcm_ether_ntoa(const struct ether_addr * ea,char * buf)1598 bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
1599 {
1600 	static const char hex[] =
1601 	  {
1602 		  '0', '1', '2', '3', '4', '5', '6', '7',
1603 		  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
1604 	  };
1605 	const uint8 *octet = ea->octet;
1606 	char *p = buf;
1607 	int i;
1608 
1609 	for (i = 0; i < 6; i++, octet++) {
1610 		*p++ = hex[(*octet >> 4) & 0xf];
1611 		*p++ = hex[*octet & 0xf];
1612 		*p++ = ':';
1613 	}
1614 
1615 	*(p-1) = '\0';
1616 
1617 	return (buf);
1618 }
1619 
1620 /* Find the position of first bit set
1621  * in the given number.
1622  */
1623 int
bcm_find_fsb(uint32 num)1624 bcm_find_fsb(uint32 num)
1625 {
1626 	uint8 pos = 0;
1627 	if (!num)
1628 		return pos;
1629 	while (!(num & 1)) {
1630 		num >>= 1;
1631 		pos++;
1632 	}
1633 	return (pos+1);
1634 }
1635 
1636 char *
bcm_ip_ntoa(struct ipv4_addr * ia,char * buf)1637 bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
1638 {
1639 	snprintf(buf, 16, "%d.%d.%d.%d",
1640 	         ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
1641 	return (buf);
1642 }
1643 
1644 char *
bcm_ipv6_ntoa(void * ipv6,char * buf)1645 bcm_ipv6_ntoa(void *ipv6, char *buf)
1646 {
1647 	/* Implementing RFC 5952 Sections 4 + 5 */
1648 	/* Not thoroughly tested */
1649 	uint16 tmp[8];
1650 	uint16 *a = &tmp[0];
1651 	char *p = buf;
1652 	int i, i_max = -1, cnt = 0, cnt_max = 1;
1653 	uint8 *a4 = NULL;
1654 	memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN);
1655 
1656 	for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
1657 		if (a[i]) {
1658 			if (cnt > cnt_max) {
1659 				cnt_max = cnt;
1660 				i_max = i - cnt;
1661 			}
1662 			cnt = 0;
1663 		} else
1664 			cnt++;
1665 	}
1666 	if (cnt > cnt_max) {
1667 		cnt_max = cnt;
1668 		i_max = i - cnt;
1669 	}
1670 	if (i_max == 0 &&
1671 		/* IPv4-translated: ::ffff:0:a.b.c.d */
1672 		((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) ||
1673 		/* IPv4-mapped: ::ffff:a.b.c.d */
1674 		(cnt_max == 5 && a[5] == 0xffff)))
1675 		a4 = (uint8*) (a + 6);
1676 
1677 	for (i = 0; i < IPV6_ADDR_LEN/2; i++) {
1678 		if ((uint8*) (a + i) == a4) {
1679 			snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]);
1680 			break;
1681 		} else if (i == i_max) {
1682 			*p++ = ':';
1683 			i += cnt_max - 1;
1684 			p[0] = ':';
1685 			p[1] = '\0';
1686 		} else {
1687 			if (i)
1688 				*p++ = ':';
1689 			p += snprintf(p, 8, "%x", ntoh16(a[i]));
1690 		}
1691 	}
1692 
1693 	return buf;
1694 }
1695 
1696 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
1697 const unsigned char bcm_ctype[] = {
1698 
1699 	_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,			/* 0-7 */
1700 	_BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
1701 	_BCM_C,	/* 8-15 */
1702 	_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,			/* 16-23 */
1703 	_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,			/* 24-31 */
1704 	_BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,		/* 32-39 */
1705 	_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,			/* 40-47 */
1706 	_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,			/* 48-55 */
1707 	_BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,			/* 56-63 */
1708 	_BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
1709 	_BCM_U|_BCM_X, _BCM_U, /* 64-71 */
1710 	_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,			/* 72-79 */
1711 	_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,			/* 80-87 */
1712 	_BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,			/* 88-95 */
1713 	_BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
1714 	_BCM_L|_BCM_X, _BCM_L, /* 96-103 */
1715 	_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
1716 	_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
1717 	_BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
1718 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		/* 128-143 */
1719 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		/* 144-159 */
1720 	_BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
1721 	_BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,	/* 160-175 */
1722 	_BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
1723 	_BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,	/* 176-191 */
1724 	_BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
1725 	_BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,	/* 192-207 */
1726 	_BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
1727 	_BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L,	/* 208-223 */
1728 	_BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
1729 	_BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,	/* 224-239 */
1730 	_BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
1731 	_BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
1732 };
1733 
1734 uint64
bcm_strtoull(const char * cp,char ** endp,uint base)1735 bcm_strtoull(const char *cp, char **endp, uint base)
1736 {
1737 	uint64 result, last_result = 0, value;
1738 	bool minus;
1739 
1740 	minus = FALSE;
1741 
1742 	while (bcm_isspace(*cp))
1743 		cp++;
1744 
1745 	if (cp[0] == '+')
1746 		cp++;
1747 	else if (cp[0] == '-') {
1748 		minus = TRUE;
1749 		cp++;
1750 	}
1751 
1752 	if (base == 0) {
1753 		if (cp[0] == '0') {
1754 			if ((cp[1] == 'x') || (cp[1] == 'X')) {
1755 				base = 16;
1756 				cp = &cp[2];
1757 			} else {
1758 				base = 8;
1759 				cp = &cp[1];
1760 			}
1761 		} else
1762 			base = 10;
1763 	} else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
1764 		cp = &cp[2];
1765 	}
1766 
1767 	result = 0;
1768 
1769 	while (bcm_isxdigit(*cp) &&
1770 	       (value = (uint64)(bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10)) < base) {
1771 		result = result*base + value;
1772 		/* Detected overflow */
1773 		if (result < last_result && !minus) {
1774 			if (endp) {
1775 				/* Go to the end of current number */
1776 				while (bcm_isxdigit(*cp)) {
1777 					cp++;
1778 				}
1779 				*endp = DISCARD_QUAL(cp, char);
1780 			}
1781 			return (ulong)-1;
1782 		}
1783 		last_result = result;
1784 		cp++;
1785 	}
1786 
1787 	if (minus)
1788 		result = (ulong)(-(long)result);
1789 
1790 	if (endp)
1791 		*endp = DISCARD_QUAL(cp, char);
1792 
1793 	return (result);
1794 }
1795 
1796 ulong
bcm_strtoul(const char * cp,char ** endp,uint base)1797 bcm_strtoul(const char *cp, char **endp, uint base)
1798 {
1799 	return (ulong) bcm_strtoull(cp, endp, base);
1800 }
1801 
1802 int
bcm_atoi(const char * s)1803 bcm_atoi(const char *s)
1804 {
1805 	return (int)bcm_strtoul(s, NULL, 10);
1806 }
1807 
1808 /* return pointer to location of substring 'needle' in 'haystack' */
1809 char *
bcmstrstr(const char * haystack,const char * needle)1810 bcmstrstr(const char *haystack, const char *needle)
1811 {
1812 	int len, nlen;
1813 	int i;
1814 
1815 	if ((haystack == NULL) || (needle == NULL))
1816 		return DISCARD_QUAL(haystack, char);
1817 
1818 	nlen = (int)strlen(needle);
1819 	len = (int)strlen(haystack) - nlen + 1;
1820 
1821 	for (i = 0; i < len; i++)
1822 		if (memcmp(needle, &haystack[i], (size_t)nlen) == 0)
1823 			return DISCARD_QUAL(&haystack[i], char);
1824 	return (NULL);
1825 }
1826 
1827 char *
bcmstrnstr(const char * s,uint s_len,const char * substr,uint substr_len)1828 bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len)
1829 {
1830 	for (; s_len >= substr_len; s++, s_len--)
1831 		if (strncmp(s, substr, substr_len) == 0)
1832 			return DISCARD_QUAL(s, char);
1833 
1834 	return NULL;
1835 }
1836 
1837 char *
bcmstrcat(char * dest,const char * src)1838 bcmstrcat(char *dest, const char *src)
1839 {
1840 	char *p;
1841 
1842 	p = dest + strlen(dest);
1843 
1844 	while ((*p++ = *src++) != '\0')
1845 		;
1846 
1847 	return (dest);
1848 }
1849 
1850 char *
bcmstrncat(char * dest,const char * src,uint size)1851 bcmstrncat(char *dest, const char *src, uint size)
1852 {
1853 	char *endp;
1854 	char *p;
1855 
1856 	p = dest + strlen(dest);
1857 	endp = p + size;
1858 
1859 	while (p != endp && (*p++ = *src++) != '\0')
1860 		;
1861 
1862 	return (dest);
1863 }
1864 
1865 /****************************************************************************
1866 * Function:   bcmstrtok
1867 *
1868 * Purpose:
1869 *  Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
1870 *  but allows strToken() to be used by different strings or callers at the same
1871 *  time. Each call modifies '*string' by substituting a NULL character for the
1872 *  first delimiter that is encountered, and updates 'string' to point to the char
1873 *  after the delimiter. Leading delimiters are skipped.
1874 *
1875 * Parameters:
1876 *  string      (mod) Ptr to string ptr, updated by token.
1877 *  delimiters  (in)  Set of delimiter characters.
1878 *  tokdelim    (out) Character that delimits the returned token. (May
1879 *                    be set to NULL if token delimiter is not required).
1880 *
1881 * Returns:  Pointer to the next token found. NULL when no more tokens are found.
1882 *****************************************************************************
1883 */
1884 char *
bcmstrtok(char ** string,const char * delimiters,char * tokdelim)1885 bcmstrtok(char **string, const char *delimiters, char *tokdelim)
1886 {
1887 	unsigned char *str;
1888 	unsigned long map[8];
1889 	int count;
1890 	char *nextoken;
1891 
1892 	if (tokdelim != NULL) {
1893 		/* Prime the token delimiter */
1894 		*tokdelim = '\0';
1895 	}
1896 
1897 	/* Clear control map */
1898 	for (count = 0; count < 8; count++) {
1899 		map[count] = 0;
1900 	}
1901 
1902 	/* Set bits in delimiter table */
1903 	do {
1904 		map[*delimiters >> 5] |= (1 << (*delimiters & 31));
1905 	}
1906 	while (*delimiters++);
1907 
1908 	str = (unsigned char*)*string;
1909 
1910 	/* Find beginning of token (skip over leading delimiters). Note that
1911 	 * there is no token iff this loop sets str to point to the terminal
1912 	 * null (*str == '\0')
1913 	 */
1914 	while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
1915 		str++;
1916 	}
1917 
1918 	nextoken = (char*)str;
1919 
1920 	/* Find the end of the token. If it is not the end of the string,
1921 	 * put a null there.
1922 	 */
1923 	for (; *str; str++) {
1924 		if (map[*str >> 5] & (1 << (*str & 31))) {
1925 			if (tokdelim != NULL) {
1926 				*tokdelim = (char)*str;
1927 			}
1928 
1929 			*str++ = '\0';
1930 			break;
1931 		}
1932 	}
1933 
1934 	*string = (char*)str;
1935 
1936 	/* Determine if a token has been found. */
1937 	if (nextoken == (char *) str) {
1938 		return NULL;
1939 	}
1940 	else {
1941 		return nextoken;
1942 	}
1943 }
1944 
1945 #define xToLower(C) \
1946 	((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
1947 
1948 /****************************************************************************
1949 * Function:   bcmstricmp
1950 *
1951 * Purpose:    Compare to strings case insensitively.
1952 *
1953 * Parameters: s1 (in) First string to compare.
1954 *             s2 (in) Second string to compare.
1955 *
1956 * Returns:    Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1957 *             t1 > t2, when ignoring case sensitivity.
1958 *****************************************************************************
1959 */
1960 int
bcmstricmp(const char * s1,const char * s2)1961 bcmstricmp(const char *s1, const char *s2)
1962 {
1963 	char dc, sc;
1964 
1965 	while (*s2 && *s1) {
1966 		dc = xToLower(*s1);
1967 		sc = xToLower(*s2);
1968 		if (dc < sc) return -1;
1969 		if (dc > sc) return 1;
1970 		s1++;
1971 		s2++;
1972 	}
1973 
1974 	if (*s1 && !*s2) return 1;
1975 	if (!*s1 && *s2) return -1;
1976 	return 0;
1977 }
1978 
1979 /****************************************************************************
1980 * Function:   bcmstrnicmp
1981 *
1982 * Purpose:    Compare to strings case insensitively, upto a max of 'cnt'
1983 *             characters.
1984 *
1985 * Parameters: s1  (in) First string to compare.
1986 *             s2  (in) Second string to compare.
1987 *             cnt (in) Max characters to compare.
1988 *
1989 * Returns:    Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
1990 *             t1 > t2, when ignoring case sensitivity.
1991 *****************************************************************************
1992 */
1993 int
bcmstrnicmp(const char * s1,const char * s2,int cnt)1994 bcmstrnicmp(const char* s1, const char* s2, int cnt)
1995 {
1996 	char dc, sc;
1997 
1998 	while (*s2 && *s1 && cnt) {
1999 		dc = xToLower(*s1);
2000 		sc = xToLower(*s2);
2001 		if (dc < sc) return -1;
2002 		if (dc > sc) return 1;
2003 		s1++;
2004 		s2++;
2005 		cnt--;
2006 	}
2007 
2008 	if (!cnt) return 0;
2009 	if (*s1 && !*s2) return 1;
2010 	if (!*s1 && *s2) return -1;
2011 	return 0;
2012 }
2013 
2014 /* parse a xx:xx:xx:xx:xx:xx format ethernet address */
2015 int
bcm_ether_atoe(const char * p,struct ether_addr * ea)2016 bcm_ether_atoe(const char *p, struct ether_addr *ea)
2017 {
2018 	int i = 0;
2019 	char *ep;
2020 
2021 	for (;;) {
2022 		ea->octet[i++] = (uint8) bcm_strtoul(p, &ep, 16);
2023 		p = ep;
2024 		if (!*p++ || i == 6)
2025 			break;
2026 	}
2027 
2028 	return (i == 6);
2029 }
2030 
2031 int
bcm_atoipv4(const char * p,struct ipv4_addr * ip)2032 bcm_atoipv4(const char *p, struct ipv4_addr *ip)
2033 {
2034 
2035 	int i = 0;
2036 	char *c;
2037 	for (;;) {
2038 		ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0);
2039 		if (*c++ != '.' || i == IPV4_ADDR_LEN)
2040 			break;
2041 		p = c;
2042 	}
2043 	return (i == IPV4_ADDR_LEN);
2044 }
2045 #endif	/* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
2046 
2047 #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
2048 /* registry routine buffer preparation utility functions:
2049  * parameter order is like strncpy, but returns count
2050  * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
2051  */
2052 ulong
wchar2ascii(char * abuf,ushort * wbuf,ushort wbuflen,ulong abuflen)2053 wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
2054 {
2055 	ulong copyct = 1;
2056 	ushort i;
2057 
2058 	if (abuflen == 0)
2059 		return 0;
2060 
2061 	/* wbuflen is in bytes */
2062 	wbuflen /= sizeof(ushort);
2063 
2064 	for (i = 0; i < wbuflen; ++i) {
2065 		if (--abuflen == 0)
2066 			break;
2067 		*abuf++ = (char) *wbuf++;
2068 		++copyct;
2069 	}
2070 	*abuf = '\0';
2071 
2072 	return copyct;
2073 }
2074 #endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
2075 
2076 #ifdef BCM_OBJECT_TRACE
2077 
2078 #define BCM_OBJECT_MERGE_SAME_OBJ	0
2079 
2080 /* some place may add / remove the object to trace list for Linux: */
2081 /* add:    osl_alloc_skb dev_alloc_skb skb_realloc_headroom dhd_start_xmit */
2082 /* remove: osl_pktfree dev_kfree_skb netif_rx */
2083 
2084 #define BCM_OBJDBG_COUNT          (1024 * 100)
2085 static spinlock_t dbgobj_lock;
2086 #define	BCM_OBJDBG_LOCK_INIT()    spin_lock_init(&dbgobj_lock)
2087 #define	BCM_OBJDBG_LOCK_DESTROY()
2088 #define	BCM_OBJDBG_LOCK           spin_lock_irqsave
2089 #define	BCM_OBJDBG_UNLOCK         spin_unlock_irqrestore
2090 
2091 #define BCM_OBJDBG_ADDTOHEAD      0
2092 #define BCM_OBJDBG_ADDTOTAIL      1
2093 
2094 #define BCM_OBJDBG_CALLER_LEN     32
2095 struct bcm_dbgobj {
2096 	struct bcm_dbgobj *prior;
2097 	struct bcm_dbgobj *next;
2098 	uint32 flag;
2099 	void   *obj;
2100 	uint32 obj_sn;
2101 	uint32 obj_state;
2102 	uint32 line;
2103 	char   caller[BCM_OBJDBG_CALLER_LEN];
2104 };
2105 
2106 static struct bcm_dbgobj *dbgobj_freehead = NULL;
2107 static struct bcm_dbgobj *dbgobj_freetail = NULL;
2108 static struct bcm_dbgobj *dbgobj_objhead = NULL;
2109 static struct bcm_dbgobj *dbgobj_objtail = NULL;
2110 
2111 static uint32 dbgobj_sn = 0;
2112 static int dbgobj_count = 0;
2113 static struct bcm_dbgobj bcm_dbg_objs[BCM_OBJDBG_COUNT];
2114 
2115 void
bcm_object_trace_init(void)2116 bcm_object_trace_init(void)
2117 {
2118 	int i = 0;
2119 	BCM_OBJDBG_LOCK_INIT();
2120 	memset(&bcm_dbg_objs, 0x00, sizeof(struct bcm_dbgobj) * BCM_OBJDBG_COUNT);
2121 	dbgobj_freehead = &bcm_dbg_objs[0];
2122 	dbgobj_freetail = &bcm_dbg_objs[BCM_OBJDBG_COUNT - 1];
2123 
2124 	for (i = 0; i < BCM_OBJDBG_COUNT; ++i) {
2125 		bcm_dbg_objs[i].next = (i == (BCM_OBJDBG_COUNT - 1)) ?
2126 			dbgobj_freehead : &bcm_dbg_objs[i + 1];
2127 		bcm_dbg_objs[i].prior = (i == 0) ?
2128 			dbgobj_freetail : &bcm_dbg_objs[i - 1];
2129 	}
2130 }
2131 
2132 void
bcm_object_trace_deinit(void)2133 bcm_object_trace_deinit(void)
2134 {
2135 	if (dbgobj_objhead || dbgobj_objtail) {
2136 		printf("%s: not all objects are released\n", __FUNCTION__);
2137 		ASSERT(0);
2138 	}
2139 	BCM_OBJDBG_LOCK_DESTROY();
2140 }
2141 
2142 static void
bcm_object_rm_list(struct bcm_dbgobj ** head,struct bcm_dbgobj ** tail,struct bcm_dbgobj * dbgobj)2143 bcm_object_rm_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
2144 	struct bcm_dbgobj *dbgobj)
2145 {
2146 	if ((dbgobj == *head) && (dbgobj == *tail)) {
2147 		*head = NULL;
2148 		*tail = NULL;
2149 	} else if (dbgobj == *head) {
2150 		*head = (*head)->next;
2151 	} else if (dbgobj == *tail) {
2152 		*tail = (*tail)->prior;
2153 	}
2154 	dbgobj->next->prior = dbgobj->prior;
2155 	dbgobj->prior->next = dbgobj->next;
2156 }
2157 
2158 static void
bcm_object_add_list(struct bcm_dbgobj ** head,struct bcm_dbgobj ** tail,struct bcm_dbgobj * dbgobj,int addtotail)2159 bcm_object_add_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
2160 	struct bcm_dbgobj *dbgobj, int addtotail)
2161 {
2162 	if (!(*head) && !(*tail)) {
2163 		*head = dbgobj;
2164 		*tail = dbgobj;
2165 		dbgobj->next = dbgobj;
2166 		dbgobj->prior = dbgobj;
2167 	} else if ((*head) && (*tail)) {
2168 		(*tail)->next = dbgobj;
2169 		(*head)->prior = dbgobj;
2170 		dbgobj->next = *head;
2171 		dbgobj->prior = *tail;
2172 		if (addtotail == BCM_OBJDBG_ADDTOTAIL)
2173 			*tail = dbgobj;
2174 		else
2175 			*head = dbgobj;
2176 	} else {
2177 		ASSERT(0); /* can't be this case */
2178 	}
2179 }
2180 
2181 static INLINE void
bcm_object_movetoend(struct bcm_dbgobj ** head,struct bcm_dbgobj ** tail,struct bcm_dbgobj * dbgobj,int movetotail)2182 bcm_object_movetoend(struct bcm_dbgobj **head, struct bcm_dbgobj **tail,
2183 	struct bcm_dbgobj *dbgobj, int movetotail)
2184 {
2185 	if ((*head) && (*tail)) {
2186 		if (movetotail == BCM_OBJDBG_ADDTOTAIL) {
2187 			if (dbgobj != (*tail)) {
2188 				bcm_object_rm_list(head, tail, dbgobj);
2189 				bcm_object_add_list(head, tail, dbgobj, movetotail);
2190 			}
2191 		} else {
2192 			if (dbgobj != (*head)) {
2193 				bcm_object_rm_list(head, tail, dbgobj);
2194 				bcm_object_add_list(head, tail, dbgobj, movetotail);
2195 			}
2196 		}
2197 	} else {
2198 		ASSERT(0); /* can't be this case */
2199 	}
2200 }
2201 
2202 void
bcm_object_trace_opr(void * obj,uint32 opt,const char * caller,int line)2203 bcm_object_trace_opr(void *obj, uint32 opt, const char *caller, int line)
2204 {
2205 	struct bcm_dbgobj *dbgobj;
2206 	unsigned long flags;
2207 
2208 	BCM_REFERENCE(flags);
2209 	BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
2210 
2211 	if (opt == BCM_OBJDBG_ADD_PKT ||
2212 		opt == BCM_OBJDBG_ADD) {
2213 		dbgobj = dbgobj_objtail;
2214 		while (dbgobj) {
2215 			if (dbgobj->obj == obj) {
2216 				printf("%s: obj %p allocated from %s(%d),"
2217 					" allocate again from %s(%d)\n",
2218 					__FUNCTION__, dbgobj->obj,
2219 					dbgobj->caller, dbgobj->line,
2220 					caller, line);
2221 				ASSERT(0);
2222 				goto EXIT;
2223 			}
2224 			dbgobj = dbgobj->prior;
2225 			if (dbgobj == dbgobj_objtail)
2226 				break;
2227 		}
2228 
2229 #if BCM_OBJECT_MERGE_SAME_OBJ
2230 		dbgobj = dbgobj_freetail;
2231 		while (dbgobj) {
2232 			if (dbgobj->obj == obj) {
2233 				goto FREED_ENTRY_FOUND;
2234 			}
2235 			dbgobj = dbgobj->prior;
2236 			if (dbgobj == dbgobj_freetail)
2237 				break;
2238 		}
2239 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
2240 
2241 		dbgobj = dbgobj_freehead;
2242 #if BCM_OBJECT_MERGE_SAME_OBJ
2243 FREED_ENTRY_FOUND:
2244 #endif /* BCM_OBJECT_MERGE_SAME_OBJ */
2245 		if (!dbgobj) {
2246 			printf("%s: already got %d objects ?????????????????????\n",
2247 				__FUNCTION__, BCM_OBJDBG_COUNT);
2248 			ASSERT(0);
2249 			goto EXIT;
2250 		}
2251 
2252 		bcm_object_rm_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj);
2253 		dbgobj->obj = obj;
2254 		strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN);
2255 		dbgobj->caller[BCM_OBJDBG_CALLER_LEN-1] = '\0';
2256 		dbgobj->line = line;
2257 		dbgobj->flag = 0;
2258 		if (opt == BCM_OBJDBG_ADD_PKT) {
2259 			dbgobj->obj_sn = dbgobj_sn++;
2260 			dbgobj->obj_state = 0;
2261 			/* first 4 bytes is pkt sn */
2262 			if (((unsigned long)PKTTAG(obj)) & 0x3)
2263 				printf("pkt tag address not aligned by 4: %p\n", PKTTAG(obj));
2264 			*(uint32*)PKTTAG(obj) = dbgobj->obj_sn;
2265 		}
2266 		bcm_object_add_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj,
2267 			BCM_OBJDBG_ADDTOTAIL);
2268 
2269 		dbgobj_count++;
2270 
2271 	} else if (opt == BCM_OBJDBG_REMOVE) {
2272 		dbgobj = dbgobj_objtail;
2273 		while (dbgobj) {
2274 			if (dbgobj->obj == obj) {
2275 				if (dbgobj->flag) {
2276 					printf("%s: rm flagged obj %p flag 0x%08x from %s(%d)\n",
2277 						__FUNCTION__, obj, dbgobj->flag, caller, line);
2278 				}
2279 				bcm_object_rm_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj);
2280 				memset(dbgobj->caller, 0x00, BCM_OBJDBG_CALLER_LEN);
2281 				strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN);
2282 				dbgobj->caller[BCM_OBJDBG_CALLER_LEN-1] = '\0';
2283 				dbgobj->line = line;
2284 				bcm_object_add_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj,
2285 					BCM_OBJDBG_ADDTOTAIL);
2286 				dbgobj_count--;
2287 				goto EXIT;
2288 			}
2289 			dbgobj = dbgobj->prior;
2290 			if (dbgobj == dbgobj_objtail)
2291 				break;
2292 		}
2293 
2294 		dbgobj = dbgobj_freetail;
2295 		while (dbgobj && dbgobj->obj) {
2296 			if (dbgobj->obj == obj) {
2297 				printf("%s: obj %p already freed from from %s(%d),"
2298 					" try free again from %s(%d)\n",
2299 					__FUNCTION__, obj,
2300 					dbgobj->caller, dbgobj->line,
2301 					caller, line);
2302 				//ASSERT(0); /* release same obj more than one time? */
2303 				goto EXIT;
2304 			}
2305 			dbgobj = dbgobj->prior;
2306 			if (dbgobj == dbgobj_freetail)
2307 				break;
2308 		}
2309 
2310 		printf("%s: ################### release none-existing obj %p from %s(%d)\n",
2311 			__FUNCTION__, obj, caller, line);
2312 		//ASSERT(0); /* release same obj more than one time? */
2313 
2314 	}
2315 
2316 EXIT:
2317 	BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
2318 	return;
2319 }
2320 
2321 void
bcm_object_trace_upd(void * obj,void * obj_new)2322 bcm_object_trace_upd(void *obj, void *obj_new)
2323 {
2324 	struct bcm_dbgobj *dbgobj;
2325 	unsigned long flags;
2326 
2327 	BCM_REFERENCE(flags);
2328 	BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
2329 
2330 	dbgobj = dbgobj_objtail;
2331 	while (dbgobj) {
2332 		if (dbgobj->obj == obj) {
2333 			dbgobj->obj = obj_new;
2334 			if (dbgobj != dbgobj_objtail) {
2335 				bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
2336 					dbgobj, BCM_OBJDBG_ADDTOTAIL);
2337 			}
2338 			goto EXIT;
2339 		}
2340 		dbgobj = dbgobj->prior;
2341 		if (dbgobj == dbgobj_objtail)
2342 			break;
2343 	}
2344 
2345 EXIT:
2346 	BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
2347 	return;
2348 }
2349 
2350 void
bcm_object_trace_chk(void * obj,uint32 chksn,uint32 sn,const char * caller,int line)2351 bcm_object_trace_chk(void *obj, uint32 chksn, uint32 sn,
2352 	const char *caller, int line)
2353 {
2354 	struct bcm_dbgobj *dbgobj;
2355 	unsigned long flags;
2356 
2357 	BCM_REFERENCE(flags);
2358 	BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
2359 
2360 	dbgobj = dbgobj_objtail;
2361 	while (dbgobj) {
2362 		if ((dbgobj->obj == obj) &&
2363 			((!chksn) || (dbgobj->obj_sn == sn))) {
2364 			if (dbgobj != dbgobj_objtail) {
2365 				bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
2366 					dbgobj, BCM_OBJDBG_ADDTOTAIL);
2367 			}
2368 			goto EXIT;
2369 		}
2370 		dbgobj = dbgobj->prior;
2371 		if (dbgobj == dbgobj_objtail)
2372 			break;
2373 	}
2374 
2375 	dbgobj = dbgobj_freetail;
2376 	while (dbgobj) {
2377 		if ((dbgobj->obj == obj) &&
2378 			((!chksn) || (dbgobj->obj_sn == sn))) {
2379 			printf("%s: (%s:%d) obj %p (sn %d state %d) was freed from %s(%d)\n",
2380 				__FUNCTION__, caller, line,
2381 				dbgobj->obj, dbgobj->obj_sn, dbgobj->obj_state,
2382 				dbgobj->caller, dbgobj->line);
2383 			goto EXIT;
2384 		}
2385 		else if (dbgobj->obj == NULL) {
2386 			break;
2387 		}
2388 		dbgobj = dbgobj->prior;
2389 		if (dbgobj == dbgobj_freetail)
2390 			break;
2391 	}
2392 
2393 	printf("%s: obj %p not found, check from %s(%d), chksn %s, sn %d\n",
2394 		__FUNCTION__, obj, caller, line, chksn ? "yes" : "no", sn);
2395 	dbgobj = dbgobj_objtail;
2396 	while (dbgobj) {
2397 		printf("%s: (%s:%d) obj %p sn %d was allocated from %s(%d)\n",
2398 				__FUNCTION__, caller, line,
2399 				dbgobj->obj, dbgobj->obj_sn, dbgobj->caller, dbgobj->line);
2400 		dbgobj = dbgobj->prior;
2401 		if (dbgobj == dbgobj_objtail)
2402 			break;
2403 	}
2404 
2405 EXIT:
2406 	BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
2407 	return;
2408 }
2409 
2410 void
bcm_object_feature_set(void * obj,uint32 type,uint32 value)2411 bcm_object_feature_set(void *obj, uint32 type, uint32 value)
2412 {
2413 	struct bcm_dbgobj *dbgobj;
2414 	unsigned long flags;
2415 
2416 	BCM_REFERENCE(flags);
2417 	BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
2418 
2419 	dbgobj = dbgobj_objtail;
2420 	while (dbgobj) {
2421 		if (dbgobj->obj == obj) {
2422 			if (type == BCM_OBJECT_FEATURE_FLAG) {
2423 				if (value & BCM_OBJECT_FEATURE_CLEAR)
2424 					dbgobj->flag &= ~(value);
2425 				else
2426 					dbgobj->flag |= (value);
2427 			} else if (type == BCM_OBJECT_FEATURE_PKT_STATE) {
2428 				dbgobj->obj_state = value;
2429 			}
2430 			if (dbgobj != dbgobj_objtail) {
2431 				bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
2432 					dbgobj, BCM_OBJDBG_ADDTOTAIL);
2433 			}
2434 			goto EXIT;
2435 		}
2436 		dbgobj = dbgobj->prior;
2437 		if (dbgobj == dbgobj_objtail)
2438 			break;
2439 	}
2440 
2441 	printf("%s: obj %p not found in active list\n", __FUNCTION__, obj);
2442 	ASSERT(0);
2443 
2444 EXIT:
2445 	BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
2446 	return;
2447 }
2448 
2449 int
bcm_object_feature_get(void * obj,uint32 type,uint32 value)2450 bcm_object_feature_get(void *obj, uint32 type, uint32 value)
2451 {
2452 	int rtn = 0;
2453 	struct bcm_dbgobj *dbgobj;
2454 	unsigned long flags;
2455 
2456 	BCM_REFERENCE(flags);
2457 	BCM_OBJDBG_LOCK(&dbgobj_lock, flags);
2458 
2459 	dbgobj = dbgobj_objtail;
2460 	while (dbgobj) {
2461 		if (dbgobj->obj == obj) {
2462 			if (type == BCM_OBJECT_FEATURE_FLAG) {
2463 				rtn = (dbgobj->flag & value) & (~BCM_OBJECT_FEATURE_CLEAR);
2464 			}
2465 			if (dbgobj != dbgobj_objtail) {
2466 				bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail,
2467 					dbgobj, BCM_OBJDBG_ADDTOTAIL);
2468 			}
2469 			goto EXIT;
2470 		}
2471 		dbgobj = dbgobj->prior;
2472 		if (dbgobj == dbgobj_objtail)
2473 			break;
2474 	}
2475 
2476 	printf("%s: obj %p not found in active list\n", __FUNCTION__, obj);
2477 	ASSERT(0);
2478 
2479 EXIT:
2480 	BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags);
2481 	return rtn;
2482 }
2483 
2484 #endif /* BCM_OBJECT_TRACE */
2485 
2486 uint8 *
bcm_write_tlv(int type,const void * data,int datalen,uint8 * dst)2487 bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst)
2488 {
2489 	uint8 *new_dst = dst;
2490 	bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst;
2491 
2492 	/* dst buffer should always be valid */
2493 	ASSERT(dst);
2494 
2495 	/* data len must be within valid range */
2496 	ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE));
2497 
2498 	/* source data buffer pointer should be valid, unless datalen is 0
2499 	 * meaning no data with this TLV
2500 	 */
2501 	ASSERT((data != NULL) || (datalen == 0));
2502 
2503 	/* only do work if the inputs are valid
2504 	 * - must have a dst to write to AND
2505 	 * - datalen must be within range AND
2506 	 * - the source data pointer must be non-NULL if datalen is non-zero
2507 	 * (this last condition detects datalen > 0 with a NULL data pointer)
2508 	 */
2509 	if ((dst != NULL) &&
2510 	    ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) &&
2511 	    ((data != NULL) || (datalen == 0))) {
2512 
2513 		/* write type, len fields */
2514 		dst_tlv->id = (uint8)type;
2515 		dst_tlv->len = (uint8)datalen;
2516 
2517 		/* if data is present, copy to the output buffer and update
2518 		 * pointer to output buffer
2519 		 */
2520 		if (datalen > 0) {
2521 
2522 			memcpy(dst_tlv->data, data, (size_t)datalen);
2523 		}
2524 
2525 		/* update the output destination poitner to point past
2526 		 * the TLV written
2527 		 */
2528 		new_dst = dst + BCM_TLV_HDR_SIZE + datalen;
2529 	}
2530 
2531 	return (new_dst);
2532 }
2533 
2534 uint8 *
bcm_write_tlv_ext(uint8 type,uint8 ext,const void * data,uint8 datalen,uint8 * dst)2535 bcm_write_tlv_ext(uint8 type, uint8 ext, const void *data, uint8 datalen, uint8 *dst)
2536 {
2537 	uint8 *new_dst = dst;
2538 	bcm_tlv_ext_t *dst_tlv = (bcm_tlv_ext_t *)dst;
2539 
2540 	/* dst buffer should always be valid */
2541 	ASSERT(dst);
2542 
2543 	/* data len must be within valid range */
2544 	ASSERT(datalen <= BCM_TLV_EXT_MAX_DATA_SIZE);
2545 
2546 	/* source data buffer pointer should be valid, unless datalen is 0
2547 	 * meaning no data with this TLV
2548 	 */
2549 	ASSERT((data != NULL) || (datalen == 0));
2550 
2551 	/* only do work if the inputs are valid
2552 	 * - must have a dst to write to AND
2553 	 * - datalen must be within range AND
2554 	 * - the source data pointer must be non-NULL if datalen is non-zero
2555 	 * (this last condition detects datalen > 0 with a NULL data pointer)
2556 	 */
2557 	if ((dst != NULL) &&
2558 	    (datalen <= BCM_TLV_EXT_MAX_DATA_SIZE) &&
2559 	    ((data != NULL) || (datalen == 0))) {
2560 
2561 		/* write type, len fields */
2562 		dst_tlv->id = (uint8)type;
2563 		dst_tlv->ext = ext;
2564 		dst_tlv->len = 1 + (uint8)datalen;
2565 
2566 		/* if data is present, copy to the output buffer and update
2567 		 * pointer to output buffer
2568 		 */
2569 		if (datalen > 0) {
2570 			memcpy(dst_tlv->data, data, datalen);
2571 		}
2572 
2573 		/* update the output destination poitner to point past
2574 		 * the TLV written
2575 		 */
2576 		new_dst = dst + BCM_TLV_EXT_HDR_SIZE + datalen;
2577 	}
2578 
2579 	return (new_dst);
2580 }
2581 
2582 uint8 *
bcm_write_tlv_safe(int type,const void * data,int datalen,uint8 * dst,int dst_maxlen)2583 bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, int dst_maxlen)
2584 {
2585 	uint8 *new_dst = dst;
2586 
2587 	if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) {
2588 
2589 		/* if len + tlv hdr len is more than destlen, don't do anything
2590 		 * just return the buffer untouched
2591 		 */
2592 		if ((int)(datalen + (int)BCM_TLV_HDR_SIZE) <= dst_maxlen) {
2593 
2594 			new_dst = bcm_write_tlv(type, data, datalen, dst);
2595 		}
2596 	}
2597 
2598 	return (new_dst);
2599 }
2600 
2601 uint8 *
bcm_copy_tlv(const void * src,uint8 * dst)2602 bcm_copy_tlv(const void *src, uint8 *dst)
2603 {
2604 	uint8 *new_dst = dst;
2605 	const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
2606 	uint totlen;
2607 
2608 	ASSERT(dst && src);
2609 	if (dst && src) {
2610 
2611 		totlen = BCM_TLV_HDR_SIZE + src_tlv->len;
2612 		memcpy(dst, src_tlv, totlen);
2613 		new_dst = dst + totlen;
2614 	}
2615 
2616 	return (new_dst);
2617 }
2618 
bcm_copy_tlv_safe(const void * src,uint8 * dst,int dst_maxlen)2619 uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen)
2620 {
2621 	uint8 *new_dst = dst;
2622 	const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src;
2623 
2624 	ASSERT(src);
2625 	if (src) {
2626 		if (bcm_valid_tlv(src_tlv, dst_maxlen)) {
2627 			new_dst = bcm_copy_tlv(src, dst);
2628 		}
2629 	}
2630 
2631 	return (new_dst);
2632 }
2633 
2634 #if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS)
2635 /*******************************************************************************
2636  * crc8
2637  *
2638  * Computes a crc8 over the input data using the polynomial:
2639  *
2640  *       x^8 + x^7 +x^6 + x^4 + x^2 + 1
2641  *
2642  * The caller provides the initial value (either CRC8_INIT_VALUE
2643  * or the previous returned value) to allow for processing of
2644  * discontiguous blocks of data.  When generating the CRC the
2645  * caller is responsible for complementing the final return value
2646  * and inserting it into the byte stream.  When checking, a final
2647  * return value of CRC8_GOOD_VALUE indicates a valid CRC.
2648  *
2649  * Reference: Dallas Semiconductor Application Note 27
2650  *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2651  *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2652  *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2653  *
2654  * ****************************************************************************
2655  */
2656 
2657 static const uint8 crc8_table[256] = {
2658     0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
2659     0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
2660     0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
2661     0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
2662     0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
2663     0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
2664     0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
2665     0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
2666     0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
2667     0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
2668     0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
2669     0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
2670     0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
2671     0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
2672     0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
2673     0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
2674     0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
2675     0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
2676     0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
2677     0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
2678     0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
2679     0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
2680     0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
2681     0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
2682     0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
2683     0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
2684     0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
2685     0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
2686     0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
2687     0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
2688     0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
2689     0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
2690 };
2691 
2692 #define CRC_INNER_LOOP(n, c, x) \
2693 	(c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
2694 
2695 uint8
hndcrc8(const uint8 * pdata,uint nbytes,uint8 crc)2696 hndcrc8(
2697 	const uint8 *pdata,	/* pointer to array of data to process */
2698 	uint  nbytes,	/* number of input data bytes to process */
2699 	uint8 crc	/* either CRC8_INIT_VALUE or previous return value */
2700 )
2701 {
2702 	/* hard code the crc loop instead of using CRC_INNER_LOOP macro
2703 	 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
2704 	 */
2705 	while (nbytes-- > 0)
2706 		crc = crc8_table[(crc ^ *pdata++) & 0xff];
2707 
2708 	return crc;
2709 }
2710 
2711 /*******************************************************************************
2712  * crc16
2713  *
2714  * Computes a crc16 over the input data using the polynomial:
2715  *
2716  *       x^16 + x^12 +x^5 + 1
2717  *
2718  * The caller provides the initial value (either CRC16_INIT_VALUE
2719  * or the previous returned value) to allow for processing of
2720  * discontiguous blocks of data.  When generating the CRC the
2721  * caller is responsible for complementing the final return value
2722  * and inserting it into the byte stream.  When checking, a final
2723  * return value of CRC16_GOOD_VALUE indicates a valid CRC.
2724  *
2725  * Reference: Dallas Semiconductor Application Note 27
2726  *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
2727  *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
2728  *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
2729  *
2730  * ****************************************************************************
2731  */
2732 
2733 static const uint16 crc16_table[256] = {
2734     0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
2735     0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
2736     0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
2737     0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
2738     0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
2739     0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
2740     0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
2741     0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
2742     0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
2743     0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
2744     0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
2745     0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
2746     0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
2747     0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
2748     0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
2749     0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
2750     0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
2751     0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
2752     0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
2753     0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
2754     0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
2755     0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
2756     0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
2757     0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
2758     0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
2759     0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
2760     0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
2761     0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
2762     0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
2763     0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
2764     0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
2765     0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
2766 };
2767 
2768 uint16
hndcrc16(const uint8 * pdata,uint nbytes,uint16 crc)2769 hndcrc16(
2770     const uint8 *pdata,  /* pointer to array of data to process */
2771     uint nbytes, /* number of input data bytes to process */
2772     uint16 crc     /* either CRC16_INIT_VALUE or previous return value */
2773 )
2774 {
2775 	while (nbytes-- > 0)
2776 		CRC_INNER_LOOP(16, crc, *pdata++);
2777 	return crc;
2778 }
2779 
2780 static const uint32 crc32_table[256] = {
2781     0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
2782     0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
2783     0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
2784     0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
2785     0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
2786     0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
2787     0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
2788     0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
2789     0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
2790     0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
2791     0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
2792     0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
2793     0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
2794     0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
2795     0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
2796     0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
2797     0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
2798     0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
2799     0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
2800     0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
2801     0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
2802     0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
2803     0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
2804     0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
2805     0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
2806     0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
2807     0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
2808     0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
2809     0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
2810     0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
2811     0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
2812     0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
2813     0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
2814     0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
2815     0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
2816     0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
2817     0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
2818     0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
2819     0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
2820     0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
2821     0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
2822     0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
2823     0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
2824     0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
2825     0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
2826     0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
2827     0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
2828     0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
2829     0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
2830     0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
2831     0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
2832     0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
2833     0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
2834     0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
2835     0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
2836     0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
2837     0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
2838     0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
2839     0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
2840     0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
2841     0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
2842     0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
2843     0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
2844     0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
2845 };
2846 
2847 /*
2848  * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
2849  * accumulating over multiple pieces.
2850  */
2851 uint32
hndcrc32(const uint8 * pdata,uint nbytes,uint32 crc)2852 hndcrc32(const uint8 *pdata, uint nbytes, uint32 crc)
2853 {
2854 	const uint8 *pend;
2855 	pend = pdata + nbytes;
2856 	while (pdata < pend)
2857 		CRC_INNER_LOOP(32, crc, *pdata++);
2858 
2859 	return crc;
2860 }
2861 
2862 #ifdef notdef
2863 #define CLEN	1499	/*  CRC Length */
2864 #define CBUFSIZ		(CLEN+4)
2865 #define CNBUFS		5 /* # of bufs */
2866 
2867 void
testcrc32(void)2868 testcrc32(void)
2869 {
2870 	uint j, k, l;
2871 	uint8 *buf;
2872 	uint len[CNBUFS];
2873 	uint32 crcr;
2874 	uint32 crc32tv[CNBUFS] =
2875 		{0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
2876 
2877 	ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
2878 
2879 	/* step through all possible alignments */
2880 	for (l = 0; l <= 4; l++) {
2881 		for (j = 0; j < CNBUFS; j++) {
2882 			len[j] = CLEN;
2883 			for (k = 0; k < len[j]; k++)
2884 				*(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
2885 		}
2886 
2887 		for (j = 0; j < CNBUFS; j++) {
2888 			crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
2889 			ASSERT(crcr == crc32tv[j]);
2890 		}
2891 	}
2892 
2893 	MFREE(buf, CBUFSIZ*CNBUFS);
2894 	return;
2895 }
2896 #endif /* notdef */
2897 
2898 /*
2899  * Advance from the current 1-byte tag/1-byte length/variable-length value
2900  * triple, to the next, returning a pointer to the next.
2901  * If the current or next TLV is invalid (does not fit in given buffer length),
2902  * NULL is returned.
2903  * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
2904  * by the TLV parameter's length if it is valid.
2905  */
2906 bcm_tlv_t *
bcm_next_tlv(const bcm_tlv_t * elt,uint * buflen)2907 bcm_next_tlv(const  bcm_tlv_t *elt, uint *buflen)
2908 {
2909 	uint len;
2910 
2911 	/* validate current elt */
2912 	if (!bcm_valid_tlv(elt, *buflen)) {
2913 		return NULL;
2914 	}
2915 
2916 	/* advance to next elt */
2917 	len = elt->len;
2918 	elt = (const  bcm_tlv_t*)(elt->data + len);
2919 	*buflen -= (TLV_HDR_LEN + len);
2920 
2921 	/* validate next elt */
2922 	if (!bcm_valid_tlv(elt, *buflen)) {
2923 		return NULL;
2924 	}
2925 
2926 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2927 	return (bcm_tlv_t *)(elt);
2928 	GCC_DIAGNOSTIC_POP();
2929 }
2930 
2931 /**
2932  * Advance a const tlv buffer pointer and length up to the given tlv element pointer
2933  * 'elt'.  The function checks that elt is a valid tlv; the elt pointer and data
2934  * are all in the range of the buffer/length.
2935  *
2936  * @param elt      pointer to a valid bcm_tlv_t in the buffer
2937  * @param buffer   pointer to a tlv buffer
2938  * @param buflen   length of the buffer in bytes
2939  *
2940  * On return, if elt is not a tlv in the buffer bounds, the *buffer parameter
2941  * will be set to NULL and *buflen parameter will be set to zero.  Otherwise,
2942  * *buffer will point to elt, and *buflen will have been adjusted by the the
2943  * difference between *buffer and elt.
2944  */
2945 void
bcm_tlv_buffer_advance_to(const bcm_tlv_t * elt,const uint8 ** buffer,uint * buflen)2946 bcm_tlv_buffer_advance_to(const bcm_tlv_t *elt, const uint8 **buffer, uint *buflen)
2947 {
2948 	uint new_buflen;
2949 	const uint8 *new_buffer;
2950 
2951 	new_buffer = (const uint8*)elt;
2952 
2953 	/* make sure the input buffer pointer is non-null, that (buffer + buflen) does not wrap,
2954 	 * and that the elt pointer is in the range of [buffer, buffer + buflen]
2955 	 */
2956 	if ((*buffer != NULL) &&
2957 	    ((uintptr)*buffer < ((uintptr)*buffer + *buflen)) &&
2958 	    (new_buffer >= *buffer) &&
2959 	    (new_buffer < (*buffer + *buflen))) {
2960 		/* delta between buffer and new_buffer is <= *buflen, so truncating cast to uint
2961 		 * from ptrdiff is ok
2962 		 */
2963 		uint delta = (uint)(new_buffer - *buffer);
2964 
2965 		/* New buffer length is old len minus the delta from the buffer start to elt.
2966 		 * The check just above guarantees that the subtractions does not underflow.
2967 		 */
2968 		new_buflen = *buflen - delta;
2969 
2970 		/* validate current elt */
2971 		if (bcm_valid_tlv(elt, new_buflen)) {
2972 			/* All good, so update the input/output parameters */
2973 			*buffer = new_buffer;
2974 			*buflen = new_buflen;
2975 			return;
2976 		}
2977 	}
2978 
2979 	/* something did not check out, clear out the buffer info */
2980 	*buffer = NULL;
2981 	*buflen = 0;
2982 
2983 	return;
2984 }
2985 
2986 /**
2987  * Advance a const tlv buffer pointer and length past the given tlv element pointer
2988  * 'elt'.  The function checks that elt is a valid tlv; the elt pointer and data
2989  * are all in the range of the buffer/length.  The function also checks that the
2990  * remaining buffer starts with a valid tlv.
2991  *
2992  * @param elt      pointer to a valid bcm_tlv_t in the buffer
2993  * @param buffer   pointer to a tlv buffer
2994  * @param buflen   length of the buffer in bytes
2995  *
2996  * On return, if elt is not a tlv in the buffer bounds, or the remaining buffer
2997  * following the elt does not begin with a tlv in the buffer bounds, the *buffer
2998  * parameter will be set to NULL and *buflen parameter will be set to zero.
2999  * Otherwise, *buffer will point to the first byte past elt, and *buflen will
3000  * have the remaining buffer length.
3001  */
3002 void
bcm_tlv_buffer_advance_past(const bcm_tlv_t * elt,const uint8 ** buffer,uint * buflen)3003 bcm_tlv_buffer_advance_past(const bcm_tlv_t *elt, const uint8 **buffer, uint *buflen)
3004 {
3005 	/* Start by advancing the buffer up to the given elt */
3006 	bcm_tlv_buffer_advance_to(elt, buffer, buflen);
3007 
3008 	/* if that did not work, bail out */
3009 	if (*buflen == 0) {
3010 		return;
3011 	}
3012 
3013 #if defined(__COVERITY__)
3014 	/* The elt has been verified by bcm_tlv_buffer_advance_to() to be a valid element,
3015 	 * so its elt->len is in the bounds of the buffer. The following check prevents
3016 	 * Coverity from flagging the (elt->data + elt->len) statement below as using a
3017 	 * tainted elt->len to index into array 'elt->data'.
3018 	 */
3019 	if (elt->len > *buflen) {
3020 		return;
3021 	}
3022 #endif /* __COVERITY__ */
3023 
3024 	/* We know we are advanced up to a good tlv.
3025 	 * Now just advance to the following tlv.
3026 	 */
3027 	elt = (const bcm_tlv_t*)(elt->data + elt->len);
3028 
3029 	bcm_tlv_buffer_advance_to(elt, buffer, buflen);
3030 
3031 	return;
3032 }
3033 
3034 /*
3035  * Traverse a string of 1-byte tag/1-byte length/variable-length value
3036  * triples, returning a pointer to the substring whose first element
3037  * matches tag
3038  */
3039 bcm_tlv_t *
bcm_parse_tlvs(const void * buf,uint buflen,uint key)3040 bcm_parse_tlvs(const void *buf, uint buflen, uint key)
3041 {
3042 	const bcm_tlv_t *elt;
3043 	int totlen;
3044 
3045 	if ((elt = (const bcm_tlv_t*)buf) == NULL) {
3046 		return NULL;
3047 	}
3048 	totlen = (int)buflen;
3049 
3050 	/* find tagged parameter */
3051 	while (totlen >= TLV_HDR_LEN) {
3052 		uint len = elt->len;
3053 
3054 		/* validate remaining totlen */
3055 		if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
3056 			GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3057 			return (bcm_tlv_t *)(elt);
3058 			GCC_DIAGNOSTIC_POP();
3059 		}
3060 
3061 		elt = (const bcm_tlv_t*)((const uint8*)elt + (len + TLV_HDR_LEN));
3062 		totlen -= (len + TLV_HDR_LEN);
3063 	}
3064 
3065 	return NULL;
3066 }
3067 
3068 bcm_tlv_t *
bcm_parse_tlvs_dot11(const void * buf,int buflen,uint key,bool id_ext)3069 bcm_parse_tlvs_dot11(const void *buf, int buflen, uint key, bool id_ext)
3070 {
3071 	bcm_tlv_t *elt;
3072 	int totlen;
3073 
3074 	/*
3075 	   ideally, we don't want to do that, but returning a const pointer
3076 	   from these parse function spreads casting everywhere in the code
3077 	*/
3078 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3079 	elt = (bcm_tlv_t*)buf;
3080 	GCC_DIAGNOSTIC_POP();
3081 
3082 	totlen = buflen;
3083 
3084 	/* find tagged parameter */
3085 	while (totlen >= TLV_HDR_LEN) {
3086 		int len = elt->len;
3087 
3088 		do {
3089 			/* validate remaining totlen */
3090 			if (totlen <  (int)(len + TLV_HDR_LEN))
3091 				break;
3092 
3093 			if (id_ext) {
3094 				if (!DOT11_MNG_IE_ID_EXT_MATCH(elt, key))
3095 					break;
3096 			} else if (elt->id != key) {
3097 				break;
3098 			}
3099 
3100 				return (bcm_tlv_t *)(elt);		/* a match */
3101 		} while (0);
3102 
3103 		elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN));
3104 		totlen -= (len + TLV_HDR_LEN);
3105 	}
3106 
3107 	return NULL;
3108 }
3109 
3110 /*
3111  * Traverse a string of 1-byte tag/1-byte length/variable-length value
3112  * triples, returning a pointer to the substring whose first element
3113  * matches tag
3114  * return NULL if not found or length field < min_varlen
3115  */
3116 bcm_tlv_t *
bcm_parse_tlvs_min_bodylen(const void * buf,int buflen,uint key,int min_bodylen)3117 bcm_parse_tlvs_min_bodylen(const  void *buf, int buflen, uint key, int min_bodylen)
3118 {
3119 	bcm_tlv_t * ret;
3120 	ret = bcm_parse_tlvs(buf, (uint)buflen, key);
3121 	if (ret == NULL || ret->len < min_bodylen) {
3122 		return NULL;
3123 	}
3124 	return ret;
3125 }
3126 
3127 /*
3128  * Traverse a string of 1-byte tag/1-byte length/variable-length value
3129  * triples, returning a pointer to the substring whose first element
3130  * matches tag.  Stop parsing when we see an element whose ID is greater
3131  * than the target key.
3132  */
3133 const  bcm_tlv_t *
bcm_parse_ordered_tlvs(const void * buf,int buflen,uint key)3134 bcm_parse_ordered_tlvs(const  void *buf, int buflen, uint key)
3135 {
3136 	const  bcm_tlv_t *elt;
3137 	int totlen;
3138 
3139 	elt = (const  bcm_tlv_t*)buf;
3140 	totlen = buflen;
3141 
3142 	/* find tagged parameter */
3143 	while (totlen >= TLV_HDR_LEN) {
3144 		uint id = elt->id;
3145 		int len = elt->len;
3146 
3147 		/* Punt if we start seeing IDs > than target key */
3148 		if (id > key) {
3149 			return (NULL);
3150 		}
3151 
3152 		/* validate remaining totlen */
3153 		if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) {
3154 			return (elt);
3155 		}
3156 
3157 		elt = (const  bcm_tlv_t*)((const  uint8*)elt + (len + TLV_HDR_LEN));
3158 		totlen -= (len + TLV_HDR_LEN);
3159 	}
3160 	return NULL;
3161 }
3162 #endif	/* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */
3163 
3164 #if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
3165 	defined(DHD_DEBUG)
3166 int
bcm_format_field(const bcm_bit_desc_ex_t * bd,uint32 flags,char * buf,int len)3167 bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len)
3168 {
3169 	int i, slen = 0;
3170 	uint32 bit, mask;
3171 	const char *name;
3172 	mask = bd->mask;
3173 	if (len < 2 || !buf)
3174 		return 0;
3175 
3176 	buf[0] = '\0';
3177 
3178 	for (i = 0;  (name = bd->bitfield[i].name) != NULL; i++) {
3179 		bit = bd->bitfield[i].bit;
3180 		if ((flags & mask) == bit) {
3181 			if (len > (int)strlen(name)) {
3182 				slen = (int)strlen(name);
3183 				strncpy(buf, name, (size_t)len);
3184 			}
3185 			break;
3186 		}
3187 	}
3188 	return slen;
3189 }
3190 
3191 int
bcm_format_flags(const bcm_bit_desc_t * bd,uint32 flags,char * buf,int len)3192 bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
3193 {
3194 	int i;
3195 	char* p = buf;
3196 	char hexstr[16];
3197 	int slen = 0, nlen = 0;
3198 	uint32 bit;
3199 	const char* name;
3200 
3201 	if (len < 2 || !buf)
3202 		return 0;
3203 
3204 	buf[0] = '\0';
3205 
3206 	for (i = 0; flags != 0; i++) {
3207 		bit = bd[i].bit;
3208 		name = bd[i].name;
3209 		if (bit == 0 && flags != 0) {
3210 			/* print any unnamed bits */
3211 			snprintf(hexstr, 16, "0x%X", flags);
3212 			name = hexstr;
3213 			flags = 0;	/* exit loop */
3214 		} else if ((flags & bit) == 0)
3215 			continue;
3216 		flags &= ~bit;
3217 		nlen = (int)strlen(name);
3218 		slen += nlen;
3219 		/* count btwn flag space */
3220 		if (flags != 0)
3221 			slen += 1;
3222 		/* need NULL char as well */
3223 		if (len <= slen)
3224 			break;
3225 		/* copy NULL char but don't count it */
3226 		strncpy(p, name, (size_t)len);
3227 		p += nlen;
3228 		/* copy btwn flag space and NULL char */
3229 		if (flags != 0)
3230 			p += snprintf(p, 2, " ");
3231 	}
3232 
3233 	/* indicate the str was too short */
3234 	if (flags != 0) {
3235 		p += snprintf(p, 2, ">");
3236 	}
3237 
3238 	return (int)(p - buf);
3239 }
3240 
3241 /* print out whcih bits in octet array 'addr' are set. bcm_bit_desc_t:bit is a bit offset. */
3242 int
bcm_format_octets(const bcm_bit_desc_t * bd,uint bdsz,const uint8 * addr,uint size,char * buf,int len)3243 bcm_format_octets(const bcm_bit_desc_t *bd, uint bdsz,
3244 	const uint8 *addr, uint size, char *buf, int len)
3245 {
3246 	uint i;
3247 	char *p = buf;
3248 	int slen = 0, nlen = 0;
3249 	uint32 bit;
3250 	const char* name;
3251 	bool more = FALSE;
3252 
3253 	BCM_REFERENCE(size);
3254 
3255 	if (len < 2 || !buf)
3256 		return 0;
3257 
3258 	buf[0] = '\0';
3259 
3260 	for (i = 0; i < bdsz; i++) {
3261 		bit = bd[i].bit;
3262 		name = bd[i].name;
3263 		CLANG_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3264 		if (isset(addr, bit)) {
3265 		CLANG_DIAGNOSTIC_POP();
3266 			nlen = (int)strlen(name);
3267 			slen += nlen;
3268 			/* need SPACE - for simplicity */
3269 			slen += 1;
3270 			/* need NULL as well */
3271 			if (len < slen + 1) {
3272 				more = TRUE;
3273 				break;
3274 			}
3275 			memcpy(p, name, (size_t)nlen);
3276 			p += nlen;
3277 			p[0] = ' ';
3278 			p += 1;
3279 			p[0] = '\0';
3280 		}
3281 	}
3282 
3283 	if (more) {
3284 		p[0] = '>';
3285 		p += 1;
3286 		p[0] = '\0';
3287 	}
3288 
3289 	return (int)(p - buf);
3290 }
3291 #endif // endif
3292 
3293 /* print bytes formatted as hex to a string. return the resulting string length */
3294 int
bcm_format_hex(char * str,const void * bytes,int len)3295 bcm_format_hex(char *str, const void *bytes, int len)
3296 {
3297 	int i;
3298 	char *p = str;
3299 	const uint8 *src = (const uint8*)bytes;
3300 
3301 	for (i = 0; i < len; i++) {
3302 		p += snprintf(p, 3, "%02X", *src);
3303 		src++;
3304 	}
3305 	return (int)(p - str);
3306 }
3307 
3308 /* pretty hex print a contiguous buffer */
3309 void
prhex(const char * msg,const uchar * buf,uint nbytes)3310 prhex(const char *msg, const uchar *buf, uint nbytes)
3311 {
3312 	char line[128], *p;
3313 	int len = sizeof(line);
3314 	int nchar;
3315 	uint i;
3316 
3317 	if (msg && (msg[0] != '\0'))
3318 		printf("%s:\n", msg);
3319 
3320 	p = line;
3321 	for (i = 0; i < nbytes; i++) {
3322 		if (i % 16 == 0) {
3323 			nchar = snprintf(p, (size_t)len, "  %04x: ", i);	/* line prefix */
3324 			p += nchar;
3325 			len -= nchar;
3326 		}
3327 		if (len > 0) {
3328 			nchar = snprintf(p, (size_t)len, "%02x ", buf[i]);
3329 			p += nchar;
3330 			len -= nchar;
3331 		}
3332 
3333 		if (i % 16 == 15) {
3334 			printf("%s\n", line);		/* flush line */
3335 			p = line;
3336 			len = sizeof(line);
3337 		}
3338 	}
3339 
3340 	/* flush last partial line */
3341 	if (p != line)
3342 		printf("%s\n", line);
3343 }
3344 
3345 static const char *crypto_algo_names[] = {
3346 	"NONE",
3347 	"WEP1",
3348 	"TKIP",
3349 	"WEP128",
3350 	"AES_CCM",
3351 	"AES_OCB_MSDU",
3352 	"AES_OCB_MPDU",
3353 #ifdef BCMCCX
3354 	"CKIP",
3355 	"CKIP_MMH",
3356 	"WEP_MMH",
3357 	"NALG",
3358 #else
3359 	"NALG",
3360 	"UNDEF",
3361 	"UNDEF",
3362 	"UNDEF",
3363 #endif /* BCMCCX */
3364 #ifdef BCMWAPI_WAI
3365 	"WAPI",
3366 #else
3367 	"UNDEF",
3368 #endif // endif
3369 	"PMK",
3370 	"BIP",
3371 	"AES_GCM",
3372 	"AES_CCM256",
3373 	"AES_GCM256",
3374 	"BIP_CMAC256",
3375 	"BIP_GMAC",
3376 	"BIP_GMAC256",
3377 	"UNDEF"
3378 };
3379 
3380 const char *
bcm_crypto_algo_name(uint algo)3381 bcm_crypto_algo_name(uint algo)
3382 {
3383 	return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
3384 }
3385 
3386 char *
bcm_chipname(uint chipid,char * buf,uint len)3387 bcm_chipname(uint chipid, char *buf, uint len)
3388 {
3389 	const char *fmt;
3390 
3391 	fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
3392 	/*
3393 	  * The following call to snprintf generates a compiler warning
3394 	  * due to -Wformat-nonliteral. However, the format string is coming
3395 	  * from internal callers rather than external data input, and is a
3396 	  * useful debugging tool serving a variety of diagnostics. Rather
3397 	  * than expand code size by replicating multiple functions with different
3398 	  * argument lists, or disabling the warning globally, let's consider
3399 	  * if we can just disable the warning for this one instance.
3400 	  */
3401 	CLANG_DIAGNOSTIC_PUSH_SUPPRESS_FORMAT()
3402 	snprintf(buf, len, fmt, chipid);
3403 	CLANG_DIAGNOSTIC_POP()
3404 	return buf;
3405 }
3406 
3407 /* Produce a human-readable string for boardrev */
3408 char *
bcm_brev_str(uint32 brev,char * buf)3409 bcm_brev_str(uint32 brev, char *buf)
3410 {
3411 	if (brev < 0x100)
3412 		snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
3413 	else
3414 		snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
3415 
3416 	return (buf);
3417 }
3418 
3419 #define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
3420 
3421 /* dump large strings to console */
3422 void
printbig(char * buf)3423 printbig(char *buf)
3424 {
3425 	uint len, max_len;
3426 	char c;
3427 
3428 	len = (uint)strlen(buf);
3429 
3430 	max_len = BUFSIZE_TODUMP_ATONCE;
3431 
3432 	while (len > max_len) {
3433 		c = buf[max_len];
3434 		buf[max_len] = '\0';
3435 		printf("%s", buf);
3436 		buf[max_len] = c;
3437 
3438 		buf += max_len;
3439 		len -= max_len;
3440 	}
3441 	/* print the remaining string */
3442 	printf("%s\n", buf);
3443 	return;
3444 }
3445 
3446 /* routine to dump fields in a fileddesc structure */
3447 uint
bcmdumpfields(bcmutl_rdreg_rtn read_rtn,void * arg0,uint arg1,struct fielddesc * fielddesc_array,char * buf,uint32 bufsize)3448 bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
3449 	char *buf, uint32 bufsize)
3450 {
3451 	uint  filled_len;
3452 	int len;
3453 	struct fielddesc *cur_ptr;
3454 
3455 	filled_len = 0;
3456 	cur_ptr = fielddesc_array;
3457 
3458 	while (bufsize > 1) {
3459 		if (cur_ptr->nameandfmt == NULL)
3460 			break;
3461 
3462 		/*
3463 		 * The following call to snprintf generates a compiler warning
3464 		 * due to -Wformat-nonliteral. However, the format string is coming
3465 		 * from internal callers rather than external data input, and is a
3466 		 * useful debugging tool serving a variety of diagnostics. Rather
3467 		 * than expand code size by replicating multiple functions with different
3468 		 * argument lists, or disabling the warning globally, let's consider
3469 		 * if we can just disable the warning for this one instance.
3470 		 */
3471 		CLANG_DIAGNOSTIC_PUSH_SUPPRESS_FORMAT()
3472 		len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
3473 		read_rtn(arg0, arg1, cur_ptr->offset));
3474 		CLANG_DIAGNOSTIC_POP()
3475 		/* check for snprintf overflow or error */
3476 		if (len < 0 || (uint32)len >= bufsize)
3477 			len = (int)(bufsize - 1);
3478 		buf += len;
3479 		bufsize -= (uint32)len;
3480 		filled_len += (uint32)len;
3481 		cur_ptr++;
3482 	}
3483 	return filled_len;
3484 }
3485 
3486 uint
bcm_mkiovar(const char * name,const char * data,uint datalen,char * buf,uint buflen)3487 bcm_mkiovar(const char *name, const char *data, uint datalen, char *buf, uint buflen)
3488 {
3489 	uint len;
3490 
3491 	len = (uint)strlen(name) + 1;
3492 
3493 	if ((len + datalen) > buflen)
3494 		return 0;
3495 
3496 	strncpy(buf, name, buflen);
3497 
3498 	/* append data onto the end of the name string */
3499 	if (data && datalen != 0) {
3500 		memcpy(&buf[len], data, datalen);
3501 		len += datalen;
3502 	}
3503 
3504 	return len;
3505 }
3506 
3507 /* Quarter dBm units to mW
3508  * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
3509  * Table is offset so the last entry is largest mW value that fits in
3510  * a uint16.
3511  */
3512 
3513 #define QDBM_OFFSET 153		/* Offset for first entry */
3514 #define QDBM_TABLE_LEN 40	/* Table size */
3515 
3516 /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
3517  * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
3518  */
3519 #define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
3520 
3521 /* Largest mW value that will round down to the last table entry,
3522  * QDBM_OFFSET + QDBM_TABLE_LEN-1.
3523  * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
3524  */
3525 #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
3526 
3527 static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
3528 /* qdBm:	+0	+1	+2	+3	+4	+5	+6	+7 */
3529 /* 153: */      6683,	7079,	7499,	7943,	8414,	8913,	9441,	10000,
3530 /* 161: */      10593,	11220,	11885,	12589,	13335,	14125,	14962,	15849,
3531 /* 169: */      16788,	17783,	18836,	19953,	21135,	22387,	23714,	25119,
3532 /* 177: */      26607,	28184,	29854,	31623,	33497,	35481,	37584,	39811,
3533 /* 185: */      42170,	44668,	47315,	50119,	53088,	56234,	59566,	63096
3534 };
3535 
3536 uint16
bcm_qdbm_to_mw(uint8 qdbm)3537 bcm_qdbm_to_mw(uint8 qdbm)
3538 {
3539 	uint factor = 1;
3540 	int idx = qdbm - QDBM_OFFSET;
3541 
3542 	if (idx >= QDBM_TABLE_LEN) {
3543 		/* clamp to max uint16 mW value */
3544 		return 0xFFFF;
3545 	}
3546 
3547 	/* scale the qdBm index up to the range of the table 0-40
3548 	 * where an offset of 40 qdBm equals a factor of 10 mW.
3549 	 */
3550 	while (idx < 0) {
3551 		idx += 40;
3552 		factor *= 10;
3553 	}
3554 
3555 	/* return the mW value scaled down to the correct factor of 10,
3556 	 * adding in factor/2 to get proper rounding.
3557 	 */
3558 	return (uint16)((nqdBm_to_mW_map[idx] + factor/2) / factor);
3559 }
3560 
3561 uint8
bcm_mw_to_qdbm(uint16 mw)3562 bcm_mw_to_qdbm(uint16 mw)
3563 {
3564 	uint8 qdbm;
3565 	int offset;
3566 	uint mw_uint = mw;
3567 	uint boundary;
3568 
3569 	/* handle boundary case */
3570 	if (mw_uint <= 1)
3571 		return 0;
3572 
3573 	offset = QDBM_OFFSET;
3574 
3575 	/* move mw into the range of the table */
3576 	while (mw_uint < QDBM_TABLE_LOW_BOUND) {
3577 		mw_uint *= 10;
3578 		offset -= 40;
3579 	}
3580 
3581 	for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
3582 		boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
3583 		                                    nqdBm_to_mW_map[qdbm])/2;
3584 		if (mw_uint < boundary) break;
3585 	}
3586 
3587 	qdbm += (uint8)offset;
3588 
3589 	return (qdbm);
3590 }
3591 
3592 uint
bcm_bitcount(uint8 * bitmap,uint length)3593 bcm_bitcount(uint8 *bitmap, uint length)
3594 {
3595 	uint bitcount = 0, i;
3596 	uint8 tmp;
3597 	for (i = 0; i < length; i++) {
3598 		tmp = bitmap[i];
3599 		while (tmp) {
3600 			bitcount++;
3601 			tmp &= (tmp - 1);
3602 		}
3603 	}
3604 	return bitcount;
3605 }
3606 
3607 /*
3608  * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
3609  * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
3610  * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
3611  * Shortens buffer as needed and pads with NULs.  End of buffer is marked by two NULs.
3612 */
3613 
3614 unsigned int
process_nvram_vars(char * varbuf,unsigned int len)3615 process_nvram_vars(char *varbuf, unsigned int len)
3616 {
3617 	char *dp;
3618 	bool findNewline;
3619 	int column;
3620 	unsigned int buf_len, n;
3621 	unsigned int pad = 0;
3622 	char nv_ver[128];
3623 
3624 	dp = varbuf;
3625 
3626 	findNewline = FALSE;
3627 	column = 0;
3628 
3629 	// terence 20130914: print out NVRAM version
3630 	if (varbuf[0] == '#') {
3631 		memset(nv_ver, 0x00, sizeof(nv_ver));
3632 		for (n=1; n<len && n<(sizeof(nv_ver)-1); n++) {
3633 			if (varbuf[n] == '\n')
3634 				break;
3635 			nv_ver[n-1] = varbuf[n];
3636 		}
3637 		printf("NVRAM version: %s\n", nv_ver);
3638 	}
3639 
3640 	for (n = 0; n < len; n++) {
3641 		if (varbuf[n] == '\r')
3642 			continue;
3643 		if (findNewline && varbuf[n] != '\n')
3644 			continue;
3645 		findNewline = FALSE;
3646 		if (varbuf[n] == '#') {
3647 			findNewline = TRUE;
3648 			continue;
3649 		}
3650 		if (varbuf[n] == '\n') {
3651 			if (column == 0)
3652 				continue;
3653 			*dp++ = 0;
3654 			column = 0;
3655 			continue;
3656 		}
3657 		*dp++ = varbuf[n];
3658 		column++;
3659 	}
3660 	buf_len = (unsigned int)(dp - varbuf);
3661 	if (buf_len % 4) {
3662 		pad = 4 - buf_len % 4;
3663 		if (pad && (buf_len + pad <= len)) {
3664 			buf_len += pad;
3665 		}
3666 	}
3667 
3668 	while (dp < varbuf + n)
3669 		*dp++ = 0;
3670 
3671 	return buf_len;
3672 }
3673 
3674 #ifndef setbit /* As in the header file */
3675 #ifdef BCMUTILS_BIT_MACROS_USE_FUNCS
3676 /* Set bit in byte array. */
3677 void
setbit(void * array,uint bit)3678 setbit(void *array, uint bit)
3679 {
3680 	((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY);
3681 }
3682 
3683 /* Clear bit in byte array. */
3684 void
clrbit(void * array,uint bit)3685 clrbit(void *array, uint bit)
3686 {
3687 	((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY));
3688 }
3689 
3690 /* Test if bit is set in byte array. */
3691 bool
isset(const void * array,uint bit)3692 isset(const void *array, uint bit)
3693 {
3694 	return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY)));
3695 }
3696 
3697 /* Test if bit is clear in byte array. */
3698 bool
isclr(const void * array,uint bit)3699 isclr(const void *array, uint bit)
3700 {
3701 	return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0);
3702 }
3703 #endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */
3704 #endif /* setbit */
3705 
3706 void
set_bitrange(void * array,uint start,uint end,uint maxbit)3707 set_bitrange(void *array, uint start, uint end, uint maxbit)
3708 {
3709 	uint startbyte = start/NBBY;
3710 	uint endbyte = end/NBBY;
3711 	uint i, startbytelastbit, endbytestartbit;
3712 
3713 	if (end >= start) {
3714 		if (endbyte - startbyte > 1)
3715 		{
3716 			startbytelastbit = (startbyte+1)*NBBY - 1;
3717 			endbytestartbit = endbyte*NBBY;
3718 			for (i = startbyte+1; i < endbyte; i++)
3719 				((uint8 *)array)[i] = 0xFF;
3720 			for (i = start; i <= startbytelastbit; i++)
3721 				setbit(array, i);
3722 			for (i = endbytestartbit; i <= end; i++)
3723 				setbit(array, i);
3724 		} else {
3725 			for (i = start; i <= end; i++)
3726 				setbit(array, i);
3727 		}
3728 	}
3729 	else {
3730 		set_bitrange(array, start, maxbit, maxbit);
3731 		set_bitrange(array, 0, end, maxbit);
3732 	}
3733 }
3734 
3735 void
bcm_bitprint32(const uint32 u32arg)3736 bcm_bitprint32(const uint32 u32arg)
3737 {
3738 	int i;
3739 	for (i = NBITS(uint32) - 1; i >= 0; i--) {
3740 		if (isbitset(u32arg, i)) {
3741 			printf("1");
3742 		} else {
3743 			printf("0");
3744 		}
3745 
3746 		if ((i % NBBY) == 0) printf(" ");
3747 	}
3748 	printf("\n");
3749 }
3750 
3751 /* calculate checksum for ip header, tcp / udp header / data */
3752 uint16
bcm_ip_cksum(uint8 * buf,uint32 len,uint32 sum)3753 bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum)
3754 {
3755 	while (len > 1) {
3756 		sum += (uint32)((buf[0] << 8) | buf[1]);
3757 		buf += 2;
3758 		len -= 2;
3759 	}
3760 
3761 	if (len > 0) {
3762 		sum += (uint32)((*buf) << 8);
3763 	}
3764 
3765 	while (sum >> 16) {
3766 		sum = (sum & 0xffff) + (sum >> 16);
3767 	}
3768 
3769 	return ((uint16)~sum);
3770 }
3771 
3772 int
BCMRAMFN(valid_bcmerror)3773 BCMRAMFN(valid_bcmerror)(int e)
3774 {
3775 	return ((e <= 0) && (e >= BCME_LAST));
3776 }
3777 
3778 #ifdef DEBUG_COUNTER
3779 #if (OSL_SYSUPTIME_SUPPORT == TRUE)
counter_printlog(counter_tbl_t * ctr_tbl)3780 void counter_printlog(counter_tbl_t *ctr_tbl)
3781 {
3782 	uint32 now;
3783 
3784 	if (!ctr_tbl->enabled)
3785 		return;
3786 
3787 	now = OSL_SYSUPTIME();
3788 
3789 	if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) {
3790 		uint8 i = 0;
3791 		printf("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print);
3792 
3793 		for (i = 0; i < ctr_tbl->needed_cnt; i++) {
3794 			printf(" %u", ctr_tbl->cnt[i]);
3795 		}
3796 		printf("\n");
3797 
3798 		ctr_tbl->prev_log_print = now;
3799 		bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint));
3800 	}
3801 }
3802 #else
3803 /* OSL_SYSUPTIME is not supported so no way to get time */
3804 #define counter_printlog(a) do {} while (0)
3805 #endif /* OSL_SYSUPTIME_SUPPORT == TRUE */
3806 #endif /* DEBUG_COUNTER */
3807 
3808 /* calculate partial checksum */
3809 static uint32
ip_cksum_partial(uint32 sum,uint8 * val8,uint32 count)3810 ip_cksum_partial(uint32 sum, uint8 *val8, uint32 count)
3811 {
3812 	uint32 i;
3813 	uint16 *val16 = (uint16 *)val8;
3814 
3815 	ASSERT(val8 != NULL);
3816 	/* partial chksum calculated on 16-bit values */
3817 	ASSERT((count % 2) == 0);
3818 
3819 	count /= 2;
3820 
3821 	for (i = 0; i < count; i++) {
3822 		sum += *val16++;
3823 	}
3824 	return sum;
3825 }
3826 
3827 /* calculate IP checksum */
3828 static uint16
ip_cksum(uint32 sum,uint8 * val8,uint32 count)3829 ip_cksum(uint32 sum, uint8 *val8, uint32 count)
3830 {
3831 	uint16 *val16 = (uint16 *)val8;
3832 
3833 	ASSERT(val8 != NULL);
3834 
3835 	while (count > 1) {
3836 		sum += *val16++;
3837 		count -= 2;
3838 	}
3839 	/*  add left-over byte, if any */
3840 	if (count > 0) {
3841 		sum += (*(uint8 *)val16);
3842 	}
3843 
3844 	/*  fold 32-bit sum to 16 bits */
3845 	sum = (sum >> 16) + (sum & 0xffff);
3846 	sum += (sum >> 16);
3847 	return ((uint16)~sum);
3848 }
3849 
3850 /* calculate IPv4 header checksum
3851  * - input ip points to IP header in network order
3852  * - output cksum is in network order
3853  */
3854 uint16
ipv4_hdr_cksum(uint8 * ip,int ip_len)3855 ipv4_hdr_cksum(uint8 *ip, int ip_len)
3856 {
3857 	uint32 sum = 0;
3858 	uint8 *ptr = ip;
3859 
3860 	ASSERT(ip != NULL);
3861 	ASSERT(ip_len >= IPV4_MIN_HEADER_LEN);
3862 
3863 	/* partial cksum skipping the hdr_chksum field */
3864 	sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct ipv4_hdr, hdr_chksum));
3865 	ptr += OFFSETOF(struct ipv4_hdr, hdr_chksum) + 2;
3866 
3867 	/* return calculated chksum */
3868 	return ip_cksum(sum, ptr, (uint32)((uint)ip_len - OFFSETOF(struct ipv4_hdr, src_ip)));
3869 }
3870 
3871 /* calculate TCP header checksum using partial sum */
3872 static uint16
tcp_hdr_chksum(uint32 sum,uint8 * tcp_hdr,uint16 tcp_len)3873 tcp_hdr_chksum(uint32 sum, uint8 *tcp_hdr, uint16 tcp_len)
3874 {
3875 	uint8 *ptr = tcp_hdr;
3876 
3877 	ASSERT(tcp_hdr != NULL);
3878 	ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
3879 
3880 	/* partial TCP cksum skipping the chksum field */
3881 	sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct bcmtcp_hdr, chksum));
3882 	ptr += OFFSETOF(struct bcmtcp_hdr, chksum) + 2;
3883 
3884 	/* return calculated chksum */
3885 	return ip_cksum(sum, ptr, tcp_len - OFFSETOF(struct bcmtcp_hdr, urg_ptr));
3886 }
3887 
3888 struct tcp_pseudo_hdr {
3889 	uint8   src_ip[IPV4_ADDR_LEN];  /* Source IP Address */
3890 	uint8   dst_ip[IPV4_ADDR_LEN];  /* Destination IP Address */
3891 	uint8	zero;
3892 	uint8	prot;
3893 	uint16	tcp_size;
3894 };
3895 
3896 /* calculate IPv4 TCP header checksum
3897  * - input ip and tcp points to IP and TCP header in network order
3898  * - output cksum is in network order
3899  */
3900 uint16
ipv4_tcp_hdr_cksum(uint8 * ip,uint8 * tcp,uint16 tcp_len)3901 ipv4_tcp_hdr_cksum(uint8 *ip, uint8 *tcp, uint16 tcp_len)
3902 {
3903 	struct ipv4_hdr *ip_hdr = (struct ipv4_hdr *)ip;
3904 	struct tcp_pseudo_hdr tcp_ps;
3905 	uint32 sum = 0;
3906 
3907 	ASSERT(ip != NULL);
3908 	ASSERT(tcp != NULL);
3909 	ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
3910 
3911 	if (!ip || !tcp || !(tcp_len >= TCP_MIN_HEADER_LEN))
3912 		return 0;
3913 	/* pseudo header cksum */
3914 	memset(&tcp_ps, 0, sizeof(tcp_ps));
3915 	memcpy(&tcp_ps.dst_ip, ip_hdr->dst_ip, IPV4_ADDR_LEN);
3916 	memcpy(&tcp_ps.src_ip, ip_hdr->src_ip, IPV4_ADDR_LEN);
3917 	tcp_ps.zero = 0;
3918 	tcp_ps.prot = ip_hdr->prot;
3919 	tcp_ps.tcp_size = hton16(tcp_len);
3920 	sum = ip_cksum_partial(sum, (uint8 *)&tcp_ps, sizeof(tcp_ps));
3921 
3922 	/* return calculated TCP header chksum */
3923 	return tcp_hdr_chksum(sum, tcp, tcp_len);
3924 }
3925 
3926 struct ipv6_pseudo_hdr {
3927 	uint8  saddr[IPV6_ADDR_LEN];
3928 	uint8  daddr[IPV6_ADDR_LEN];
3929 	uint16 payload_len;
3930 	uint8  zero;
3931 	uint8  next_hdr;
3932 };
3933 
3934 /* calculate IPv6 TCP header checksum
3935  * - input ipv6 and tcp points to IPv6 and TCP header in network order
3936  * - output cksum is in network order
3937  */
3938 uint16
ipv6_tcp_hdr_cksum(uint8 * ipv6,uint8 * tcp,uint16 tcp_len)3939 ipv6_tcp_hdr_cksum(uint8 *ipv6, uint8 *tcp, uint16 tcp_len)
3940 {
3941 	struct ipv6_hdr *ipv6_hdr = (struct ipv6_hdr *)ipv6;
3942 	struct ipv6_pseudo_hdr ipv6_pseudo;
3943 	uint32 sum = 0;
3944 
3945 	ASSERT(ipv6 != NULL);
3946 	ASSERT(tcp != NULL);
3947 	ASSERT(tcp_len >= TCP_MIN_HEADER_LEN);
3948 
3949 	if (!ipv6 || !tcp || !(tcp_len >= TCP_MIN_HEADER_LEN))
3950 		return 0;
3951 	/* pseudo header cksum */
3952 	memset((char *)&ipv6_pseudo, 0, sizeof(ipv6_pseudo));
3953 	memcpy((char *)ipv6_pseudo.saddr, (char *)ipv6_hdr->saddr.addr,
3954 		sizeof(ipv6_pseudo.saddr));
3955 	memcpy((char *)ipv6_pseudo.daddr, (char *)ipv6_hdr->daddr.addr,
3956 		sizeof(ipv6_pseudo.daddr));
3957 	ipv6_pseudo.payload_len = ipv6_hdr->payload_len;
3958 	ipv6_pseudo.next_hdr = ipv6_hdr->nexthdr;
3959 	sum = ip_cksum_partial(sum, (uint8 *)&ipv6_pseudo, sizeof(ipv6_pseudo));
3960 
3961 	/* return calculated TCP header chksum */
3962 	return tcp_hdr_chksum(sum, tcp, tcp_len);
3963 }
3964 
3965 void *_bcmutils_dummy_fn = NULL;
3966 
3967 /* GROUP 1 --- start
3968  * These function under GROUP 1 are general purpose functions to do complex number
3969  * calculations and square root calculation.
3970  */
3971 
sqrt_int(uint32 value)3972 uint32 sqrt_int(uint32 value)
3973 {
3974 	uint32 root = 0, shift = 0;
3975 
3976 	/* Compute integer nearest to square root of input integer value */
3977 	for (shift = 0; shift < 32; shift += 2) {
3978 		if (((0x40000000 >> shift) + root) <= value) {
3979 			value -= ((0x40000000 >> shift) + root);
3980 			root = (root >> 1) | (0x40000000 >> shift);
3981 		}
3982 		else {
3983 			root = root >> 1;
3984 		}
3985 	}
3986 
3987 	/* round to the nearest integer */
3988 	if (root < value) ++root;
3989 
3990 	return root;
3991 }
3992 /* GROUP 1 --- end */
3993 
3994 /* read/write field in a consecutive bits in an octet array.
3995  * 'addr' is the octet array's start byte address
3996  * 'size' is the octet array's byte size
3997  * 'stbit' is the value's start bit offset
3998  * 'nbits' is the value's bit size
3999  * This set of utilities are for convenience. Don't use them
4000  * in time critical/data path as there's a great overhead in them.
4001  */
4002 void
setbits(uint8 * addr,uint size,uint stbit,uint nbits,uint32 val)4003 setbits(uint8 *addr, uint size, uint stbit, uint nbits, uint32 val)
4004 {
4005 	uint fbyte = stbit >> 3;		/* first byte */
4006 	uint lbyte = (stbit + nbits - 1) >> 3;	/* last byte */
4007 	uint fbit = stbit & 7;			/* first bit in the first byte */
4008 	uint rbits = (nbits > 8 - fbit ?
4009 	              nbits - (8 - fbit) :
4010 	              0) & 7;			/* remaining bits of the last byte when not 0 */
4011 	uint8 mask;
4012 	uint byte;
4013 
4014 	BCM_REFERENCE(size);
4015 
4016 	ASSERT(fbyte < size);
4017 	ASSERT(lbyte < size);
4018 	ASSERT(nbits <= (sizeof(val) << 3));
4019 
4020 	/* all bits are in the same byte */
4021 	if (fbyte == lbyte) {
4022 		mask = (uint8)(((1 << nbits) - 1) << fbit);
4023 		addr[fbyte] &= ~mask;
4024 		addr[fbyte] |= (uint8)(val << fbit);
4025 		return;
4026 	}
4027 
4028 	/* first partial byte */
4029 	if (fbit > 0) {
4030 		mask = (uint8)(0xff << fbit);
4031 		addr[fbyte] &= ~mask;
4032 		addr[fbyte] |= (uint8)(val << fbit);
4033 		val >>= (8 - fbit);
4034 		nbits -= (8 - fbit);
4035 		fbyte ++;	/* first full byte */
4036 	}
4037 
4038 	/* last partial byte */
4039 	if (rbits > 0) {
4040 		mask = (uint8)((1 << rbits) - 1);
4041 		addr[lbyte] &= ~mask;
4042 		addr[lbyte] |= (uint8)(val >> (nbits - rbits));
4043 		lbyte --;	/* last full byte */
4044 	}
4045 
4046 	/* remaining full byte(s) */
4047 	for (byte = fbyte; byte <= lbyte; byte ++) {
4048 		addr[byte] = (uint8)val;
4049 		val >>= 8;
4050 	}
4051 }
4052 
4053 uint32
getbits(const uint8 * addr,uint size,uint stbit,uint nbits)4054 getbits(const uint8 *addr, uint size, uint stbit, uint nbits)
4055 {
4056 	uint fbyte = stbit >> 3;		/* first byte */
4057 	uint lbyte = (stbit + nbits - 1) >> 3;	/* last byte */
4058 	uint fbit = stbit & 7;			/* first bit in the first byte */
4059 	uint rbits = (nbits > 8 - fbit ?
4060 	              nbits - (8 - fbit) :
4061 	              0) & 7;			/* remaining bits of the last byte when not 0 */
4062 	uint32 val = 0;
4063 	uint bits = 0;				/* bits in first partial byte */
4064 	uint8 mask;
4065 	uint byte;
4066 
4067 	BCM_REFERENCE(size);
4068 
4069 	ASSERT(fbyte < size);
4070 	ASSERT(lbyte < size);
4071 	ASSERT(nbits <= (sizeof(val) << 3));
4072 
4073 	/* all bits are in the same byte */
4074 	if (fbyte == lbyte) {
4075 		mask = (uint8)(((1 << nbits) - 1) << fbit);
4076 		val = (addr[fbyte] & mask) >> fbit;
4077 		return val;
4078 	}
4079 
4080 	/* first partial byte */
4081 	if (fbit > 0) {
4082 		bits = 8 - fbit;
4083 		mask = (uint8)(0xFFu << fbit);
4084 		val |= (addr[fbyte] & mask) >> fbit;
4085 		fbyte ++;	/* first full byte */
4086 	}
4087 
4088 	/* last partial byte */
4089 	if (rbits > 0) {
4090 		mask = (uint8)((1 << rbits) - 1);
4091 		val |= (uint32)((addr[lbyte] & mask) << (nbits - rbits));
4092 		lbyte --;	/* last full byte */
4093 	}
4094 
4095 	/* remaining full byte(s) */
4096 	for (byte = fbyte; byte <= lbyte; byte ++) {
4097 		val |= (uint32)((addr[byte] << (((byte - fbyte) << 3) + bits)));
4098 	}
4099 
4100 	return val;
4101 }
4102 
4103 #ifdef BCMDRIVER
4104 
4105 /** allocate variable sized data with 'size' bytes. note: vld should NOT be null.
4106  */
4107 int
bcm_vdata_alloc(osl_t * osh,var_len_data_t * vld,uint32 size)4108 bcm_vdata_alloc(osl_t *osh, var_len_data_t *vld, uint32 size)
4109 {
4110 	int ret = BCME_ERROR;
4111 	uint8 *dat = NULL;
4112 
4113 	if (vld == NULL) {
4114 		ASSERT(0);
4115 		goto done;
4116 	}
4117 
4118 	/* trying to allocate twice? */
4119 	if (vld->vdata != NULL) {
4120 		ASSERT(0);
4121 		goto done;
4122 	}
4123 
4124 	/* trying to allocate 0 size? */
4125 	if (size == 0) {
4126 		ASSERT(0);
4127 		ret = BCME_BADARG;
4128 		goto done;
4129 	}
4130 
4131 	dat = MALLOCZ(osh, size);
4132 	if (dat == NULL) {
4133 		ret = BCME_NOMEM;
4134 		goto done;
4135 	}
4136 	vld->vlen = size;
4137 	vld->vdata = dat;
4138 	ret = BCME_OK;
4139 done:
4140 	return ret;
4141 }
4142 
4143 /** free memory associated with variable sized data. note: vld should NOT be null.
4144  */
4145 int
bcm_vdata_free(osl_t * osh,var_len_data_t * vld)4146 bcm_vdata_free(osl_t *osh, var_len_data_t *vld)
4147 {
4148 	int ret = BCME_ERROR;
4149 
4150 	if (vld == NULL) {
4151 		ASSERT(0);
4152 		goto done;
4153 	}
4154 
4155 	if (vld->vdata) {
4156 		MFREE(osh, vld->vdata, vld->vlen);
4157 		vld->vdata = NULL;
4158 		vld->vlen = 0;
4159 		ret = BCME_OK;
4160 	}
4161 done:
4162 	return ret;
4163 }
4164 
4165 #endif /* BCMDRIVER */
4166 
4167 /* Count the number of elements not matching a given value in a null terminated array */
4168 int
array_value_mismatch_count(uint8 value,uint8 * array,int array_size)4169 array_value_mismatch_count(uint8 value, uint8 *array, int array_size)
4170 {
4171 	int i;
4172 	int count = 0;
4173 
4174 	for (i = 0; i < array_size; i++) {
4175 		/* exit if a null terminator is found */
4176 		if (array[i] == 0) {
4177 			break;
4178 		}
4179 		if (array[i] != value) {
4180 			count++;
4181 		}
4182 	}
4183 	return count;
4184 }
4185 
4186 /* Count the number of non-zero elements in an uint8 array */
4187 int
array_nonzero_count(uint8 * array,int array_size)4188 array_nonzero_count(uint8 *array, int array_size)
4189 {
4190 	return array_value_mismatch_count(0, array, array_size);
4191 }
4192 
4193 /* Count the number of non-zero elements in an int16 array */
4194 int
array_nonzero_count_int16(int16 * array,int array_size)4195 array_nonzero_count_int16(int16 *array, int array_size)
4196 {
4197 	int i;
4198 	int count = 0;
4199 
4200 	for (i = 0; i < array_size; i++) {
4201 		if (array[i] != 0) {
4202 			count++;
4203 		}
4204 	}
4205 	return count;
4206 }
4207 
4208 /* Count the number of zero elements in an uint8 array */
4209 int
array_zero_count(uint8 * array,int array_size)4210 array_zero_count(uint8 *array, int array_size)
4211 {
4212 	int i;
4213 	int count = 0;
4214 
4215 	for (i = 0; i < array_size; i++) {
4216 		if (array[i] == 0) {
4217 			count++;
4218 		}
4219 	}
4220 	return count;
4221 }
4222 
4223 /* Validate an array that can be 1 of 2 data types.
4224  * One of array1 or array2 should be non-NULL.  The other should be NULL.
4225  */
4226 static int
verify_ordered_array(uint8 * array1,int16 * array2,int array_size,int range_lo,int range_hi,bool err_if_no_zero_term,bool is_ordered)4227 verify_ordered_array(uint8 *array1, int16 *array2, int array_size,
4228 	int range_lo, int range_hi, bool err_if_no_zero_term, bool is_ordered)
4229 {
4230 	int ret;
4231 	int i;
4232 	int val = 0;
4233 	int prev_val = 0;
4234 
4235 	ret = err_if_no_zero_term ? BCME_NOTFOUND : BCME_OK;
4236 
4237 	/* Check that:
4238 	 * - values are in strict descending order.
4239 	 * - values are within the valid range.
4240 	 */
4241 	for (i = 0; i < array_size; i++) {
4242 		if (array1) {
4243 			val = (int)array1[i];
4244 		} else if (array2) {
4245 			val = (int)array2[i];
4246 		} else {
4247 			/* both array parameters are NULL */
4248 			return BCME_NOTFOUND;
4249 		}
4250 		if (val == 0) {
4251 			/* array is zero-terminated */
4252 			ret = BCME_OK;
4253 			break;
4254 		}
4255 
4256 		if (is_ordered && i > 0 && val >= prev_val) {
4257 			/* array is not in descending order */
4258 			ret = BCME_BADOPTION;
4259 			break;
4260 		}
4261 		prev_val = val;
4262 
4263 		if (val < range_lo || val > range_hi) {
4264 			/* array value out of range */
4265 			ret = BCME_RANGE;
4266 			break;
4267 		}
4268 	}
4269 
4270 	return ret;
4271 }
4272 
4273 /* Validate an ordered uint8 configuration array */
4274 int
verify_ordered_array_uint8(uint8 * array,int array_size,uint8 range_lo,uint8 range_hi)4275 verify_ordered_array_uint8(uint8 *array, int array_size,
4276 	uint8 range_lo, uint8 range_hi)
4277 {
4278 	return verify_ordered_array(array, NULL, array_size, (int)range_lo, (int)range_hi,
4279 		TRUE, TRUE);
4280 }
4281 
4282 /* Validate an ordered int16 non-zero-terminated configuration array */
4283 int
verify_ordered_array_int16(int16 * array,int array_size,int16 range_lo,int16 range_hi)4284 verify_ordered_array_int16(int16 *array, int array_size,
4285 	int16 range_lo, int16 range_hi)
4286 {
4287 	return verify_ordered_array(NULL, array, array_size, (int)range_lo, (int)range_hi,
4288 		FALSE, TRUE);
4289 }
4290 
4291 /* Validate all values in an array are in range */
4292 int
verify_array_values(uint8 * array,int array_size,int range_lo,int range_hi,bool zero_terminated)4293 verify_array_values(uint8 *array, int array_size,
4294 	int range_lo, int range_hi, bool zero_terminated)
4295 {
4296 	int ret = BCME_OK;
4297 	int i;
4298 	int val = 0;
4299 
4300 	/* Check that:
4301 	 * - values are in strict descending order.
4302 	 * - values are within the valid range.
4303 	 */
4304 	for (i = 0; i < array_size; i++) {
4305 		val = (int)array[i];
4306 		if (val == 0 && zero_terminated) {
4307 			ret = BCME_OK;
4308 			break;
4309 		}
4310 		if (val < range_lo || val > range_hi) {
4311 			/* array value out of range */
4312 			ret = BCME_RANGE;
4313 			break;
4314 		}
4315 	}
4316 	return ret;
4317 }
4318 
4319 /* Adds/replaces NVRAM variable with given value
4320  * varbuf[in,out]   - Buffer with NVRAM variables (sequence of zero-terminated 'name=value' records,
4321  *                    terminated with additional zero)
4322  * buflen[in]       - Length of buffer (may, even should, have some unused space)
4323  * variable[in]     - Variable to add/replace in 'name=value' form
4324  * datalen[out,opt] - Optional output parameter - resulting length of data in buffer
4325  * Returns TRUE on success, FALSE if buffer too short or variable specified incorrectly
4326  */
4327 bool
replace_nvram_variable(char * varbuf,unsigned int buflen,const char * variable,unsigned int * datalen)4328 replace_nvram_variable(char *varbuf, unsigned int buflen, const char *variable,
4329 	unsigned int *datalen)
4330 {
4331 	char *p;
4332 	int variable_heading_len, record_len, variable_record_len = (int)strlen(variable) + 1;
4333 	char *buf_end = varbuf + buflen;
4334 	p = strchr(variable, '=');
4335 	if (!p) {
4336 		return FALSE;
4337 	}
4338 	/* Length of given variable name, followed by '=' */
4339 	variable_heading_len = (int)((const char *)(p + 1) - variable);
4340 	/* Scanning NVRAM, record by record up to trailing 0 */
4341 	for (p = varbuf; *p; p += strlen(p) + 1) {
4342 		/* If given variable found - remove it */
4343 		if (!strncmp(p, variable, (size_t)variable_heading_len)) {
4344 			record_len = (int)strlen(p) + 1;
4345 			memmove_s(p, buf_end - p, p + record_len,
4346 				(size_t)(buf_end - (p + record_len)));
4347 		}
4348 	}
4349 	/* If buffer does not have space for given variable - return FALSE */
4350 	if ((p + variable_record_len + 1) > buf_end) {
4351 		return FALSE;
4352 	}
4353 	/* Copy given variable to end of buffer */
4354 	memmove_s(p, buf_end - p, variable, (size_t)variable_record_len);
4355 	/* Adding trailing 0 */
4356 	p[variable_record_len] = 0;
4357 	/* Setting optional output parameter - length of data in buffer */
4358 	if (datalen) {
4359 		*datalen = (unsigned int)(p + variable_record_len + 1  - varbuf);
4360 	}
4361 	return TRUE;
4362 }
4363 
4364 /* Add to adjust the 802.1x priority */
4365 void
pktset8021xprio(void * pkt,int prio)4366 pktset8021xprio(void *pkt, int prio)
4367 {
4368 	struct ether_header *eh;
4369 	uint8 *pktdata;
4370 	if(prio == PKTPRIO(pkt))
4371 		return;
4372 	pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
4373 	ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
4374 	eh = (struct ether_header *) pktdata;
4375 	if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
4376 		ASSERT(prio >= 0 && prio <= MAXPRIO);
4377 		PKTSETPRIO(pkt, prio);
4378 	}
4379 }
4380