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