1 /* 2 Copyright 2021 Jo-Philipp Wich <jo@mein.io> 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #include <stdio.h> 18 #include <stdint.h> 19 #include <stdbool.h> 20 #include <stdarg.h> 21 #include <unistd.h> 22 #include <errno.h> 23 #include <string.h> 24 #include <limits.h> 25 #include <math.h> 26 #include <assert.h> 27 #include <fcntl.h> 28 #include <poll.h> 29 30 #include <net/if.h> 31 #include <netinet/ether.h> 32 #include <arpa/inet.h> 33 #include <netlink/msg.h> 34 #include <netlink/attr.h> 35 #include <netlink/socket.h> 36 #include <netlink/genl/genl.h> 37 #include <netlink/genl/family.h> 38 #include <netlink/genl/ctrl.h> 39 40 #include <linux/nl80211.h> 41 #include <linux/ieee80211.h> 42 #include <linux/mac80211_hwsim.h> 43 #include <libubox/uloop.h> 44 45 #include "ucode/module.h" 46 #include "ucode/platform.h" 47 48 #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) 49 50 #define err_return(code, ...) do { set_error(code, __VA_ARGS__); return NULL; } while(0) 51 52 /* Modified downstream nl80211.h headers may disable certain unsupported 53 * attributes by setting the corresponding defines to 0x10000 without having 54 * to patch the attribute dictionaries within this file. */ 55 56 #define NL80211_ATTR_NOT_IMPLEMENTED 0x10000 57 58 #define NL80211_CMDS_BITMAP_SIZE DIV_ROUND_UP(NL80211_CMD_MAX + 1, 32) 59 60 static struct { 61 int code; 62 char *msg; 63 } last_error; 64 65 __attribute__((format(printf, 2, 3))) static void 66 set_error(int errcode, const char *fmt, ...) { 67 va_list ap; 68 69 if (errcode == -(NLE_MAX + 1)) 70 return; 71 72 free(last_error.msg); 73 74 last_error.code = errcode; 75 last_error.msg = NULL; 76 77 if (fmt) { 78 va_start(ap, fmt); 79 xvasprintf(&last_error.msg, fmt, ap); 80 va_end(ap); 81 } 82 } 83 84 static uc_resource_type_t *listener_type; 85 static uc_value_t *listener_registry; 86 static uc_vm_t *listener_vm; 87 88 typedef struct { 89 uint32_t cmds[NL80211_CMDS_BITMAP_SIZE]; 90 size_t index; 91 } uc_nl_listener_t; 92 93 static bool 94 uc_nl_parse_u32(uc_value_t *val, uint32_t *n) 95 { 96 uint64_t u; 97 98 u = ucv_to_unsigned(val); 99 100 if (errno != 0 || u > UINT32_MAX) 101 return false; 102 103 *n = (uint32_t)u; 104 105 return true; 106 } 107 108 static bool 109 uc_nl_parse_s32(uc_value_t *val, uint32_t *n) 110 { 111 int64_t i; 112 113 i = ucv_to_integer(val); 114 115 if (errno != 0 || i < INT32_MIN || i > INT32_MAX) 116 return false; 117 118 *n = (uint32_t)i; 119 120 return true; 121 } 122 123 static bool 124 uc_nl_parse_u64(uc_value_t *val, uint64_t *n) 125 { 126 *n = ucv_to_unsigned(val); 127 128 return (errno == 0); 129 } 130 131 static bool 132 uc_nl_parse_ipaddr(uc_vm_t *vm, uc_value_t *val, struct in_addr *in) 133 { 134 char *s = ucv_to_string(vm, val); 135 bool valid = true; 136 137 if (!s) 138 return false; 139 140 valid = (inet_pton(AF_INET, s, in) == 1); 141 142 free(s); 143 144 return valid; 145 } 146 147 typedef enum { 148 DT_FLAG, 149 DT_BOOL, 150 DT_U8, 151 DT_S8, 152 DT_U16, 153 DT_U32, 154 DT_S32, 155 DT_U64, 156 DT_STRING, 157 DT_NETDEV, 158 DT_LLADDR, 159 DT_INADDR, 160 DT_NESTED, 161 DT_HT_MCS, 162 DT_HT_CAP, 163 DT_VHT_MCS, 164 DT_HE_MCS, 165 DT_IE, 166 } uc_nl_attr_datatype_t; 167 168 enum { 169 DF_NO_SET = (1 << 0), 170 DF_MULTIPLE = (1 << 1), 171 DF_AUTOIDX = (1 << 2), 172 DF_TYPEIDX = (1 << 3), 173 DF_OFFSET1 = (1 << 4), 174 DF_ARRAY = (1 << 5), 175 DF_BINARY = (1 << 6), 176 DF_RELATED = (1 << 7), 177 DF_REPEATED = (1 << 8), 178 }; 179 180 typedef struct uc_nl_attr_spec { 181 size_t attr; 182 const char *key; 183 uc_nl_attr_datatype_t type; 184 uint32_t flags; 185 const void *auxdata; 186 } uc_nl_attr_spec_t; 187 188 typedef struct uc_nl_nested_spec { 189 size_t headsize; 190 size_t nattrs; 191 const uc_nl_attr_spec_t attrs[]; 192 } uc_nl_nested_spec_t; 193 194 #define SIZE(type) (void *)(uintptr_t)sizeof(struct type) 195 #define MEMBER(type, field) (void *)(uintptr_t)offsetof(struct type, field) 196 #define ATTRID(id) (void *)(uintptr_t)(id) 197 198 static const uc_nl_nested_spec_t nl80211_cqm_nla = { 199 .headsize = 0, 200 .nattrs = 5, 201 .attrs = { 202 { NL80211_ATTR_CQM_PKT_LOSS_EVENT, "cqm_pkt_loss_event", DT_U32, 0, NULL }, 203 { NL80211_ATTR_CQM_RSSI_HYST, "cqm_rssi_hyst", DT_U32, 0, NULL }, 204 { NL80211_ATTR_CQM_RSSI_LEVEL, "cqm_rssi_level", DT_S32, 0, NULL }, 205 { NL80211_ATTR_CQM_RSSI_THOLD, "cqm_rssi_thold", DT_U32, 0, NULL }, 206 { NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, "cqm_rssi_threshold_event", DT_U32, 0, NULL }, 207 } 208 }; 209 210 static const uc_nl_nested_spec_t nl80211_ftm_responder_stats_nla = { 211 .headsize = 0, 212 .nattrs = 9, 213 .attrs = { 214 { NL80211_FTM_STATS_SUCCESS_NUM, "success_num", DT_U32, 0, NULL }, 215 { NL80211_FTM_STATS_PARTIAL_NUM, "partial_num", DT_U32, 0, NULL }, 216 { NL80211_FTM_STATS_FAILED_NUM, "failed_num", DT_U32, 0, NULL }, 217 { NL80211_FTM_STATS_ASAP_NUM, "asap_num", DT_U32, 0, NULL }, 218 { NL80211_FTM_STATS_NON_ASAP_NUM, "non_asap_num", DT_U32, 0, NULL }, 219 { NL80211_FTM_STATS_TOTAL_DURATION_MSEC, "total_duration_msec", DT_U64, 0, NULL }, 220 { NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM, "unknown_triggers_num", DT_U32, 0, NULL }, 221 { NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM, "reschedule_requests_num", DT_U32, 0, NULL }, 222 { NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM, "out_of_window_triggers_num", DT_U32, 0, NULL }, 223 } 224 }; 225 226 static const uc_nl_nested_spec_t nl80211_ifcomb_limit_types_nla = { 227 .headsize = 0, 228 .nattrs = 12, 229 .attrs = { 230 { 1, "ibss", DT_FLAG, 0, NULL }, 231 { 2, "managed", DT_FLAG, 0, NULL }, 232 { 3, "ap", DT_FLAG, 0, NULL }, 233 { 4, "ap_vlan", DT_FLAG, 0, NULL }, 234 { 5, "wds", DT_FLAG, 0, NULL }, 235 { 6, "monitor", DT_FLAG, 0, NULL }, 236 { 7, "mesh_point", DT_FLAG, 0, NULL }, 237 { 8, "p2p_client", DT_FLAG, 0, NULL }, 238 { 9, "p2p_go", DT_FLAG, 0, NULL }, 239 { 10, "p2p_device", DT_FLAG, 0, NULL }, 240 { 11, "outside_bss_context", DT_FLAG, 0, NULL }, 241 { 12, "nan", DT_FLAG, 0, NULL }, 242 } 243 }; 244 245 static const uc_nl_nested_spec_t nl80211_ifcomb_limits_nla = { 246 .headsize = 0, 247 .nattrs = 2, 248 .attrs = { 249 { NL80211_IFACE_LIMIT_TYPES, "types", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla }, 250 { NL80211_IFACE_LIMIT_MAX, "max", DT_U32, 0, NULL }, 251 } 252 }; 253 254 static const uc_nl_nested_spec_t nl80211_ifcomb_nla = { 255 .headsize = 0, 256 .nattrs = 5, 257 .attrs = { 258 { NL80211_IFACE_COMB_LIMITS, "limits", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_ifcomb_limits_nla }, 259 { NL80211_IFACE_COMB_MAXNUM, "maxnum", DT_U32, 0, NULL }, 260 { NL80211_IFACE_COMB_STA_AP_BI_MATCH, "sta_ap_bi_match", DT_FLAG, 0, NULL }, 261 { NL80211_IFACE_COMB_NUM_CHANNELS, "num_channels", DT_U32, 0, NULL }, 262 { NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, "radar_detect_widths", DT_U32, 0, NULL }, 263 } 264 }; 265 266 static const uc_nl_nested_spec_t nl80211_ftm_responder_nla = { 267 .headsize = 0, 268 .nattrs = 3, 269 .attrs = { 270 { NL80211_FTM_RESP_ATTR_ENABLED, "enabled", DT_FLAG, 0, NULL }, 271 { NL80211_FTM_RESP_ATTR_LCI, "lci", DT_STRING, DF_BINARY, NULL }, 272 { NL80211_FTM_RESP_ATTR_CIVICLOC, "civicloc", DT_STRING, DF_BINARY, NULL }, 273 } 274 }; 275 276 static const uc_nl_nested_spec_t nl80211_keys_nla = { 277 .headsize = 0, 278 .nattrs = 4, 279 .attrs = { 280 { NL80211_KEY_DEFAULT, "default", DT_FLAG, 0, NULL }, 281 { NL80211_KEY_IDX, "idx", DT_U8, 0, NULL }, 282 { NL80211_KEY_CIPHER, "cipher", DT_U32, 0, NULL }, 283 { NL80211_KEY_DATA, "data", DT_STRING, DF_BINARY, NULL }, 284 } 285 }; 286 287 static const uc_nl_nested_spec_t nl80211_mesh_params_nla = { 288 .headsize = 0, 289 .nattrs = 29, 290 .attrs = { 291 { NL80211_MESHCONF_RETRY_TIMEOUT, "retry_timeout", DT_U16, 0, NULL }, 292 { NL80211_MESHCONF_CONFIRM_TIMEOUT, "confirm_timeout", DT_U16, 0, NULL }, 293 { NL80211_MESHCONF_HOLDING_TIMEOUT, "holding_timeout", DT_U16, 0, NULL }, 294 { NL80211_MESHCONF_MAX_PEER_LINKS, "max_peer_links", DT_U16, 0, NULL }, 295 { NL80211_MESHCONF_MAX_RETRIES, "max_retries", DT_U8, 0, NULL }, 296 { NL80211_MESHCONF_TTL, "ttl", DT_U8, 0, NULL }, 297 { NL80211_MESHCONF_ELEMENT_TTL, "element_ttl", DT_U8, 0, NULL }, 298 { NL80211_MESHCONF_AUTO_OPEN_PLINKS, "auto_open_plinks", DT_BOOL, 0, NULL }, 299 { NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, "hwmp_max_preq_retries", DT_U8, 0, NULL }, 300 { NL80211_MESHCONF_PATH_REFRESH_TIME, "path_refresh_time", DT_U32, 0, NULL }, 301 { NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, "min_discovery_timeout", DT_U16, 0, NULL }, 302 { NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, "hwmp_active_path_timeout", DT_U32, 0, NULL }, 303 { NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, "hwmp_preq_min_interval", DT_U16, 0, NULL }, 304 { NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, "hwmp_net_diam_trvs_time", DT_U16, 0, NULL }, 305 { NL80211_MESHCONF_HWMP_ROOTMODE, "hwmp_rootmode", DT_U8, 0, NULL }, 306 { NL80211_MESHCONF_HWMP_RANN_INTERVAL, "hwmp_rann_interval", DT_U16, 0, NULL }, 307 { NL80211_MESHCONF_GATE_ANNOUNCEMENTS, "gate_announcements", DT_U8, 0, NULL }, 308 { NL80211_MESHCONF_FORWARDING, "forwarding", DT_BOOL, 0, NULL }, 309 { NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, "sync_offset_max_neighbor", DT_U32, 0, NULL }, 310 { NL80211_MESHCONF_RSSI_THRESHOLD, "rssi_threshold", DT_S32, 0, NULL }, 311 { NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, "hwmp_path_to_root_timeout", DT_U32, 0, NULL }, 312 { NL80211_MESHCONF_HWMP_ROOT_INTERVAL, "hwmp_root_interval", DT_U16, 0, NULL }, 313 { NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, "hwmp_confirmation_interval", DT_U16, 0, NULL }, 314 { NL80211_MESHCONF_POWER_MODE, "power_mode", DT_U32, 0, NULL }, 315 { NL80211_MESHCONF_AWAKE_WINDOW, "awake_window", DT_U16, 0, NULL }, 316 { NL80211_MESHCONF_PLINK_TIMEOUT, "plink_timeout", DT_U32, 0, NULL }, 317 { NL80211_MESHCONF_CONNECTED_TO_GATE, "connected_to_gate", DT_BOOL, 0, NULL }, 318 { NL80211_MESHCONF_NOLEARN, "nolearn", DT_BOOL, 0, NULL }, 319 { NL80211_MESHCONF_CONNECTED_TO_AS, "connected_to_as", DT_BOOL, 0, NULL }, 320 } 321 }; 322 323 static const uc_nl_nested_spec_t nl80211_mesh_setup_nla = { 324 .headsize = 0, 325 .nattrs = 1, 326 .attrs = { 327 { NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, "enable_vendor_sync", DT_BOOL, 0, NULL }, 328 } 329 }; 330 331 static const uc_nl_nested_spec_t nl80211_mntr_flags_nla = { 332 .headsize = 0, 333 .nattrs = 7, 334 .attrs = { 335 { NL80211_MNTR_FLAG_FCSFAIL, "fcsfail", DT_FLAG, 0, NULL }, 336 { NL80211_MNTR_FLAG_PLCPFAIL, "plcpfail", DT_FLAG, 0, NULL }, 337 { NL80211_MNTR_FLAG_CONTROL, "control", DT_FLAG, 0, NULL }, 338 { NL80211_MNTR_FLAG_OTHER_BSS, "other_bss", DT_FLAG, 0, NULL }, 339 { NL80211_MNTR_FLAG_COOK_FRAMES, "cook_frames", DT_FLAG, 0, NULL }, 340 { NL80211_MNTR_FLAG_ACTIVE, "active", DT_FLAG, 0, NULL }, 341 { NL80211_MNTR_FLAG_SKIP_TX, "skip_tx", DT_FLAG, 0, NULL }, 342 } 343 }; 344 345 static const uc_nl_nested_spec_t nl80211_nan_func_srf_nla = { 346 .headsize = 0, 347 .nattrs = 4, 348 .attrs = { 349 { NL80211_NAN_SRF_INCLUDE, "include", DT_FLAG, 0, NULL }, 350 { NL80211_NAN_SRF_BF_IDX, "bf_idx", DT_U8, 0, NULL }, 351 { NL80211_NAN_SRF_BF, "bf", DT_STRING, DF_BINARY, NULL }, 352 { NL80211_NAN_SRF_MAC_ADDRS, "mac_addrs", DT_LLADDR, DF_MULTIPLE|DF_AUTOIDX, NULL }, 353 } 354 }; 355 356 static const uc_nl_nested_spec_t nl80211_nan_func_nla = { 357 .headsize = 0, 358 .nattrs = 16, 359 .attrs = { 360 { NL80211_NAN_FUNC_TYPE, "type", DT_U8, 0, NULL }, 361 { NL80211_NAN_FUNC_SERVICE_ID, "service_id", DT_STRING, DF_BINARY, NULL }, 362 { NL80211_NAN_FUNC_PUBLISH_TYPE, "publish_type", DT_U8, 0, NULL }, 363 { NL80211_NAN_FUNC_PUBLISH_BCAST, "publish_bcast", DT_FLAG, 0, NULL }, 364 { NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE, "subscribe_active", DT_FLAG, 0, NULL }, 365 { NL80211_NAN_FUNC_FOLLOW_UP_ID, "follow_up_id", DT_U8, 0, NULL }, 366 { NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID, "follow_up_req_id", DT_U8, 0, NULL }, 367 { NL80211_NAN_FUNC_FOLLOW_UP_DEST, "follow_up_dest", DT_LLADDR, 0, NULL }, 368 { NL80211_NAN_FUNC_CLOSE_RANGE, "close_range", DT_FLAG, 0, NULL }, 369 { NL80211_NAN_FUNC_TTL, "ttl", DT_U32, 0, NULL }, 370 { NL80211_NAN_FUNC_SERVICE_INFO, "service_info", DT_STRING, 0, NULL }, 371 { NL80211_NAN_FUNC_SRF, "srf", DT_NESTED, 0, &nl80211_nan_func_srf_nla }, 372 { NL80211_NAN_FUNC_RX_MATCH_FILTER, "rx_match_filter", DT_STRING, DF_MULTIPLE|DF_AUTOIDX, NULL }, 373 { NL80211_NAN_FUNC_TX_MATCH_FILTER, "tx_match_filter", DT_STRING, DF_MULTIPLE|DF_AUTOIDX, NULL }, 374 { NL80211_NAN_FUNC_INSTANCE_ID, "instance_id", DT_U8, 0, NULL }, 375 { NL80211_NAN_FUNC_TERM_REASON, "term_reason", DT_U8, 0, NULL }, 376 } 377 }; 378 379 static const uc_nl_nested_spec_t nl80211_peer_measurements_type_ftm_nla = { 380 .headsize = 0, 381 .nattrs = 13, 382 .attrs = { 383 { NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP, "num_bursts_exp", DT_U8, 0, NULL }, 384 { NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD, "burst_period", DT_U16, 0, NULL }, 385 { NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES, "num_ftmr_retries", DT_U8, 0, NULL }, 386 { NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION, "burst_duration", DT_U8, 0, NULL }, 387 { NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST, "ftms_per_burst", DT_U8, 0, NULL }, 388 { NL80211_PMSR_FTM_REQ_ATTR_ASAP, "asap", DT_FLAG, 0, NULL }, 389 { NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC, "request_civicloc", DT_FLAG, 0, NULL }, 390 { NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI, "request_lci", DT_FLAG, 0, NULL }, 391 { NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED, "trigger_based", DT_FLAG, 0, NULL }, 392 { NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE, "preamble", DT_U32, 0, NULL }, 393 { NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED, "non_trigger_based", DT_FLAG, 0, NULL }, 394 { NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK, "lmr_feedback", DT_FLAG, 0, NULL }, 395 { NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR, "bss_color", DT_U8, 0, NULL }, 396 } 397 }; 398 399 static const uc_nl_nested_spec_t nl80211_peer_measurements_peers_req_data_nla = { 400 .headsize = 0, 401 .nattrs = 2, 402 .attrs = { 403 { NL80211_PMSR_TYPE_FTM, "ftm", DT_NESTED, 0, &nl80211_peer_measurements_type_ftm_nla }, 404 { NL80211_PMSR_REQ_ATTR_GET_AP_TSF, "get_ap_tsf", DT_FLAG, 0, NULL }, 405 } 406 }; 407 408 static const uc_nl_nested_spec_t nl80211_peer_measurements_peers_req_nla = { 409 .headsize = 0, 410 .nattrs = 1, 411 .attrs = { 412 { NL80211_PMSR_REQ_ATTR_DATA, "data", DT_NESTED, 0, &nl80211_peer_measurements_peers_req_data_nla }, 413 } 414 }; 415 416 static const uc_nl_nested_spec_t nl80211_peer_measurements_peers_chan_nla = { 417 .headsize = 0, 418 .nattrs = 4, 419 .attrs = { 420 { NL80211_ATTR_WIPHY_FREQ, "freq", DT_U32, 0, NULL }, 421 { NL80211_ATTR_CENTER_FREQ1, "center_freq1", DT_U32, 0, NULL }, 422 { NL80211_ATTR_CENTER_FREQ2, "center_freq2", DT_U32, 0, NULL }, 423 { NL80211_ATTR_CHANNEL_WIDTH, "channel_width", DT_U32, 0, NULL }, 424 } 425 }; 426 427 static const uc_nl_nested_spec_t nl80211_peer_measurements_peers_resp_data_nla = { 428 .headsize = 0, 429 .nattrs = 1, 430 .attrs = { 431 { NL80211_PMSR_TYPE_FTM, "ftm", DT_NESTED, 0, &nl80211_peer_measurements_type_ftm_nla }, 432 } 433 }; 434 435 static const uc_nl_nested_spec_t nl80211_peer_measurements_peers_resp_nla = { 436 .headsize = 0, 437 .nattrs = 5, 438 .attrs = { 439 { NL80211_PMSR_RESP_ATTR_STATUS, "status", DT_U32, 0, NULL }, 440 { NL80211_PMSR_RESP_ATTR_HOST_TIME, "host_time", DT_U64, 0, NULL }, 441 { NL80211_PMSR_RESP_ATTR_AP_TSF, "ap_tsf", DT_U64, 0, NULL }, 442 { NL80211_PMSR_RESP_ATTR_FINAL, "final", DT_FLAG, 0, NULL }, 443 { NL80211_PMSR_RESP_ATTR_DATA, "data", DT_NESTED, 0, &nl80211_peer_measurements_peers_resp_data_nla }, 444 } 445 }; 446 447 static const uc_nl_nested_spec_t nl80211_peer_measurements_peers_nla = { 448 .headsize = 0, 449 .nattrs = 4, 450 .attrs = { 451 { NL80211_PMSR_PEER_ATTR_ADDR, "addr", DT_LLADDR, 0, NULL }, 452 { NL80211_PMSR_PEER_ATTR_REQ, "req", DT_NESTED, 0, &nl80211_peer_measurements_peers_req_nla }, 453 { NL80211_PMSR_PEER_ATTR_CHAN, "chan", DT_NESTED, 0, &nl80211_peer_measurements_peers_chan_nla }, 454 { NL80211_PMSR_PEER_ATTR_RESP, "resp", DT_NESTED, 0, &nl80211_peer_measurements_peers_resp_nla } 455 } 456 }; 457 458 static const uc_nl_nested_spec_t nl80211_peer_measurements_nla = { 459 .headsize = 0, 460 .nattrs = 1, 461 .attrs = { 462 { NL80211_PMSR_ATTR_PEERS, "peers", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_peer_measurements_peers_nla }, 463 } 464 }; 465 466 static const uc_nl_nested_spec_t nl80211_reg_rules_nla = { 467 .headsize = 0, 468 .nattrs = 7, 469 .attrs = { 470 { NL80211_ATTR_REG_RULE_FLAGS, "reg_rule_flags", DT_U32, 0, NULL }, 471 { NL80211_ATTR_FREQ_RANGE_START, "freq_range_start", DT_U32, 0, NULL }, 472 { NL80211_ATTR_FREQ_RANGE_END, "freq_range_end", DT_U32, 0, NULL }, 473 { NL80211_ATTR_FREQ_RANGE_MAX_BW, "freq_range_max_bw", DT_U32, 0, NULL }, 474 { NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, "power_rule_max_ant_gain", DT_U32, 0, NULL }, 475 { NL80211_ATTR_POWER_RULE_MAX_EIRP, "power_rule_max_eirp", DT_U32, 0, NULL }, 476 { NL80211_ATTR_DFS_CAC_TIME, "dfs_cac_time", DT_U32, 0, NULL }, 477 } 478 }; 479 480 static const uc_nl_nested_spec_t nl80211_frame_types_nla = { 481 .headsize = 0, 482 .nattrs = 12, 483 .attrs = { 484 { 1, "ibss", DT_U16, DF_MULTIPLE, NULL }, 485 { 2, "managed", DT_U16, DF_MULTIPLE, NULL }, 486 { 3, "ap", DT_U16, DF_MULTIPLE, NULL }, 487 { 4, "ap_vlan", DT_U16, DF_MULTIPLE, NULL }, 488 { 5, "wds", DT_U16, DF_MULTIPLE, NULL }, 489 { 6, "monitor", DT_U16, DF_MULTIPLE, NULL }, 490 { 7, "mesh_point", DT_U16, DF_MULTIPLE, NULL }, 491 { 8, "p2p_client", DT_U16, DF_MULTIPLE, NULL }, 492 { 9, "p2p_go", DT_U16, DF_MULTIPLE, NULL }, 493 { 10, "p2p_device", DT_U16, DF_MULTIPLE, NULL }, 494 { 11, "outside_bss_context", DT_U16, DF_MULTIPLE, NULL }, 495 { 12, "nan", DT_U16, DF_MULTIPLE, NULL }, 496 } 497 }; 498 499 static const uc_nl_nested_spec_t nl80211_sched_scan_match_nla = { 500 .headsize = 0, 501 .nattrs = 1, 502 .attrs = { 503 { NL80211_SCHED_SCAN_MATCH_ATTR_SSID, "ssid", DT_STRING, DF_BINARY, NULL }, 504 } 505 }; 506 507 static const uc_nl_nested_spec_t nl80211_sched_scan_plan_nla = { 508 .headsize = 0, 509 .nattrs = 2, 510 .attrs = { 511 { NL80211_SCHED_SCAN_PLAN_INTERVAL, "interval", DT_U32, 0, NULL }, 512 { NL80211_SCHED_SCAN_PLAN_ITERATIONS, "iterations", DT_U32, 0, NULL }, 513 } 514 }; 515 516 enum { 517 HWSIM_TM_ATTR_CMD = 1, 518 HWSIM_TM_ATTR_PS = 2, 519 }; 520 521 static const uc_nl_nested_spec_t nl80211_testdata_nla = { 522 .headsize = 0, 523 .nattrs = 2, 524 .attrs = { 525 { HWSIM_TM_ATTR_CMD, "cmd", DT_U32, 0, NULL }, 526 { HWSIM_TM_ATTR_PS, "ps", DT_U32, 0, NULL }, 527 } 528 }; 529 530 static const uc_nl_nested_spec_t nl80211_tid_config_nla = { 531 .headsize = 0, 532 .nattrs = 1, 533 .attrs = { 534 { NL80211_TID_CONFIG_ATTR_TIDS, "tids", DT_U16, 0, NULL }, 535 } 536 }; 537 538 static const uc_nl_nested_spec_t nl80211_wiphy_bands_freqs_wmm_nla = { 539 .headsize = 0, 540 .nattrs = 4, 541 .attrs = { 542 { NL80211_WMMR_CW_MIN, "cw_min", DT_U16, 0, NULL }, 543 { NL80211_WMMR_CW_MAX, "cw_max", DT_U16, 0, NULL }, 544 { NL80211_WMMR_AIFSN, "aifsn", DT_U8, 0, NULL }, 545 { NL80211_WMMR_TXOP, "txop", DT_U16, 0, NULL }, 546 } 547 }; 548 549 static const uc_nl_nested_spec_t nl80211_wiphy_bands_freqs_nla = { 550 .headsize = 0, 551 .nattrs = 25, 552 .attrs = { 553 { NL80211_FREQUENCY_ATTR_FREQ, "freq", DT_U32, 0, NULL }, 554 { NL80211_FREQUENCY_ATTR_DISABLED, "disabled", DT_FLAG, 0, NULL }, 555 { NL80211_FREQUENCY_ATTR_NO_IR, "no_ir", DT_FLAG, 0, NULL }, 556 { __NL80211_FREQUENCY_ATTR_NO_IBSS, "no_ibss", DT_FLAG, 0, NULL }, 557 { NL80211_FREQUENCY_ATTR_RADAR, "radar", DT_FLAG, 0, NULL }, 558 { NL80211_FREQUENCY_ATTR_MAX_TX_POWER, "max_tx_power", DT_U32, 0, NULL }, 559 { NL80211_FREQUENCY_ATTR_DFS_STATE, "dfs_state", DT_U32, 0, NULL }, 560 { NL80211_FREQUENCY_ATTR_DFS_TIME, "dfs_time", DT_U32, 0, NULL }, 561 { NL80211_FREQUENCY_ATTR_NO_HT40_MINUS, "no_ht40_minus", DT_FLAG, 0, NULL }, 562 { NL80211_FREQUENCY_ATTR_NO_HT40_PLUS, "no_ht40_plus", DT_FLAG, 0, NULL }, 563 { NL80211_FREQUENCY_ATTR_NO_80MHZ, "no_80mhz", DT_FLAG, 0, NULL }, 564 { NL80211_FREQUENCY_ATTR_NO_160MHZ, "no_160mhz", DT_FLAG, 0, NULL }, 565 { NL80211_FREQUENCY_ATTR_DFS_CAC_TIME, "dfs_cac_time", DT_FLAG, 0, NULL }, 566 { NL80211_FREQUENCY_ATTR_INDOOR_ONLY, "indoor_only", DT_FLAG, 0, NULL }, 567 { NL80211_FREQUENCY_ATTR_IR_CONCURRENT, "ir_concurrent", DT_FLAG, 0, NULL }, 568 { NL80211_FREQUENCY_ATTR_NO_20MHZ, "no_20mhz", DT_FLAG, 0, NULL }, 569 { NL80211_FREQUENCY_ATTR_NO_10MHZ, "no_10mhz", DT_FLAG, 0, NULL }, 570 { NL80211_FREQUENCY_ATTR_WMM, "wmm", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_wiphy_bands_freqs_wmm_nla }, 571 { NL80211_FREQUENCY_ATTR_NO_HE, "no_he", DT_FLAG, 0, NULL }, 572 { NL80211_FREQUENCY_ATTR_OFFSET, "offset", DT_U32, 0, NULL }, 573 { NL80211_FREQUENCY_ATTR_1MHZ, "1mhz", DT_FLAG, 0, NULL }, 574 { NL80211_FREQUENCY_ATTR_2MHZ, "2mhz", DT_FLAG, 0, NULL }, 575 { NL80211_FREQUENCY_ATTR_4MHZ, "4mhz", DT_FLAG, 0, NULL }, 576 { NL80211_FREQUENCY_ATTR_8MHZ, "8mhz", DT_FLAG, 0, NULL }, 577 { NL80211_FREQUENCY_ATTR_16MHZ, "16mhz", DT_FLAG, 0, NULL }, 578 } 579 }; 580 581 static const uc_nl_nested_spec_t nl80211_wiphy_bands_rates_nla = { 582 .headsize = 0, 583 .nattrs = 2, 584 .attrs = { 585 { NL80211_BITRATE_ATTR_RATE, "rate", DT_U32, 0, NULL }, 586 { NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE, "2ghz_shortpreamble", DT_FLAG, 0, NULL }, 587 } 588 }; 589 590 static const uc_nl_nested_spec_t nl80211_wiphy_bands_iftype_data_nla = { 591 .headsize = 0, 592 .nattrs = 9, 593 .attrs = { 594 { NL80211_BAND_IFTYPE_ATTR_IFTYPES, "iftypes", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla }, 595 { NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC, "he_cap_mac", DT_U8, DF_ARRAY, NULL }, 596 { NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY, "he_cap_phy", DT_U8, DF_ARRAY, NULL }, 597 { NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, "he_cap_mcs_set", DT_HE_MCS, DF_RELATED, ATTRID(NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY) }, 598 { NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE, "he_cap_ppe", DT_U8, DF_ARRAY, NULL }, 599 { NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA, "he_6ghz_capa", DT_U16, 0, NULL }, 600 { NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS, "vendor_elems", DT_STRING, DF_BINARY, NULL }, 601 { NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC, "eht_cap_mac", DT_U8, DF_ARRAY, NULL }, 602 { NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY, "eht_cap_phy", DT_U8, DF_ARRAY, NULL }, 603 } 604 }; 605 606 static const uc_nl_nested_spec_t nl80211_wiphy_bands_nla = { 607 .headsize = 0, 608 .nattrs = 11, 609 .attrs = { 610 { NL80211_BAND_ATTR_FREQS, "freqs", DT_NESTED, DF_MULTIPLE|DF_TYPEIDX, &nl80211_wiphy_bands_freqs_nla }, 611 { NL80211_BAND_ATTR_RATES, "rates", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_wiphy_bands_rates_nla }, 612 { NL80211_BAND_ATTR_HT_MCS_SET, "ht_mcs_set", DT_HT_MCS, 0, NULL }, 613 { NL80211_BAND_ATTR_HT_CAPA, "ht_capa", DT_U16, 0, NULL }, 614 { NL80211_BAND_ATTR_HT_AMPDU_FACTOR, "ht_ampdu_factor", DT_U8, 0, NULL }, 615 { NL80211_BAND_ATTR_HT_AMPDU_DENSITY, "ht_ampdu_density", DT_U8, 0, NULL }, 616 { NL80211_BAND_ATTR_VHT_MCS_SET, "vht_mcs_set", DT_VHT_MCS, 0, NULL }, 617 { NL80211_BAND_ATTR_VHT_CAPA, "vht_capa", DT_U32, 0, NULL }, 618 { NL80211_BAND_ATTR_IFTYPE_DATA, "iftype_data", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_wiphy_bands_iftype_data_nla }, 619 { NL80211_BAND_ATTR_EDMG_CHANNELS, "edmg_channels", DT_U8, 0, NULL }, 620 { NL80211_BAND_ATTR_EDMG_BW_CONFIG, "edmg_bw_config", DT_U8, 0, NULL }, 621 } 622 }; 623 624 static const uc_nl_nested_spec_t nl80211_wowlan_triggers_tcp_nla = { 625 .headsize = 0, 626 .nattrs = 11, 627 .attrs = { 628 { NL80211_WOWLAN_TCP_SRC_IPV4, "src_ipv4", DT_INADDR, 0, NULL }, 629 { NL80211_WOWLAN_TCP_SRC_PORT, "src_port", DT_U16, 0, NULL }, 630 { NL80211_WOWLAN_TCP_DST_IPV4, "dst_ipv4", DT_INADDR, 0, NULL }, 631 { NL80211_WOWLAN_TCP_DST_PORT, "dst_port", DT_U16, 0, NULL }, 632 { NL80211_WOWLAN_TCP_DST_MAC, "dst_mac", DT_LLADDR, 0, NULL }, 633 { NL80211_WOWLAN_TCP_DATA_PAYLOAD, "data_payload", DT_STRING, DF_BINARY, NULL }, 634 { NL80211_WOWLAN_TCP_DATA_INTERVAL, "data_interval", DT_U32, 0, NULL }, 635 { NL80211_WOWLAN_TCP_WAKE_MASK, "wake_mask", DT_STRING, DF_BINARY, NULL }, 636 { NL80211_WOWLAN_TCP_WAKE_PAYLOAD, "wake_payload", DT_STRING, DF_BINARY, NULL }, 637 { NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ, "data_payload_seq", DT_U32, DF_ARRAY, NULL }, 638 { NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, "data_payload_token", DT_STRING, DF_BINARY, NULL }, /* XXX: struct nl80211_wowlan_tcp_data_token */ 639 } 640 }; 641 642 static const uc_nl_nested_spec_t nl80211_pkt_pattern_nla = { 643 .headsize = 0, 644 .nattrs = 3, 645 .attrs = { 646 { NL80211_PKTPAT_MASK, "mask", DT_STRING, DF_BINARY, NULL }, 647 { NL80211_PKTPAT_PATTERN, "pattern", DT_STRING, DF_BINARY, NULL }, 648 { NL80211_PKTPAT_OFFSET, "offset", DT_U32, 0, NULL }, 649 } 650 }; 651 652 static const uc_nl_nested_spec_t nl80211_wowlan_triggers_nla = { 653 .headsize = 0, 654 .nattrs = 9, 655 .attrs = { 656 { NL80211_WOWLAN_TRIG_ANY, "any", DT_FLAG, 0, NULL }, 657 { NL80211_WOWLAN_TRIG_DISCONNECT, "disconnect", DT_FLAG, 0, NULL }, 658 { NL80211_WOWLAN_TRIG_MAGIC_PKT, "magic_pkt", DT_FLAG, 0, NULL }, 659 { NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE, "gtk_rekey_failure", DT_FLAG, 0, NULL }, 660 { NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST, "eap_ident_request", DT_FLAG, 0, NULL }, 661 { NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE, "4way_handshake", DT_FLAG, 0, NULL }, 662 { NL80211_WOWLAN_TRIG_RFKILL_RELEASE, "rfkill_release", DT_FLAG, 0, NULL }, 663 { NL80211_WOWLAN_TRIG_TCP_CONNECTION, "tcp_connection", DT_NESTED, 0, &nl80211_wowlan_triggers_tcp_nla }, 664 { NL80211_WOWLAN_TRIG_PKT_PATTERN, "pkt_pattern", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX|DF_OFFSET1, &nl80211_pkt_pattern_nla }, 665 } 666 }; 667 668 static const uc_nl_nested_spec_t nl80211_coalesce_rule_nla = { 669 .headsize = 0, 670 .nattrs = 3, 671 .attrs = { 672 { NL80211_ATTR_COALESCE_RULE_CONDITION, "coalesce_rule_condition", DT_U32, 0, NULL }, 673 { NL80211_ATTR_COALESCE_RULE_DELAY, "coalesce_rule_delay", DT_U32, 0, NULL }, 674 { NL80211_ATTR_COALESCE_RULE_PKT_PATTERN, "coalesce_rule_pkt_pattern", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX|DF_OFFSET1, &nl80211_pkt_pattern_nla }, 675 } 676 }; 677 678 static const uc_nl_nested_spec_t nl80211_bss_nla = { 679 .headsize = 0, 680 .nattrs = 12, 681 .attrs = { 682 { NL80211_BSS_BSSID, "bssid", DT_LLADDR, 0, NULL }, 683 { NL80211_BSS_STATUS, "status", DT_U32, 0, NULL }, 684 { NL80211_BSS_LAST_SEEN_BOOTTIME, "last_seen_boottime", DT_U64, 0, NULL }, 685 { NL80211_BSS_TSF, "tsf", DT_U64, 0, NULL }, 686 { NL80211_BSS_FREQUENCY, "frequency", DT_U32, 0, NULL }, 687 { NL80211_BSS_BEACON_INTERVAL, "beacon_interval", DT_U16, 0, NULL }, 688 { NL80211_BSS_CAPABILITY, "capability", DT_U16, 0, NULL }, 689 { NL80211_BSS_SIGNAL_MBM, "signal_mbm", DT_S32, 0, NULL }, 690 { NL80211_BSS_SIGNAL_UNSPEC, "signal_unspec", DT_U8, 0, NULL }, 691 { NL80211_BSS_SEEN_MS_AGO, "seen_ms_ago", DT_S32, 0, NULL }, 692 { NL80211_BSS_INFORMATION_ELEMENTS, "information_elements", DT_IE, 0, NULL }, 693 { NL80211_BSS_BEACON_IES, "beacon_ies", DT_IE, 0, NULL }, 694 } 695 }; 696 697 static const uc_nl_nested_spec_t nl80211_sta_info_bitrate_nla = { 698 .headsize = 0, 699 .nattrs = 22, 700 .attrs = { 701 { NL80211_RATE_INFO_BITRATE, "bitrate", DT_U16, 0, NULL }, 702 { NL80211_RATE_INFO_BITRATE32, "bitrate32", DT_U32, 0, NULL }, 703 { NL80211_RATE_INFO_MCS, "mcs", DT_U8, 0, NULL }, 704 { NL80211_RATE_INFO_40_MHZ_WIDTH, "40_mhz_width", DT_FLAG, 0, NULL }, 705 { NL80211_RATE_INFO_SHORT_GI, "short_gi", DT_FLAG, 0, NULL }, 706 { NL80211_RATE_INFO_VHT_MCS, "vht_mcs", DT_U8, 0, NULL }, 707 { NL80211_RATE_INFO_VHT_NSS, "vht_nss", DT_U8, 0, NULL }, 708 { NL80211_RATE_INFO_HE_MCS, "he_mcs", DT_U8, 0, NULL }, 709 { NL80211_RATE_INFO_HE_NSS, "he_nss", DT_U8, 0, NULL }, 710 { NL80211_RATE_INFO_HE_GI, "he_gi", DT_U8, 0, NULL }, 711 { NL80211_RATE_INFO_HE_DCM, "he_dcm", DT_U8, 0, NULL }, 712 { NL80211_RATE_INFO_HE_RU_ALLOC, "he_ru_alloc", DT_U8, 0, NULL }, 713 { NL80211_RATE_INFO_EHT_MCS, "eht_mcs", DT_U8, 0, NULL }, 714 { NL80211_RATE_INFO_EHT_NSS, "eht_nss", DT_U8, 0, NULL }, 715 { NL80211_RATE_INFO_EHT_GI, "eht_gi", DT_U8, 0, NULL }, 716 { NL80211_RATE_INFO_40_MHZ_WIDTH, "width_40", DT_FLAG, 0, NULL }, 717 { NL80211_RATE_INFO_80_MHZ_WIDTH, "width_80", DT_FLAG, 0, NULL }, 718 { NL80211_RATE_INFO_80P80_MHZ_WIDTH, "width_80p80", DT_FLAG, 0, NULL }, 719 { NL80211_RATE_INFO_160_MHZ_WIDTH, "width_160", DT_FLAG, 0, NULL }, 720 { NL80211_RATE_INFO_320_MHZ_WIDTH, "width_320", DT_FLAG, 0, NULL }, 721 { NL80211_RATE_INFO_10_MHZ_WIDTH, "width_10", DT_FLAG, 0, NULL }, 722 { NL80211_RATE_INFO_5_MHZ_WIDTH, "width_5", DT_FLAG, 0, NULL }, 723 } 724 }; 725 726 static const uc_nl_nested_spec_t nl80211_tid_txq_stats_nla = { 727 .headsize = 0, 728 .nattrs = 9, 729 .attrs = { 730 { NL80211_TXQ_STATS_BACKLOG_BYTES, "backlog_bytes", DT_U32, 0, NULL }, 731 { NL80211_TXQ_STATS_BACKLOG_PACKETS, "backlog_packets", DT_U32, 0, NULL }, 732 { NL80211_TXQ_STATS_FLOWS, "flows", DT_U32, 0, NULL }, 733 { NL80211_TXQ_STATS_DROPS, "drops", DT_U32, 0, NULL }, 734 { NL80211_TXQ_STATS_ECN_MARKS, "ecn_marks", DT_U32, 0, NULL }, 735 { NL80211_TXQ_STATS_OVERLIMIT, "overlimit", DT_U32, 0, NULL }, 736 { NL80211_TXQ_STATS_COLLISIONS, "collisions", DT_U32, 0, NULL }, 737 { NL80211_TXQ_STATS_TX_BYTES, "tx_bytes", DT_U32, 0, NULL }, 738 { NL80211_TXQ_STATS_TX_PACKETS, "tx_packets", DT_U32, 0, NULL }, 739 } 740 }; 741 742 static const uc_nl_nested_spec_t nl80211_tid_stats_nla = { 743 .headsize = 0, 744 .nattrs = 5, 745 .attrs = { 746 { NL80211_TID_STATS_RX_MSDU, "rx_msdu", DT_U64, 0, NULL }, 747 { NL80211_TID_STATS_TX_MSDU, "tx_msdu", DT_U64, 0, NULL }, 748 { NL80211_TID_STATS_TX_MSDU_RETRIES, "tx_msdu_retries", DT_U64, 0, NULL }, 749 { NL80211_TID_STATS_TX_MSDU_FAILED, "tx_msdu_failed", DT_U64, 0, NULL }, 750 { NL80211_TID_STATS_TXQ_STATS, "txq_stats", DT_NESTED, 0, &nl80211_tid_txq_stats_nla }, 751 } 752 }; 753 754 static const uc_nl_nested_spec_t nl80211_bss_param_nla = { 755 .headsize = 0, 756 .nattrs = 5, 757 .attrs = { 758 { NL80211_STA_BSS_PARAM_CTS_PROT, "cts_prot", DT_FLAG, 0, NULL }, 759 { NL80211_STA_BSS_PARAM_SHORT_PREAMBLE, "short_preamble", DT_FLAG, 0, NULL }, 760 { NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME, "short_slot_time", DT_FLAG, 0, NULL }, 761 { NL80211_STA_BSS_PARAM_DTIM_PERIOD, "dtim_period", DT_U8, 0, NULL }, 762 { NL80211_STA_BSS_PARAM_BEACON_INTERVAL, "beacon_interval", DT_U16, 0, NULL }, 763 } 764 }; 765 766 static const uc_nl_nested_spec_t nl80211_sta_info_nla = { 767 .headsize = 0, 768 .nattrs = 40, 769 .attrs = { 770 { NL80211_STA_INFO_INACTIVE_TIME, "inactive_time", DT_U32, 0, NULL }, 771 { NL80211_STA_INFO_RX_BYTES, "rx_bytes", DT_U32, 0, NULL }, 772 { NL80211_STA_INFO_TX_BYTES, "tx_bytes", DT_U32, 0, NULL }, 773 { NL80211_STA_INFO_RX_BYTES64, "rx_bytes64", DT_U64, 0, NULL }, 774 { NL80211_STA_INFO_TX_BYTES64, "tx_bytes64", DT_U64, 0, NULL }, 775 { NL80211_STA_INFO_RX_PACKETS, "rx_packets", DT_U32, 0, NULL }, 776 { NL80211_STA_INFO_TX_PACKETS, "tx_packets", DT_U32, 0, NULL }, 777 { NL80211_STA_INFO_BEACON_RX, "beacon_rx", DT_U64, 0, NULL }, 778 { NL80211_STA_INFO_SIGNAL, "signal", DT_S8, 0, NULL }, 779 { NL80211_STA_INFO_T_OFFSET, "t_offset", DT_U64, 0, NULL }, 780 { NL80211_STA_INFO_TX_BITRATE, "tx_bitrate", DT_NESTED, 0, &nl80211_sta_info_bitrate_nla }, 781 { NL80211_STA_INFO_RX_BITRATE, "rx_bitrate", DT_NESTED, 0, &nl80211_sta_info_bitrate_nla }, 782 { NL80211_STA_INFO_LLID, "llid", DT_U16, 0, NULL }, 783 { NL80211_STA_INFO_PLID, "plid", DT_U16, 0, NULL }, 784 { NL80211_STA_INFO_PLINK_STATE, "plink_state", DT_U8, 0, NULL }, 785 { NL80211_STA_INFO_TX_RETRIES, "tx_retries", DT_U32, 0, NULL }, 786 { NL80211_STA_INFO_TX_FAILED, "tx_failed", DT_U32, 0, NULL }, 787 { NL80211_STA_INFO_BEACON_LOSS, "beacon_loss", DT_U32, 0, NULL }, 788 { NL80211_STA_INFO_RX_DROP_MISC, "rx_drop_misc", DT_U64, 0, NULL }, 789 { NL80211_STA_INFO_STA_FLAGS, "sta_flags", DT_U32, DF_ARRAY, NULL }, 790 { NL80211_STA_INFO_LOCAL_PM, "local_pm", DT_U32, 0, NULL }, 791 { NL80211_STA_INFO_PEER_PM, "peer_pm", DT_U32, 0, NULL }, 792 { NL80211_STA_INFO_NONPEER_PM, "nonpeer_pm", DT_U32, 0, NULL }, 793 { NL80211_STA_INFO_CHAIN_SIGNAL, "chain_signal", DT_S8, DF_MULTIPLE|DF_AUTOIDX, NULL }, 794 { NL80211_STA_INFO_CHAIN_SIGNAL_AVG, "chain_signal_avg", DT_S8, DF_MULTIPLE|DF_AUTOIDX, NULL }, 795 { NL80211_STA_INFO_TID_STATS, "tid_stats", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_tid_stats_nla }, 796 { NL80211_STA_INFO_BSS_PARAM, "bss_param", DT_NESTED, 0, &nl80211_bss_param_nla }, 797 { NL80211_STA_INFO_RX_DURATION, "rx_duration", DT_U64, 0, NULL }, 798 { NL80211_STA_INFO_TX_DURATION, "tx_duration", DT_U64, 0, NULL }, 799 { NL80211_STA_INFO_ACK_SIGNAL, "ack_signal", DT_S8, 0, NULL }, 800 { NL80211_STA_INFO_ACK_SIGNAL_AVG, "ack_signal_avg", DT_S8, 0, NULL }, 801 { NL80211_STA_INFO_AIRTIME_LINK_METRIC, "airtime_link_metric", DT_U32, 0, NULL }, 802 { NL80211_STA_INFO_AIRTIME_WEIGHT, "airtime_weight", DT_U16, 0, NULL }, 803 { NL80211_STA_INFO_CONNECTED_TO_AS, "connected_to_as", DT_BOOL, 0, NULL }, 804 { NL80211_STA_INFO_CONNECTED_TO_GATE, "connected_to_gate", DT_BOOL, 0, NULL }, 805 { NL80211_STA_INFO_CONNECTED_TIME, "connected_time", DT_U32, 0, NULL }, 806 { NL80211_STA_INFO_ASSOC_AT_BOOTTIME, "assoc_at_boottime", DT_U64, 0, NULL }, 807 { NL80211_STA_INFO_BEACON_SIGNAL_AVG, "beacon_signal_avg", DT_S8, 0, NULL }, 808 { NL80211_STA_INFO_EXPECTED_THROUGHPUT, "expected_throughput", DT_U32, 0, NULL }, 809 { NL80211_STA_INFO_SIGNAL_AVG, "signal_avg", DT_S8, 0, NULL }, 810 } 811 }; 812 813 static const uc_nl_nested_spec_t nl80211_survey_info_nla = { 814 .headsize = 0, 815 .nattrs = 8, 816 .attrs = { 817 { NL80211_SURVEY_INFO_FREQUENCY, "frequency", DT_U32, 0, NULL }, 818 { NL80211_SURVEY_INFO_TIME, "time", DT_U64, 0, NULL }, 819 { NL80211_SURVEY_INFO_TIME_TX, "time_tx", DT_U64, 0, NULL }, 820 { NL80211_SURVEY_INFO_TIME_RX, "time_rx", DT_U64, 0, NULL }, 821 { NL80211_SURVEY_INFO_TIME_BUSY, "busy", DT_U64, 0, NULL }, 822 { NL80211_SURVEY_INFO_TIME_EXT_BUSY, "ext_busy", DT_U64, 0, NULL }, 823 { NL80211_SURVEY_INFO_TIME_SCAN, "scan", DT_U64, 0, NULL }, 824 { NL80211_SURVEY_INFO_NOISE, "noise", DT_S8, 0, NULL }, 825 } 826 }; 827 828 static const uc_nl_nested_spec_t nl80211_mpath_info_nla = { 829 .headsize = 0, 830 .nattrs = 8, 831 .attrs = { 832 { NL80211_MPATH_INFO_SN, "sn", DT_U32, 0, NULL }, 833 { NL80211_MPATH_INFO_METRIC, "metric", DT_U32, 0, NULL }, 834 { NL80211_MPATH_INFO_EXPTIME, "expire", DT_U32, 0, NULL }, 835 { NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, "discovery_timeout", DT_U32, 0, NULL }, 836 { NL80211_MPATH_INFO_DISCOVERY_RETRIES, "discovery_retries", DT_U8, 0, NULL }, 837 { NL80211_MPATH_INFO_FLAGS, "flags", DT_U8, 0, NULL }, 838 { NL80211_MPATH_INFO_HOP_COUNT, "hop_count", DT_U8, 0, NULL }, 839 { NL80211_MPATH_INFO_PATH_CHANGE, "path_change", DT_U32, 0, NULL }, 840 } 841 }; 842 843 static const uc_nl_nested_spec_t nl80211_radio_freq_range_nla = { 844 .headsize = 0, 845 .nattrs = 2, 846 .attrs = { 847 { NL80211_WIPHY_RADIO_FREQ_ATTR_START, "start", DT_U32, 0, NULL }, 848 { NL80211_WIPHY_RADIO_FREQ_ATTR_END, "end", DT_U32, 0, NULL }, 849 } 850 }; 851 852 static const uc_nl_nested_spec_t nl80211_wiphy_radio_nla = { 853 .headsize = 0, 854 .nattrs = 4, 855 .attrs = { 856 { NL80211_WIPHY_RADIO_ATTR_INDEX, "index", DT_U32, 0, NULL }, 857 { NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE, "freq_ranges", DT_NESTED, DF_REPEATED, &nl80211_radio_freq_range_nla }, 858 { NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION, "interface_combinations", DT_NESTED, DF_REPEATED, &nl80211_ifcomb_nla }, 859 { NL80211_WIPHY_RADIO_ATTR_ANTENNA_MASK, "antenna_mask", DT_U32, 0, NULL }, 860 } 861 }; 862 863 static const uc_nl_nested_spec_t nl80211_msg = { 864 .headsize = 0, 865 .nattrs = 130, 866 .attrs = { 867 { NL80211_ATTR_4ADDR, "4addr", DT_U8, 0, NULL }, 868 { NL80211_ATTR_AIRTIME_WEIGHT, "airtime_weight", DT_U16, 0, NULL }, 869 { NL80211_ATTR_AKM_SUITES, "akm_suites", DT_U32, 0, NULL }, 870 { NL80211_ATTR_AUTH_TYPE, "auth_type", DT_U32, 0, NULL }, 871 { NL80211_ATTR_BANDS, "bands", DT_U32, 0, NULL }, 872 { NL80211_ATTR_BEACON_HEAD, "beacon_head", DT_STRING, DF_BINARY, NULL }, 873 { NL80211_ATTR_BEACON_INTERVAL, "beacon_interval", DT_U32, 0, NULL }, 874 { NL80211_ATTR_BEACON_TAIL, "beacon_tail", DT_STRING, DF_BINARY, NULL }, 875 { NL80211_ATTR_BSS, "bss", DT_NESTED, 0, &nl80211_bss_nla }, 876 { NL80211_ATTR_BSS_BASIC_RATES, "bss_basic_rates", DT_U32, DF_ARRAY, NULL }, 877 { NL80211_ATTR_CENTER_FREQ1, "center_freq1", DT_U32, 0, NULL }, 878 { NL80211_ATTR_CENTER_FREQ2, "center_freq2", DT_U32, 0, NULL }, 879 { NL80211_ATTR_CHANNEL_WIDTH, "channel_width", DT_U32, 0, NULL }, 880 { NL80211_ATTR_CH_SWITCH_BLOCK_TX, "ch_switch_block_tx", DT_FLAG, 0, NULL }, 881 { NL80211_ATTR_CH_SWITCH_COUNT, "ch_switch_count", DT_U32, 0, NULL }, 882 { NL80211_ATTR_CIPHER_SUITES, "cipher_suites", DT_U32, DF_ARRAY, NULL }, 883 { NL80211_ATTR_CIPHER_SUITES_PAIRWISE, "cipher_suites_pairwise", DT_U32, 0, NULL }, 884 { NL80211_ATTR_CIPHER_SUITE_GROUP, "cipher_suite_group", DT_U32, 0, NULL }, 885 { NL80211_ATTR_COALESCE_RULE, "coalesce_rule", DT_NESTED, 0, &nl80211_coalesce_rule_nla }, 886 { NL80211_ATTR_COOKIE, "cookie", DT_U64, 0, NULL }, 887 { NL80211_ATTR_CQM, "cqm", DT_NESTED, 0, &nl80211_cqm_nla }, 888 { NL80211_ATTR_DFS_CAC_TIME, "dfs_cac_time", DT_U32, 0, NULL }, 889 { NL80211_ATTR_DFS_REGION, "dfs_region", DT_U8, 0, NULL }, 890 { NL80211_ATTR_DTIM_PERIOD, "dtim_period", DT_U32, 0, NULL }, 891 { NL80211_ATTR_DURATION, "duration", DT_U32, 0, NULL }, 892 { NL80211_ATTR_EXT_FEATURES, "extended_features", DT_U8, DF_ARRAY, NULL }, 893 { NL80211_ATTR_FEATURE_FLAGS, "feature_flags", DT_U32, 0, NULL }, 894 { NL80211_ATTR_FRAME, "frame", DT_STRING, DF_BINARY, NULL }, 895 { NL80211_ATTR_FRAME_MATCH, "frame_match", DT_STRING, DF_BINARY, NULL }, 896 { NL80211_ATTR_FRAME_TYPE, "frame_type", DT_U16, 0, NULL }, 897 { NL80211_ATTR_FREQ_FIXED, "freq_fixed", DT_FLAG, 0, NULL }, 898 { NL80211_ATTR_FTM_RESPONDER, "ftm_responder", DT_NESTED, 0, &nl80211_ftm_responder_nla }, 899 { NL80211_ATTR_FTM_RESPONDER_STATS, "ftm_responder_stats", DT_NESTED, 0, &nl80211_ftm_responder_stats_nla }, 900 { NL80211_ATTR_HIDDEN_SSID, "hidden_ssid", DT_U32, 0, NULL }, 901 { NL80211_ATTR_HT_CAPABILITY_MASK, "ht_capability_mask", DT_HT_CAP, 0, NULL }, 902 { NL80211_ATTR_IE, "ie", DT_IE, 0, NULL }, 903 { NL80211_ATTR_IFINDEX, "dev", DT_NETDEV, 0, NULL }, 904 { NL80211_ATTR_IFNAME, "ifname", DT_STRING, 0, NULL }, 905 { NL80211_ATTR_IFTYPE, "iftype", DT_U32, 0, NULL }, 906 { NL80211_ATTR_INACTIVITY_TIMEOUT, "inactivity_timeout", DT_U16, 0, NULL }, 907 { NL80211_ATTR_INTERFACE_COMBINATIONS, "interface_combinations", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_ifcomb_nla }, 908 { NL80211_ATTR_KEYS, "keys", DT_NESTED, DF_AUTOIDX, &nl80211_keys_nla }, 909 { NL80211_ATTR_KEY_SEQ, "key_seq", DT_STRING, DF_BINARY, NULL }, 910 { NL80211_ATTR_KEY_TYPE, "key_type", DT_U32, 0, NULL }, 911 { NL80211_ATTR_LOCAL_MESH_POWER_MODE, "local_mesh_power_mode", DT_U32, 0, NULL }, 912 { NL80211_ATTR_MAC, "mac", DT_LLADDR, 0, NULL }, 913 { NL80211_ATTR_MAC_MASK, "mac_mask", DT_LLADDR, 0, NULL }, 914 { NL80211_ATTR_MCAST_RATE, "mcast_rate", DT_U32, 0, NULL }, 915 { NL80211_ATTR_MEASUREMENT_DURATION, "measurement_duration", DT_U16, 0, NULL }, 916 { NL80211_ATTR_MESH_ID, "mesh_id", DT_STRING, 0, NULL }, 917 { NL80211_ATTR_MESH_PARAMS, "mesh_params", DT_NESTED, 0, &nl80211_mesh_params_nla }, 918 { NL80211_ATTR_MESH_SETUP, "mesh_setup", DT_NESTED, 0, &nl80211_mesh_setup_nla }, 919 { NL80211_ATTR_MGMT_SUBTYPE, "mgmt_subtype", DT_U8, 0, NULL }, 920 { NL80211_ATTR_MNTR_FLAGS, "mntr_flags", DT_NESTED, 0, &nl80211_mntr_flags_nla }, 921 { NL80211_ATTR_MPATH_NEXT_HOP, "mpath_next_hop", DT_LLADDR, 0, NULL }, 922 { NL80211_ATTR_MPATH_INFO, "mpath_info", DT_NESTED, 0, &nl80211_mpath_info_nla }, 923 { NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR, "mu_mimo_follow_mac_addr", DT_LLADDR, 0, NULL }, 924 { NL80211_ATTR_NAN_FUNC, "nan_func", DT_NESTED, 0, &nl80211_nan_func_nla }, 925 { NL80211_ATTR_NAN_MASTER_PREF, "nan_master_pref", DT_U8, 0, NULL }, 926 { NL80211_ATTR_NETNS_FD, "netns_fd", DT_U32, 0, NULL }, 927 { NL80211_ATTR_NOACK_MAP, "noack_map", DT_U16, 0, NULL }, 928 { NL80211_ATTR_NSS, "nss", DT_U8, 0, NULL }, 929 { NL80211_ATTR_PEER_MEASUREMENTS, "peer_measurements", DT_NESTED, 0, &nl80211_peer_measurements_nla }, 930 { NL80211_ATTR_PID, "pid", DT_U32, 0, NULL }, 931 { NL80211_ATTR_PMK, "pmk", DT_STRING, DF_BINARY, NULL }, 932 { NL80211_ATTR_PRIVACY, "privacy", DT_FLAG, 0, NULL }, 933 { NL80211_ATTR_PROTOCOL_FEATURES, "protocol_features", DT_U32, 0, NULL }, 934 { NL80211_ATTR_PS_STATE, "ps_state", DT_U32, 0, NULL }, 935 { NL80211_ATTR_RADAR_EVENT, "radar_event", DT_U32, 0, NULL }, 936 { NL80211_ATTR_REASON_CODE, "reason_code", DT_U16, 0, NULL }, 937 { NL80211_ATTR_REG_ALPHA2, "reg_alpha2", DT_STRING, 0, NULL }, 938 { NL80211_ATTR_REG_INITIATOR, "reg_initiator", DT_U32, 0, NULL }, 939 { NL80211_ATTR_REG_RULES, "reg_rules", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_reg_rules_nla }, 940 { NL80211_ATTR_REG_TYPE, "reg_type", DT_U8, 0, NULL }, 941 { NL80211_ATTR_RX_FRAME_TYPES, "rx_frame_types", DT_NESTED, 0, &nl80211_frame_types_nla }, 942 { NL80211_ATTR_RX_SIGNAL_DBM, "rx_signal_dbm", DT_U32, 0, NULL }, 943 { NL80211_ATTR_SCAN_FLAGS, "scan_flags", DT_U32, 0, NULL }, 944 { NL80211_ATTR_SCAN_FREQUENCIES, "scan_frequencies", DT_U32, DF_MULTIPLE|DF_AUTOIDX, NULL }, 945 { NL80211_ATTR_SCAN_SSIDS, "scan_ssids", DT_STRING, DF_MULTIPLE|DF_AUTOIDX, NULL }, 946 { NL80211_ATTR_SCHED_SCAN_DELAY, "sched_scan_delay", DT_U32, 0, NULL }, 947 { NL80211_ATTR_SCHED_SCAN_INTERVAL, "sched_scan_interval", DT_U32, 0, NULL }, 948 { NL80211_ATTR_SCHED_SCAN_MATCH, "sched_scan_match", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_sched_scan_match_nla }, 949 { NL80211_ATTR_SCHED_SCAN_PLANS, "sched_scan_plans", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX|DF_OFFSET1, &nl80211_sched_scan_plan_nla }, 950 { NL80211_ATTR_SMPS_MODE, "smps_mode", DT_U8, 0, NULL }, 951 { NL80211_ATTR_SPLIT_WIPHY_DUMP, "split_wiphy_dump", DT_FLAG, 0, NULL }, 952 { NL80211_ATTR_SSID, "ssid", DT_STRING, DF_BINARY, NULL }, 953 { NL80211_ATTR_STATUS_CODE, "status_code", DT_U16, 0, NULL }, 954 { NL80211_ATTR_STA_INFO, "sta_info", DT_NESTED, 0, &nl80211_sta_info_nla }, 955 { NL80211_ATTR_STA_PLINK_ACTION, "sta_plink_action", DT_U8, 0, NULL }, 956 { NL80211_ATTR_STA_TX_POWER, "sta_tx_power", DT_U16, 0, NULL }, 957 { NL80211_ATTR_STA_TX_POWER_SETTING, "sta_tx_power_setting", DT_U8, 0, NULL }, 958 { NL80211_ATTR_STA_VLAN, "sta_vlan", DT_U32, 0, NULL }, 959 { NL80211_ATTR_SUPPORTED_COMMANDS, "supported_commands", DT_U32, DF_NO_SET|DF_MULTIPLE|DF_AUTOIDX, NULL }, 960 { NL80211_ATTR_TESTDATA, "testdata", DT_NESTED, 0, &nl80211_testdata_nla }, 961 { NL80211_ATTR_TID_CONFIG, "tid_config", DT_NESTED, DF_MULTIPLE, &nl80211_tid_config_nla }, 962 { NL80211_ATTR_TIMEOUT, "timeout", DT_U32, 0, NULL }, 963 { NL80211_ATTR_TXQ_LIMIT, "txq_limit", DT_U32, 0, NULL }, 964 { NL80211_ATTR_TXQ_MEMORY_LIMIT, "txq_memory_limit", DT_U32, 0, NULL }, 965 { NL80211_ATTR_TXQ_QUANTUM, "txq_quantum", DT_U32, 0, NULL }, 966 { NL80211_ATTR_TX_FRAME_TYPES, "tx_frame_types", DT_NESTED, 0, &nl80211_frame_types_nla }, 967 { NL80211_ATTR_USE_MFP, "use_mfp", DT_U32, 0, NULL }, 968 { NL80211_ATTR_VENDOR_DATA, "vendor_data", DT_STRING, DF_BINARY, NULL }, 969 { NL80211_ATTR_VENDOR_ID, "vendor_id", DT_U32, 0, NULL }, 970 { NL80211_ATTR_VENDOR_SUBCMD, "vendor_subcmd", DT_U32, 0, NULL }, 971 { NL80211_ATTR_WDEV, "wdev", DT_U64, 0, NULL }, 972 { NL80211_ATTR_WIPHY, "wiphy", DT_U32, 0, NULL }, 973 { NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, "wiphy_antenna_avail_rx", DT_U32, 0, NULL }, 974 { NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, "wiphy_antenna_avail_tx", DT_U32, 0, NULL }, 975 { NL80211_ATTR_WIPHY_ANTENNA_RX, "wiphy_antenna_rx", DT_U32, 0, NULL }, 976 { NL80211_ATTR_WIPHY_ANTENNA_TX, "wiphy_antenna_tx", DT_U32, 0, NULL }, 977 { NL80211_ATTR_WIPHY_BANDS, "wiphy_bands", DT_NESTED, DF_NO_SET|DF_MULTIPLE|DF_TYPEIDX, &nl80211_wiphy_bands_nla }, 978 { NL80211_ATTR_WIPHY_CHANNEL_TYPE, "wiphy_channel_type", DT_U32, 0, NULL }, 979 { NL80211_ATTR_WIPHY_COVERAGE_CLASS, "wiphy_coverage_class", DT_U8, 0, NULL }, 980 { NL80211_ATTR_WIPHY_DYN_ACK, "wiphy_dyn_ack", DT_FLAG, 0, NULL }, 981 { NL80211_ATTR_WIPHY_FRAG_THRESHOLD, "wiphy_frag_threshold", DT_S32, 0, NULL }, 982 { NL80211_ATTR_WIPHY_FREQ, "wiphy_freq", DT_U32, 0, NULL }, 983 { NL80211_ATTR_WIPHY_NAME, "wiphy_name", DT_STRING, 0, NULL }, 984 { NL80211_ATTR_WIPHY_RETRY_LONG, "wiphy_retry_long", DT_U8, 0, NULL }, 985 { NL80211_ATTR_WIPHY_RETRY_SHORT, "wiphy_retry_short", DT_U8, 0, NULL }, 986 { NL80211_ATTR_WIPHY_RTS_THRESHOLD, "wiphy_rts_threshold", DT_S32, 0, NULL }, 987 { NL80211_ATTR_WIPHY_TX_POWER_LEVEL, "wiphy_tx_power_level", DT_U32, 0, NULL }, 988 { NL80211_ATTR_WIPHY_TX_POWER_SETTING, "wiphy_tx_power_setting", DT_U32, 0, NULL }, 989 { NL80211_ATTR_WOWLAN_TRIGGERS, "wowlan_triggers", DT_NESTED, 0, &nl80211_wowlan_triggers_nla }, 990 { NL80211_ATTR_WPA_VERSIONS, "wpa_versions", DT_U32, 0, NULL }, 991 { NL80211_ATTR_SUPPORTED_IFTYPES, "supported_iftypes", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla }, 992 { NL80211_ATTR_SOFTWARE_IFTYPES, "software_iftypes", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla }, 993 { NL80211_ATTR_MAX_AP_ASSOC_STA, "max_ap_assoc", DT_U16, 0, NULL }, 994 { NL80211_ATTR_SURVEY_INFO, "survey_info", DT_NESTED, 0, &nl80211_survey_info_nla }, 995 { NL80211_ATTR_WIPHY_RADIOS, "radios", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_wiphy_radio_nla }, 996 { NL80211_ATTR_VIF_RADIO_MASK, "vif_radio_mask", DT_U32, 0, NULL }, 997 } 998 }; 999 1000 static const uc_nl_nested_spec_t hwsim_tx_info_struct = { 1001 .headsize = sizeof(struct hwsim_tx_rate), 1002 .nattrs = 2, 1003 .attrs = { 1004 { NLA_UNSPEC, "idx", DT_S8, 0, MEMBER(hwsim_tx_rate, idx) }, 1005 { NLA_UNSPEC, "count", DT_U8, 0, MEMBER(hwsim_tx_rate, count) }, 1006 } 1007 }; 1008 1009 static const uc_nl_nested_spec_t hwsim_tx_info_flags_struct = { 1010 .headsize = sizeof(struct hwsim_tx_rate_flag), 1011 .nattrs = 2, 1012 .attrs = { 1013 { NLA_UNSPEC, "idx", DT_S8, 0, MEMBER(hwsim_tx_rate_flag, idx) }, 1014 { NLA_UNSPEC, "flags", DT_U16, 0, MEMBER(hwsim_tx_rate_flag, flags) }, 1015 } 1016 }; 1017 1018 static const uc_nl_nested_spec_t hwsim_pmsr_support_nla = { 1019 .headsize = 0, 1020 .nattrs = 5, 1021 .attrs = { 1022 { NL80211_PMSR_ATTR_MAX_PEERS, "max_peers", DT_U32, 0, NULL }, 1023 { NL80211_PMSR_ATTR_REPORT_AP_TSF, "report_ap_tsf", DT_FLAG, 0, NULL }, 1024 { NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR, "randomize_mac_addr", DT_FLAG, 0, NULL }, 1025 { NL80211_PMSR_ATTR_TYPE_CAPA, "type_capa", DT_U32, 0, NULL }, 1026 { NL80211_PMSR_ATTR_PEERS, "peers", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_peer_measurements_peers_nla }, 1027 } 1028 }; 1029 1030 static const uc_nl_nested_spec_t hwsim_pmsr_request_nla = { 1031 .headsize = 0, 1032 .nattrs = 1, 1033 .attrs = { 1034 { NL80211_ATTR_PEER_MEASUREMENTS, "peer_measurements", DT_NESTED, 0, &nl80211_peer_measurements_nla }, 1035 } 1036 }; 1037 1038 static const uc_nl_nested_spec_t hwsim_msg = { 1039 .headsize = 0, 1040 .nattrs = 27, 1041 .attrs = { 1042 { HWSIM_ATTR_ADDR_RECEIVER, "addr_receiver", DT_LLADDR, 0, NULL }, 1043 { HWSIM_ATTR_ADDR_TRANSMITTER, "addr_transmitter", DT_LLADDR, 0, NULL }, 1044 { HWSIM_ATTR_FRAME, "frame", DT_STRING, DF_BINARY, NULL }, 1045 { HWSIM_ATTR_FLAGS, "flags", DT_U32, 0, NULL }, 1046 { HWSIM_ATTR_RX_RATE, "rx_rate", DT_U32, 0, NULL }, 1047 { HWSIM_ATTR_SIGNAL, "signal", DT_U32, 0, NULL }, 1048 { HWSIM_ATTR_TX_INFO, "tx_info", DT_NESTED, DF_ARRAY, &hwsim_tx_info_struct }, 1049 { HWSIM_ATTR_COOKIE, "cookie", DT_U64, 0, NULL }, 1050 { HWSIM_ATTR_CHANNELS, "channels", DT_U32, 0, NULL }, 1051 { HWSIM_ATTR_RADIO_ID, "radio_id", DT_U32, 0, NULL }, 1052 { HWSIM_ATTR_REG_HINT_ALPHA2, "reg_hint_alpha2", DT_STRING, DF_BINARY, NULL }, 1053 { HWSIM_ATTR_REG_CUSTOM_REG, "reg_custom_reg", DT_U32, 0, NULL }, 1054 { HWSIM_ATTR_REG_STRICT_REG, "reg_strict_reg", DT_FLAG, 0, NULL }, 1055 { HWSIM_ATTR_SUPPORT_P2P_DEVICE, "support_p2p_device", DT_FLAG, 0, NULL }, 1056 { HWSIM_ATTR_USE_CHANCTX, "use_chanctx", DT_FLAG, 0, NULL }, 1057 { HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE, "destroy_radio_on_close", DT_FLAG, 0, NULL }, 1058 { HWSIM_ATTR_RADIO_NAME, "radio_name", DT_STRING, DF_BINARY, NULL }, 1059 { HWSIM_ATTR_NO_VIF, "no_vif", DT_FLAG, 0, NULL }, 1060 { HWSIM_ATTR_FREQ, "freq", DT_U32, 0, NULL }, 1061 { HWSIM_ATTR_TX_INFO_FLAGS, "tx_info_flags", DT_NESTED, DF_ARRAY, &hwsim_tx_info_flags_struct }, 1062 { HWSIM_ATTR_PERM_ADDR, "perm_addr", DT_LLADDR, 0, NULL }, 1063 { HWSIM_ATTR_IFTYPE_SUPPORT, "iftype_support", DT_U32, 0, NULL }, 1064 { HWSIM_ATTR_CIPHER_SUPPORT, "cipher_support", DT_U32, DF_ARRAY, NULL }, 1065 { HWSIM_ATTR_MLO_SUPPORT, "mlo_support", DT_FLAG, 0, NULL }, 1066 { HWSIM_ATTR_PMSR_SUPPORT, "pmsr_support", DT_NESTED, 0, &hwsim_pmsr_support_nla }, 1067 { HWSIM_ATTR_PMSR_REQUEST, "pmsr_request", DT_NESTED, 0, &hwsim_pmsr_request_nla }, 1068 { HWSIM_ATTR_PMSR_RESULT, "pmsr_result", DT_NESTED, 0, &hwsim_pmsr_support_nla }, 1069 } 1070 }; 1071 1072 1073 static bool 1074 nla_check_len(struct nlattr *nla, size_t sz) 1075 { 1076 return (nla && nla_len(nla) >= (ssize_t)sz); 1077 } 1078 1079 static bool 1080 nla_parse_error(const uc_nl_attr_spec_t *spec, uc_vm_t *vm, uc_value_t *v, const char *msg) 1081 { 1082 char *s; 1083 1084 s = ucv_to_string(vm, v); 1085 1086 set_error(NLE_INVAL, "%s `%s` has invalid value `%s`: %s", 1087 spec->attr ? "attribute" : "field", 1088 spec->key, 1089 s, 1090 msg); 1091 1092 free(s); 1093 1094 return false; 1095 } 1096 1097 static void 1098 uc_nl_put_struct_member(char *base, const void *offset, size_t datalen, void *data) 1099 { 1100 memcpy(base + (uintptr_t)offset, data, datalen); 1101 } 1102 1103 static void 1104 uc_nl_put_struct_member_u8(char *base, const void *offset, uint8_t u8) 1105 { 1106 base[(uintptr_t)offset] = u8; 1107 } 1108 1109 static void 1110 uc_nl_put_struct_member_u32(char *base, const void *offset, uint32_t u32) 1111 { 1112 uc_nl_put_struct_member(base, offset, sizeof(u32), &u32); 1113 } 1114 1115 static void * 1116 uc_nl_get_struct_member(char *base, const void *offset, size_t datalen, void *data) 1117 { 1118 memcpy(data, base + (uintptr_t)offset, datalen); 1119 1120 return data; 1121 } 1122 1123 static uint8_t 1124 uc_nl_get_struct_member_u8(char *base, const void *offset) 1125 { 1126 return (uint8_t)base[(uintptr_t)offset]; 1127 } 1128 1129 static uint32_t 1130 uc_nl_get_struct_member_u32(char *base, const void *offset) 1131 { 1132 uint32_t u32; 1133 1134 uc_nl_get_struct_member(base, offset, sizeof(u32), &u32); 1135 1136 return u32; 1137 } 1138 1139 static bool 1140 uc_nl_parse_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val, size_t idx); 1141 1142 static uc_value_t * 1143 uc_nl_convert_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, struct nlattr *attr, struct nlattr *attr2, uc_vm_t *vm); 1144 1145 static bool 1146 uc_nl_convert_attrs(struct nl_msg *msg, void *buf, size_t buflen, size_t headsize, const uc_nl_attr_spec_t *attrs, size_t nattrs, uc_vm_t *vm, uc_value_t *obj) 1147 { 1148 struct nlattr **tb, *nla, *nla2, *nla_nest; 1149 size_t i, type, maxattr = 0; 1150 uc_value_t *v, *arr; 1151 int rem; 1152 1153 for (i = 0; i < nattrs; i++) 1154 if (attrs[i].attr > maxattr) 1155 maxattr = attrs[i].attr; 1156 1157 tb = calloc(maxattr + 1, sizeof(struct nlattr *)); 1158 1159 if (!tb) 1160 return false; 1161 1162 nla_for_each_attr(nla, buf + headsize, buflen - headsize, rem) { 1163 type = nla_type(nla); 1164 1165 if (type <= maxattr && !tb[type]) 1166 tb[type] = nla; 1167 } 1168 1169 for (i = 0; i < nattrs; i++) { 1170 if (attrs[i].attr != 0 && !tb[attrs[i].attr]) 1171 continue; 1172 1173 if (attrs[i].flags & DF_REPEATED) { 1174 arr = ucv_array_new(vm); 1175 1176 nla = tb[attrs[i].attr]; 1177 rem = buflen - ((void *)nla - buf); 1178 for (; nla_ok(nla, rem); nla = nla_next(nla, &rem)) { 1179 if (nla_type(nla) != (int)attrs[i].attr) 1180 break; 1181 v = uc_nl_convert_attr(&attrs[i], msg, (char *)buf, nla, NULL, vm); 1182 if (!v) 1183 continue; 1184 1185 ucv_array_push(arr, v); 1186 } 1187 if (!ucv_array_length(arr)) { 1188 ucv_put(arr); 1189 continue; 1190 } 1191 1192 v = arr; 1193 } 1194 else if (attrs[i].flags & DF_MULTIPLE) { 1195 arr = ucv_array_new(vm); 1196 nla_nest = tb[attrs[i].attr]; 1197 1198 nla_for_each_attr(nla, nla_data(nla_nest), nla_len(nla_nest), rem) { 1199 if (!(attrs[i].flags & (DF_AUTOIDX|DF_TYPEIDX)) && 1200 attrs[i].auxdata && nla_type(nla) != (intptr_t)attrs[i].auxdata) 1201 continue; 1202 1203 v = uc_nl_convert_attr(&attrs[i], msg, (char *)buf, nla, NULL, vm); 1204 1205 if (!v) 1206 continue; 1207 1208 if (attrs[i].flags & DF_TYPEIDX) 1209 ucv_array_set(arr, nla_type(nla) - !!(attrs[i].flags & DF_OFFSET1), v); 1210 else 1211 ucv_array_push(arr, v); 1212 } 1213 1214 if (!ucv_array_length(arr)) { 1215 ucv_put(arr); 1216 1217 continue; 1218 } 1219 1220 v = arr; 1221 } 1222 else { 1223 if (attrs[i].flags & DF_RELATED) 1224 nla2 = tb[(uintptr_t)attrs[i].auxdata]; 1225 else 1226 nla2 = NULL; 1227 1228 v = uc_nl_convert_attr(&attrs[i], msg, (char *)buf, tb[attrs[i].attr], nla2, vm); 1229 1230 if (!v) 1231 continue; 1232 } 1233 1234 ucv_object_add(obj, attrs[i].key, v); 1235 } 1236 1237 free(tb); 1238 1239 return true; 1240 } 1241 1242 static bool 1243 uc_nl_parse_attrs(struct nl_msg *msg, char *base, const uc_nl_attr_spec_t *attrs, size_t nattrs, uc_vm_t *vm, uc_value_t *obj) 1244 { 1245 struct nlattr *nla_nest = NULL; 1246 uc_value_t *v, *item; 1247 size_t i, j, idx; 1248 bool exists; 1249 1250 for (i = 0; i < nattrs; i++) { 1251 if (attrs[i].attr == NL80211_ATTR_NOT_IMPLEMENTED) 1252 continue; 1253 1254 v = ucv_object_get(obj, attrs[i].key, &exists); 1255 1256 if (!exists) 1257 continue; 1258 1259 if (attrs[i].flags & DF_MULTIPLE) { 1260 nla_nest = nla_nest_start(msg, attrs[i].attr); 1261 1262 if (ucv_type(v) == UC_ARRAY) { 1263 for (j = 0; j < ucv_array_length(v); j++) { 1264 item = ucv_array_get(v, j); 1265 1266 if (!item && (attrs[i].flags & DF_TYPEIDX)) 1267 continue; 1268 1269 if (!attrs[i].auxdata || (attrs[i].flags & (DF_AUTOIDX|DF_TYPEIDX))) 1270 idx = j + !!(attrs[i].flags & DF_OFFSET1); 1271 else 1272 idx = (uintptr_t)attrs[i].auxdata; 1273 1274 if (!uc_nl_parse_attr(&attrs[i], msg, base, vm, item, idx)) 1275 return false; 1276 } 1277 } 1278 else { 1279 if (!attrs[i].auxdata || (attrs[i].flags & (DF_AUTOIDX|DF_TYPEIDX))) 1280 idx = !!(attrs[i].flags & DF_OFFSET1); 1281 else 1282 idx = (uintptr_t)attrs[i].auxdata; 1283 1284 if (!uc_nl_parse_attr(&attrs[i], msg, base, vm, v, idx)) 1285 return false; 1286 } 1287 1288 nla_nest_end(msg, nla_nest); 1289 } 1290 else if (!uc_nl_parse_attr(&attrs[i], msg, base, vm, v, 0)) { 1291 return false; 1292 } 1293 } 1294 1295 return true; 1296 } 1297 1298 static bool 1299 uc_nl_parse_rta_nested(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val) 1300 { 1301 const uc_nl_nested_spec_t *nest = spec->auxdata; 1302 struct nlattr *nested_nla; 1303 1304 if (!nest) 1305 return false; 1306 1307 nested_nla = nla_reserve(msg, spec->attr, nest->headsize); 1308 1309 if (!uc_nl_parse_attrs(msg, nla_data(nested_nla), nest->attrs, nest->nattrs, vm, val)) 1310 return false; 1311 1312 nla_nest_end(msg, nested_nla); 1313 1314 return true; 1315 } 1316 1317 static uc_value_t * 1318 uc_nl_convert_rta_nested(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr *attr, uc_vm_t *vm) 1319 { 1320 const uc_nl_nested_spec_t *nest = spec->auxdata; 1321 uc_value_t *nested_obj; 1322 bool rv; 1323 1324 if (!nest) 1325 return NULL; 1326 1327 if (!nla_check_len(attr, nest->headsize)) 1328 return NULL; 1329 1330 nested_obj = ucv_object_new(vm); 1331 1332 rv = uc_nl_convert_attrs(msg, 1333 nla_data(attr), nla_len(attr), nest->headsize, 1334 nest->attrs, nest->nattrs, 1335 vm, nested_obj); 1336 1337 if (!rv) { 1338 ucv_put(nested_obj); 1339 1340 return NULL; 1341 } 1342 1343 return nested_obj; 1344 } 1345 1346 static uc_value_t * 1347 uc_nl_convert_rta_ht_mcs(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr *attr, uc_vm_t *vm) 1348 { 1349 uc_value_t *mcs_obj, *mcs_idx; 1350 uint16_t max_rate = 0; 1351 uint8_t *mcs; 1352 size_t i; 1353 1354 if (!nla_check_len(attr, 16)) 1355 return NULL; 1356 1357 mcs = nla_data(attr); 1358 mcs_obj = ucv_object_new(vm); 1359 1360 max_rate = (mcs[10] | ((mcs[11] & 0x3) << 8)); 1361 1362 if (max_rate) 1363 ucv_object_add(mcs_obj, "rx_highest_data_rate", ucv_uint64_new(max_rate)); 1364 1365 mcs_idx = ucv_array_new(vm); 1366 1367 for (i = 0; i <= 76; i++) 1368 if (mcs[i / 8] & (1 << (i % 8))) 1369 ucv_array_push(mcs_idx, ucv_uint64_new(i)); 1370 1371 ucv_object_add(mcs_obj, "rx_mcs_indexes", mcs_idx); 1372 1373 ucv_object_add(mcs_obj, "tx_mcs_set_defined", ucv_boolean_new(mcs[12] & (1 << 0))); 1374 ucv_object_add(mcs_obj, "tx_rx_mcs_set_equal", ucv_boolean_new(!(mcs[12] & (1 << 1)))); 1375 ucv_object_add(mcs_obj, "tx_max_spatial_streams", ucv_uint64_new(((mcs[12] >> 2) & 3) + 1)); 1376 ucv_object_add(mcs_obj, "tx_unequal_modulation", ucv_boolean_new(mcs[12] & (1 << 4))); 1377 1378 return mcs_obj; 1379 } 1380 1381 static uc_value_t * 1382 uc_nl_convert_rta_ht_cap(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr *attr, uc_vm_t *vm) 1383 { 1384 uc_value_t *cap_obj, *mcs_obj, *rx_mask; 1385 struct ieee80211_ht_cap *cap; 1386 size_t i; 1387 1388 if (!nla_check_len(attr, sizeof(*cap))) 1389 return NULL; 1390 1391 cap = nla_data(attr); 1392 cap_obj = ucv_object_new(vm); 1393 1394 ucv_object_add(cap_obj, "cap_info", ucv_uint64_new(le16toh(cap->cap_info))); 1395 ucv_object_add(cap_obj, "ampdu_params_info", ucv_uint64_new(cap->ampdu_params_info)); 1396 ucv_object_add(cap_obj, "extended_ht_cap_info", ucv_uint64_new(le16toh(cap->extended_ht_cap_info))); 1397 ucv_object_add(cap_obj, "tx_BF_cap_info", ucv_uint64_new(le32toh(cap->tx_BF_cap_info))); 1398 ucv_object_add(cap_obj, "antenna_selection_info", ucv_uint64_new(cap->antenna_selection_info)); 1399 1400 mcs_obj = ucv_object_new(vm); 1401 rx_mask = ucv_array_new_length(vm, sizeof(cap->mcs.rx_mask)); 1402 1403 for (i = 0; i < sizeof(cap->mcs.rx_mask); i++) 1404 ucv_array_push(rx_mask, ucv_uint64_new(cap->mcs.rx_mask[i])); 1405 1406 ucv_object_add(mcs_obj, "rx_mask", rx_mask); 1407 ucv_object_add(mcs_obj, "rx_highest", ucv_uint64_new(le16toh(cap->mcs.rx_highest))); 1408 ucv_object_add(mcs_obj, "tx_params", ucv_uint64_new(cap->mcs.tx_params)); 1409 1410 ucv_object_add(cap_obj, "mcs", mcs_obj); 1411 1412 return cap_obj; 1413 } 1414 1415 static uc_value_t * 1416 uc_nl_convert_rta_vht_mcs(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr *attr, uc_vm_t *vm) 1417 { 1418 uc_value_t *mcs_obj, *mcs_set, *mcs_entry, *mcs_idx; 1419 size_t i, j, max_idx; 1420 uint16_t u16; 1421 uint8_t *mcs; 1422 1423 if (!nla_check_len(attr, 8)) 1424 return NULL; 1425 1426 mcs = nla_data(attr); 1427 mcs_obj = ucv_object_new(vm); 1428 1429 u16 = mcs[0] | (mcs[1] << 8); 1430 mcs_set = ucv_array_new(vm); 1431 1432 for (i = 1; i <= 8; i++) { 1433 switch ((u16 >> ((i - 1) * 2)) & 3) { 1434 case 0: max_idx = 7; break; 1435 case 1: max_idx = 8; break; 1436 case 2: max_idx = 9; break; 1437 default: continue; 1438 } 1439 1440 mcs_idx = ucv_array_new_length(vm, max_idx + 1); 1441 1442 for (j = 0; j <= max_idx; j++) 1443 ucv_array_push(mcs_idx, ucv_uint64_new(j)); 1444 1445 mcs_entry = ucv_object_new(vm); 1446 1447 ucv_object_add(mcs_entry, "streams", ucv_uint64_new(i)); 1448 ucv_object_add(mcs_entry, "mcs_indexes", mcs_idx); 1449 1450 ucv_array_push(mcs_set, mcs_entry); 1451 } 1452 1453 ucv_object_add(mcs_obj, "rx_mcs_set", mcs_set); 1454 ucv_object_add(mcs_obj, "rx_highest_data_rate", ucv_uint64_new((mcs[2] | (mcs[3] << 8)) & 0x1fff)); 1455 1456 u16 = mcs[4] | (mcs[5] << 8); 1457 mcs_set = ucv_array_new(vm); 1458 1459 for (i = 1; i <= 8; i++) { 1460 switch ((u16 >> ((i - 1) * 2)) & 3) { 1461 case 0: max_idx = 7; break; 1462 case 1: max_idx = 8; break; 1463 case 2: max_idx = 9; break; 1464 default: continue; 1465 } 1466 1467 mcs_idx = ucv_array_new_length(vm, max_idx + 1); 1468 1469 for (j = 0; j <= max_idx; j++) 1470 ucv_array_push(mcs_idx, ucv_uint64_new(j)); 1471 1472 mcs_entry = ucv_object_new(vm); 1473 1474 ucv_object_add(mcs_entry, "streams", ucv_uint64_new(i)); 1475 ucv_object_add(mcs_entry, "mcs_indexes", mcs_idx); 1476 1477 ucv_array_push(mcs_set, mcs_entry); 1478 } 1479 1480 ucv_object_add(mcs_obj, "tx_mcs_set", mcs_set); 1481 ucv_object_add(mcs_obj, "tx_highest_data_rate", ucv_uint64_new((mcs[6] | (mcs[7] << 8)) & 0x1fff)); 1482 1483 return mcs_obj; 1484 } 1485 1486 static uc_value_t * 1487 uc_nl_convert_rta_he_mcs(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr *attr, struct nlattr *phy_attr, uc_vm_t *vm) 1488 { 1489 uint8_t bw_support_mask[] = { (1 << 1) | (1 << 2), (1 << 3), (1 << 4) }; 1490 uc_value_t *mcs_set, *mcs_bw, *mcs_dir, *mcs_entry, *mcs_idx; 1491 uint16_t bw[] = { 80, 160, 8080 }, mcs[6]; 1492 uint16_t u16, phy_cap_0 = 0; 1493 size_t i, j, k, l, max_idx; 1494 1495 if (!nla_check_len(attr, sizeof(mcs))) 1496 return NULL; 1497 1498 if (nla_check_len(phy_attr, sizeof(phy_cap_0))) 1499 phy_cap_0 = nla_get_u16(phy_attr); 1500 1501 memcpy(mcs, nla_data(attr), sizeof(mcs)); 1502 1503 mcs_set = ucv_array_new_length(vm, 3); 1504 1505 for (i = 0; i < ARRAY_SIZE(bw); i++) { 1506 if (!(phy_cap_0 & (bw_support_mask[i] << 8))) 1507 continue; 1508 1509 mcs_bw = ucv_object_new(vm); 1510 1511 for (j = 0; j < 2; j++) { 1512 mcs_dir = ucv_array_new_length(vm, 8); 1513 1514 for (k = 0; k < 8; k++) { 1515 u16 = mcs[(i * 2) + j]; 1516 u16 >>= k * 2; 1517 u16 &= 0x3; 1518 1519 switch (u16) { 1520 case 0: max_idx = 7; break; 1521 case 1: max_idx = 9; break; 1522 case 2: max_idx = 11; break; 1523 case 3: continue; 1524 } 1525 1526 mcs_idx = ucv_array_new_length(vm, max_idx + 1); 1527 1528 for (l = 0; l <= max_idx; l++) 1529 ucv_array_push(mcs_idx, ucv_uint64_new(l)); 1530 1531 mcs_entry = ucv_object_new(vm); 1532 1533 ucv_object_add(mcs_entry, "streams", ucv_uint64_new(k + 1)); 1534 ucv_object_add(mcs_entry, "mcs_indexes", mcs_idx); 1535 1536 ucv_array_push(mcs_dir, mcs_entry); 1537 } 1538 1539 if (ucv_array_length(mcs_dir)) 1540 ucv_object_add(mcs_bw, j ? "tx_mcs_set" : "rx_mcs_set", mcs_dir); 1541 else 1542 ucv_put(mcs_dir); 1543 } 1544 1545 if (ucv_object_length(mcs_bw)) { 1546 ucv_object_add(mcs_bw, "bandwidth", ucv_uint64_new(bw[i])); 1547 ucv_array_push(mcs_set, mcs_bw); 1548 } 1549 else { 1550 ucv_put(mcs_bw); 1551 } 1552 } 1553 1554 return mcs_set; 1555 } 1556 1557 static uc_value_t * 1558 uc_nl_convert_rta_ie(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr *attr, uc_vm_t *vm) 1559 { 1560 uc_value_t *ie_arr, *ie_obj; 1561 uint8_t *ie; 1562 size_t len; 1563 1564 len = nla_len(attr); 1565 ie = nla_data(attr); 1566 1567 if (len < 2) 1568 return NULL; 1569 1570 ie_arr = ucv_array_new(vm); 1571 1572 while (len >= 2 && len - 2 >= ie[1]) { 1573 ie_obj = ucv_object_new(vm); 1574 1575 ucv_object_add(ie_obj, "type", ucv_uint64_new(ie[0])); 1576 ucv_object_add(ie_obj, "data", ucv_string_new_length((char *)&ie[2], ie[1])); 1577 1578 ucv_array_push(ie_arr, ie_obj); 1579 1580 len -= ie[1] + 2; 1581 ie += ie[1] + 2; 1582 } 1583 1584 return ie_arr; 1585 } 1586 1587 1588 static bool 1589 uc_nl_parse_numval(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val, void *dst) 1590 { 1591 uint64_t u64; 1592 uint32_t u32; 1593 uint16_t u16; 1594 uint8_t u8; 1595 1596 switch (spec->type) { 1597 case DT_U8: 1598 if (!uc_nl_parse_u32(val, &u32) || u32 > 255) 1599 return nla_parse_error(spec, vm, val, "not an integer or out of range 0-255"); 1600 1601 u8 = (uint8_t)u32; 1602 1603 memcpy(dst, &u8, sizeof(u8)); 1604 break; 1605 1606 case DT_U16: 1607 if (!uc_nl_parse_u32(val, &u32) || u32 > 65535) 1608 return nla_parse_error(spec, vm, val, "not an integer or out of range 0-65535"); 1609 1610 u16 = (uint16_t)u32; 1611 1612 memcpy(dst, &u16, sizeof(u16)); 1613 break; 1614 1615 case DT_S32: 1616 case DT_U32: 1617 if (spec->type == DT_S32 && !uc_nl_parse_s32(val, &u32)) 1618 return nla_parse_error(spec, vm, val, "not an integer or out of range -2147483648-2147483647"); 1619 else if (spec->type == DT_U32 && !uc_nl_parse_u32(val, &u32)) 1620 return nla_parse_error(spec, vm, val, "not an integer or out of range 0-4294967295"); 1621 1622 memcpy(dst, &u32, sizeof(u32)); 1623 break; 1624 1625 case DT_U64: 1626 if (!uc_nl_parse_u64(val, &u64)) 1627 return nla_parse_error(spec, vm, val, "not an integer or negative"); 1628 1629 memcpy(dst, &u64, sizeof(u64)); 1630 break; 1631 1632 default: 1633 return false; 1634 } 1635 1636 return true; 1637 } 1638 1639 static const uint8_t dt_sizes[] = { 1640 [DT_U8] = sizeof(uint8_t), 1641 [DT_S8] = sizeof(int8_t), 1642 [DT_U16] = sizeof(uint16_t), 1643 [DT_U32] = sizeof(uint32_t), 1644 [DT_S32] = sizeof(int32_t), 1645 [DT_U64] = sizeof(uint64_t), 1646 }; 1647 1648 static bool 1649 uc_nl_parse_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, uc_vm_t *vm, uc_value_t *val, size_t idx) 1650 { 1651 char buf[sizeof(uint64_t)]; 1652 struct in_addr in = { 0 }; 1653 struct ether_addr *ea; 1654 struct nlattr *nla; 1655 uc_value_t *item; 1656 size_t attr, i; 1657 uint32_t u32; 1658 char *s; 1659 1660 if (spec->flags & DF_MULTIPLE) 1661 attr = idx; 1662 else 1663 attr = spec->attr; 1664 1665 switch (spec->type) { 1666 case DT_U8: 1667 case DT_U16: 1668 case DT_U32: 1669 case DT_S32: 1670 case DT_U64: 1671 if (spec->flags & DF_ARRAY) { 1672 assert(spec->attr != 0); 1673 1674 if (ucv_type(val) != UC_ARRAY) 1675 return nla_parse_error(spec, vm, val, "not an array"); 1676 1677 nla = nla_reserve(msg, spec->attr, ucv_array_length(val) * dt_sizes[spec->type]); 1678 s = nla_data(nla); 1679 1680 for (i = 0; i < ucv_array_length(val); i++) { 1681 item = ucv_array_get(val, i); 1682 1683 if (!uc_nl_parse_numval(spec, msg, base, vm, item, buf)) 1684 return false; 1685 1686 memcpy(s, buf, dt_sizes[spec->type]); 1687 1688 s += dt_sizes[spec->type]; 1689 } 1690 } 1691 else { 1692 if (!uc_nl_parse_numval(spec, msg, base, vm, val, buf)) 1693 return false; 1694 1695 if (spec->attr == 0) 1696 uc_nl_put_struct_member(base, spec->auxdata, dt_sizes[spec->type], buf); 1697 else 1698 nla_put(msg, attr, dt_sizes[spec->type], buf); 1699 } 1700 1701 break; 1702 1703 case DT_BOOL: 1704 u32 = (uint32_t)ucv_is_truish(val); 1705 1706 if (spec->attr == 0) 1707 uc_nl_put_struct_member_u8(base, spec->auxdata, u32); 1708 else 1709 nla_put_u8(msg, attr, u32); 1710 1711 break; 1712 1713 case DT_FLAG: 1714 u32 = (uint32_t)ucv_is_truish(val); 1715 1716 if (spec->attr == 0) 1717 uc_nl_put_struct_member_u8(base, spec->auxdata, u32); 1718 else if (u32 == 1) 1719 nla_put_flag(msg, attr); 1720 1721 break; 1722 1723 case DT_STRING: 1724 assert(spec->attr != 0); 1725 1726 s = ucv_to_string(vm, val); 1727 1728 if (!s) 1729 return nla_parse_error(spec, vm, val, "out of memory"); 1730 1731 nla_put_string(msg, attr, s); 1732 free(s); 1733 1734 break; 1735 1736 case DT_NETDEV: 1737 if (ucv_type(val) == UC_INTEGER) { 1738 if (ucv_int64_get(val) < 0 || 1739 ucv_int64_get(val) > UINT32_MAX) 1740 return nla_parse_error(spec, vm, val, "interface index out of range 0-4294967295"); 1741 1742 u32 = (uint32_t)ucv_int64_get(val); 1743 } 1744 else { 1745 s = ucv_to_string(vm, val); 1746 1747 if (!s) 1748 return nla_parse_error(spec, vm, val, "out of memory"); 1749 1750 u32 = if_nametoindex(s); 1751 1752 free(s); 1753 } 1754 1755 if (spec->attr == 0) 1756 uc_nl_put_struct_member_u32(base, spec->auxdata, u32); 1757 else 1758 nla_put_u32(msg, attr, u32); 1759 1760 break; 1761 1762 case DT_LLADDR: 1763 assert(spec->attr != 0); 1764 1765 s = ucv_to_string(vm, val); 1766 1767 if (!s) 1768 return nla_parse_error(spec, vm, val, "out of memory"); 1769 1770 ea = ether_aton(s); 1771 1772 free(s); 1773 1774 if (!ea) 1775 return nla_parse_error(spec, vm, val, "invalid MAC address"); 1776 1777 nla_put(msg, attr, sizeof(*ea), ea); 1778 1779 break; 1780 1781 case DT_INADDR: 1782 assert(spec->attr != 0); 1783 1784 if (!uc_nl_parse_ipaddr(vm, val, &in)) 1785 return nla_parse_error(spec, vm, val, "invalid IP address"); 1786 1787 nla_put(msg, attr, sizeof(in), &in); 1788 1789 break; 1790 1791 case DT_NESTED: 1792 if (spec->flags & DF_ARRAY) { 1793 const uc_nl_nested_spec_t *nested = spec->auxdata; 1794 1795 assert(nested != NULL); 1796 assert(nested->headsize > 0); 1797 1798 if (ucv_type(val) != UC_ARRAY) 1799 return nla_parse_error(spec, vm, val, "not an array"); 1800 1801 nla = nla_reserve(msg, spec->attr, ucv_array_length(val) * nested->headsize); 1802 s = nla_data(nla); 1803 1804 for (i = 0; i < ucv_array_length(val); i++) { 1805 item = ucv_array_get(val, i); 1806 1807 if (!uc_nl_parse_attrs(msg, s, nested->attrs, nested->nattrs, vm, item)) 1808 return false; 1809 1810 s += nested->headsize; 1811 } 1812 1813 return true; 1814 } 1815 1816 if (!uc_nl_parse_rta_nested(spec, msg, base, vm, val)) 1817 return false; 1818 1819 break; 1820 1821 default: 1822 assert(0); 1823 } 1824 1825 return true; 1826 } 1827 1828 static uc_value_t * 1829 uc_nl_convert_numval(const uc_nl_attr_spec_t *spec, char *base) 1830 { 1831 union { uint8_t *u8; uint16_t *u16; uint32_t *u32; uint64_t *u64; char *base; } t = { .base = base }; 1832 1833 switch (spec->type) { 1834 case DT_U8: 1835 return ucv_uint64_new(t.u8[0]); 1836 1837 case DT_S8: 1838 return ucv_int64_new((int8_t)t.u8[0]); 1839 1840 case DT_U16: 1841 return ucv_uint64_new(t.u16[0]); 1842 1843 case DT_U32: 1844 return ucv_uint64_new(t.u32[0]); 1845 1846 case DT_S32: 1847 return ucv_int64_new((int32_t)t.u32[0]); 1848 1849 case DT_U64: 1850 return ucv_uint64_new(t.u64[0]); 1851 1852 default: 1853 return NULL; 1854 } 1855 } 1856 1857 static uc_value_t * 1858 uc_nl_convert_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, struct nlattr *attr, struct nlattr *attr2, uc_vm_t *vm) 1859 { 1860 union { uint8_t u8; uint16_t u16; uint32_t u32; uint64_t u64; size_t sz; } t = { 0 }; 1861 char buf[sizeof("FF:FF:FF:FF:FF:FF")]; 1862 struct ether_addr *ea; 1863 uc_value_t *v; 1864 int i; 1865 1866 switch (spec->type) { 1867 case DT_U8: 1868 case DT_S8: 1869 case DT_U16: 1870 case DT_U32: 1871 case DT_S32: 1872 case DT_U64: 1873 if (spec->flags & DF_ARRAY) { 1874 assert(spec->attr != 0); 1875 assert((nla_len(attr) % dt_sizes[spec->type]) == 0); 1876 1877 v = ucv_array_new_length(vm, nla_len(attr) / dt_sizes[spec->type]); 1878 1879 for (i = 0; i < nla_len(attr); i += dt_sizes[spec->type]) 1880 ucv_array_push(v, uc_nl_convert_numval(spec, nla_data(attr) + i)); 1881 1882 return v; 1883 } 1884 else if (nla_check_len(attr, dt_sizes[spec->type])) { 1885 return uc_nl_convert_numval(spec, nla_data(attr)); 1886 } 1887 1888 return NULL; 1889 1890 case DT_BOOL: 1891 if (spec->attr == 0) 1892 t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata); 1893 else if (nla_check_len(attr, sizeof(t.u8))) 1894 t.u8 = nla_get_u8(attr); 1895 1896 return ucv_boolean_new(t.u8 != 0); 1897 1898 case DT_FLAG: 1899 if (spec->attr == 0) 1900 t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata); 1901 else if (attr != NULL) 1902 t.u8 = 1; 1903 1904 return ucv_boolean_new(t.u8 != 0); 1905 1906 case DT_STRING: 1907 assert(spec->attr != 0); 1908 1909 if (!nla_check_len(attr, 1)) 1910 return NULL; 1911 1912 t.sz = nla_len(attr); 1913 1914 if (!(spec->flags & DF_BINARY)) 1915 t.sz -= 1; 1916 1917 return ucv_string_new_length(nla_data(attr), t.sz); 1918 1919 case DT_NETDEV: 1920 if (spec->attr == 0) 1921 t.u32 = uc_nl_get_struct_member_u32(base, spec->auxdata); 1922 else if (nla_check_len(attr, sizeof(t.u32))) 1923 t.u32 = nla_get_u32(attr); 1924 1925 if (if_indextoname(t.u32, buf)) 1926 return ucv_string_new(buf); 1927 1928 return NULL; 1929 1930 case DT_LLADDR: 1931 assert(spec->attr != 0); 1932 1933 if (!nla_check_len(attr, sizeof(*ea))) 1934 return NULL; 1935 1936 ea = nla_data(attr); 1937 1938 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", 1939 ea->ether_addr_octet[0], ea->ether_addr_octet[1], 1940 ea->ether_addr_octet[2], ea->ether_addr_octet[3], 1941 ea->ether_addr_octet[4], ea->ether_addr_octet[5]); 1942 1943 return ucv_string_new(buf); 1944 1945 case DT_INADDR: 1946 assert(spec->attr != 0); 1947 1948 if (!nla_check_len(attr, sizeof(struct in_addr)) || 1949 !inet_ntop(AF_INET, nla_data(attr), buf, sizeof(buf))) 1950 return NULL; 1951 1952 return ucv_string_new(buf); 1953 1954 case DT_NESTED: 1955 if (spec->flags & DF_ARRAY) { 1956 const uc_nl_nested_spec_t *nested = spec->auxdata; 1957 1958 assert(nested != NULL); 1959 assert(nested->headsize > 0); 1960 assert((nla_len(attr) % nested->headsize) == 0); 1961 1962 v = ucv_array_new_length(vm, nla_len(attr) / nested->headsize); 1963 1964 for (i = 0; i < nla_len(attr); i += nested->headsize) { 1965 uc_value_t *item = ucv_object_new(vm); 1966 1967 ucv_array_push(v, item); 1968 1969 bool rv = uc_nl_convert_attrs(msg, 1970 nla_data(attr) + i, nla_len(attr) - i, nested->headsize, 1971 nested->attrs, nested->nattrs, vm, item); 1972 1973 if (!rv) { 1974 ucv_put(v); 1975 1976 return NULL; 1977 } 1978 } 1979 1980 return v; 1981 } 1982 1983 return uc_nl_convert_rta_nested(spec, msg, attr, vm); 1984 1985 case DT_HT_MCS: 1986 return uc_nl_convert_rta_ht_mcs(spec, msg, attr, vm); 1987 1988 case DT_HT_CAP: 1989 return uc_nl_convert_rta_ht_cap(spec, msg, attr, vm); 1990 1991 case DT_VHT_MCS: 1992 return uc_nl_convert_rta_vht_mcs(spec, msg, attr, vm); 1993 1994 case DT_HE_MCS: 1995 return uc_nl_convert_rta_he_mcs(spec, msg, attr, attr2, vm); 1996 1997 case DT_IE: 1998 return uc_nl_convert_rta_ie(spec, msg, attr, vm); 1999 2000 default: 2001 assert(0); 2002 } 2003 2004 return NULL; 2005 } 2006 2007 2008 static struct { 2009 struct nl_sock *sock; 2010 struct nl_sock *evsock; 2011 struct nl_cache *cache; 2012 struct uloop_fd evsock_fd; 2013 struct nl_cb *evsock_cb; 2014 } nl80211_conn; 2015 2016 typedef enum { 2017 STATE_UNREPLIED, 2018 STATE_CONTINUE, 2019 STATE_REPLIED, 2020 STATE_ERROR 2021 } reply_state_t; 2022 2023 typedef struct { 2024 reply_state_t state; 2025 uc_vm_t *vm; 2026 uc_value_t *res; 2027 bool merge_phy_info; 2028 bool single_phy_info; 2029 const uc_nl_nested_spec_t *spec; 2030 } request_state_t; 2031 2032 2033 static uc_value_t * 2034 uc_nl_error(uc_vm_t *vm, size_t nargs) 2035 { 2036 uc_stringbuf_t *buf; 2037 const char *s; 2038 2039 if (last_error.code == 0) 2040 return NULL; 2041 2042 buf = ucv_stringbuf_new(); 2043 2044 if (last_error.code == NLE_FAILURE && last_error.msg) { 2045 ucv_stringbuf_addstr(buf, last_error.msg, strlen(last_error.msg)); 2046 } 2047 else { 2048 s = nl_geterror(last_error.code); 2049 2050 ucv_stringbuf_addstr(buf, s, strlen(s)); 2051 2052 if (last_error.msg) 2053 ucv_stringbuf_printf(buf, ": %s", last_error.msg); 2054 } 2055 2056 set_error(0, NULL); 2057 2058 return ucv_stringbuf_finish(buf); 2059 } 2060 2061 static int 2062 cb_done(struct nl_msg *msg, void *arg) 2063 { 2064 request_state_t *s = arg; 2065 2066 s->state = STATE_REPLIED; 2067 2068 return NL_STOP; 2069 } 2070 2071 static void 2072 deep_merge_array(uc_value_t *dest, uc_value_t *src); 2073 2074 static void 2075 deep_merge_object(uc_value_t *dest, uc_value_t *src); 2076 2077 static void 2078 deep_merge_array(uc_value_t *dest, uc_value_t *src) 2079 { 2080 uc_value_t *e, *v; 2081 size_t i; 2082 2083 if (ucv_type(dest) == UC_ARRAY && ucv_type(src) == UC_ARRAY) { 2084 for (i = 0; i < ucv_array_length(src); i++) { 2085 e = ucv_array_get(dest, i); 2086 v = ucv_array_get(src, i); 2087 2088 if (!e) 2089 ucv_array_set(dest, i, ucv_get(v)); 2090 else if (ucv_type(v) == UC_ARRAY) 2091 deep_merge_array(e, v); 2092 else if (ucv_type(v) == UC_OBJECT) 2093 deep_merge_object(e, v); 2094 } 2095 } 2096 } 2097 2098 static void 2099 deep_merge_object(uc_value_t *dest, uc_value_t *src) 2100 { 2101 uc_value_t *e; 2102 bool exists; 2103 2104 if (ucv_type(dest) == UC_OBJECT && ucv_type(src) == UC_OBJECT) { 2105 ucv_object_foreach(src, k, v) { 2106 e = ucv_object_get(dest, k, &exists); 2107 2108 if (!exists) 2109 ucv_object_add(dest, k, ucv_get(v)); 2110 else if (ucv_type(v) == UC_ARRAY) 2111 deep_merge_array(e, v); 2112 else if (ucv_type(v) == UC_OBJECT) 2113 deep_merge_object(e, v); 2114 } 2115 } 2116 } 2117 2118 static int 2119 cb_reply(struct nl_msg *msg, void *arg) 2120 { 2121 struct nlmsghdr *hdr = nlmsg_hdr(msg); 2122 struct genlmsghdr *gnlh = nlmsg_data(hdr); 2123 request_state_t *s = arg; 2124 uc_value_t *o, *idx; 2125 int64_t i; 2126 bool rv; 2127 2128 o = ucv_object_new(s->vm); 2129 2130 rv = uc_nl_convert_attrs(msg, 2131 genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), 2132 0, s->spec->attrs, s->spec->nattrs, s->vm, o); 2133 2134 if (rv) { 2135 if (hdr->nlmsg_flags & NLM_F_MULTI) { 2136 if (s->merge_phy_info && s->single_phy_info) { 2137 if (!s->res) { 2138 s->res = o; 2139 } 2140 else { 2141 deep_merge_object(s->res, o); 2142 ucv_put(o); 2143 } 2144 } 2145 else if (s->merge_phy_info) { 2146 idx = ucv_object_get(o, "wiphy", NULL); 2147 i = idx ? ucv_int64_get(idx) : -1; 2148 2149 if (i >= 0) { 2150 if (!s->res) 2151 s->res = ucv_array_new(s->vm); 2152 2153 idx = ucv_array_get(s->res, i); 2154 2155 if (idx) { 2156 deep_merge_object(idx, o); 2157 ucv_put(o); 2158 } 2159 else { 2160 ucv_array_set(s->res, i, o); 2161 } 2162 } 2163 } 2164 else { 2165 if (!s->res) 2166 s->res = ucv_array_new(s->vm); 2167 2168 ucv_array_push(s->res, o); 2169 } 2170 } 2171 else { 2172 s->res = o; 2173 } 2174 } 2175 else { 2176 ucv_put(o); 2177 } 2178 2179 s->state = STATE_CONTINUE; 2180 2181 return NL_SKIP; 2182 } 2183 2184 static bool 2185 uc_nl_connect_sock(struct nl_sock **sk, bool nonblocking) 2186 { 2187 int err, fd; 2188 2189 if (*sk) 2190 return true; 2191 2192 *sk = nl_socket_alloc(); 2193 2194 if (!*sk) { 2195 set_error(NLE_NOMEM, NULL); 2196 goto err; 2197 } 2198 2199 err = genl_connect(*sk); 2200 2201 if (err != 0) { 2202 set_error(err, NULL); 2203 goto err; 2204 } 2205 2206 fd = nl_socket_get_fd(*sk); 2207 2208 if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0) { 2209 set_error(NLE_FAILURE, "unable to set FD_CLOEXEC flag on socket: %s", strerror(errno)); 2210 goto err; 2211 } 2212 2213 if (nonblocking) { 2214 err = nl_socket_set_nonblocking(*sk); 2215 2216 if (err != 0) { 2217 set_error(err, NULL); 2218 goto err; 2219 } 2220 } 2221 2222 return true; 2223 2224 err: 2225 if (*sk) { 2226 nl_socket_free(*sk); 2227 *sk = NULL; 2228 } 2229 2230 return false; 2231 } 2232 2233 static int 2234 uc_nl_find_family_id(const char *name) 2235 { 2236 struct genl_family *fam; 2237 2238 if (!nl80211_conn.cache && genl_ctrl_alloc_cache(nl80211_conn.sock, &nl80211_conn.cache)) 2239 return -NLE_NOMEM; 2240 2241 fam = genl_ctrl_search_by_name(nl80211_conn.cache, name); 2242 2243 if (!fam) 2244 return -NLE_OBJ_NOTFOUND; 2245 2246 return genl_family_get_id(fam); 2247 } 2248 2249 static int 2250 cb_errno(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) 2251 { 2252 int *ret = arg; 2253 2254 if (err->error > 0) { 2255 set_error(NLE_RANGE, 2256 "Illegal error code %d in netlink reply", err->error); 2257 2258 *ret = -(NLE_MAX + 1); 2259 } 2260 else { 2261 *ret = -nl_syserr2nlerr(err->error); 2262 } 2263 2264 return NL_STOP; 2265 } 2266 2267 static int 2268 cb_ack(struct nl_msg *msg, void *arg) 2269 { 2270 int *ret = arg; 2271 2272 *ret = 0; 2273 2274 return NL_STOP; 2275 } 2276 2277 static int 2278 cb_subscribe(struct nl_msg *msg, void *arg) 2279 { 2280 struct nlattr *nla, *tb[CTRL_ATTR_MAX + 1], *grp[CTRL_ATTR_MCAST_GRP_MAX + 1]; 2281 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 2282 struct { int id; const char *group; } *ret = arg; 2283 int rem; 2284 2285 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); 2286 2287 if (!tb[CTRL_ATTR_MCAST_GROUPS]) 2288 return NL_SKIP; 2289 2290 nla_for_each_nested(nla, tb[CTRL_ATTR_MCAST_GROUPS], rem) { 2291 nla_parse(grp, CTRL_ATTR_MCAST_GRP_MAX, nla_data(nla), nla_len(nla), NULL); 2292 2293 if (!grp[CTRL_ATTR_MCAST_GRP_NAME] || !grp[CTRL_ATTR_MCAST_GRP_ID]) 2294 continue; 2295 2296 if (strncmp(nla_data(grp[CTRL_ATTR_MCAST_GRP_NAME]), 2297 ret->group, nla_len(grp[CTRL_ATTR_MCAST_GRP_NAME]))) 2298 continue; 2299 2300 ret->id = nla_get_u32(grp[CTRL_ATTR_MCAST_GRP_ID]); 2301 2302 break; 2303 } 2304 2305 return NL_SKIP; 2306 } 2307 2308 static bool 2309 uc_nl_subscribe(struct nl_sock *sk, const char *family, const char *group) 2310 { 2311 struct { int id; const char *group; } grp = { -NLE_OBJ_NOTFOUND, group }; 2312 struct nl_msg *msg; 2313 struct nl_cb *cb; 2314 int id, ret; 2315 2316 if (!uc_nl_connect_sock(&nl80211_conn.sock, false)) 2317 return NULL; 2318 2319 msg = nlmsg_alloc(); 2320 2321 if (!msg) 2322 err_return(NLE_NOMEM, NULL); 2323 2324 id = uc_nl_find_family_id("nlctrl"); 2325 2326 if (id < 0) 2327 err_return(-id, NULL); 2328 2329 genlmsg_put(msg, 0, 0, id, 0, 0, CTRL_CMD_GETFAMILY, 0); 2330 nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family); 2331 2332 cb = nl_cb_alloc(NL_CB_DEFAULT); 2333 2334 if (!cb) { 2335 nlmsg_free(msg); 2336 err_return(NLE_NOMEM, NULL); 2337 } 2338 2339 nl_send_auto_complete(nl80211_conn.sock, msg); 2340 2341 ret = 1; 2342 2343 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, cb_ack, &ret); 2344 nl_cb_err(cb, NL_CB_CUSTOM, cb_errno, &ret); 2345 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_subscribe, &grp); 2346 2347 while (ret > 0) 2348 nl_recvmsgs(nl80211_conn.sock, cb); 2349 2350 nlmsg_free(msg); 2351 nl_cb_put(cb); 2352 2353 if (ret < 0) 2354 err_return(ret, NULL); 2355 2356 if (grp.id < 0) 2357 err_return(grp.id, NULL); 2358 2359 ret = nl_socket_add_membership(sk, grp.id); 2360 2361 if (ret != 0) 2362 err_return(ret, NULL); 2363 2364 return true; 2365 } 2366 2367 2368 struct waitfor_ctx { 2369 uint8_t cmd; 2370 uc_vm_t *vm; 2371 uc_value_t *res; 2372 uint32_t cmds[NL80211_CMDS_BITMAP_SIZE]; 2373 }; 2374 2375 static uc_value_t * 2376 uc_nl_prepare_event(uc_vm_t *vm, struct nl_msg *msg) 2377 { 2378 struct nlmsghdr *hdr = nlmsg_hdr(msg); 2379 struct genlmsghdr *gnlh = nlmsg_data(hdr); 2380 uc_value_t *o = ucv_object_new(vm); 2381 2382 if (!uc_nl_convert_attrs(msg, genlmsg_attrdata(gnlh, 0), 2383 genlmsg_attrlen(gnlh, 0), 0, 2384 nl80211_msg.attrs, nl80211_msg.nattrs, vm, o)) { 2385 ucv_put(o); 2386 return NULL; 2387 } 2388 2389 return o; 2390 } 2391 2392 static int 2393 cb_listener_event(struct nl_msg *msg, void *arg) 2394 { 2395 struct nlmsghdr *hdr = nlmsg_hdr(msg); 2396 struct genlmsghdr *gnlh = nlmsg_data(hdr); 2397 uc_vm_t *vm = listener_vm; 2398 2399 if (!nl80211_conn.evsock_fd.registered || !vm) 2400 return NL_SKIP; 2401 2402 for (size_t i = 0; i < ucv_array_length(listener_registry); i += 2) { 2403 uc_value_t *this = ucv_array_get(listener_registry, i); 2404 uc_value_t *func = ucv_array_get(listener_registry, i + 1); 2405 uc_nl_listener_t *l; 2406 uc_value_t *o, *data; 2407 2408 l = ucv_resource_data(this, "nl80211.listener"); 2409 if (!l) 2410 continue; 2411 2412 if (gnlh->cmd > NL80211_CMD_MAX || 2413 !(l->cmds[gnlh->cmd / 32] & (1 << (gnlh->cmd % 32)))) 2414 continue; 2415 2416 if (!ucv_is_callable(func)) 2417 continue; 2418 2419 data = uc_nl_prepare_event(vm, msg); 2420 if (!data) 2421 return NL_SKIP; 2422 2423 o = ucv_object_new(vm); 2424 ucv_object_add(o, "cmd", ucv_int64_new(gnlh->cmd)); 2425 ucv_object_add(o, "msg", data); 2426 2427 uc_vm_stack_push(vm, ucv_get(this)); 2428 uc_vm_stack_push(vm, ucv_get(func)); 2429 uc_vm_stack_push(vm, o); 2430 2431 if (uc_vm_call(vm, true, 1) != EXCEPTION_NONE) { 2432 uloop_end(); 2433 return NL_STOP; 2434 } 2435 2436 ucv_put(uc_vm_stack_pop(vm)); 2437 } 2438 2439 return NL_SKIP; 2440 } 2441 2442 static int 2443 cb_event(struct nl_msg *msg, void *arg) 2444 { 2445 struct nlmsghdr *hdr = nlmsg_hdr(msg); 2446 struct genlmsghdr *gnlh = nlmsg_data(hdr); 2447 struct waitfor_ctx *s = arg; 2448 uc_value_t *o; 2449 2450 cb_listener_event(msg, arg); 2451 2452 if (gnlh->cmd > NL80211_CMD_MAX || 2453 !(s->cmds[gnlh->cmd / 32] & (1 << (gnlh->cmd % 32)))) 2454 return NL_SKIP; 2455 2456 o = uc_nl_prepare_event(s->vm, msg); 2457 if (o) 2458 s->res = o; 2459 2460 s->cmd = gnlh->cmd; 2461 2462 return NL_SKIP; 2463 } 2464 2465 static int 2466 cb_seq(struct nl_msg *msg, void *arg) 2467 { 2468 return NL_OK; 2469 } 2470 2471 static bool 2472 uc_nl_fill_cmds(uint32_t *cmd_bits, uc_value_t *cmds) 2473 { 2474 if (ucv_type(cmds) == UC_ARRAY) { 2475 for (size_t i = 0; i < ucv_array_length(cmds); i++) { 2476 int64_t n = ucv_int64_get(ucv_array_get(cmds, i)); 2477 2478 if (errno || n < 0 || n > NL80211_CMD_MAX) 2479 return false; 2480 2481 cmd_bits[n / 32] |= (1 << (n % 32)); 2482 } 2483 } 2484 else if (ucv_type(cmds) == UC_INTEGER) { 2485 int64_t n = ucv_int64_get(cmds); 2486 2487 if (errno || n < 0 || n > 255) 2488 return false; 2489 2490 cmd_bits[n / 32] |= (1 << (n % 32)); 2491 } 2492 else if (!cmds) 2493 memset(cmd_bits, 0xff, NL80211_CMDS_BITMAP_SIZE * sizeof(*cmd_bits)); 2494 else 2495 return false; 2496 2497 return true; 2498 } 2499 2500 static bool 2501 uc_nl_evsock_init(void) 2502 { 2503 if (nl80211_conn.evsock) 2504 return true; 2505 2506 if (!uc_nl_connect_sock(&nl80211_conn.evsock, true)) 2507 return false; 2508 2509 if (!uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "config") || 2510 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "scan") || 2511 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "regulatory") || 2512 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "mlme") || 2513 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "vendor") || 2514 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "nan")) { 2515 nl_socket_free(nl80211_conn.evsock); 2516 nl80211_conn.evsock = NULL; 2517 return false; 2518 } 2519 2520 return true; 2521 } 2522 2523 static uc_value_t * 2524 uc_nl_waitfor(uc_vm_t *vm, size_t nargs) 2525 { 2526 struct pollfd pfd = { .events = POLLIN }; 2527 uc_value_t *cmds = uc_fn_arg(0); 2528 uc_value_t *timeout = uc_fn_arg(1); 2529 uc_value_t *rv = NULL; 2530 struct waitfor_ctx ctx = { .vm = vm }; 2531 struct nl_cb *cb; 2532 int ms = -1, err; 2533 2534 if (timeout) { 2535 int64_t n = ucv_int64_get(timeout); 2536 2537 if (ucv_type(timeout) != UC_INTEGER || n < INT32_MIN || n > INT32_MAX) 2538 err_return(NLE_INVAL, "Invalid timeout specified"); 2539 2540 ms = (int)n; 2541 } 2542 2543 if (!uc_nl_fill_cmds(ctx.cmds, cmds)) 2544 err_return(NLE_INVAL, "Invalid command ID specified"); 2545 2546 if (!uc_nl_evsock_init()) 2547 return NULL; 2548 2549 cb = nl_cb_alloc(NL_CB_DEFAULT); 2550 2551 if (!cb) 2552 err_return(NLE_NOMEM, NULL); 2553 2554 err = 0; 2555 2556 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, cb_seq, NULL); 2557 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_event, &ctx); 2558 nl_cb_err(cb, NL_CB_CUSTOM, cb_errno, &err); 2559 2560 pfd.fd = nl_socket_get_fd(nl80211_conn.evsock); 2561 2562 if (poll(&pfd, 1, ms) == 1) { 2563 while (err == 0 && ctx.cmd == 0) 2564 nl_recvmsgs(nl80211_conn.evsock, cb); 2565 } 2566 2567 nl_cb_put(cb); 2568 2569 if (ctx.cmd) { 2570 rv = ucv_object_new(vm); 2571 2572 ucv_object_add(rv, "cmd", ucv_int64_new(ctx.cmd)); 2573 ucv_object_add(rv, "msg", ctx.res); 2574 2575 return rv; 2576 } 2577 else if (err) { 2578 err_return(err, NULL); 2579 } 2580 else { 2581 err_return(NLE_FAILURE, "No event received"); 2582 } 2583 } 2584 2585 static uc_value_t * 2586 uc_nl_request(uc_vm_t *vm, size_t nargs) 2587 { 2588 request_state_t st = { .vm = vm }; 2589 uc_value_t *cmd = uc_fn_arg(0); 2590 uc_value_t *flags = uc_fn_arg(1); 2591 uc_value_t *payload = uc_fn_arg(2); 2592 uint16_t flagval = 0; 2593 struct nl_msg *msg; 2594 struct nl_cb *cb; 2595 int ret, id, cid; 2596 2597 if (ucv_type(cmd) != UC_INTEGER || ucv_int64_get(cmd) < 0 || 2598 (flags != NULL && ucv_type(flags) != UC_INTEGER) || 2599 (payload != NULL && ucv_type(payload) != UC_OBJECT)) 2600 err_return(NLE_INVAL, NULL); 2601 2602 if (flags) { 2603 if (ucv_int64_get(flags) < 0 || ucv_int64_get(flags) > 0xffff) 2604 err_return(NLE_INVAL, NULL); 2605 else 2606 flagval = (uint16_t)ucv_int64_get(flags); 2607 } 2608 2609 if (!uc_nl_connect_sock(&nl80211_conn.sock, false)) 2610 return NULL; 2611 2612 msg = nlmsg_alloc(); 2613 2614 if (!msg) 2615 err_return(NLE_NOMEM, NULL); 2616 2617 cid = ucv_int64_get(cmd); 2618 2619 if (cid >= HWSIM_CMD_OFFSET) { 2620 id = uc_nl_find_family_id("MAC80211_HWSIM"); 2621 cid -= HWSIM_CMD_OFFSET; 2622 st.spec = &hwsim_msg; 2623 } 2624 else if (cid == NL80211_CMD_GET_WIPHY) { 2625 id = uc_nl_find_family_id("nl80211"); 2626 st.spec = &nl80211_msg; 2627 st.merge_phy_info = true; 2628 2629 if (ucv_object_get(payload, "wiphy", NULL) != NULL) 2630 st.single_phy_info = true; 2631 2632 if (ucv_is_truish(ucv_object_get(payload, "split_wiphy_dump", NULL))) 2633 flagval |= NLM_F_DUMP; 2634 } 2635 else { 2636 id = uc_nl_find_family_id("nl80211"); 2637 st.spec = &nl80211_msg; 2638 } 2639 2640 if (id < 0) 2641 err_return(-id, NULL); 2642 2643 genlmsg_put(msg, 0, 0, id, 0, flagval, cid, 0); 2644 2645 if (!uc_nl_parse_attrs(msg, nlmsg_data(nlmsg_hdr(msg)), st.spec->attrs, st.spec->nattrs, vm, payload)) { 2646 nlmsg_free(msg); 2647 2648 return NULL; 2649 } 2650 2651 cb = nl_cb_alloc(NL_CB_DEFAULT); 2652 2653 if (!cb) { 2654 nlmsg_free(msg); 2655 err_return(NLE_NOMEM, NULL); 2656 } 2657 2658 ret = 1; 2659 2660 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_reply, &st); 2661 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_done, &st); 2662 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, cb_done, &st); 2663 nl_cb_err(cb, NL_CB_CUSTOM, cb_errno, &ret); 2664 2665 nl_send_auto_complete(nl80211_conn.sock, msg); 2666 2667 while (ret > 0 && st.state < STATE_REPLIED) 2668 nl_recvmsgs(nl80211_conn.sock, cb); 2669 2670 nlmsg_free(msg); 2671 nl_cb_put(cb); 2672 2673 if (ret < 0) 2674 err_return(ret, NULL); 2675 2676 switch (st.state) { 2677 case STATE_REPLIED: 2678 return st.res; 2679 2680 case STATE_UNREPLIED: 2681 return ucv_boolean_new(true); 2682 2683 default: 2684 set_error(NLE_FAILURE, "Interrupted reply"); 2685 2686 return ucv_boolean_new(false); 2687 } 2688 } 2689 2690 static void 2691 uc_nl_listener_cb(struct uloop_fd *fd, unsigned int events) 2692 { 2693 nl_recvmsgs(nl80211_conn.evsock, nl80211_conn.evsock_cb); 2694 } 2695 2696 static uc_value_t * 2697 uc_nl_listener(uc_vm_t *vm, size_t nargs) 2698 { 2699 struct uloop_fd *fd = &nl80211_conn.evsock_fd; 2700 uc_nl_listener_t *l; 2701 uc_value_t *cb_func = uc_fn_arg(0); 2702 uc_value_t *cmds = uc_fn_arg(1); 2703 uc_value_t *rv; 2704 size_t i; 2705 2706 if (!ucv_is_callable(cb_func)) { 2707 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid callback"); 2708 return NULL; 2709 } 2710 2711 if (!uc_nl_evsock_init()) 2712 return NULL; 2713 2714 if (!fd->registered) { 2715 fd->fd = nl_socket_get_fd(nl80211_conn.evsock); 2716 fd->cb = uc_nl_listener_cb; 2717 uloop_fd_add(fd, ULOOP_READ); 2718 } 2719 2720 if (!nl80211_conn.evsock_cb) { 2721 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT); 2722 2723 if (!cb) 2724 err_return(NLE_NOMEM, NULL); 2725 2726 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, cb_seq, NULL); 2727 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_listener_event, NULL); 2728 nl80211_conn.evsock_cb = cb; 2729 } 2730 2731 for (i = 0; i < ucv_array_length(listener_registry); i += 2) { 2732 if (!ucv_array_get(listener_registry, i)) 2733 break; 2734 } 2735 2736 ucv_array_set(listener_registry, i + 1, ucv_get(cb_func)); 2737 l = xalloc(sizeof(*l)); 2738 l->index = i; 2739 if (!uc_nl_fill_cmds(l->cmds, cmds)) { 2740 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid command ID"); 2741 free(l); 2742 return NULL; 2743 } 2744 2745 rv = uc_resource_new(listener_type, l); 2746 ucv_array_set(listener_registry, i, ucv_get(rv)); 2747 listener_vm = vm; 2748 2749 return rv; 2750 } 2751 2752 static void 2753 uc_nl_listener_free(void *arg) 2754 { 2755 uc_nl_listener_t *l = arg; 2756 2757 ucv_array_set(listener_registry, l->index, NULL); 2758 ucv_array_set(listener_registry, l->index + 1, NULL); 2759 free(l); 2760 } 2761 2762 static uc_value_t * 2763 uc_nl_listener_set_commands(uc_vm_t *vm, size_t nargs) 2764 { 2765 uc_nl_listener_t *l = uc_fn_thisval("nl80211.listener"); 2766 uc_value_t *cmds = uc_fn_arg(0); 2767 2768 if (!l) 2769 return NULL; 2770 2771 memset(l->cmds, 0, sizeof(l->cmds)); 2772 if (!uc_nl_fill_cmds(l->cmds, cmds)) 2773 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid command ID"); 2774 2775 return NULL; 2776 } 2777 2778 static uc_value_t * 2779 uc_nl_listener_close(uc_vm_t *vm, size_t nargs) 2780 { 2781 uc_nl_listener_t **lptr = uc_fn_this("nl80211.listener"); 2782 uc_nl_listener_t *l; 2783 2784 if (!lptr) 2785 return NULL; 2786 2787 l = *lptr; 2788 if (!l) 2789 return NULL; 2790 2791 *lptr = NULL; 2792 uc_nl_listener_free(l); 2793 2794 return NULL; 2795 } 2796 2797 2798 static void 2799 register_constants(uc_vm_t *vm, uc_value_t *scope) 2800 { 2801 uc_value_t *c = ucv_object_new(vm); 2802 2803 #define ADD_CONST(x) ucv_object_add(c, #x, ucv_int64_new(x)) 2804 2805 ADD_CONST(NLM_F_ACK); 2806 ADD_CONST(NLM_F_ACK_TLVS); 2807 ADD_CONST(NLM_F_APPEND); 2808 ADD_CONST(NLM_F_ATOMIC); 2809 ADD_CONST(NLM_F_CAPPED); 2810 ADD_CONST(NLM_F_CREATE); 2811 ADD_CONST(NLM_F_DUMP); 2812 ADD_CONST(NLM_F_DUMP_FILTERED); 2813 ADD_CONST(NLM_F_DUMP_INTR); 2814 ADD_CONST(NLM_F_ECHO); 2815 ADD_CONST(NLM_F_EXCL); 2816 ADD_CONST(NLM_F_MATCH); 2817 ADD_CONST(NLM_F_MULTI); 2818 ADD_CONST(NLM_F_NONREC); 2819 ADD_CONST(NLM_F_REPLACE); 2820 ADD_CONST(NLM_F_REQUEST); 2821 ADD_CONST(NLM_F_ROOT); 2822 2823 ADD_CONST(NL80211_CMD_GET_WIPHY); 2824 ADD_CONST(NL80211_CMD_SET_WIPHY); 2825 ADD_CONST(NL80211_CMD_NEW_WIPHY); 2826 ADD_CONST(NL80211_CMD_DEL_WIPHY); 2827 ADD_CONST(NL80211_CMD_GET_INTERFACE); 2828 ADD_CONST(NL80211_CMD_SET_INTERFACE); 2829 ADD_CONST(NL80211_CMD_NEW_INTERFACE); 2830 ADD_CONST(NL80211_CMD_DEL_INTERFACE); 2831 ADD_CONST(NL80211_CMD_GET_KEY); 2832 ADD_CONST(NL80211_CMD_SET_KEY); 2833 ADD_CONST(NL80211_CMD_NEW_KEY); 2834 ADD_CONST(NL80211_CMD_DEL_KEY); 2835 ADD_CONST(NL80211_CMD_GET_BEACON); 2836 ADD_CONST(NL80211_CMD_SET_BEACON); 2837 ADD_CONST(NL80211_CMD_START_AP); 2838 ADD_CONST(NL80211_CMD_NEW_BEACON); 2839 ADD_CONST(NL80211_CMD_STOP_AP); 2840 ADD_CONST(NL80211_CMD_DEL_BEACON); 2841 ADD_CONST(NL80211_CMD_GET_STATION); 2842 ADD_CONST(NL80211_CMD_SET_STATION); 2843 ADD_CONST(NL80211_CMD_NEW_STATION); 2844 ADD_CONST(NL80211_CMD_DEL_STATION); 2845 ADD_CONST(NL80211_CMD_GET_MPATH); 2846 ADD_CONST(NL80211_CMD_SET_MPATH); 2847 ADD_CONST(NL80211_CMD_NEW_MPATH); 2848 ADD_CONST(NL80211_CMD_DEL_MPATH); 2849 ADD_CONST(NL80211_CMD_SET_BSS); 2850 ADD_CONST(NL80211_CMD_SET_REG); 2851 ADD_CONST(NL80211_CMD_REQ_SET_REG); 2852 ADD_CONST(NL80211_CMD_GET_MESH_CONFIG); 2853 ADD_CONST(NL80211_CMD_SET_MESH_CONFIG); 2854 ADD_CONST(NL80211_CMD_GET_REG); 2855 ADD_CONST(NL80211_CMD_GET_SCAN); 2856 ADD_CONST(NL80211_CMD_TRIGGER_SCAN); 2857 ADD_CONST(NL80211_CMD_NEW_SCAN_RESULTS); 2858 ADD_CONST(NL80211_CMD_SCAN_ABORTED); 2859 ADD_CONST(NL80211_CMD_REG_CHANGE); 2860 ADD_CONST(NL80211_CMD_AUTHENTICATE); 2861 ADD_CONST(NL80211_CMD_ASSOCIATE); 2862 ADD_CONST(NL80211_CMD_DEAUTHENTICATE); 2863 ADD_CONST(NL80211_CMD_DISASSOCIATE); 2864 ADD_CONST(NL80211_CMD_MICHAEL_MIC_FAILURE); 2865 ADD_CONST(NL80211_CMD_REG_BEACON_HINT); 2866 ADD_CONST(NL80211_CMD_JOIN_IBSS); 2867 ADD_CONST(NL80211_CMD_LEAVE_IBSS); 2868 ADD_CONST(NL80211_CMD_TESTMODE); 2869 ADD_CONST(NL80211_CMD_CONNECT); 2870 ADD_CONST(NL80211_CMD_ROAM); 2871 ADD_CONST(NL80211_CMD_DISCONNECT); 2872 ADD_CONST(NL80211_CMD_SET_WIPHY_NETNS); 2873 ADD_CONST(NL80211_CMD_GET_SURVEY); 2874 ADD_CONST(NL80211_CMD_NEW_SURVEY_RESULTS); 2875 ADD_CONST(NL80211_CMD_SET_PMKSA); 2876 ADD_CONST(NL80211_CMD_DEL_PMKSA); 2877 ADD_CONST(NL80211_CMD_FLUSH_PMKSA); 2878 ADD_CONST(NL80211_CMD_REMAIN_ON_CHANNEL); 2879 ADD_CONST(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL); 2880 ADD_CONST(NL80211_CMD_SET_TX_BITRATE_MASK); 2881 ADD_CONST(NL80211_CMD_REGISTER_FRAME); 2882 ADD_CONST(NL80211_CMD_REGISTER_ACTION); 2883 ADD_CONST(NL80211_CMD_FRAME); 2884 ADD_CONST(NL80211_CMD_ACTION); 2885 ADD_CONST(NL80211_CMD_FRAME_TX_STATUS); 2886 ADD_CONST(NL80211_CMD_ACTION_TX_STATUS); 2887 ADD_CONST(NL80211_CMD_SET_POWER_SAVE); 2888 ADD_CONST(NL80211_CMD_GET_POWER_SAVE); 2889 ADD_CONST(NL80211_CMD_SET_CQM); 2890 ADD_CONST(NL80211_CMD_NOTIFY_CQM); 2891 ADD_CONST(NL80211_CMD_SET_CHANNEL); 2892 ADD_CONST(NL80211_CMD_SET_WDS_PEER); 2893 ADD_CONST(NL80211_CMD_FRAME_WAIT_CANCEL); 2894 ADD_CONST(NL80211_CMD_JOIN_MESH); 2895 ADD_CONST(NL80211_CMD_LEAVE_MESH); 2896 ADD_CONST(NL80211_CMD_UNPROT_DEAUTHENTICATE); 2897 ADD_CONST(NL80211_CMD_UNPROT_DISASSOCIATE); 2898 ADD_CONST(NL80211_CMD_NEW_PEER_CANDIDATE); 2899 ADD_CONST(NL80211_CMD_GET_WOWLAN); 2900 ADD_CONST(NL80211_CMD_SET_WOWLAN); 2901 ADD_CONST(NL80211_CMD_START_SCHED_SCAN); 2902 ADD_CONST(NL80211_CMD_STOP_SCHED_SCAN); 2903 ADD_CONST(NL80211_CMD_SCHED_SCAN_RESULTS); 2904 ADD_CONST(NL80211_CMD_SCHED_SCAN_STOPPED); 2905 ADD_CONST(NL80211_CMD_SET_REKEY_OFFLOAD); 2906 ADD_CONST(NL80211_CMD_PMKSA_CANDIDATE); 2907 ADD_CONST(NL80211_CMD_TDLS_OPER); 2908 ADD_CONST(NL80211_CMD_TDLS_MGMT); 2909 ADD_CONST(NL80211_CMD_UNEXPECTED_FRAME); 2910 ADD_CONST(NL80211_CMD_PROBE_CLIENT); 2911 ADD_CONST(NL80211_CMD_REGISTER_BEACONS); 2912 ADD_CONST(NL80211_CMD_UNEXPECTED_4ADDR_FRAME); 2913 ADD_CONST(NL80211_CMD_SET_NOACK_MAP); 2914 ADD_CONST(NL80211_CMD_CH_SWITCH_NOTIFY); 2915 ADD_CONST(NL80211_CMD_START_P2P_DEVICE); 2916 ADD_CONST(NL80211_CMD_STOP_P2P_DEVICE); 2917 ADD_CONST(NL80211_CMD_CONN_FAILED); 2918 ADD_CONST(NL80211_CMD_SET_MCAST_RATE); 2919 ADD_CONST(NL80211_CMD_SET_MAC_ACL); 2920 ADD_CONST(NL80211_CMD_RADAR_DETECT); 2921 ADD_CONST(NL80211_CMD_GET_PROTOCOL_FEATURES); 2922 ADD_CONST(NL80211_CMD_UPDATE_FT_IES); 2923 ADD_CONST(NL80211_CMD_FT_EVENT); 2924 ADD_CONST(NL80211_CMD_CRIT_PROTOCOL_START); 2925 ADD_CONST(NL80211_CMD_CRIT_PROTOCOL_STOP); 2926 ADD_CONST(NL80211_CMD_GET_COALESCE); 2927 ADD_CONST(NL80211_CMD_SET_COALESCE); 2928 ADD_CONST(NL80211_CMD_CHANNEL_SWITCH); 2929 ADD_CONST(NL80211_CMD_VENDOR); 2930 ADD_CONST(NL80211_CMD_SET_QOS_MAP); 2931 ADD_CONST(NL80211_CMD_ADD_TX_TS); 2932 ADD_CONST(NL80211_CMD_DEL_TX_TS); 2933 ADD_CONST(NL80211_CMD_GET_MPP); 2934 ADD_CONST(NL80211_CMD_JOIN_OCB); 2935 ADD_CONST(NL80211_CMD_LEAVE_OCB); 2936 ADD_CONST(NL80211_CMD_CH_SWITCH_STARTED_NOTIFY); 2937 ADD_CONST(NL80211_CMD_TDLS_CHANNEL_SWITCH); 2938 ADD_CONST(NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH); 2939 2940 ADD_CONST(HWSIM_CMD_REGISTER), 2941 ADD_CONST(HWSIM_CMD_FRAME), 2942 ADD_CONST(HWSIM_CMD_TX_INFO_FRAME), 2943 ADD_CONST(HWSIM_CMD_NEW_RADIO), 2944 ADD_CONST(HWSIM_CMD_DEL_RADIO), 2945 ADD_CONST(HWSIM_CMD_GET_RADIO), 2946 ADD_CONST(HWSIM_CMD_ADD_MAC_ADDR), 2947 ADD_CONST(HWSIM_CMD_DEL_MAC_ADDR), 2948 ADD_CONST(HWSIM_CMD_START_PMSR), 2949 ADD_CONST(HWSIM_CMD_ABORT_PMSR), 2950 ADD_CONST(HWSIM_CMD_REPORT_PMSR), 2951 2952 ADD_CONST(NL80211_IFTYPE_ADHOC); 2953 ADD_CONST(NL80211_IFTYPE_STATION); 2954 ADD_CONST(NL80211_IFTYPE_AP); 2955 ADD_CONST(NL80211_IFTYPE_AP_VLAN); 2956 ADD_CONST(NL80211_IFTYPE_WDS); 2957 ADD_CONST(NL80211_IFTYPE_MONITOR); 2958 ADD_CONST(NL80211_IFTYPE_MESH_POINT); 2959 ADD_CONST(NL80211_IFTYPE_P2P_CLIENT); 2960 ADD_CONST(NL80211_IFTYPE_P2P_GO); 2961 ADD_CONST(NL80211_IFTYPE_P2P_DEVICE); 2962 ADD_CONST(NL80211_IFTYPE_OCB); 2963 2964 ucv_object_add(scope, "const", c); 2965 }; 2966 2967 static const uc_function_list_t global_fns[] = { 2968 { "error", uc_nl_error }, 2969 { "request", uc_nl_request }, 2970 { "waitfor", uc_nl_waitfor }, 2971 { "listener", uc_nl_listener }, 2972 }; 2973 2974 2975 static const uc_function_list_t listener_fns[] = { 2976 { "set_commands", uc_nl_listener_set_commands }, 2977 { "close", uc_nl_listener_close }, 2978 }; 2979 2980 void uc_module_init(uc_vm_t *vm, uc_value_t *scope) 2981 { 2982 uc_function_list_register(scope, global_fns); 2983 2984 listener_type = uc_type_declare(vm, "nl80211.listener", listener_fns, uc_nl_listener_free); 2985 listener_registry = ucv_array_new(vm); 2986 2987 uc_vm_registry_set(vm, "nl80211.registry", listener_registry); 2988 2989 register_constants(vm, scope); 2990 } 2991
This page was automatically generated by LXR 0.3.1. • OpenWrt