From cde9070d9970eef1f7ec2360586c802a16230ad8 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 07:43:50 +0000 Subject: [PATCH] rtl88x2CE_WiFi_linux driver --- kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmxtlv.c | 494 ++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 328 insertions(+), 166 deletions(-) diff --git a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmxtlv.c b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmxtlv.c index f300cb1..4fe00a8 100644 --- a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmxtlv.c +++ b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmxtlv.c @@ -1,15 +1,16 @@ -/* SPDX-License-Identifier: GPL-2.0 */ /* * Driver O/S-independent utility routines * - * Copyright (C) 1999-2019, Broadcom Corporation - * + * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation + * + * Copyright (C) 1999-2017, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -17,7 +18,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -25,7 +26,7 @@ * * <<Broadcom-WL-IPTag/Open:>> * - * $Id: bcmxtlv.c 603083 2015-11-30 23:40:43Z $ + * $Id: bcmxtlv.c 700655 2017-05-20 06:09:06Z $ */ #include <bcm_cfg.h> @@ -38,40 +39,110 @@ #ifdef BCMDRIVER #include <osl.h> #else /* !BCMDRIVER */ - #include <stdlib.h> /* AS!!! */ #include <stdio.h> #include <string.h> #include <stdlib.h> #ifndef ASSERT #define ASSERT(exp) -#endif -INLINE void* MALLOCZ(void *o, size_t s) { BCM_REFERENCE(o); return calloc(1, s); } -INLINE void MFREE(void *o, void *p, size_t s) { BCM_REFERENCE(o); BCM_REFERENCE(s); free(p); } +#endif // endif #endif /* !BCMDRIVER */ +#include <bcmtlv.h> #include <bcmendian.h> #include <bcmutils.h> -static INLINE int bcm_xtlv_size_for_data(int dlen, bcm_xtlv_opts_t opts) +int +bcm_xtlv_hdr_size(bcm_xtlv_opts_t opts) { - return ((opts & BCM_XTLV_OPTION_ALIGN32) ? ALIGN_SIZE(dlen + BCM_XTLV_HDR_SIZE, 4) - : (dlen + BCM_XTLV_HDR_SIZE)); + int len = (int)OFFSETOF(bcm_xtlv_t, data); /* nominal */ + if (opts & BCM_XTLV_OPTION_LENU8) --len; + if (opts & BCM_XTLV_OPTION_IDU8) --len; + + return len; +} + +bool +bcm_valid_xtlv(const bcm_xtlv_t *elt, int buf_len, bcm_xtlv_opts_t opts) +{ + return elt != NULL && + buf_len >= bcm_xtlv_hdr_size(opts) && + buf_len >= bcm_xtlv_size(elt, opts); +} + +int +bcm_xtlv_size_for_data(int dlen, bcm_xtlv_opts_t opts) +{ + int hsz; + + hsz = bcm_xtlv_hdr_size(opts); + return ((opts & BCM_XTLV_OPTION_ALIGN32) ? ALIGN_SIZE(dlen + hsz, 4) + : (dlen + hsz)); +} + +int +bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts) +{ + int size; /* size including header, data, and any pad */ + int len; /* length wthout padding */ + + len = BCM_XTLV_LEN_EX(elt, opts); + size = bcm_xtlv_size_for_data(len, opts); + return size; +} + +int +bcm_xtlv_len(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts) +{ + const uint8 *lenp; + int len; + + lenp = (const uint8 *)&elt->len; /* nominal */ + if (opts & BCM_XTLV_OPTION_IDU8) { + --lenp; + } + + if (opts & BCM_XTLV_OPTION_LENU8) { + len = *lenp; + } else if (opts & BCM_XTLV_OPTION_LENBE) { + len = (uint32)hton16(elt->len); + } else { + len = ltoh16_ua(lenp); + } + + return len; +} + +int +bcm_xtlv_id(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts) +{ + int id = 0; + if (opts & BCM_XTLV_OPTION_IDU8) { + id = *(const uint8 *)elt; + } else if (opts & BCM_XTLV_OPTION_IDBE) { + id = (uint32)hton16(elt->id); + } else { + id = ltoh16_ua((const uint8 *)elt); + } + + return id; } bcm_xtlv_t * -bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen, bcm_xtlv_opts_t opts) +bcm_next_xtlv(const bcm_xtlv_t *elt, int *buflen, bcm_xtlv_opts_t opts) { int sz; /* advance to next elt */ - sz = BCM_XTLV_SIZE(elt, opts); - elt = (bcm_xtlv_t*)((uint8 *)elt + sz); + sz = BCM_XTLV_SIZE_EX(elt, opts); + elt = (const bcm_xtlv_t*)((const uint8 *)elt + sz); *buflen -= sz; /* validate next elt */ if (!bcm_valid_xtlv(elt, *buflen, opts)) return NULL; - return elt; + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + return (bcm_xtlv_t *)(elt); + GCC_DIAGNOSTIC_POP(); } int @@ -90,99 +161,191 @@ uint16 bcm_xtlv_buf_len(bcm_xtlvbuf_t *tbuf) { - if (tbuf == NULL) return 0; - return (uint16)(tbuf->buf - tbuf->head); + uint16 len; + + if (tbuf) + len = (uint16)(tbuf->buf - tbuf->head); + else + len = 0; + + return len; } + uint16 bcm_xtlv_buf_rlen(bcm_xtlvbuf_t *tbuf) { - if (tbuf == NULL) return 0; - return tbuf->size - bcm_xtlv_buf_len(tbuf); + uint16 rlen; + if (tbuf) + rlen = tbuf->size - bcm_xtlv_buf_len(tbuf); + else + rlen = 0; + + return rlen; } + uint8 * bcm_xtlv_buf(bcm_xtlvbuf_t *tbuf) { - if (tbuf == NULL) return NULL; - return tbuf->buf; + return tbuf ? tbuf->buf : NULL; } + uint8 * bcm_xtlv_head(bcm_xtlvbuf_t *tbuf) { - if (tbuf == NULL) return NULL; - return tbuf->head; + return tbuf ? tbuf->head : NULL; } + +void +bcm_xtlv_pack_xtlv(bcm_xtlv_t *xtlv, uint16 type, uint16 len, const uint8 *data, + bcm_xtlv_opts_t opts) +{ + uint8 *data_buf; + bcm_xtlv_opts_t mask = BCM_XTLV_OPTION_IDU8 | BCM_XTLV_OPTION_LENU8; + + if (!(opts & mask)) { /* default */ + uint8 *idp = (uint8 *)xtlv; + uint8 *lenp = idp + sizeof(xtlv->id); + htol16_ua_store(type, idp); + htol16_ua_store(len, lenp); + data_buf = lenp + sizeof(uint16); + } else if ((opts & mask) == mask) { /* u8 id and u8 len */ + uint8 *idp = (uint8 *)xtlv; + uint8 *lenp = idp + 1; + *idp = (uint8)type; + *lenp = (uint8)len; + data_buf = lenp + sizeof(uint8); + } else if (opts & BCM_XTLV_OPTION_IDU8) { /* u8 id, u16 len */ + uint8 *idp = (uint8 *)xtlv; + uint8 *lenp = idp + 1; + *idp = (uint8)type; + htol16_ua_store(len, lenp); + data_buf = lenp + sizeof(uint16); + } else if (opts & BCM_XTLV_OPTION_LENU8) { /* u16 id, u8 len */ + uint8 *idp = (uint8 *)xtlv; + uint8 *lenp = idp + sizeof(uint16); + htol16_ua_store(type, idp); + *lenp = (uint8)len; + data_buf = lenp + sizeof(uint8); + } else { + bool Unexpected_xtlv_option = TRUE; + BCM_REFERENCE(Unexpected_xtlv_option); + ASSERT(!Unexpected_xtlv_option); + return; + } + + if (opts & BCM_XTLV_OPTION_LENU8) { + ASSERT(len <= 0x00ff); + len &= 0xff; + } + + if (data != NULL) + memcpy(data_buf, data, len); +} + +/* xtlv header is always packed in LE order */ +void +bcm_xtlv_unpack_xtlv(const bcm_xtlv_t *xtlv, uint16 *type, uint16 *len, + const uint8 **data, bcm_xtlv_opts_t opts) +{ + if (type) + *type = (uint16)bcm_xtlv_id(xtlv, opts); + if (len) + *len = (uint16)bcm_xtlv_len(xtlv, opts); + if (data) + *data = (const uint8 *)xtlv + BCM_XTLV_HDR_SIZE_EX(opts); +} + int -bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const void *data, uint16 dlen) +bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const uint8 *data, int n) { bcm_xtlv_t *xtlv; int size; if (tbuf == NULL) return BCME_BADARG; - size = bcm_xtlv_size_for_data(dlen, tbuf->opts); + + size = bcm_xtlv_size_for_data(n, tbuf->opts); if (bcm_xtlv_buf_rlen(tbuf) < size) return BCME_NOMEM; + xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(dlen); - memcpy(xtlv->data, data, dlen); - tbuf->buf += size; + bcm_xtlv_pack_xtlv(xtlv, type, (uint16)n, data, tbuf->opts); + tbuf->buf += size; /* note: data may be NULL, reserves space */ return BCME_OK; } -int -bcm_xtlv_put_8(bcm_xtlvbuf_t *tbuf, uint16 type, const int8 data) + +static int +bcm_xtlv_put_int(bcm_xtlvbuf_t *tbuf, uint16 type, const uint8 *data, int n, int int_sz) { bcm_xtlv_t *xtlv; - int size; + int xtlv_len; + uint8 *xtlv_data; + int err = BCME_OK; - if (tbuf == NULL) - return BCME_BADARG; - size = bcm_xtlv_size_for_data(1, tbuf->opts); - if (bcm_xtlv_buf_rlen(tbuf) < size) - return BCME_NOMEM; + if (tbuf == NULL) { + err = BCME_BADARG; + goto done; + } + xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(sizeof(data)); - xtlv->data[0] = data; - tbuf->buf += size; - return BCME_OK; + + /* put type and length in xtlv and reserve data space */ + xtlv_len = n * int_sz; + err = bcm_xtlv_put_data(tbuf, type, NULL, xtlv_len); + if (err != BCME_OK) + goto done; + + xtlv_data = (uint8 *)xtlv + bcm_xtlv_hdr_size(tbuf->opts); + + /* write data w/ little-endianness into buffer - single loop, aligned access */ + for (; n != 0; --n, xtlv_data += int_sz, data += int_sz) { + switch (int_sz) { + case sizeof(uint8): + break; + case sizeof(uint16): + { + uint16 v = load16_ua(data); + htol16_ua_store(v, xtlv_data); + break; + } + case sizeof(uint32): + { + uint32 v = load32_ua(data); + htol32_ua_store(v, xtlv_data); + break; + } + case sizeof(uint64): + { + uint64 v = load64_ua(data); + htol64_ua_store(v, xtlv_data); + break; + } + default: + err = BCME_UNSUPPORTED; + goto done; + } + } + +done: + return err; } + int -bcm_xtlv_put_16(bcm_xtlvbuf_t *tbuf, uint16 type, const int16 data) +bcm_xtlv_put16(bcm_xtlvbuf_t *tbuf, uint16 type, const uint16 *data, int n) { - bcm_xtlv_t *xtlv; - int size; - - if (tbuf == NULL) - return BCME_BADARG; - size = bcm_xtlv_size_for_data(2, tbuf->opts); - if (bcm_xtlv_buf_rlen(tbuf) < size) - return BCME_NOMEM; - - xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(sizeof(data)); - htol16_ua_store(data, xtlv->data); - tbuf->buf += size; - return BCME_OK; + return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint16)); } -int -bcm_xtlv_put_32(bcm_xtlvbuf_t *tbuf, uint16 type, const int32 data) -{ - bcm_xtlv_t *xtlv; - int size; - if (tbuf == NULL) - return BCME_BADARG; - size = bcm_xtlv_size_for_data(4, tbuf->opts); - if (bcm_xtlv_buf_rlen(tbuf) < size) - return BCME_NOMEM; - xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(sizeof(data)); - htol32_ua_store(data, xtlv->data); - tbuf->buf += size; - return BCME_OK; +int +bcm_xtlv_put32(bcm_xtlvbuf_t *tbuf, uint16 type, const uint32 *data, int n) +{ + return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint32)); +} + +int +bcm_xtlv_put64(bcm_xtlvbuf_t *tbuf, uint16 type, const uint64 *data, int n) +{ + return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint64)); } /* @@ -192,65 +355,51 @@ * caller's resposible for dst space check */ int -bcm_unpack_xtlv_entry(uint8 **tlv_buf, uint16 xpct_type, uint16 xpct_len, void *dst, - bcm_xtlv_opts_t opts) +bcm_unpack_xtlv_entry(const uint8 **tlv_buf, uint16 xpct_type, uint16 xpct_len, + uint8 *dst_data, bcm_xtlv_opts_t opts) { - bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf; + const bcm_xtlv_t *ptlv = (const bcm_xtlv_t *)*tlv_buf; uint16 len; uint16 type; + const uint8 *data; ASSERT(ptlv); - /* tlv headr is always packed in LE order */ - len = ltoh16(ptlv->len); - type = ltoh16(ptlv->id); - if (len == 0) { - /* z-len tlv headers: allow, but don't process */ - printf("z-len, skip unpack\n"); - } else { - if ((type != xpct_type) || - (len > xpct_len)) { - printf("xtlv_unpack Error: found[type:%d,len:%d] != xpct[type:%d,len:%d]\n", - type, len, xpct_type, xpct_len); + + bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts); + if (len) { + if ((type != xpct_type) || (len > xpct_len)) return BCME_BADARG; - } - /* copy tlv record to caller's buffer */ - memcpy(dst, ptlv->data, ptlv->len); + if (dst_data && data) + memcpy(dst_data, data, len); /* copy data to dst */ } - *tlv_buf += BCM_XTLV_SIZE(ptlv, opts); + + *tlv_buf += BCM_XTLV_SIZE_EX(ptlv, opts); return BCME_OK; } /* - * packs user data into tlv record - * advances tlv pointer to next xtlv slot + * packs user data into tlv record and advances tlv pointer to next xtlv slot * buflen is used for tlv_buf space check */ int -bcm_pack_xtlv_entry(uint8 **tlv_buf, uint16 *buflen, uint16 type, uint16 len, void *src, - bcm_xtlv_opts_t opts) +bcm_pack_xtlv_entry(uint8 **tlv_buf, uint16 *buflen, uint16 type, uint16 len, + const uint8 *src_data, bcm_xtlv_opts_t opts) { bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf; int size; ASSERT(ptlv); - ASSERT(src); size = bcm_xtlv_size_for_data(len, opts); /* copy data from tlv buffer to dst provided by user */ - if (size > *buflen) { - printf("bcm_pack_xtlv_entry: no space tlv_buf: requested:%d, available:%d\n", - size, *buflen); + if (size > *buflen) return BCME_BADLEN; - } - ptlv->id = htol16(type); - ptlv->len = htol16(len); - /* copy callers data */ - memcpy(ptlv->data, src, len); + bcm_xtlv_pack_xtlv(ptlv, type, len, src_data, opts); /* advance callers pointer to tlv buff */ - *tlv_buf += size; + *tlv_buf = (uint8*)(*tlv_buf) + size; /* decrement the len */ *buflen -= (uint16)size; return BCME_OK; @@ -261,34 +410,33 @@ * to set function one call per found tlv record */ int -bcm_unpack_xtlv_buf(void *ctx, uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts, +bcm_unpack_xtlv_buf(void *ctx, const uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts, bcm_xtlv_unpack_cbfn_t *cbfn) { uint16 len; uint16 type; int res = BCME_OK; int size; - bcm_xtlv_t *ptlv; + const bcm_xtlv_t *ptlv; int sbuflen = buflen; + const uint8 *data; + int hdr_size; ASSERT(!buflen || tlv_buf); ASSERT(!buflen || cbfn); - while (sbuflen >= (int)BCM_XTLV_HDR_SIZE) { - ptlv = (bcm_xtlv_t *)tlv_buf; + hdr_size = BCM_XTLV_HDR_SIZE_EX(opts); + while (sbuflen >= hdr_size) { + ptlv = (const bcm_xtlv_t *)tlv_buf; - /* tlv header is always packed in LE order */ - len = ltoh16(ptlv->len); - type = ltoh16(ptlv->id); - + bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts); size = bcm_xtlv_size_for_data(len, opts); sbuflen -= size; - /* check for possible buffer overrun */ - if (sbuflen < 0) + if (sbuflen < 0) /* check for buffer overrun */ break; - if ((res = cbfn(ctx, ptlv->data, type, len)) != BCME_OK) + if ((res = cbfn(ctx, data, type, len)) != BCME_OK) break; tlv_buf += size; } @@ -296,7 +444,7 @@ } int -bcm_pack_xtlv_buf(void *ctx, void *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts, +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) { @@ -308,24 +456,26 @@ uint8 *buf; bool more; int size; + int hdr_size; ASSERT(get_next && pack_next); - buf = (uint8 *)tlv_buf; + buf = tlv_buf; startp = buf; endp = (uint8 *)buf + buflen; more = TRUE; + hdr_size = BCM_XTLV_HDR_SIZE_EX(opts); + while (more && (buf < endp)) { more = get_next(ctx, &tlv_id, &tlv_len); size = bcm_xtlv_size_for_data(tlv_len, opts); - if ((buf + size) >= endp) { + if ((buf + size) > endp) { res = BCME_BUFTOOSHORT; goto done; } - htol16_ua_store(tlv_id, buf); - htol16_ua_store(tlv_len, buf + sizeof(tlv_id)); - pack_next(ctx, tlv_id, tlv_len, buf + BCM_XTLV_HDR_SIZE); + bcm_xtlv_pack_xtlv((bcm_xtlv_t *)buf, tlv_id, tlv_len, NULL, opts); + pack_next(ctx, tlv_id, tlv_len, buf + hdr_size); buf += size; } @@ -343,20 +493,22 @@ * pack xtlv buffer from memory according to xtlv_desc_t */ int -bcm_pack_xtlv_buf_from_mem(void **tlv_buf, uint16 *buflen, xtlv_desc_t *items, +bcm_pack_xtlv_buf_from_mem(uint8 **tlv_buf, uint16 *buflen, const xtlv_desc_t *items, bcm_xtlv_opts_t opts) { int res = BCME_OK; - uint8 *ptlv = (uint8 *)*tlv_buf; + uint8 *ptlv = *tlv_buf; while (items->type != 0) { - if ((res = bcm_pack_xtlv_entry(&ptlv, - buflen, items->type, - items->len, items->ptr, opts) != BCME_OK)) { - break; + if (items->len && items->ptr) { + res = bcm_pack_xtlv_entry(&ptlv, buflen, items->type, + items->len, items->ptr, opts); + if (res != BCME_OK) + break; } items++; } + *tlv_buf = ptlv; /* update the external pointer */ return res; } @@ -366,7 +518,8 @@ * */ int -bcm_unpack_xtlv_buf_to_mem(void *tlv_buf, int *buflen, xtlv_desc_t *items, bcm_xtlv_opts_t opts) +bcm_unpack_xtlv_buf_to_mem(uint8 *tlv_buf, int *buflen, xtlv_desc_t *items, + bcm_xtlv_opts_t opts) { int res = BCME_OK; bcm_xtlv_t *elt; @@ -380,14 +533,16 @@ for (; elt != NULL && res == BCME_OK; elt = bcm_next_xtlv(elt, buflen, opts)) { /* find matches in desc_t items */ xtlv_desc_t *dst_desc = items; - uint16 len = ltoh16(elt->len); + uint16 len, type; + const uint8 *data; + bcm_xtlv_unpack_xtlv(elt, &type, &len, &data, opts); while (dst_desc->type != 0) { - if (ltoh16(elt->id) == dst_desc->type) { + if (type == dst_desc->type) { if (len != dst_desc->len) { res = BCME_BADLEN; } else { - memcpy(dst_desc->ptr, elt->data, len); + memcpy(dst_desc->ptr, data, len); } break; } @@ -403,60 +558,67 @@ /* * return data pointer of a given ID from xtlv buffer. - * If the specified xTLV ID is found, on return *data_len_out will contain + * If the specified xTLV ID is found, on return *datalen will contain * the the data length of the xTLV ID. */ -void * -bcm_get_data_from_xtlv_buf(uint8 *tlv_buf, uint16 buflen, uint16 id, - uint16 *datalen_out, bcm_xtlv_opts_t opts) +const uint8* +bcm_get_data_from_xtlv_buf(const uint8 *tlv_buf, uint16 buflen, uint16 id, + uint16 *datalen, bcm_xtlv_opts_t opts) { - void *retptr = NULL; + const uint8 *retptr = NULL; uint16 type, len; int size; - bcm_xtlv_t *ptlv; + const bcm_xtlv_t *ptlv; int sbuflen = buflen; + const uint8 *data; + int hdr_size; + + hdr_size = BCM_XTLV_HDR_SIZE_EX(opts); /* Init the datalength */ - if (datalen_out) { - *datalen_out = 0; + if (datalen) { + *datalen = 0; } - while (sbuflen >= (int)BCM_XTLV_HDR_SIZE) { - ptlv = (bcm_xtlv_t *)tlv_buf; + while (sbuflen >= hdr_size) { + ptlv = (const bcm_xtlv_t *)tlv_buf; + bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts); - /* tlv header is always packed in LE order */ - type = ltoh16(ptlv->id); - len = ltoh16(ptlv->len); size = bcm_xtlv_size_for_data(len, opts); - sbuflen -= size; - /* check for possible buffer overrun */ - if (sbuflen < 0) { - printf("%s %d: Invalid sbuflen %d\n", - __FUNCTION__, __LINE__, sbuflen); + if (sbuflen < 0) /* buffer overrun? */ break; - } if (id == type) { - retptr = ptlv->data; - if (datalen_out) { - *datalen_out = len; - } + retptr = data; + if (datalen) + *datalen = len; break; } + tlv_buf += size; } return retptr; } -int bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts) +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) { - int size; /* entire size of the XTLV including header, data, and optional padding */ - int len; /* XTLV's value real length wthout padding */ + bcm_xtlv_t *dst_next = NULL; + src = (src && bcm_valid_xtlv(src, src_buf_len, opts)) ? src : NULL; + if (src && dst) { + uint16 type; + uint16 len; + const uint8 *data; + int size; + bcm_xtlv_unpack_xtlv(src, &type, &len, &data, opts); + size = bcm_xtlv_size_for_data(len, opts); + if (size <= dst_buf_len) { + bcm_xtlv_pack_xtlv(dst, type, len, data, opts); + dst_next = (bcm_xtlv_t *)((uint8 *)dst + size); + } + } - len = BCM_XTLV_LEN(elt); - - size = bcm_xtlv_size_for_data(len, opts); - - return size; + return dst_next; } -- Gitblit v1.6.2