1 /* 2 * TLV and XTLV support 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 * <<Broadcom-WL-IPTag/Open:>> 25 * 26 * $Id: $ 27 */ 28 29 #ifndef _bcmtlv_h_ 30 #define _bcmtlv_h_ 31 32 #include <typedefs.h> 33 34 #ifdef __cplusplus 35 extern "C" { 36 #endif /* __cplusplus */ 37 38 /* begin tlvs - used in 802.11 IEs etc. */ 39 40 /* type(aka id)/length/value buffer triple */ 41 typedef struct bcm_tlv { 42 uint8 id; 43 uint8 len; 44 uint8 data[1]; 45 } bcm_tlv_t; 46 47 /* size of tlv including data */ 48 #define BCM_TLV_SIZE(_tlv) \ 49 ((_tlv) ? (OFFSETOF(bcm_tlv_t, data) + (_tlv)->len) : 0) 50 51 /* get next tlv - no length checks */ 52 #define BCM_TLV_NEXT(_tlv) (bcm_tlv_t *)((uint8 *)(_tlv) + BCM_TLV_SIZE(_tlv)) 53 54 /* tlv length is restricted to 1 byte */ 55 #define BCM_TLV_MAX_DATA_SIZE (255) 56 57 /* tlv header - two bytes */ 58 #define BCM_TLV_HDR_SIZE (OFFSETOF(bcm_tlv_t, data)) 59 60 /* Check that bcm_tlv_t fits into the given buffer len */ 61 #define bcm_valid_tlv(elt, buflen) \ 62 (((int)(buflen) >= (int)BCM_TLV_HDR_SIZE) && \ 63 ((int)(buflen) >= (int)(BCM_TLV_HDR_SIZE + (elt)->len))) 64 65 /* type(aka id)/length/ext/value buffer */ 66 typedef struct bcm_tlv_ext { 67 uint8 id; 68 uint8 len; 69 uint8 ext; 70 uint8 data[1]; 71 } bcm_tlv_ext_t; 72 73 /* get next tlv_ext - no length checks */ 74 #define BCM_TLV_EXT_NEXT(_tlv_ext) \ 75 (bcm_tlv_ext_t *)((uint8 *)(_tlv_ext) + BCM_TLV_EXT_SIZE(_tlv_ext)) 76 77 /* tlv_ext length is restricted to 1 byte */ 78 #define BCM_TLV_EXT_MAX_DATA_SIZE (254) 79 80 /* tlv_ext header - three bytes */ 81 #define BCM_TLV_EXT_HDR_SIZE (OFFSETOF(bcm_tlv_ext_t, data)) 82 83 /* size of tlv_ext including data */ 84 #define BCM_TLV_EXT_SIZE(_tlv_ext) (BCM_TLV_EXT_HDR_SIZE + (_tlv_ext)->len) 85 86 /* find the next tlv */ 87 bcm_tlv_t *bcm_next_tlv(const bcm_tlv_t *elt, uint *buflen); 88 89 /* move buffer/buflen up to the given tlv, or set to NULL/0 on error */ 90 void bcm_tlv_buffer_advance_to(const bcm_tlv_t *elt, const uint8 **buffer, 91 uint *buflen); 92 93 /* move buffer/buflen past the given tlv, or set to NULL/0 on error */ 94 void bcm_tlv_buffer_advance_past(const bcm_tlv_t *elt, const uint8 **buffer, 95 uint *buflen); 96 97 /* find the tlv for a given id */ 98 bcm_tlv_t *bcm_parse_tlvs(const void *buf, uint buflen, uint key); 99 100 /* 101 * Traverse tlvs and return pointer to the first tlv that 102 * matches the key. Return NULL if not found or tlv len < min_bodylen 103 */ 104 bcm_tlv_t *bcm_parse_tlvs_min_bodylen(const void *buf, int buflen, uint key, 105 int min_bodylen); 106 107 /* parse tlvs for dot11 - same as parse_tlvs but supports 802.11 id extension */ 108 bcm_tlv_t *bcm_parse_tlvs_dot11(const void *buf, int buflen, uint key, 109 bool id_ext); 110 111 /* same as parse_tlvs, but stops when found id > key */ 112 const bcm_tlv_t *bcm_parse_ordered_tlvs(const void *buf, int buflen, uint key); 113 114 /* find a tlv with DOT11_MNG_PROPR_ID as id, and the given oui and type */ 115 bcm_tlv_t *bcm_find_vendor_ie(const void *tlvs, uint tlvs_len, const char *voui, 116 uint8 *type, uint type_len); 117 118 /* write tlv at dst and return next tlv ptr */ 119 uint8 *bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst); 120 121 /* write tlv_ext at dst and return next tlv ptr */ 122 uint8 *bcm_write_tlv_ext(uint8 type, uint8 ext, const void *data, uint8 datalen, 123 uint8 *dst); 124 125 /* write tlv at dst if space permits and return next tlv ptr */ 126 uint8 *bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, 127 int dst_maxlen); 128 129 /* copy a tlv and return next tlv ptr */ 130 uint8 *bcm_copy_tlv(const void *src, uint8 *dst); 131 132 /* copy a tlv if space permits and return next tlv ptr */ 133 uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen); 134 135 /* end tlvs */ 136 137 /* begin xtlv - used for iovars, nan attributes etc. */ 138 139 /* bcm type(id), length, value with w/16 bit id/len. The structure below 140 * is nominal, and is used to support variable length id and type. See 141 * xtlv options below. 142 */ 143 typedef struct bcm_xtlv { 144 uint16 id; 145 uint16 len; 146 uint8 data[1]; 147 } bcm_xtlv_t; 148 149 /* xtlv options */ 150 #define BCM_XTLV_OPTION_NONE 0x0000 151 #define BCM_XTLV_OPTION_ALIGN32 0x0001 /* 32bit alignment of type.len.data */ 152 #define BCM_XTLV_OPTION_IDU8 0x0002 /* shorter id */ 153 #define BCM_XTLV_OPTION_LENU8 0x0004 /* shorted length */ 154 #define BCM_XTLV_OPTION_IDBE 0x0008 /* big endian format id */ 155 #define BCM_XTLV_OPTION_LENBE 0x0010 /* big endian format length */ 156 typedef uint16 bcm_xtlv_opts_t; 157 158 /* header size. depends on options. Macros names ending w/ _EX are where 159 * options are explcitly specified that may be less common. The ones 160 * without use default values that correspond to ...OPTION_NONE 161 */ 162 163 /* xtlv header size depends on options */ 164 #define BCM_XTLV_HDR_SIZE 4 165 #define BCM_XTLV_HDR_SIZE_EX(_opts) bcm_xtlv_hdr_size(_opts) 166 167 /* note: xtlv len only stores the value's length without padding */ 168 #define BCM_XTLV_LEN(_elt) ltoh16_ua(&(_elt)->len) 169 #define BCM_XTLV_LEN_EX(_elt, _opts) bcm_xtlv_len(_elt, _opts) 170 171 #define BCM_XTLV_ID(_elt) ltoh16_ua(&(_elt)->id) 172 #define BCM_XTLV_ID_EX(_elt, _opts) bcm_xtlv_id(_elt, _opts) 173 174 /* entire size of the XTLV including header, data, and optional padding */ 175 #define BCM_XTLV_SIZE(elt, opts) bcm_xtlv_size(elt, opts) 176 #define BCM_XTLV_SIZE_EX(_elt, _opts) bcm_xtlv_size(_elt, _opts) 177 178 /* max xtlv data size */ 179 #define BCM_XTLV_MAX_DATA_SIZE 65535 180 #define BCM_XTLV_MAX_DATA_SIZE_EX(_opts) \ 181 ((_opts & BCM_XTLV_OPTION_LENU8) ? 255 : 65535) 182 183 /* descriptor of xtlv data, packing(src) and unpacking(dst) support */ 184 typedef struct { 185 uint16 type; 186 uint16 len; 187 void *ptr; /* ptr to memory location */ 188 } xtlv_desc_t; 189 190 /* xtlv buffer - packing/unpacking support */ 191 struct bcm_xtlvbuf { 192 bcm_xtlv_opts_t opts; 193 uint16 size; 194 uint8 *head; /* point to head of buffer */ 195 uint8 *buf; /* current position of buffer */ 196 /* allocated buffer may follow, but not necessarily */ 197 }; 198 typedef struct bcm_xtlvbuf bcm_xtlvbuf_t; 199 200 /* valid xtlv ? */ 201 bool bcm_valid_xtlv(const bcm_xtlv_t *elt, int buf_len, bcm_xtlv_opts_t opts); 202 203 /* return the next xtlv element, and update buffer len (remaining). Buffer 204 * length updated includes padding as specified by options 205 */ 206 bcm_xtlv_t *bcm_next_xtlv(const bcm_xtlv_t *elt, int *buf_len, 207 bcm_xtlv_opts_t opts); 208 209 /* initialize an xtlv buffer. Use options specified for packing/unpacking using 210 * the buffer. Caller is responsible for allocating both buffers. 211 */ 212 int bcm_xtlv_buf_init(bcm_xtlvbuf_t *tlv_buf, uint8 *buf, uint16 len, 213 bcm_xtlv_opts_t opts); 214 215 /* length of data in the xtlv buffer */ 216 uint16 bcm_xtlv_buf_len(struct bcm_xtlvbuf *tbuf); 217 218 /* remaining space in the xtlv buffer */ 219 uint16 bcm_xtlv_buf_rlen(struct bcm_xtlvbuf *tbuf); 220 221 /* write ptr */ 222 uint8 *bcm_xtlv_buf(struct bcm_xtlvbuf *tbuf); 223 224 /* head */ 225 uint8 *bcm_xtlv_head(struct bcm_xtlvbuf *tbuf); 226 227 /* put a data buffer into xtlv */ 228 int bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const uint8 *data, 229 int n); 230 231 /* put one or more u16 elts into xtlv */ 232 int bcm_xtlv_put16(bcm_xtlvbuf_t *tbuf, uint16 type, const uint16 *data, int n); 233 234 /* put one or more u32 elts into xtlv */ 235 int bcm_xtlv_put32(bcm_xtlvbuf_t *tbuf, uint16 type, const uint32 *data, int n); 236 237 /* put one or more u64 elts into xtlv */ 238 int bcm_xtlv_put64(bcm_xtlvbuf_t *tbuf, uint16 type, const uint64 *data, int n); 239 240 /* note: there are no get equivalent of integer unpacking, becasuse bcmendian.h 241 * can be used directly using pointers returned in the buffer being processed. 242 */ 243 244 /* unpack a single xtlv entry, advances buffer and copies data to dst_data on 245 * match type and length match must be exact 246 */ 247 int bcm_unpack_xtlv_entry(const uint8 **buf, uint16 expected_type, 248 uint16 expected_len, uint8 *dst_data, 249 bcm_xtlv_opts_t opts); 250 251 /* packs an xtlv into buffer, and advances buffer, decreements buffer length. 252 * buffer length is checked and must be >= size of xtlv - otherwise BCME_BADLEN 253 */ 254 int bcm_pack_xtlv_entry(uint8 **buf, uint16 *buflen, uint16 type, uint16 len, 255 const uint8 *src_data, bcm_xtlv_opts_t opts); 256 257 /* accessors and lengths for element given options */ 258 int bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts); 259 int bcm_xtlv_hdr_size(bcm_xtlv_opts_t opts); 260 int bcm_xtlv_len(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts); 261 int bcm_xtlv_id(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts); 262 int bcm_xtlv_size_for_data(int dlen, bcm_xtlv_opts_t opts); 263 264 /* compute size needed for number of tlvs whose total data len is given */ 265 #define BCM_XTLV_SIZE_FOR_TLVS(_data_len, _num_tlvs, _opts) \ 266 (bcm_xtlv_size_for_data(_data_len, _opts) + \ 267 ((_num_tlvs)*BCM_XTLV_HDR_SIZE_EX(_opts))) 268 269 /* unsafe copy xtlv */ 270 #define BCM_XTLV_BCOPY(_src, _dst, _opts) \ 271 bcm_xtlv_bcopy(_src, _dst, BCM_XTLV_MAX_DATA_SIZE_EX(_opts), \ 272 BCM_XTLV_MAX_DATA_SIZE_EX(_opts), _opts) 273 274 /* copy xtlv - note: src->dst bcopy order - to be compatible w/ tlv version */ 275 bcm_xtlv_t *bcm_xtlv_bcopy(const bcm_xtlv_t *src, bcm_xtlv_t *dst, 276 int src_buf_len, int dst_buf_len, 277 bcm_xtlv_opts_t opts); 278 279 /* callback for unpacking xtlv from a buffer into context. */ 280 typedef int(bcm_xtlv_unpack_cbfn_t)(void *ctx, const uint8 *buf, uint16 type, 281 uint16 len); 282 283 /* unpack a tlv buffer using buffer, options, and callback */ 284 int bcm_unpack_xtlv_buf(void *ctx, const uint8 *buf, uint16 buflen, 285 bcm_xtlv_opts_t opts, bcm_xtlv_unpack_cbfn_t *cbfn); 286 287 /* unpack a set of tlvs from the buffer using provided xtlv descriptors */ 288 int bcm_unpack_xtlv_buf_to_mem(uint8 *buf, int *buflen, xtlv_desc_t *items, 289 bcm_xtlv_opts_t opts); 290 291 /* pack a set of tlvs into buffer using provided xtlv descriptors */ 292 int bcm_pack_xtlv_buf_from_mem(uint8 **buf, uint16 *buflen, 293 const xtlv_desc_t *items, bcm_xtlv_opts_t opts); 294 295 /* return data pointer and data length of a given id from xtlv buffer 296 * data_len may be NULL 297 */ 298 const uint8 *bcm_get_data_from_xtlv_buf(const uint8 *tlv_buf, uint16 buflen, 299 uint16 id, uint16 *datalen, 300 bcm_xtlv_opts_t opts); 301 302 /* callback to return next tlv id and len to pack, if there is more tlvs to come 303 * and options e.g. alignment 304 */ 305 typedef bool (*bcm_pack_xtlv_next_info_cbfn_t)(void *ctx, uint16 *tlv_id, 306 uint16 *tlv_len); 307 308 /* callback to pack the tlv into length validated buffer */ 309 typedef void (*bcm_pack_xtlv_pack_next_cbfn_t)(void *ctx, uint16 tlv_id, 310 uint16 tlv_len, uint8 *buf); 311 312 /* pack a set of tlvs into buffer using get_next to interate */ 313 int bcm_pack_xtlv_buf(void *ctx, uint8 *tlv_buf, uint16 buflen, 314 bcm_xtlv_opts_t opts, 315 bcm_pack_xtlv_next_info_cbfn_t get_next, 316 bcm_pack_xtlv_pack_next_cbfn_t pack_next, int *outlen); 317 318 /* pack an xtlv. does not do any error checking. if data is not NULL 319 * data of given length is copied to buffer (xtlv) 320 */ 321 void bcm_xtlv_pack_xtlv(bcm_xtlv_t *xtlv, uint16 type, uint16 len, 322 const uint8 *data, bcm_xtlv_opts_t opts); 323 324 /* unpack an xtlv and return ptr to data, and data length */ 325 void bcm_xtlv_unpack_xtlv(const bcm_xtlv_t *xtlv, uint16 *type, uint16 *len, 326 const uint8 **data, bcm_xtlv_opts_t opts); 327 328 /* end xtlvs */ 329 330 /* length value pairs */ 331 struct bcm_xlv { 332 uint16 len; 333 uint8 data[1]; 334 }; 335 typedef struct bcm_xlv bcm_xlv_t; 336 337 struct bcm_xlvp { 338 uint16 len; 339 uint8 *data; 340 }; 341 typedef struct bcm_xlvp bcm_xlvp_t; 342 343 struct bcm_const_xlvp { 344 uint16 len; 345 const uint8 *data; 346 }; 347 typedef struct bcm_const_xlvp bcm_const_xlvp_t; 348 349 /* end length value pairs */ 350 351 #ifdef __cplusplus 352 } 353 #endif /* __cplusplus */ 354 355 #endif /* _bcmtlv_h_ */ 356