| 1 | /* |
| 2 | * bcmiov.h |
| 3 | * Common iovar handling/parsing support - batching, parsing, sub-cmd dispatch etc. |
| 4 | * To be used in firmware and host apps or dhd - reducing code size, |
| 5 | * duplication, and maintenance overhead. |
| 6 | * |
| 7 | * Copyright (C) 2020, Broadcom. |
| 8 | * |
| 9 | * Unless you and Broadcom execute a separate written software license |
| 10 | * agreement governing use of this software, this software is licensed to you |
| 11 | * under the terms of the GNU General Public License version 2 (the "GPL"), |
| 12 | * available at http://www.broadcom.com/licenses/GPLv2.php, with the |
| 13 | * following added to such license: |
| 14 | * |
| 15 | * As a special exception, the copyright holders of this software give you |
| 16 | * permission to link this software with independent modules, and to copy and |
| 17 | * distribute the resulting executable under terms of your choice, provided that |
| 18 | * you also meet, for each linked independent module, the terms and conditions of |
| 19 | * the license of that module. An independent module is a module which is not |
| 20 | * derived from this software. The special exception does not apply to any |
| 21 | * modifications of the software. |
| 22 | * |
| 23 | * |
| 24 | * <<Broadcom-WL-IPTag/Dual:>> |
| 25 | */ |
| 26 | |
| 27 | #ifndef _bcmiov_h_ |
| 28 | #define _bcmiov_h_ |
| 29 | |
| 30 | #include <typedefs.h> |
| 31 | #include <bcmutils.h> |
| 32 | #include <wlioctl.h> |
| 33 | #ifdef BCMDRIVER |
| 34 | #include <osl.h> |
| 35 | #else |
| 36 | #include <stddef.h> /* For size_t */ |
| 37 | #endif /* BCMDRIVER */ |
| 38 | |
| 39 | /* Forward declarations */ |
| 40 | typedef uint16 bcm_iov_cmd_id_t; |
| 41 | typedef uint16 bcm_iov_cmd_flags_t; |
| 42 | typedef uint16 bcm_iov_cmd_mflags_t; |
| 43 | typedef struct bcm_iov_cmd_info bcm_iov_cmd_info_t; |
| 44 | typedef struct bcm_iov_cmd_digest bcm_iov_cmd_digest_t; |
| 45 | typedef struct bcm_iov_cmd_tlv_info bcm_iov_cmd_tlv_info_t; |
| 46 | typedef struct bcm_iov_buf bcm_iov_buf_t; |
| 47 | typedef struct bcm_iov_batch_buf bcm_iov_batch_buf_t; |
| 48 | typedef struct bcm_iov_parse_context bcm_iov_parse_context_t; |
| 49 | typedef struct bcm_iov_sub_cmd_context bcm_iov_sub_cmd_context_t; |
| 50 | |
| 51 | typedef void* (*bcm_iov_malloc_t)(void* alloc_ctx, size_t len); |
| 52 | typedef void (*bcm_iov_free_t)(void* alloc_ctx, void *buf, size_t len); |
| 53 | |
| 54 | typedef uint8 bcm_iov_tlp_data_type_t; |
| 55 | typedef struct bcm_iov_tlp bcm_iov_tlp_t; |
| 56 | typedef struct bcm_iov_tlp_node bcm_iov_tlp_node_t; |
| 57 | typedef struct bcm_iov_batch_subcmd bcm_iov_batch_subcmd_t; |
| 58 | |
| 59 | /* |
| 60 | * iov validation handler - All the common checks that are required |
| 61 | * for processing of iovars for any given command. |
| 62 | */ |
| 63 | typedef int (*bcm_iov_cmd_validate_t)(const bcm_iov_cmd_digest_t *dig, |
| 64 | uint32 actionid, const uint8* ibuf, size_t ilen, uint8 *obuf, size_t *olen); |
| 65 | |
| 66 | /* iov get handler - process subcommand specific input and return output. |
| 67 | * input and output may overlap, so the callee needs to check if |
| 68 | * that is supported. For xtlv data a tlv digest is provided to make |
| 69 | * parsing simpler. Output tlvs may be packed into output buffer using |
| 70 | * bcm xtlv support. olen is input/output parameter. On input contains |
| 71 | * max available obuf length and callee must fill the correct length |
| 72 | * to represent the length of output returned. |
| 73 | */ |
| 74 | typedef int (*bcm_iov_cmd_get_t)(const bcm_iov_cmd_digest_t *dig, |
| 75 | const uint8* ibuf, size_t ilen, uint8 *obuf, size_t *olen); |
| 76 | |
| 77 | /* iov set handler - process subcommand specific input and return output |
| 78 | * input and output may overlap, so the callee needs to check if |
| 79 | * that is supported. olen is input/output parameter. On input contains |
| 80 | * max available obuf length and callee must fill the correct length |
| 81 | * to represent the length of output returned. |
| 82 | */ |
| 83 | typedef int (*bcm_iov_cmd_set_t)(const bcm_iov_cmd_digest_t *dig, |
| 84 | const uint8* ibuf, size_t ilen, uint8 *obuf, size_t *olen); |
| 85 | |
| 86 | /* iov (sub-cmd) batch - a vector of commands. count can be zero |
| 87 | * to support a version query. Each command is a tlv - whose data |
| 88 | * portion may have an optional return status, followed by a fixed |
| 89 | * length data header, optionally followed by tlvs. |
| 90 | * cmd = type|length|<status|options>[header][tlvs] |
| 91 | */ |
| 92 | |
| 93 | /* |
| 94 | * Batch sub-commands have status length included in the |
| 95 | * response length packed in TLV. |
| 96 | */ |
| 97 | #define BCM_IOV_STATUS_LEN sizeof(uint32) |
| 98 | |
| 99 | /* batch version is indicated by setting high bit. */ |
| 100 | #define BCM_IOV_BATCH_MASK 0x8000 |
| 101 | |
| 102 | /* |
| 103 | * Batched commands will have the following memory layout |
| 104 | * +--------+---------+--------+-------+ |
| 105 | * |version |count | is_set |sub-cmd| |
| 106 | * +--------+---------+--------+-------+ |
| 107 | * version >= 0x8000 |
| 108 | * count = number of sub-commands encoded in the iov buf |
| 109 | * sub-cmd one or more sub-commands for processing |
| 110 | * Where sub-cmd is padded byte buffer with memory layout as follows |
| 111 | * +--------+---------+-----------------------+-------------+------ |
| 112 | * |cmd-id |length |IN(options) OUT(status)|command data |...... |
| 113 | * +--------+---------+-----------------------+-------------+------ |
| 114 | * cmd-id =sub-command ID |
| 115 | * length = length of this sub-command |
| 116 | * IN(options) = On input processing options/flags for this command |
| 117 | * OUT(status) on output processing status for this command |
| 118 | * command data = encapsulated IOVAR data as a single structure or packed TLVs for each |
| 119 | * individual sub-command. |
| 120 | */ |
| 121 | struct bcm_iov_batch_subcmd { |
| 122 | uint16 id; |
| 123 | uint16 len; |
| 124 | union { |
| 125 | uint32 options; |
| 126 | uint32 status; |
| 127 | } u; |
| 128 | uint8 data[1]; |
| 129 | }; |
| 130 | |
| 131 | struct bcm_iov_batch_buf { |
| 132 | uint16 version; |
| 133 | uint8 count; |
| 134 | uint8 is_set; /* to differentiate set or get */ |
| 135 | struct bcm_iov_batch_subcmd cmds[0]; |
| 136 | }; |
| 137 | |
| 138 | /* non-batched command version = major|minor w/ major <= 127 */ |
| 139 | struct bcm_iov_buf { |
| 140 | uint16 version; |
| 141 | uint16 len; |
| 142 | bcm_iov_cmd_id_t id; |
| 143 | uint16 data[1]; /* 32 bit alignment may be repurposed by the command */ |
| 144 | /* command specific data follows */ |
| 145 | }; |
| 146 | |
| 147 | /* iov options flags */ |
| 148 | enum { |
| 149 | BCM_IOV_CMD_OPT_ALIGN_NONE = 0x0000, |
| 150 | BCM_IOV_CMD_OPT_ALIGN32 = 0x0001, |
| 151 | BCM_IOV_CMD_OPT_TERMINATE_SUB_CMDS = 0x0002 |
| 152 | }; |
| 153 | |
| 154 | /* iov command flags */ |
| 155 | enum { |
| 156 | BCM_IOV_CMD_FLAG_NONE = 0, |
| 157 | BCM_IOV_CMD_FLAG_STATUS_PRESENT = (1 << 0), /* status present at data start - output only */ |
| 158 | BCM_IOV_CMD_FLAG_XTLV_DATA = (1 << 1), /* data is a set of xtlvs */ |
| 159 | BCM_IOV_CMD_FLAG_HDR_IN_LEN = (1 << 2), /* length starts at version - non-bacthed only */ |
| 160 | BCM_IOV_CMD_FLAG_NOPAD = (1 << 3) /* No padding needed after iov_buf */ |
| 161 | }; |
| 162 | |
| 163 | /* information about the command, xtlv options and xtlvs_off are meaningful |
| 164 | * only if XTLV_DATA cmd flag is selected |
| 165 | */ |
| 166 | struct bcm_iov_cmd_info { |
| 167 | bcm_iov_cmd_id_t cmd; /* the (sub)command - module specific */ |
| 168 | bcm_iov_cmd_flags_t flags; /* checked by bcmiov but set by module */ |
| 169 | bcm_iov_cmd_mflags_t mflags; /* owned and checked by module */ |
| 170 | bcm_xtlv_opts_t xtlv_opts; |
| 171 | bcm_iov_cmd_validate_t validate_h; /* command validation handler */ |
| 172 | bcm_iov_cmd_get_t get_h; |
| 173 | bcm_iov_cmd_set_t set_h; |
| 174 | uint16 xtlvs_off; /* offset to beginning of xtlvs in cmd data */ |
| 175 | uint16 min_len_set; |
| 176 | uint16 max_len_set; |
| 177 | uint16 min_len_get; |
| 178 | uint16 max_len_get; |
| 179 | }; |
| 180 | |
| 181 | /* tlv digest to support parsing of xtlvs for commands w/ tlv data; the tlv |
| 182 | * digest is available in the handler for the command. The count and order in |
| 183 | * which tlvs appear in the digest are exactly the same as the order of tlvs |
| 184 | * passed in the registration for the command. Unknown tlvs are ignored. |
| 185 | * If registered tlvs are missing datap will be NULL. common iov rocessing |
| 186 | * acquires an input digest to process input buffer. The handler is responsible |
| 187 | * for constructing an output digest and use packing functions to generate |
| 188 | * the output buffer. The handler may use the input digest as output digest once |
| 189 | * the tlv data is extracted and used. Multiple tlv support involves allocation of |
| 190 | * tlp nodes, except the first, as required, |
| 191 | */ |
| 192 | |
| 193 | /* tlp data type indicates if the data is not used/invalid, input or output */ |
| 194 | enum { |
| 195 | BCM_IOV_TLP_NODE_INVALID = 0, |
| 196 | BCM_IOV_TLP_NODE_IN = 1, |
| 197 | BCM_IOV_TLP_NODE_OUT = 2 |
| 198 | }; |
| 199 | |
| 200 | struct bcm_iov_tlp { |
| 201 | uint16 type; |
| 202 | uint16 len; |
| 203 | uint16 nodeix; /* node index */ |
| 204 | }; |
| 205 | |
| 206 | /* tlp data for a given tlv - multiple tlvs of same type chained */ |
| 207 | struct bcm_iov_tlp_node { |
| 208 | uint8 *next; /* multiple tlv support */ |
| 209 | bcm_iov_tlp_data_type_t type; |
| 210 | uint8 *data; /* pointer to data in buffer or state */ |
| 211 | }; |
| 212 | |
| 213 | struct bcm_iov_cmd_digest { |
| 214 | uint32 version; /* Version */ |
| 215 | void *cmd_ctx; |
| 216 | struct wlc_bsscfg *bsscfg; |
| 217 | const bcm_iov_cmd_info_t *cmd_info; |
| 218 | uint16 max_tlps; /* number of tlps allocated */ |
| 219 | uint16 max_nodes; /* number of nods allocated */ |
| 220 | uint16 num_tlps; /* number of tlps valid */ |
| 221 | uint16 num_nodes; /* number of nods valid */ |
| 222 | uint16 tlps_off; /* offset to tlps */ |
| 223 | uint16 nodes_off; /* offset to nodes */ |
| 224 | /* |
| 225 | * bcm_iov_tlp_t tlps[max_tlps]; |
| 226 | * bcm_iov_tlp_node_t nodes[max_nodes] |
| 227 | */ |
| 228 | }; |
| 229 | |
| 230 | /* get length callback - default length is min_len taken from digest */ |
| 231 | typedef size_t (*bcm_iov_xtlv_get_len_t)(const bcm_iov_cmd_digest_t *dig, |
| 232 | const bcm_iov_cmd_tlv_info_t *tlv_info); |
| 233 | |
| 234 | /* pack to buffer data callback. under some conditions it might |
| 235 | * not be a straight copy and can refer to context(ual) information and |
| 236 | * endian conversions... |
| 237 | */ |
| 238 | typedef void (*bcm_iov_xtlv_pack_t)(const bcm_iov_cmd_digest_t *dig, |
| 239 | const bcm_iov_cmd_tlv_info_t *tlv_info, |
| 240 | uint8 *out_buf, const uint8 *in_data, size_t len); |
| 241 | |
| 242 | struct bcm_iov_cmd_tlv_info { |
| 243 | uint16 id; |
| 244 | uint16 min_len; /* inclusive */ |
| 245 | uint16 max_len; /* inclusive */ |
| 246 | bcm_iov_xtlv_get_len_t get_len; |
| 247 | bcm_iov_xtlv_pack_t pack; |
| 248 | }; |
| 249 | |
| 250 | /* |
| 251 | * module private parse context. Default version type len is uint16 |
| 252 | */ |
| 253 | |
| 254 | /* Command parsing options with respect to validation */ |
| 255 | /* Possible values for parse context options */ |
| 256 | /* Bit 0 - Validate only */ |
| 257 | #define BCM_IOV_PARSE_OPT_BATCH_VALIDATE 0x00000001 |
| 258 | |
| 259 | typedef uint32 bcm_iov_parse_opts_t; |
| 260 | |
| 261 | /* get digest callback */ |
| 262 | typedef int (*bcm_iov_get_digest_t)(void *cmd_ctx, bcm_iov_cmd_digest_t **dig); |
| 263 | |
| 264 | typedef struct bcm_iov_parse_config { |
| 265 | bcm_iov_parse_opts_t options; /* to handle different ver lengths */ |
| 266 | bcm_iov_malloc_t alloc_fn; |
| 267 | bcm_iov_free_t free_fn; |
| 268 | bcm_iov_get_digest_t dig_fn; |
| 269 | int max_regs; |
| 270 | void *alloc_ctx; |
| 271 | } bcm_iov_parse_config_t; |
| 272 | |
| 273 | /* API */ |
| 274 | |
| 275 | /* All calls return an integer status code BCME_* unless otherwise indicated */ |
| 276 | |
| 277 | /* return length of allocation for 'num_cmds' commands. data_len |
| 278 | * includes length of data for all the commands excluding the headers |
| 279 | */ |
| 280 | size_t bcm_iov_get_alloc_len(int num_cmds, size_t data_len); |
| 281 | |
| 282 | /* create parsing context using allocator provided; max_regs provides |
| 283 | * the number of allowed registrations for commands using the context |
| 284 | * sub-components of a module may register their own commands indepdently |
| 285 | * using the parsing context. If digest callback is NULL or returns NULL, |
| 286 | * the (input) digest is allocated using the provided allocators and released on |
| 287 | * completion of processing. |
| 288 | */ |
| 289 | int bcm_iov_create_parse_context(const bcm_iov_parse_config_t *parse_cfg, |
| 290 | bcm_iov_parse_context_t **parse_ctx); |
| 291 | |
| 292 | /* free the parsing context; ctx is set to NULL on exit */ |
| 293 | int bcm_iov_free_parse_context(bcm_iov_parse_context_t **ctx, bcm_iov_free_t free_fn); |
| 294 | |
| 295 | /* Return the command context for the module */ |
| 296 | void *bcm_iov_get_cmd_ctx_info(bcm_iov_parse_context_t *parse_ctx); |
| 297 | |
| 298 | /* register a command info vector along with supported tlvs. Each command |
| 299 | * may support a subset of tlvs |
| 300 | */ |
| 301 | int bcm_iov_register_commands(bcm_iov_parse_context_t *parse_ctx, void *cmd_ctx, |
| 302 | const bcm_iov_cmd_info_t *info, size_t num_cmds, |
| 303 | const bcm_iov_cmd_tlv_info_t *tlv_info, size_t num_tlvs); |
| 304 | |
| 305 | /* pack the xtlvs provided in the digest. may returns BCME_BUFTOOSHORT, but the |
| 306 | * out_len is set to required length in that case. |
| 307 | */ |
| 308 | int bcm_iov_pack_xtlvs(const bcm_iov_cmd_digest_t *dig, bcm_xtlv_opts_t xtlv_opts, |
| 309 | uint8 *out_buf, size_t out_size, size_t *out_len); |
| 310 | |
| 311 | #ifdef BCMDRIVER |
| 312 | /* wlc modules register their iovar(s) using the parsing context w/ wlc layer |
| 313 | * during attach. |
| 314 | */ |
| 315 | struct wlc_if; |
| 316 | struct wlc_info; |
| 317 | extern struct wlc_bsscfg *bcm_iov_bsscfg_find_from_wlcif(struct wlc_info *wlc, |
| 318 | struct wlc_if *wlcif); |
| 319 | int bcm_iov_doiovar(void *parse_ctx, uint32 id, void *params, uint params_len, |
| 320 | void *arg, uint arg_len, uint vsize, struct wlc_if *intf); |
| 321 | #endif /* BCMDRIVER */ |
| 322 | |
| 323 | /* parsing context helpers */ |
| 324 | |
| 325 | /* get the maximum number of tlvs - can be used to allocate digest for all |
| 326 | * commands. the digest can be shared. Negative values are BCM_*, >=0, the |
| 327 | * number of tlvs |
| 328 | */ |
| 329 | int bcm_iov_parse_get_max_tlvs(const bcm_iov_parse_context_t *ctx); |
| 330 | |
| 331 | /* common packing support */ |
| 332 | |
| 333 | /* pack a buffer of uint8s - memcpy wrapper */ |
| 334 | int bcm_iov_pack_buf(const bcm_iov_cmd_digest_t *dig, uint8 *buf, |
| 335 | const uint8 *data, size_t len); |
| 336 | |
| 337 | #define bcm_iov_packv_u8 bcm_iov_pack_buf |
| 338 | |
| 339 | /* |
| 340 | * pack a buffer with uint16s - serialized in LE order, data points to uint16 |
| 341 | * length is not checked. |
| 342 | */ |
| 343 | int bcm_iov_packv_u16(const bcm_iov_cmd_digest_t *dig, uint8 *buf, |
| 344 | const uint16 *data, int n); |
| 345 | |
| 346 | /* |
| 347 | * pack a buffer with uint32s - serialized in LE order - data points to uint32 |
| 348 | * length is not checked. |
| 349 | */ |
| 350 | int bcm_iov_packv_u32(const bcm_iov_cmd_digest_t *dig, uint8 *buf, |
| 351 | const uint32 *data, int n); |
| 352 | |
| 353 | #endif /* _bcmiov_h_ */ |