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