xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/bcmxtlv.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Driver O/S-independent utility routines
3  *
4  * Copyright (C) 2020, Broadcom.
5  *
6  *      Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  *
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions of
16  * the license of that module.  An independent module is a module which is not
17  * derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  *
20  *
21  * <<Broadcom-WL-IPTag/Dual:>>
22  */
23 
24 #include <typedefs.h>
25 #include <bcmdefs.h>
26 
27 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0))
28 #include <stdarg.h>
29 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0) */
30 
31 #ifdef BCMDRIVER
32 #include <osl.h>
33 #else /* !BCMDRIVER */
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #ifndef ASSERT
38 #define ASSERT(exp)
39 #endif
40 #endif /* !BCMDRIVER */
41 
42 #include <bcmtlv.h>
43 #include <bcmendian.h>
44 #include <bcmutils.h>
45 
46 int
BCMPOSTTRAPFN(bcm_xtlv_hdr_size)47 BCMPOSTTRAPFN(bcm_xtlv_hdr_size)(bcm_xtlv_opts_t opts)
48 {
49 	int len = (int)OFFSETOF(bcm_xtlv_t, data); /* nominal */
50 	if (opts & BCM_XTLV_OPTION_LENU8) --len;
51 	if (opts & BCM_XTLV_OPTION_IDU8) --len;
52 
53 	return len;
54 }
55 
56 bool
bcm_valid_xtlv(const bcm_xtlv_t * elt,int buf_len,bcm_xtlv_opts_t opts)57 bcm_valid_xtlv(const bcm_xtlv_t *elt, int buf_len, bcm_xtlv_opts_t opts)
58 {
59 	return elt != NULL &&
60 	        buf_len >= bcm_xtlv_hdr_size(opts) &&
61 		buf_len  >= bcm_xtlv_size(elt, opts);
62 }
63 
64 int
BCMPOSTTRAPFN(bcm_xtlv_size_for_data)65 BCMPOSTTRAPFN(bcm_xtlv_size_for_data)(int dlen, bcm_xtlv_opts_t opts)
66 {
67 	int hsz;
68 
69 	hsz = bcm_xtlv_hdr_size(opts);
70 	return ((opts & BCM_XTLV_OPTION_ALIGN32) ? ALIGN_SIZE(dlen + hsz, 4)
71 		: (dlen + hsz));
72 }
73 
74 int
bcm_xtlv_size(const bcm_xtlv_t * elt,bcm_xtlv_opts_t opts)75 bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts)
76 {
77 	int size;	/* size including header, data, and any pad */
78 	int len;	/* length wthout padding */
79 
80 	len = BCM_XTLV_LEN_EX(elt, opts);
81 	size = bcm_xtlv_size_for_data(len, opts);
82 	return size;
83 }
84 
85 int
bcm_xtlv_len(const bcm_xtlv_t * elt,bcm_xtlv_opts_t opts)86 bcm_xtlv_len(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts)
87 {
88 	const uint8 *lenp;
89 	int len;
90 
91 	lenp = (const uint8 *)elt + OFFSETOF(bcm_xtlv_t, len); /* nominal */
92 	if (opts & BCM_XTLV_OPTION_IDU8) {
93 		--lenp;
94 	}
95 
96 	if (opts & BCM_XTLV_OPTION_LENU8) {
97 		len = *lenp;
98 	} else if (opts & BCM_XTLV_OPTION_LENBE) {
99 		len = (uint32)hton16(elt->len);
100 	} else {
101 		len = ltoh16_ua(lenp);
102 	}
103 
104 	return len;
105 }
106 
107 int
bcm_xtlv_id(const bcm_xtlv_t * elt,bcm_xtlv_opts_t opts)108 bcm_xtlv_id(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts)
109 {
110 	int id = 0;
111 	if (opts & BCM_XTLV_OPTION_IDU8) {
112 		id =  *(const uint8 *)elt;
113 	} else if (opts & BCM_XTLV_OPTION_IDBE) {
114 		id = (uint32)hton16(elt->id);
115 	} else {
116 		id = ltoh16_ua((const uint8 *)elt);
117 	}
118 
119 	return id;
120 }
121 
122 bcm_xtlv_t *
bcm_next_xtlv(const bcm_xtlv_t * elt,int * buflen,bcm_xtlv_opts_t opts)123 bcm_next_xtlv(const bcm_xtlv_t *elt, int *buflen, bcm_xtlv_opts_t opts)
124 {
125 	uint sz;
126 
127 	COV_TAINTED_DATA_SINK(buflen);
128 	COV_NEG_SINK(buflen);
129 
130 	/* validate current elt */
131 	if (!bcm_valid_xtlv(elt, *buflen, opts))
132 		return NULL;
133 
134 	/* advance to next elt */
135 	sz = BCM_XTLV_SIZE_EX(elt, opts);
136 	elt = (const bcm_xtlv_t*)((const uint8 *)elt + sz);
137 
138 #if defined(__COVERITY__)
139 	/* The 'sz' value is tainted in Coverity because it is read from the tainted data pointed
140 	 * to by 'elt'.  However, bcm_valid_xtlv() verifies that the elt pointer is a valid element,
141 	 * so its size, sz = BCM_XTLV_SIZE_EX(elt, opts), is in the bounds of the buffer.
142 	 * Clearing the tainted attribute of 'sz' for Coverity.
143 	 */
144 	__coverity_tainted_data_sanitize__(sz);
145 	if (sz > *buflen) {
146 		return NULL;
147 	}
148 #endif /* __COVERITY__ */
149 
150 	*buflen -= sz;
151 
152 	/* validate next elt */
153 	if (!bcm_valid_xtlv(elt, *buflen, opts))
154 		return NULL;
155 
156 	COV_TAINTED_DATA_ARG(elt);
157 
158 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST()
159 	return (bcm_xtlv_t *)(elt);
160 	GCC_DIAGNOSTIC_POP()
161 }
162 
163 int
bcm_xtlv_buf_init(bcm_xtlvbuf_t * tlv_buf,uint8 * buf,uint16 len,bcm_xtlv_opts_t opts)164 bcm_xtlv_buf_init(bcm_xtlvbuf_t *tlv_buf, uint8 *buf, uint16 len, bcm_xtlv_opts_t opts)
165 {
166 	if (!tlv_buf || !buf || !len)
167 		return BCME_BADARG;
168 
169 	tlv_buf->opts = opts;
170 	tlv_buf->size = len;
171 	tlv_buf->head = buf;
172 	tlv_buf->buf  = buf;
173 	return BCME_OK;
174 }
175 
176 uint16
bcm_xtlv_buf_len(bcm_xtlvbuf_t * tbuf)177 bcm_xtlv_buf_len(bcm_xtlvbuf_t *tbuf)
178 {
179 	uint16 len;
180 
181 	if (tbuf)
182 		len = (uint16)(tbuf->buf - tbuf->head);
183 	else
184 		len = 0;
185 
186 	return len;
187 }
188 
189 uint16
bcm_xtlv_buf_rlen(bcm_xtlvbuf_t * tbuf)190 bcm_xtlv_buf_rlen(bcm_xtlvbuf_t *tbuf)
191 {
192 	uint16 rlen;
193 	if (tbuf)
194 		rlen = tbuf->size - bcm_xtlv_buf_len(tbuf);
195 	else
196 		rlen = 0;
197 
198 	return rlen;
199 }
200 
201 uint8 *
bcm_xtlv_buf(bcm_xtlvbuf_t * tbuf)202 bcm_xtlv_buf(bcm_xtlvbuf_t *tbuf)
203 {
204 	return tbuf ? tbuf->buf : NULL;
205 }
206 
207 uint8 *
bcm_xtlv_head(bcm_xtlvbuf_t * tbuf)208 bcm_xtlv_head(bcm_xtlvbuf_t *tbuf)
209 {
210 	return tbuf ? tbuf->head : NULL;
211 }
212 
213 void
BCMPOSTTRAPFN(bcm_xtlv_pack_xtlv)214 BCMPOSTTRAPFN(bcm_xtlv_pack_xtlv)(bcm_xtlv_t *xtlv, uint16 type, uint16 len, const uint8 *data,
215 	bcm_xtlv_opts_t opts)
216 {
217 	uint8 *data_buf;
218 	bcm_xtlv_opts_t mask = BCM_XTLV_OPTION_IDU8 | BCM_XTLV_OPTION_LENU8;
219 
220 	if (!(opts & mask)) {		/* default */
221 		uint8 *idp = (uint8 *)xtlv;
222 		uint8 *lenp = idp + sizeof(xtlv->id);
223 		htol16_ua_store(type, idp);
224 		htol16_ua_store(len, lenp);
225 		data_buf = lenp + sizeof(uint16);
226 	} else if ((opts & mask) == mask) { /* u8 id and u8 len */
227 		uint8 *idp = (uint8 *)xtlv;
228 		uint8 *lenp = idp + 1;
229 		*idp = (uint8)type;
230 		*lenp = (uint8)len;
231 		data_buf = lenp + sizeof(uint8);
232 	} else if (opts & BCM_XTLV_OPTION_IDU8) { /* u8 id, u16 len */
233 		uint8 *idp = (uint8 *)xtlv;
234 		uint8 *lenp = idp + 1;
235 		*idp = (uint8)type;
236 		htol16_ua_store(len, lenp);
237 		data_buf = lenp + sizeof(uint16);
238 	} else if (opts & BCM_XTLV_OPTION_LENU8) { /* u16 id, u8 len */
239 		uint8 *idp = (uint8 *)xtlv;
240 		uint8 *lenp = idp + sizeof(uint16);
241 		htol16_ua_store(type, idp);
242 		*lenp = (uint8)len;
243 		data_buf = lenp + sizeof(uint8);
244 	} else {
245 		ASSERT(!"Unexpected xtlv option");
246 		return;
247 	}
248 
249 	if (opts & BCM_XTLV_OPTION_LENU8) {
250 		ASSERT(len <= 0x00ff);
251 		len &= 0xff;
252 	}
253 
254 	if (data != NULL) {
255 		memcpy(data_buf, data, len);
256 	}
257 }
258 
259 /* xtlv header is always packed in LE order */
260 void
bcm_xtlv_unpack_xtlv(const bcm_xtlv_t * xtlv,uint16 * type,uint16 * len,const uint8 ** data,bcm_xtlv_opts_t opts)261 bcm_xtlv_unpack_xtlv(const bcm_xtlv_t *xtlv, uint16 *type, uint16 *len,
262 	const uint8 **data, bcm_xtlv_opts_t opts)
263 {
264 	if (type)
265 		*type = (uint16)bcm_xtlv_id(xtlv, opts);
266 	if (len)
267 		*len = (uint16)bcm_xtlv_len(xtlv, opts);
268 	if (data)
269 		*data = (const uint8 *)xtlv + BCM_XTLV_HDR_SIZE_EX(opts);
270 }
271 
272 int
bcm_xtlv_put_data(bcm_xtlvbuf_t * tbuf,uint16 type,const uint8 * data,int n)273 bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const uint8 *data, int n)
274 {
275 	bcm_xtlv_t *xtlv;
276 	int size;
277 
278 	if (tbuf == NULL)
279 		return BCME_BADARG;
280 
281 	size = bcm_xtlv_size_for_data(n, tbuf->opts);
282 	if (bcm_xtlv_buf_rlen(tbuf) < size)
283 		return BCME_NOMEM;
284 
285 	xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf);
286 	bcm_xtlv_pack_xtlv(xtlv, type, (uint16)n, data, tbuf->opts);
287 	tbuf->buf += size; /* note: data may be NULL, reserves space */
288 	return BCME_OK;
289 }
290 
291 static int
bcm_xtlv_put_int(bcm_xtlvbuf_t * tbuf,uint16 type,const uint8 * data,int n,int int_sz)292 bcm_xtlv_put_int(bcm_xtlvbuf_t *tbuf, uint16 type, const uint8 *data, int n, int int_sz)
293 {
294 	bcm_xtlv_t *xtlv;
295 	int xtlv_len;
296 	uint8 *xtlv_data;
297 	int err = BCME_OK;
298 
299 	if (tbuf == NULL) {
300 		err = BCME_BADARG;
301 		goto done;
302 	}
303 
304 	xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf);
305 
306 	/* put type and length in xtlv and reserve data space */
307 	xtlv_len = n * int_sz;
308 	err = bcm_xtlv_put_data(tbuf, type, NULL, xtlv_len);
309 	if (err != BCME_OK)
310 		goto done;
311 
312 	xtlv_data = (uint8 *)xtlv + bcm_xtlv_hdr_size(tbuf->opts);
313 
314 	/* write data w/ little-endianness into buffer - single loop, aligned access */
315 	for (; n != 0; --n, xtlv_data += int_sz, data += int_sz) {
316 		switch (int_sz) {
317 		case sizeof(uint8):
318 			break;
319 		case sizeof(uint16):
320 			{
321 				uint16 v =  load16_ua(data);
322 				htol16_ua_store(v, xtlv_data);
323 				break;
324 			}
325 		case sizeof(uint32):
326 			{
327 				uint32 v = load32_ua(data);
328 				htol32_ua_store(v, xtlv_data);
329 				break;
330 			}
331 		case sizeof(uint64):
332 			{
333 				uint64 v = load64_ua(data);
334 				htol64_ua_store(v, xtlv_data);
335 				break;
336 			}
337 		default:
338 			err = BCME_UNSUPPORTED;
339 			goto done;
340 		}
341 	}
342 
343 done:
344 	return err;
345 }
346 
347 int
bcm_xtlv_put16(bcm_xtlvbuf_t * tbuf,uint16 type,const uint16 * data,int n)348 bcm_xtlv_put16(bcm_xtlvbuf_t *tbuf, uint16 type, const uint16 *data, int n)
349 {
350 	return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint16));
351 }
352 
353 int
bcm_xtlv_put32(bcm_xtlvbuf_t * tbuf,uint16 type,const uint32 * data,int n)354 bcm_xtlv_put32(bcm_xtlvbuf_t *tbuf, uint16 type, const uint32 *data, int n)
355 {
356 	return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint32));
357 }
358 
359 int
bcm_xtlv_put64(bcm_xtlvbuf_t * tbuf,uint16 type,const uint64 * data,int n)360 bcm_xtlv_put64(bcm_xtlvbuf_t *tbuf, uint16 type, const uint64 *data, int n)
361 {
362 	return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint64));
363 }
364 
365 /*
366  *  upacks xtlv record from buf checks the type
367  *  copies data to callers buffer
368  *  advances tlv pointer to next record
369  *  caller's resposible for dst space check
370  */
371 int
bcm_unpack_xtlv_entry(const uint8 ** tlv_buf,uint16 xpct_type,uint16 xpct_len,uint8 * dst_data,bcm_xtlv_opts_t opts)372 bcm_unpack_xtlv_entry(const uint8 **tlv_buf, uint16 xpct_type, uint16 xpct_len,
373 	uint8 *dst_data, bcm_xtlv_opts_t opts)
374 {
375 	const bcm_xtlv_t *ptlv = (const bcm_xtlv_t *)*tlv_buf;
376 	uint16 len;
377 	uint16 type;
378 	const uint8 *data;
379 
380 	ASSERT(ptlv);
381 
382 	bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts);
383 	if (len) {
384 		if ((type != xpct_type) || (len > xpct_len))
385 			return BCME_BADARG;
386 		if (dst_data && data)
387 			memcpy(dst_data, data, len); /* copy data to dst */
388 	}
389 
390 	*tlv_buf += BCM_XTLV_SIZE_EX(ptlv, opts);
391 	return BCME_OK;
392 }
393 
394 /*
395  *  packs user data into tlv record and advances tlv pointer to next xtlv slot
396  *  buflen is used for tlv_buf space check
397  */
398 int
bcm_pack_xtlv_entry(uint8 ** tlv_buf,uint16 * buflen,uint16 type,uint16 len,const uint8 * src_data,bcm_xtlv_opts_t opts)399 bcm_pack_xtlv_entry(uint8 **tlv_buf, uint16 *buflen, uint16 type, uint16 len,
400 	const uint8 *src_data, bcm_xtlv_opts_t opts)
401 {
402 	bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf;
403 	int size;
404 
405 	ASSERT(ptlv);
406 
407 	size = bcm_xtlv_size_for_data(len, opts);
408 
409 	/* copy data from tlv buffer to dst provided by user */
410 	if (size > *buflen) {
411 		return BCME_BADLEN;
412 	}
413 
414 	bcm_xtlv_pack_xtlv(ptlv, type, len, src_data, opts);
415 
416 	/* advance callers pointer to tlv buff */
417 	*tlv_buf = (uint8*)(*tlv_buf) + size;
418 	/* decrement the len */
419 	*buflen -= (uint16)size;
420 	return BCME_OK;
421 }
422 
423 /*
424  *  unpack all xtlv records from the issue a callback
425  *  to set function one call per found tlv record
426  */
427 int
bcm_unpack_xtlv_buf(void * ctx,const uint8 * tlv_buf,uint16 buflen,bcm_xtlv_opts_t opts,bcm_xtlv_unpack_cbfn_t * cbfn)428 bcm_unpack_xtlv_buf(void *ctx, const uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts,
429 	bcm_xtlv_unpack_cbfn_t *cbfn)
430 {
431 	uint16 len;
432 	uint16 type;
433 	int res = BCME_OK;
434 	int size;
435 	const bcm_xtlv_t *ptlv;
436 	int sbuflen = buflen;
437 	const uint8 *data;
438 	int hdr_size;
439 
440 	ASSERT(!buflen || tlv_buf);
441 	ASSERT(!buflen || cbfn);
442 
443 	hdr_size = BCM_XTLV_HDR_SIZE_EX(opts);
444 	while (sbuflen >= hdr_size) {
445 		ptlv = (const bcm_xtlv_t *)tlv_buf;
446 
447 		bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts);
448 		size = bcm_xtlv_size_for_data(len, opts);
449 
450 		sbuflen -= size;
451 
452 		/* check for buffer overrun */
453 		if (sbuflen < 0) {
454 			break;
455 		}
456 
457 		if ((res = cbfn(ctx, data, type, len)) != BCME_OK) {
458 			break;
459 		}
460 		tlv_buf += size;
461 	}
462 	return res;
463 }
464 
465 int
bcm_pack_xtlv_buf(void * ctx,uint8 * tlv_buf,uint16 buflen,bcm_xtlv_opts_t opts,bcm_pack_xtlv_next_info_cbfn_t get_next,bcm_pack_xtlv_pack_next_cbfn_t pack_next,int * outlen)466 bcm_pack_xtlv_buf(void *ctx, uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts,
467 	bcm_pack_xtlv_next_info_cbfn_t get_next, bcm_pack_xtlv_pack_next_cbfn_t pack_next,
468 	int *outlen)
469 {
470 	int res = BCME_OK;
471 	uint16 tlv_id;
472 	uint16 tlv_len;
473 	uint8 *startp;
474 	uint8 *endp;
475 	uint8 *buf;
476 	bool more;
477 	int size;
478 	int hdr_size;
479 
480 	ASSERT(get_next && pack_next);
481 
482 	buf = tlv_buf;
483 	startp = buf;
484 	endp = (uint8 *)buf + buflen;
485 	more = TRUE;
486 	hdr_size = BCM_XTLV_HDR_SIZE_EX(opts);
487 
488 	while (more && (buf < endp)) {
489 		more = get_next(ctx, &tlv_id, &tlv_len);
490 		size = bcm_xtlv_size_for_data(tlv_len, opts);
491 		if ((buf + size) > endp) {
492 			res = BCME_BUFTOOSHORT;
493 			goto done;
494 		}
495 
496 		bcm_xtlv_pack_xtlv((bcm_xtlv_t *)buf, tlv_id, tlv_len, NULL, opts);
497 		pack_next(ctx, tlv_id, tlv_len, buf + hdr_size);
498 		buf += size;
499 	}
500 
501 	if (more)
502 		res = BCME_BUFTOOSHORT;
503 
504 done:
505 	if (outlen) {
506 		*outlen = (int)(buf - startp);
507 	}
508 	return res;
509 }
510 
511 /*
512  *  pack xtlv buffer from memory according to xtlv_desc_t
513  */
514 int
bcm_pack_xtlv_buf_from_mem(uint8 ** tlv_buf,uint16 * buflen,const xtlv_desc_t * items,bcm_xtlv_opts_t opts)515 bcm_pack_xtlv_buf_from_mem(uint8 **tlv_buf, uint16 *buflen, const xtlv_desc_t *items,
516 	bcm_xtlv_opts_t opts)
517 {
518 	int res = BCME_OK;
519 	uint8 *ptlv = *tlv_buf;
520 
521 	while (items->type != 0) {
522 		if (items->len && items->ptr) {
523 			res = bcm_pack_xtlv_entry(&ptlv, buflen, items->type,
524 				items->len, items->ptr, opts);
525 			if (res != BCME_OK)
526 				break;
527 		}
528 		items++;
529 	}
530 
531 	*tlv_buf = ptlv; /* update the external pointer */
532 	return res;
533 }
534 
535 /*
536  *  unpack xtlv buffer to memory according to xtlv_desc_t
537  *
538  */
539 int
bcm_unpack_xtlv_buf_to_mem(const uint8 * tlv_buf,int * buflen,xtlv_desc_t * items,bcm_xtlv_opts_t opts)540 bcm_unpack_xtlv_buf_to_mem(const uint8 *tlv_buf, int *buflen, xtlv_desc_t *items,
541 	bcm_xtlv_opts_t opts)
542 {
543 	int res = BCME_OK;
544 	const bcm_xtlv_t *elt;
545 
546 	elt =  bcm_valid_xtlv((const bcm_xtlv_t *)tlv_buf, *buflen, opts) ?
547 		(const bcm_xtlv_t *)tlv_buf : NULL;
548 	if (!elt || !items) {
549 		res = BCME_BADARG;
550 		return res;
551 	}
552 
553 	for (; elt != NULL && res == BCME_OK; elt = bcm_next_xtlv(elt, buflen, opts)) {
554 		/*  find matches in desc_t items  */
555 		xtlv_desc_t *dst_desc = items;
556 		uint16 len, type;
557 		const uint8 *data;
558 
559 		bcm_xtlv_unpack_xtlv(elt, &type, &len, &data, opts);
560 		while (dst_desc->type != 0) {
561 			if (type == dst_desc->type) {
562 				if (len != dst_desc->len) {
563 					res = BCME_BADLEN;
564 				} else {
565 					memcpy(dst_desc->ptr, data, len);
566 				}
567 				break;
568 			}
569 			dst_desc++;
570 		}
571 	}
572 
573 	if (res == BCME_OK && *buflen != 0)		/* this does not look right */
574 		res =  BCME_BUFTOOSHORT;
575 
576 	return res;
577 }
578 
579 /*
580  * return data pointer of a given ID from xtlv buffer.
581  * If the specified xTLV ID is found, on return *datalen will contain
582  * the the data length of the xTLV ID.
583  */
584 const uint8*
bcm_get_data_from_xtlv_buf(const uint8 * tlv_buf,uint16 buflen,uint16 id,uint16 * datalen,bcm_xtlv_opts_t opts)585 bcm_get_data_from_xtlv_buf(const uint8 *tlv_buf, uint16 buflen, uint16 id,
586 	uint16 *datalen, bcm_xtlv_opts_t opts)
587 {
588 	const uint8 *retptr = NULL;
589 	uint16 type, len;
590 	int size;
591 	const bcm_xtlv_t *ptlv;
592 	int sbuflen = buflen;
593 	const uint8 *data;
594 	int hdr_size;
595 
596 	COV_TAINTED_DATA_SINK(buflen);
597 	COV_NEG_SINK(buflen);
598 
599 	hdr_size = BCM_XTLV_HDR_SIZE_EX(opts);
600 
601 	/* Init the datalength */
602 	if (datalen) {
603 		*datalen = 0;
604 	}
605 	while (sbuflen >= hdr_size) {
606 		ptlv = (const bcm_xtlv_t *)tlv_buf;
607 		bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts);
608 
609 		size = bcm_xtlv_size_for_data(len, opts);
610 		sbuflen -= size;
611 		if (sbuflen < 0) /* buffer overrun? */
612 			break;
613 
614 		if (id == type) {
615 			retptr = data;
616 			if (datalen)
617 				*datalen = len;
618 			break;
619 		}
620 
621 		tlv_buf += size;
622 	}
623 
624 	COV_TAINTED_DATA_ARG(retptr);
625 
626 	return retptr;
627 }
628 
629 bcm_xtlv_t*
bcm_xtlv_bcopy(const bcm_xtlv_t * src,bcm_xtlv_t * dst,int src_buf_len,int dst_buf_len,bcm_xtlv_opts_t opts)630 bcm_xtlv_bcopy(const bcm_xtlv_t *src, bcm_xtlv_t *dst,
631 	int src_buf_len, int dst_buf_len, bcm_xtlv_opts_t opts)
632 {
633 	bcm_xtlv_t *dst_next = NULL;
634 	src =  (src && bcm_valid_xtlv(src, src_buf_len, opts)) ? src : NULL;
635 	if (src && dst) {
636 		uint16 type;
637 		uint16 len;
638 		const uint8 *data;
639 		int size;
640 		bcm_xtlv_unpack_xtlv(src, &type, &len, &data, opts);
641 		size = bcm_xtlv_size_for_data(len, opts);
642 		if (size <= dst_buf_len) {
643 			bcm_xtlv_pack_xtlv(dst, type, len, data, opts);
644 			dst_next = (bcm_xtlv_t *)((uint8 *)dst + size);
645 		}
646 	}
647 
648 	return dst_next;
649 }
650