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