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 if (ucv_type(val) == UC_STRING) { 1727 nla_put(msg, attr, 1728 ucv_string_length(val) + !(spec->flags & DF_BINARY), 1729 ucv_string_get(val)); 1730 } 1731 else { 1732 s = ucv_to_string(vm, val); 1733 1734 if (!s) 1735 return nla_parse_error(spec, vm, val, "out of memory"); 1736 1737 nla_put(msg, attr, strlen(s) + !(spec->flags & DF_BINARY), s); 1738 free(s); 1739 } 1740 1741 break; 1742 1743 case DT_NETDEV: 1744 if (ucv_type(val) == UC_INTEGER) { 1745 if (ucv_int64_get(val) < 0 || 1746 ucv_int64_get(val) > UINT32_MAX) 1747 return nla_parse_error(spec, vm, val, "interface index out of range 0-4294967295"); 1748 1749 u32 = (uint32_t)ucv_int64_get(val); 1750 } 1751 else { 1752 s = ucv_to_string(vm, val); 1753 1754 if (!s) 1755 return nla_parse_error(spec, vm, val, "out of memory"); 1756 1757 u32 = if_nametoindex(s); 1758 1759 free(s); 1760 } 1761 1762 if (spec->attr == 0) 1763 uc_nl_put_struct_member_u32(base, spec->auxdata, u32); 1764 else 1765 nla_put_u32(msg, attr, u32); 1766 1767 break; 1768 1769 case DT_LLADDR: 1770 assert(spec->attr != 0); 1771 1772 s = ucv_to_string(vm, val); 1773 1774 if (!s) 1775 return nla_parse_error(spec, vm, val, "out of memory"); 1776 1777 ea = ether_aton(s); 1778 1779 free(s); 1780 1781 if (!ea) 1782 return nla_parse_error(spec, vm, val, "invalid MAC address"); 1783 1784 nla_put(msg, attr, sizeof(*ea), ea); 1785 1786 break; 1787 1788 case DT_INADDR: 1789 assert(spec->attr != 0); 1790 1791 if (!uc_nl_parse_ipaddr(vm, val, &in)) 1792 return nla_parse_error(spec, vm, val, "invalid IP address"); 1793 1794 nla_put(msg, attr, sizeof(in), &in); 1795 1796 break; 1797 1798 case DT_NESTED: 1799 if (spec->flags & DF_ARRAY) { 1800 const uc_nl_nested_spec_t *nested = spec->auxdata; 1801 1802 assert(nested != NULL); 1803 assert(nested->headsize > 0); 1804 1805 if (ucv_type(val) != UC_ARRAY) 1806 return nla_parse_error(spec, vm, val, "not an array"); 1807 1808 nla = nla_reserve(msg, spec->attr, ucv_array_length(val) * nested->headsize); 1809 s = nla_data(nla); 1810 1811 for (i = 0; i < ucv_array_length(val); i++) { 1812 item = ucv_array_get(val, i); 1813 1814 if (!uc_nl_parse_attrs(msg, s, nested->attrs, nested->nattrs, vm, item)) 1815 return false; 1816 1817 s += nested->headsize; 1818 } 1819 1820 return true; 1821 } 1822 1823 if (!uc_nl_parse_rta_nested(spec, msg, base, vm, val)) 1824 return false; 1825 1826 break; 1827 1828 default: 1829 assert(0); 1830 } 1831 1832 return true; 1833 } 1834 1835 static uc_value_t * 1836 uc_nl_convert_numval(const uc_nl_attr_spec_t *spec, char *base) 1837 { 1838 union { uint8_t *u8; uint16_t *u16; uint32_t *u32; uint64_t *u64; char *base; } t = { .base = base }; 1839 1840 switch (spec->type) { 1841 case DT_U8: 1842 return ucv_uint64_new(t.u8[0]); 1843 1844 case DT_S8: 1845 return ucv_int64_new((int8_t)t.u8[0]); 1846 1847 case DT_U16: 1848 return ucv_uint64_new(t.u16[0]); 1849 1850 case DT_U32: 1851 return ucv_uint64_new(t.u32[0]); 1852 1853 case DT_S32: 1854 return ucv_int64_new((int32_t)t.u32[0]); 1855 1856 case DT_U64: 1857 return ucv_uint64_new(t.u64[0]); 1858 1859 default: 1860 return NULL; 1861 } 1862 } 1863 1864 static uc_value_t * 1865 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) 1866 { 1867 union { uint8_t u8; uint16_t u16; uint32_t u32; uint64_t u64; size_t sz; } t = { 0 }; 1868 char buf[sizeof("FF:FF:FF:FF:FF:FF")]; 1869 struct ether_addr *ea; 1870 uc_value_t *v; 1871 int i; 1872 1873 switch (spec->type) { 1874 case DT_U8: 1875 case DT_S8: 1876 case DT_U16: 1877 case DT_U32: 1878 case DT_S32: 1879 case DT_U64: 1880 if (spec->flags & DF_ARRAY) { 1881 assert(spec->attr != 0); 1882 assert((nla_len(attr) % dt_sizes[spec->type]) == 0); 1883 1884 v = ucv_array_new_length(vm, nla_len(attr) / dt_sizes[spec->type]); 1885 1886 for (i = 0; i < nla_len(attr); i += dt_sizes[spec->type]) 1887 ucv_array_push(v, uc_nl_convert_numval(spec, nla_data(attr) + i)); 1888 1889 return v; 1890 } 1891 else if (spec->attr == 0) { 1892 return uc_nl_convert_numval(spec, base + (uintptr_t)spec->auxdata); 1893 } 1894 else if (nla_check_len(attr, dt_sizes[spec->type])) { 1895 return uc_nl_convert_numval(spec, nla_data(attr)); 1896 } 1897 1898 return NULL; 1899 1900 case DT_BOOL: 1901 if (spec->attr == 0) 1902 t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata); 1903 else if (nla_check_len(attr, sizeof(t.u8))) 1904 t.u8 = nla_get_u8(attr); 1905 1906 return ucv_boolean_new(t.u8 != 0); 1907 1908 case DT_FLAG: 1909 if (spec->attr == 0) 1910 t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata); 1911 else if (attr != NULL) 1912 t.u8 = 1; 1913 1914 return ucv_boolean_new(t.u8 != 0); 1915 1916 case DT_STRING: 1917 assert(spec->attr != 0); 1918 1919 if (!nla_check_len(attr, 1)) 1920 return NULL; 1921 1922 t.sz = nla_len(attr); 1923 1924 if (!(spec->flags & DF_BINARY)) 1925 t.sz -= 1; 1926 1927 return ucv_string_new_length(nla_data(attr), t.sz); 1928 1929 case DT_NETDEV: 1930 if (spec->attr == 0) 1931 t.u32 = uc_nl_get_struct_member_u32(base, spec->auxdata); 1932 else if (nla_check_len(attr, sizeof(t.u32))) 1933 t.u32 = nla_get_u32(attr); 1934 1935 if (if_indextoname(t.u32, buf)) 1936 return ucv_string_new(buf); 1937 1938 return NULL; 1939 1940 case DT_LLADDR: 1941 assert(spec->attr != 0); 1942 1943 if (!nla_check_len(attr, sizeof(*ea))) 1944 return NULL; 1945 1946 ea = nla_data(attr); 1947 1948 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", 1949 ea->ether_addr_octet[0], ea->ether_addr_octet[1], 1950 ea->ether_addr_octet[2], ea->ether_addr_octet[3], 1951 ea->ether_addr_octet[4], ea->ether_addr_octet[5]); 1952 1953 return ucv_string_new(buf); 1954 1955 case DT_INADDR: 1956 assert(spec->attr != 0); 1957 1958 if (!nla_check_len(attr, sizeof(struct in_addr)) || 1959 !inet_ntop(AF_INET, nla_data(attr), buf, sizeof(buf))) 1960 return NULL; 1961 1962 return ucv_string_new(buf); 1963 1964 case DT_NESTED: 1965 if (spec->flags & DF_ARRAY) { 1966 const uc_nl_nested_spec_t *nested = spec->auxdata; 1967 1968 assert(nested != NULL); 1969 assert(nested->headsize > 0); 1970 assert((nla_len(attr) % nested->headsize) == 0); 1971 1972 v = ucv_array_new_length(vm, nla_len(attr) / nested->headsize); 1973 1974 for (i = 0; i < nla_len(attr); i += nested->headsize) { 1975 uc_value_t *item = ucv_object_new(vm); 1976 1977 ucv_array_push(v, item); 1978 1979 bool rv = uc_nl_convert_attrs(msg, 1980 nla_data(attr) + i, nla_len(attr) - i, nested->headsize, 1981 nested->attrs, nested->nattrs, vm, item); 1982 1983 if (!rv) { 1984 ucv_put(v); 1985 1986 return NULL; 1987 } 1988 } 1989 1990 return v; 1991 } 1992 1993 return uc_nl_convert_rta_nested(spec, msg, attr, vm); 1994 1995 case DT_HT_MCS: 1996 return uc_nl_convert_rta_ht_mcs(spec, msg, attr, vm); 1997 1998 case DT_HT_CAP: 1999 return uc_nl_convert_rta_ht_cap(spec, msg, attr, vm); 2000 2001 case DT_VHT_MCS: 2002 return uc_nl_convert_rta_vht_mcs(spec, msg, attr, vm); 2003 2004 case DT_HE_MCS: 2005 return uc_nl_convert_rta_he_mcs(spec, msg, attr, attr2, vm); 2006 2007 case DT_IE: 2008 return uc_nl_convert_rta_ie(spec, msg, attr, vm); 2009 2010 default: 2011 assert(0); 2012 } 2013 2014 return NULL; 2015 } 2016 2017 2018 static struct { 2019 struct nl_sock *sock; 2020 struct nl_sock *evsock; 2021 struct nl_cache *cache; 2022 struct uloop_fd evsock_fd; 2023 struct nl_cb *evsock_cb; 2024 } nl80211_conn; 2025 2026 typedef enum { 2027 STATE_UNREPLIED, 2028 STATE_CONTINUE, 2029 STATE_REPLIED, 2030 STATE_ERROR 2031 } reply_state_t; 2032 2033 typedef struct { 2034 reply_state_t state; 2035 uc_vm_t *vm; 2036 uc_value_t *res; 2037 bool merge_phy_info; 2038 bool single_phy_info; 2039 const uc_nl_nested_spec_t *spec; 2040 } request_state_t; 2041 2042 2043 static uc_value_t * 2044 uc_nl_error(uc_vm_t *vm, size_t nargs) 2045 { 2046 uc_stringbuf_t *buf; 2047 const char *s; 2048 2049 if (last_error.code == 0) 2050 return NULL; 2051 2052 buf = ucv_stringbuf_new(); 2053 2054 if (last_error.code == NLE_FAILURE && last_error.msg) { 2055 ucv_stringbuf_addstr(buf, last_error.msg, strlen(last_error.msg)); 2056 } 2057 else { 2058 s = nl_geterror(last_error.code); 2059 2060 ucv_stringbuf_addstr(buf, s, strlen(s)); 2061 2062 if (last_error.msg) 2063 ucv_stringbuf_printf(buf, ": %s", last_error.msg); 2064 } 2065 2066 set_error(0, NULL); 2067 2068 return ucv_stringbuf_finish(buf); 2069 } 2070 2071 static int 2072 cb_done(struct nl_msg *msg, void *arg) 2073 { 2074 request_state_t *s = arg; 2075 2076 s->state = STATE_REPLIED; 2077 2078 return NL_STOP; 2079 } 2080 2081 static void 2082 deep_merge_array(uc_value_t *dest, uc_value_t *src); 2083 2084 static void 2085 deep_merge_object(uc_value_t *dest, uc_value_t *src); 2086 2087 static void 2088 deep_merge_array(uc_value_t *dest, uc_value_t *src) 2089 { 2090 uc_value_t *e, *v; 2091 size_t i; 2092 2093 if (ucv_type(dest) == UC_ARRAY && ucv_type(src) == UC_ARRAY) { 2094 for (i = 0; i < ucv_array_length(src); i++) { 2095 e = ucv_array_get(dest, i); 2096 v = ucv_array_get(src, i); 2097 2098 if (!e) 2099 ucv_array_set(dest, i, ucv_get(v)); 2100 else if (ucv_type(v) == UC_ARRAY) 2101 deep_merge_array(e, v); 2102 else if (ucv_type(v) == UC_OBJECT) 2103 deep_merge_object(e, v); 2104 } 2105 } 2106 } 2107 2108 static void 2109 deep_merge_object(uc_value_t *dest, uc_value_t *src) 2110 { 2111 uc_value_t *e; 2112 bool exists; 2113 2114 if (ucv_type(dest) == UC_OBJECT && ucv_type(src) == UC_OBJECT) { 2115 ucv_object_foreach(src, k, v) { 2116 e = ucv_object_get(dest, k, &exists); 2117 2118 if (!exists) 2119 ucv_object_add(dest, k, ucv_get(v)); 2120 else if (ucv_type(v) == UC_ARRAY) 2121 deep_merge_array(e, v); 2122 else if (ucv_type(v) == UC_OBJECT) 2123 deep_merge_object(e, v); 2124 } 2125 } 2126 } 2127 2128 static int 2129 cb_reply(struct nl_msg *msg, void *arg) 2130 { 2131 struct nlmsghdr *hdr = nlmsg_hdr(msg); 2132 struct genlmsghdr *gnlh = nlmsg_data(hdr); 2133 request_state_t *s = arg; 2134 uc_value_t *o, *idx; 2135 int64_t i; 2136 bool rv; 2137 2138 o = ucv_object_new(s->vm); 2139 2140 rv = uc_nl_convert_attrs(msg, 2141 genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), 2142 0, s->spec->attrs, s->spec->nattrs, s->vm, o); 2143 2144 if (rv) { 2145 if (hdr->nlmsg_flags & NLM_F_MULTI) { 2146 if (s->merge_phy_info && s->single_phy_info) { 2147 if (!s->res) { 2148 s->res = o; 2149 } 2150 else { 2151 deep_merge_object(s->res, o); 2152 ucv_put(o); 2153 } 2154 } 2155 else if (s->merge_phy_info) { 2156 idx = ucv_object_get(o, "wiphy", NULL); 2157 i = idx ? ucv_int64_get(idx) : -1; 2158 2159 if (i >= 0) { 2160 if (!s->res) 2161 s->res = ucv_array_new(s->vm); 2162 2163 idx = ucv_array_get(s->res, i); 2164 2165 if (idx) { 2166 deep_merge_object(idx, o); 2167 ucv_put(o); 2168 } 2169 else { 2170 ucv_array_set(s->res, i, o); 2171 } 2172 } 2173 } 2174 else { 2175 if (!s->res) 2176 s->res = ucv_array_new(s->vm); 2177 2178 ucv_array_push(s->res, o); 2179 } 2180 } 2181 else { 2182 s->res = o; 2183 } 2184 } 2185 else { 2186 ucv_put(o); 2187 } 2188 2189 s->state = STATE_CONTINUE; 2190 2191 return NL_SKIP; 2192 } 2193 2194 static bool 2195 uc_nl_connect_sock(struct nl_sock **sk, bool nonblocking) 2196 { 2197 int err, fd; 2198 2199 if (*sk) 2200 return true; 2201 2202 *sk = nl_socket_alloc(); 2203 2204 if (!*sk) { 2205 set_error(NLE_NOMEM, NULL); 2206 goto err; 2207 } 2208 2209 err = genl_connect(*sk); 2210 2211 if (err != 0) { 2212 set_error(err, NULL); 2213 goto err; 2214 } 2215 2216 fd = nl_socket_get_fd(*sk); 2217 2218 if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0) { 2219 set_error(NLE_FAILURE, "unable to set FD_CLOEXEC flag on socket: %s", strerror(errno)); 2220 goto err; 2221 } 2222 2223 if (nonblocking) { 2224 err = nl_socket_set_nonblocking(*sk); 2225 2226 if (err != 0) { 2227 set_error(err, NULL); 2228 goto err; 2229 } 2230 } 2231 2232 return true; 2233 2234 err: 2235 if (*sk) { 2236 nl_socket_free(*sk); 2237 *sk = NULL; 2238 } 2239 2240 return false; 2241 } 2242 2243 static int 2244 uc_nl_find_family_id(const char *name) 2245 { 2246 struct genl_family *fam; 2247 2248 if (!nl80211_conn.cache && genl_ctrl_alloc_cache(nl80211_conn.sock, &nl80211_conn.cache)) 2249 return -NLE_NOMEM; 2250 2251 fam = genl_ctrl_search_by_name(nl80211_conn.cache, name); 2252 2253 if (!fam) 2254 return -NLE_OBJ_NOTFOUND; 2255 2256 return genl_family_get_id(fam); 2257 } 2258 2259 static int 2260 cb_errno(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) 2261 { 2262 int *ret = arg; 2263 2264 if (err->error > 0) { 2265 set_error(NLE_RANGE, 2266 "Illegal error code %d in netlink reply", err->error); 2267 2268 *ret = -(NLE_MAX + 1); 2269 } 2270 else { 2271 *ret = -nl_syserr2nlerr(err->error); 2272 } 2273 2274 return NL_STOP; 2275 } 2276 2277 static int 2278 cb_ack(struct nl_msg *msg, void *arg) 2279 { 2280 int *ret = arg; 2281 2282 *ret = 0; 2283 2284 return NL_STOP; 2285 } 2286 2287 static int 2288 cb_subscribe(struct nl_msg *msg, void *arg) 2289 { 2290 struct nlattr *nla, *tb[CTRL_ATTR_MAX + 1], *grp[CTRL_ATTR_MCAST_GRP_MAX + 1]; 2291 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 2292 struct { int id; const char *group; } *ret = arg; 2293 int rem; 2294 2295 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); 2296 2297 if (!tb[CTRL_ATTR_MCAST_GROUPS]) 2298 return NL_SKIP; 2299 2300 nla_for_each_nested(nla, tb[CTRL_ATTR_MCAST_GROUPS], rem) { 2301 nla_parse(grp, CTRL_ATTR_MCAST_GRP_MAX, nla_data(nla), nla_len(nla), NULL); 2302 2303 if (!grp[CTRL_ATTR_MCAST_GRP_NAME] || !grp[CTRL_ATTR_MCAST_GRP_ID]) 2304 continue; 2305 2306 if (strncmp(nla_data(grp[CTRL_ATTR_MCAST_GRP_NAME]), 2307 ret->group, nla_len(grp[CTRL_ATTR_MCAST_GRP_NAME]))) 2308 continue; 2309 2310 ret->id = nla_get_u32(grp[CTRL_ATTR_MCAST_GRP_ID]); 2311 2312 break; 2313 } 2314 2315 return NL_SKIP; 2316 } 2317 2318 static bool 2319 uc_nl_subscribe(struct nl_sock *sk, const char *family, const char *group) 2320 { 2321 struct { int id; const char *group; } grp = { -NLE_OBJ_NOTFOUND, group }; 2322 struct nl_msg *msg; 2323 struct nl_cb *cb; 2324 int id, ret; 2325 2326 if (!uc_nl_connect_sock(&nl80211_conn.sock, false)) 2327 return NULL; 2328 2329 msg = nlmsg_alloc(); 2330 2331 if (!msg) 2332 err_return(NLE_NOMEM, NULL); 2333 2334 id = uc_nl_find_family_id("nlctrl"); 2335 2336 if (id < 0) 2337 err_return(-id, NULL); 2338 2339 genlmsg_put(msg, 0, 0, id, 0, 0, CTRL_CMD_GETFAMILY, 0); 2340 nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family); 2341 2342 cb = nl_cb_alloc(NL_CB_DEFAULT); 2343 2344 if (!cb) { 2345 nlmsg_free(msg); 2346 err_return(NLE_NOMEM, NULL); 2347 } 2348 2349 nl_send_auto_complete(nl80211_conn.sock, msg); 2350 2351 ret = 1; 2352 2353 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, cb_ack, &ret); 2354 nl_cb_err(cb, NL_CB_CUSTOM, cb_errno, &ret); 2355 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_subscribe, &grp); 2356 2357 while (ret > 0) 2358 nl_recvmsgs(nl80211_conn.sock, cb); 2359 2360 nlmsg_free(msg); 2361 nl_cb_put(cb); 2362 2363 if (ret < 0) 2364 err_return(ret, NULL); 2365 2366 if (grp.id < 0) 2367 err_return(grp.id, NULL); 2368 2369 ret = nl_socket_add_membership(sk, grp.id); 2370 2371 if (ret != 0) 2372 err_return(ret, NULL); 2373 2374 return true; 2375 } 2376 2377 2378 struct waitfor_ctx { 2379 uint8_t cmd; 2380 uc_vm_t *vm; 2381 uc_value_t *res; 2382 uint32_t cmds[NL80211_CMDS_BITMAP_SIZE]; 2383 }; 2384 2385 static uc_value_t * 2386 uc_nl_prepare_event(uc_vm_t *vm, struct nl_msg *msg) 2387 { 2388 struct nlmsghdr *hdr = nlmsg_hdr(msg); 2389 struct genlmsghdr *gnlh = nlmsg_data(hdr); 2390 uc_value_t *o = ucv_object_new(vm); 2391 const uc_nl_attr_spec_t *attrs; 2392 size_t nattrs; 2393 2394 if (hdr->nlmsg_type == uc_nl_find_family_id("MAC80211_HWSIM")) { 2395 attrs = hwsim_msg.attrs; 2396 nattrs = hwsim_msg.nattrs; 2397 } 2398 else { 2399 attrs = nl80211_msg.attrs; 2400 nattrs = nl80211_msg.nattrs; 2401 } 2402 2403 if (!uc_nl_convert_attrs(msg, genlmsg_attrdata(gnlh, 0), 2404 genlmsg_attrlen(gnlh, 0), 0, attrs, nattrs, vm, o)) { 2405 ucv_put(o); 2406 return NULL; 2407 } 2408 2409 return o; 2410 } 2411 2412 static int 2413 cb_listener_event(struct nl_msg *msg, void *arg) 2414 { 2415 struct nlmsghdr *hdr = nlmsg_hdr(msg); 2416 struct genlmsghdr *gnlh = nlmsg_data(hdr); 2417 uc_vm_t *vm = listener_vm; 2418 2419 if (!nl80211_conn.evsock_fd.registered || !vm) 2420 return NL_SKIP; 2421 2422 for (size_t i = 0; i < ucv_array_length(listener_registry); i += 2) { 2423 uc_value_t *this = ucv_array_get(listener_registry, i); 2424 uc_value_t *func = ucv_array_get(listener_registry, i + 1); 2425 uc_nl_listener_t *l; 2426 uc_value_t *o, *data; 2427 2428 l = ucv_resource_data(this, "nl80211.listener"); 2429 if (!l) 2430 continue; 2431 2432 if (gnlh->cmd > NL80211_CMD_MAX || 2433 !(l->cmds[gnlh->cmd / 32] & (1 << (gnlh->cmd % 32)))) 2434 continue; 2435 2436 if (!ucv_is_callable(func)) 2437 continue; 2438 2439 data = uc_nl_prepare_event(vm, msg); 2440 if (!data) 2441 return NL_SKIP; 2442 2443 o = ucv_object_new(vm); 2444 ucv_object_add(o, "cmd", ucv_int64_new(gnlh->cmd)); 2445 ucv_object_add(o, "msg", data); 2446 2447 uc_vm_stack_push(vm, ucv_get(this)); 2448 uc_vm_stack_push(vm, ucv_get(func)); 2449 uc_vm_stack_push(vm, o); 2450 2451 if (uc_vm_call(vm, true, 1) != EXCEPTION_NONE) { 2452 uloop_end(); 2453 return NL_STOP; 2454 } 2455 2456 ucv_put(uc_vm_stack_pop(vm)); 2457 } 2458 2459 return NL_SKIP; 2460 } 2461 2462 static int 2463 cb_event(struct nl_msg *msg, void *arg) 2464 { 2465 struct nlmsghdr *hdr = nlmsg_hdr(msg); 2466 struct genlmsghdr *gnlh = nlmsg_data(hdr); 2467 struct waitfor_ctx *s = arg; 2468 uc_value_t *o; 2469 2470 cb_listener_event(msg, arg); 2471 2472 if (gnlh->cmd > NL80211_CMD_MAX || 2473 !(s->cmds[gnlh->cmd / 32] & (1 << (gnlh->cmd % 32)))) 2474 return NL_SKIP; 2475 2476 o = uc_nl_prepare_event(s->vm, msg); 2477 if (o) 2478 s->res = o; 2479 2480 s->cmd = gnlh->cmd; 2481 2482 return NL_SKIP; 2483 } 2484 2485 static int 2486 cb_seq(struct nl_msg *msg, void *arg) 2487 { 2488 return NL_OK; 2489 } 2490 2491 static bool 2492 uc_nl_fill_cmds(uint32_t *cmd_bits, uc_value_t *cmds) 2493 { 2494 if (ucv_type(cmds) == UC_ARRAY) { 2495 for (size_t i = 0; i < ucv_array_length(cmds); i++) { 2496 int64_t n = ucv_int64_get(ucv_array_get(cmds, i)); 2497 2498 if (n >= HWSIM_CMD_OFFSET) 2499 n -= HWSIM_CMD_OFFSET; 2500 2501 if (errno || n < 0 || n > NL80211_CMD_MAX) 2502 return false; 2503 2504 cmd_bits[n / 32] |= (1 << (n % 32)); 2505 } 2506 } 2507 else if (ucv_type(cmds) == UC_INTEGER) { 2508 int64_t n = ucv_int64_get(cmds); 2509 2510 if (n >= HWSIM_CMD_OFFSET) 2511 n -= HWSIM_CMD_OFFSET; 2512 2513 if (errno || n < 0 || n > NL80211_CMD_MAX) 2514 return false; 2515 2516 cmd_bits[n / 32] |= (1 << (n % 32)); 2517 } 2518 else if (!cmds) 2519 memset(cmd_bits, 0xff, NL80211_CMDS_BITMAP_SIZE * sizeof(*cmd_bits)); 2520 else 2521 return false; 2522 2523 return true; 2524 } 2525 2526 static bool 2527 uc_nl_evsock_init(void) 2528 { 2529 if (nl80211_conn.evsock) 2530 return true; 2531 2532 if (!uc_nl_connect_sock(&nl80211_conn.evsock, true)) 2533 return false; 2534 2535 if (!uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "config") || 2536 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "scan") || 2537 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "regulatory") || 2538 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "mlme") || 2539 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "vendor") || 2540 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "nan")) { 2541 nl_socket_free(nl80211_conn.evsock); 2542 nl80211_conn.evsock = NULL; 2543 return false; 2544 } 2545 2546 return true; 2547 } 2548 2549 static uc_value_t * 2550 uc_nl_waitfor(uc_vm_t *vm, size_t nargs) 2551 { 2552 struct pollfd pfd = { .events = POLLIN }; 2553 uc_value_t *cmds = uc_fn_arg(0); 2554 uc_value_t *timeout = uc_fn_arg(1); 2555 uc_value_t *rv = NULL; 2556 struct waitfor_ctx ctx = { .vm = vm }; 2557 struct nl_cb *cb; 2558 int ms = -1, err; 2559 2560 if (timeout) { 2561 int64_t n = ucv_int64_get(timeout); 2562 2563 if (ucv_type(timeout) != UC_INTEGER || n < INT32_MIN || n > INT32_MAX) 2564 err_return(NLE_INVAL, "Invalid timeout specified"); 2565 2566 ms = (int)n; 2567 } 2568 2569 if (!uc_nl_fill_cmds(ctx.cmds, cmds)) 2570 err_return(NLE_INVAL, "Invalid command ID specified"); 2571 2572 if (!uc_nl_evsock_init()) 2573 return NULL; 2574 2575 cb = nl_cb_alloc(NL_CB_DEFAULT); 2576 2577 if (!cb) 2578 err_return(NLE_NOMEM, NULL); 2579 2580 err = 0; 2581 2582 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, cb_seq, NULL); 2583 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_event, &ctx); 2584 nl_cb_err(cb, NL_CB_CUSTOM, cb_errno, &err); 2585 2586 pfd.fd = nl_socket_get_fd(nl80211_conn.evsock); 2587 2588 if (poll(&pfd, 1, ms) == 1) { 2589 while (err == 0 && ctx.cmd == 0) 2590 nl_recvmsgs(nl80211_conn.evsock, cb); 2591 } 2592 2593 nl_cb_put(cb); 2594 2595 if (ctx.cmd) { 2596 rv = ucv_object_new(vm); 2597 2598 ucv_object_add(rv, "cmd", ucv_int64_new(ctx.cmd)); 2599 ucv_object_add(rv, "msg", ctx.res); 2600 2601 return rv; 2602 } 2603 else if (err) { 2604 err_return(err, NULL); 2605 } 2606 else { 2607 err_return(NLE_FAILURE, "No event received"); 2608 } 2609 } 2610 2611 static uc_value_t * 2612 uc_nl_request_common(struct nl_sock *sock, uc_vm_t *vm, size_t nargs) 2613 { 2614 request_state_t st = { .vm = vm }; 2615 uc_value_t *cmd = uc_fn_arg(0); 2616 uc_value_t *flags = uc_fn_arg(1); 2617 uc_value_t *payload = uc_fn_arg(2); 2618 uint16_t flagval = 0; 2619 struct nl_msg *msg; 2620 struct nl_cb *cb; 2621 int ret, id, cid; 2622 2623 if (ucv_type(cmd) != UC_INTEGER || ucv_int64_get(cmd) < 0 || 2624 (flags != NULL && ucv_type(flags) != UC_INTEGER) || 2625 (payload != NULL && ucv_type(payload) != UC_OBJECT)) 2626 err_return(NLE_INVAL, NULL); 2627 2628 if (flags) { 2629 if (ucv_int64_get(flags) < 0 || ucv_int64_get(flags) > 0xffff) 2630 err_return(NLE_INVAL, NULL); 2631 else 2632 flagval = (uint16_t)ucv_int64_get(flags); 2633 } 2634 2635 msg = nlmsg_alloc(); 2636 2637 if (!msg) 2638 err_return(NLE_NOMEM, NULL); 2639 2640 cid = ucv_int64_get(cmd); 2641 2642 if (cid >= HWSIM_CMD_OFFSET) { 2643 id = uc_nl_find_family_id("MAC80211_HWSIM"); 2644 cid -= HWSIM_CMD_OFFSET; 2645 st.spec = &hwsim_msg; 2646 } 2647 else if (cid == NL80211_CMD_GET_WIPHY) { 2648 id = uc_nl_find_family_id("nl80211"); 2649 st.spec = &nl80211_msg; 2650 st.merge_phy_info = true; 2651 2652 if (ucv_object_get(payload, "wiphy", NULL) != NULL) 2653 st.single_phy_info = true; 2654 2655 if (ucv_is_truish(ucv_object_get(payload, "split_wiphy_dump", NULL))) 2656 flagval |= NLM_F_DUMP; 2657 } 2658 else { 2659 id = uc_nl_find_family_id("nl80211"); 2660 st.spec = &nl80211_msg; 2661 } 2662 2663 if (id < 0) 2664 err_return(-id, NULL); 2665 2666 genlmsg_put(msg, 0, 0, id, 0, flagval, cid, 0); 2667 2668 if (!uc_nl_parse_attrs(msg, nlmsg_data(nlmsg_hdr(msg)), st.spec->attrs, st.spec->nattrs, vm, payload)) { 2669 nlmsg_free(msg); 2670 2671 return NULL; 2672 } 2673 2674 cb = nl_cb_alloc(NL_CB_DEFAULT); 2675 2676 if (!cb) { 2677 nlmsg_free(msg); 2678 err_return(NLE_NOMEM, NULL); 2679 } 2680 2681 ret = 1; 2682 2683 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_reply, &st); 2684 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_done, &st); 2685 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, cb_done, &st); 2686 nl_cb_err(cb, NL_CB_CUSTOM, cb_errno, &ret); 2687 2688 nl_send_auto_complete(sock, msg); 2689 2690 while (ret > 0 && st.state < STATE_REPLIED) 2691 nl_recvmsgs(sock, cb); 2692 2693 nlmsg_free(msg); 2694 nl_cb_put(cb); 2695 2696 if (ret < 0) 2697 err_return(ret, NULL); 2698 2699 switch (st.state) { 2700 case STATE_REPLIED: 2701 return st.res; 2702 2703 case STATE_UNREPLIED: 2704 return ucv_boolean_new(true); 2705 2706 default: 2707 set_error(NLE_FAILURE, "Interrupted reply"); 2708 2709 return ucv_boolean_new(false); 2710 } 2711 } 2712 2713 static uc_value_t * 2714 uc_nl_request(uc_vm_t *vm, size_t nargs) 2715 { 2716 if (!uc_nl_connect_sock(&nl80211_conn.sock, false)) 2717 return NULL; 2718 2719 return uc_nl_request_common(nl80211_conn.sock, vm, nargs); 2720 } 2721 2722 static void 2723 uc_nl_listener_cb(struct uloop_fd *fd, unsigned int events) 2724 { 2725 while (nl_recvmsgs(nl80211_conn.evsock, nl80211_conn.evsock_cb) == 0) 2726 ; 2727 } 2728 2729 static uc_value_t * 2730 uc_nl_listener(uc_vm_t *vm, size_t nargs) 2731 { 2732 struct uloop_fd *fd = &nl80211_conn.evsock_fd; 2733 uc_nl_listener_t *l; 2734 uc_value_t *cb_func = uc_fn_arg(0); 2735 uc_value_t *cmds = uc_fn_arg(1); 2736 uc_value_t *rv; 2737 size_t i; 2738 2739 if (!ucv_is_callable(cb_func)) { 2740 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid callback"); 2741 return NULL; 2742 } 2743 2744 if (!uc_nl_evsock_init()) 2745 return NULL; 2746 2747 if (!fd->registered) { 2748 fd->fd = nl_socket_get_fd(nl80211_conn.evsock); 2749 fd->cb = uc_nl_listener_cb; 2750 uloop_fd_add(fd, ULOOP_READ); 2751 } 2752 2753 if (!nl80211_conn.evsock_cb) { 2754 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT); 2755 2756 if (!cb) 2757 err_return(NLE_NOMEM, NULL); 2758 2759 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, cb_seq, NULL); 2760 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_listener_event, NULL); 2761 nl80211_conn.evsock_cb = cb; 2762 } 2763 2764 for (i = 0; i < ucv_array_length(listener_registry); i += 2) { 2765 if (!ucv_array_get(listener_registry, i)) 2766 break; 2767 } 2768 2769 ucv_array_set(listener_registry, i + 1, ucv_get(cb_func)); 2770 l = xalloc(sizeof(*l)); 2771 l->index = i; 2772 if (!uc_nl_fill_cmds(l->cmds, cmds)) { 2773 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid command ID"); 2774 free(l); 2775 return NULL; 2776 } 2777 2778 rv = uc_resource_new(listener_type, l); 2779 ucv_array_set(listener_registry, i, ucv_get(rv)); 2780 listener_vm = vm; 2781 2782 return rv; 2783 } 2784 2785 static void 2786 uc_nl_listener_free(void *arg) 2787 { 2788 uc_nl_listener_t *l = arg; 2789 2790 ucv_array_set(listener_registry, l->index, NULL); 2791 ucv_array_set(listener_registry, l->index + 1, NULL); 2792 free(l); 2793 } 2794 2795 static uc_value_t * 2796 uc_nl_listener_set_commands(uc_vm_t *vm, size_t nargs) 2797 { 2798 uc_nl_listener_t *l = uc_fn_thisval("nl80211.listener"); 2799 uc_value_t *cmds = uc_fn_arg(0); 2800 2801 if (!l) 2802 return NULL; 2803 2804 memset(l->cmds, 0, sizeof(l->cmds)); 2805 if (!uc_nl_fill_cmds(l->cmds, cmds)) 2806 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid command ID"); 2807 2808 return NULL; 2809 } 2810 2811 static uc_value_t * 2812 uc_nl_listener_request(uc_vm_t *vm, size_t nargs) 2813 { 2814 return uc_nl_request_common(nl80211_conn.evsock, vm, nargs); 2815 } 2816 2817 static uc_value_t * 2818 uc_nl_listener_close(uc_vm_t *vm, size_t nargs) 2819 { 2820 uc_nl_listener_t **lptr = uc_fn_this("nl80211.listener"); 2821 uc_nl_listener_t *l; 2822 2823 if (!lptr) 2824 return NULL; 2825 2826 l = *lptr; 2827 if (!l) 2828 return NULL; 2829 2830 *lptr = NULL; 2831 uc_nl_listener_free(l); 2832 2833 return NULL; 2834 } 2835 2836 2837 static void 2838 register_constants(uc_vm_t *vm, uc_value_t *scope) 2839 { 2840 uc_value_t *c = ucv_object_new(vm); 2841 2842 #define ADD_CONST(x) ucv_object_add(c, #x, ucv_int64_new(x)) 2843 2844 ADD_CONST(NLM_F_ACK); 2845 ADD_CONST(NLM_F_ACK_TLVS); 2846 ADD_CONST(NLM_F_APPEND); 2847 ADD_CONST(NLM_F_ATOMIC); 2848 ADD_CONST(NLM_F_CAPPED); 2849 ADD_CONST(NLM_F_CREATE); 2850 ADD_CONST(NLM_F_DUMP); 2851 ADD_CONST(NLM_F_DUMP_FILTERED); 2852 ADD_CONST(NLM_F_DUMP_INTR); 2853 ADD_CONST(NLM_F_ECHO); 2854 ADD_CONST(NLM_F_EXCL); 2855 ADD_CONST(NLM_F_MATCH); 2856 ADD_CONST(NLM_F_MULTI); 2857 ADD_CONST(NLM_F_NONREC); 2858 ADD_CONST(NLM_F_REPLACE); 2859 ADD_CONST(NLM_F_REQUEST); 2860 ADD_CONST(NLM_F_ROOT); 2861 2862 ADD_CONST(NL80211_CMD_GET_WIPHY); 2863 ADD_CONST(NL80211_CMD_SET_WIPHY); 2864 ADD_CONST(NL80211_CMD_NEW_WIPHY); 2865 ADD_CONST(NL80211_CMD_DEL_WIPHY); 2866 ADD_CONST(NL80211_CMD_GET_INTERFACE); 2867 ADD_CONST(NL80211_CMD_SET_INTERFACE); 2868 ADD_CONST(NL80211_CMD_NEW_INTERFACE); 2869 ADD_CONST(NL80211_CMD_DEL_INTERFACE); 2870 ADD_CONST(NL80211_CMD_GET_KEY); 2871 ADD_CONST(NL80211_CMD_SET_KEY); 2872 ADD_CONST(NL80211_CMD_NEW_KEY); 2873 ADD_CONST(NL80211_CMD_DEL_KEY); 2874 ADD_CONST(NL80211_CMD_GET_BEACON); 2875 ADD_CONST(NL80211_CMD_SET_BEACON); 2876 ADD_CONST(NL80211_CMD_START_AP); 2877 ADD_CONST(NL80211_CMD_NEW_BEACON); 2878 ADD_CONST(NL80211_CMD_STOP_AP); 2879 ADD_CONST(NL80211_CMD_DEL_BEACON); 2880 ADD_CONST(NL80211_CMD_GET_STATION); 2881 ADD_CONST(NL80211_CMD_SET_STATION); 2882 ADD_CONST(NL80211_CMD_NEW_STATION); 2883 ADD_CONST(NL80211_CMD_DEL_STATION); 2884 ADD_CONST(NL80211_CMD_GET_MPATH); 2885 ADD_CONST(NL80211_CMD_SET_MPATH); 2886 ADD_CONST(NL80211_CMD_NEW_MPATH); 2887 ADD_CONST(NL80211_CMD_DEL_MPATH); 2888 ADD_CONST(NL80211_CMD_SET_BSS); 2889 ADD_CONST(NL80211_CMD_SET_REG); 2890 ADD_CONST(NL80211_CMD_REQ_SET_REG); 2891 ADD_CONST(NL80211_CMD_GET_MESH_CONFIG); 2892 ADD_CONST(NL80211_CMD_SET_MESH_CONFIG); 2893 ADD_CONST(NL80211_CMD_GET_REG); 2894 ADD_CONST(NL80211_CMD_GET_SCAN); 2895 ADD_CONST(NL80211_CMD_TRIGGER_SCAN); 2896 ADD_CONST(NL80211_CMD_NEW_SCAN_RESULTS); 2897 ADD_CONST(NL80211_CMD_SCAN_ABORTED); 2898 ADD_CONST(NL80211_CMD_REG_CHANGE); 2899 ADD_CONST(NL80211_CMD_AUTHENTICATE); 2900 ADD_CONST(NL80211_CMD_ASSOCIATE); 2901 ADD_CONST(NL80211_CMD_DEAUTHENTICATE); 2902 ADD_CONST(NL80211_CMD_DISASSOCIATE); 2903 ADD_CONST(NL80211_CMD_MICHAEL_MIC_FAILURE); 2904 ADD_CONST(NL80211_CMD_REG_BEACON_HINT); 2905 ADD_CONST(NL80211_CMD_JOIN_IBSS); 2906 ADD_CONST(NL80211_CMD_LEAVE_IBSS); 2907 ADD_CONST(NL80211_CMD_TESTMODE); 2908 ADD_CONST(NL80211_CMD_CONNECT); 2909 ADD_CONST(NL80211_CMD_ROAM); 2910 ADD_CONST(NL80211_CMD_DISCONNECT); 2911 ADD_CONST(NL80211_CMD_SET_WIPHY_NETNS); 2912 ADD_CONST(NL80211_CMD_GET_SURVEY); 2913 ADD_CONST(NL80211_CMD_NEW_SURVEY_RESULTS); 2914 ADD_CONST(NL80211_CMD_SET_PMKSA); 2915 ADD_CONST(NL80211_CMD_DEL_PMKSA); 2916 ADD_CONST(NL80211_CMD_FLUSH_PMKSA); 2917 ADD_CONST(NL80211_CMD_REMAIN_ON_CHANNEL); 2918 ADD_CONST(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL); 2919 ADD_CONST(NL80211_CMD_SET_TX_BITRATE_MASK); 2920 ADD_CONST(NL80211_CMD_REGISTER_FRAME); 2921 ADD_CONST(NL80211_CMD_REGISTER_ACTION); 2922 ADD_CONST(NL80211_CMD_FRAME); 2923 ADD_CONST(NL80211_CMD_ACTION); 2924 ADD_CONST(NL80211_CMD_FRAME_TX_STATUS); 2925 ADD_CONST(NL80211_CMD_ACTION_TX_STATUS); 2926 ADD_CONST(NL80211_CMD_SET_POWER_SAVE); 2927 ADD_CONST(NL80211_CMD_GET_POWER_SAVE); 2928 ADD_CONST(NL80211_CMD_SET_CQM); 2929 ADD_CONST(NL80211_CMD_NOTIFY_CQM); 2930 ADD_CONST(NL80211_CMD_SET_CHANNEL); 2931 ADD_CONST(NL80211_CMD_SET_WDS_PEER); 2932 ADD_CONST(NL80211_CMD_FRAME_WAIT_CANCEL); 2933 ADD_CONST(NL80211_CMD_JOIN_MESH); 2934 ADD_CONST(NL80211_CMD_LEAVE_MESH); 2935 ADD_CONST(NL80211_CMD_UNPROT_DEAUTHENTICATE); 2936 ADD_CONST(NL80211_CMD_UNPROT_DISASSOCIATE); 2937 ADD_CONST(NL80211_CMD_NEW_PEER_CANDIDATE); 2938 ADD_CONST(NL80211_CMD_GET_WOWLAN); 2939 ADD_CONST(NL80211_CMD_SET_WOWLAN); 2940 ADD_CONST(NL80211_CMD_START_SCHED_SCAN); 2941 ADD_CONST(NL80211_CMD_STOP_SCHED_SCAN); 2942 ADD_CONST(NL80211_CMD_SCHED_SCAN_RESULTS); 2943 ADD_CONST(NL80211_CMD_SCHED_SCAN_STOPPED); 2944 ADD_CONST(NL80211_CMD_SET_REKEY_OFFLOAD); 2945 ADD_CONST(NL80211_CMD_PMKSA_CANDIDATE); 2946 ADD_CONST(NL80211_CMD_TDLS_OPER); 2947 ADD_CONST(NL80211_CMD_TDLS_MGMT); 2948 ADD_CONST(NL80211_CMD_UNEXPECTED_FRAME); 2949 ADD_CONST(NL80211_CMD_PROBE_CLIENT); 2950 ADD_CONST(NL80211_CMD_REGISTER_BEACONS); 2951 ADD_CONST(NL80211_CMD_UNEXPECTED_4ADDR_FRAME); 2952 ADD_CONST(NL80211_CMD_SET_NOACK_MAP); 2953 ADD_CONST(NL80211_CMD_CH_SWITCH_NOTIFY); 2954 ADD_CONST(NL80211_CMD_START_P2P_DEVICE); 2955 ADD_CONST(NL80211_CMD_STOP_P2P_DEVICE); 2956 ADD_CONST(NL80211_CMD_CONN_FAILED); 2957 ADD_CONST(NL80211_CMD_SET_MCAST_RATE); 2958 ADD_CONST(NL80211_CMD_SET_MAC_ACL); 2959 ADD_CONST(NL80211_CMD_RADAR_DETECT); 2960 ADD_CONST(NL80211_CMD_GET_PROTOCOL_FEATURES); 2961 ADD_CONST(NL80211_CMD_UPDATE_FT_IES); 2962 ADD_CONST(NL80211_CMD_FT_EVENT); 2963 ADD_CONST(NL80211_CMD_CRIT_PROTOCOL_START); 2964 ADD_CONST(NL80211_CMD_CRIT_PROTOCOL_STOP); 2965 ADD_CONST(NL80211_CMD_GET_COALESCE); 2966 ADD_CONST(NL80211_CMD_SET_COALESCE); 2967 ADD_CONST(NL80211_CMD_CHANNEL_SWITCH); 2968 ADD_CONST(NL80211_CMD_VENDOR); 2969 ADD_CONST(NL80211_CMD_SET_QOS_MAP); 2970 ADD_CONST(NL80211_CMD_ADD_TX_TS); 2971 ADD_CONST(NL80211_CMD_DEL_TX_TS); 2972 ADD_CONST(NL80211_CMD_GET_MPP); 2973 ADD_CONST(NL80211_CMD_JOIN_OCB); 2974 ADD_CONST(NL80211_CMD_LEAVE_OCB); 2975 ADD_CONST(NL80211_CMD_CH_SWITCH_STARTED_NOTIFY); 2976 ADD_CONST(NL80211_CMD_TDLS_CHANNEL_SWITCH); 2977 ADD_CONST(NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH); 2978 2979 ADD_CONST(HWSIM_CMD_REGISTER), 2980 ADD_CONST(HWSIM_CMD_FRAME), 2981 ADD_CONST(HWSIM_CMD_TX_INFO_FRAME), 2982 ADD_CONST(HWSIM_CMD_NEW_RADIO), 2983 ADD_CONST(HWSIM_CMD_DEL_RADIO), 2984 ADD_CONST(HWSIM_CMD_GET_RADIO), 2985 ADD_CONST(HWSIM_CMD_ADD_MAC_ADDR), 2986 ADD_CONST(HWSIM_CMD_DEL_MAC_ADDR), 2987 ADD_CONST(HWSIM_CMD_START_PMSR), 2988 ADD_CONST(HWSIM_CMD_ABORT_PMSR), 2989 ADD_CONST(HWSIM_CMD_REPORT_PMSR), 2990 2991 ADD_CONST(NL80211_IFTYPE_ADHOC); 2992 ADD_CONST(NL80211_IFTYPE_STATION); 2993 ADD_CONST(NL80211_IFTYPE_AP); 2994 ADD_CONST(NL80211_IFTYPE_AP_VLAN); 2995 ADD_CONST(NL80211_IFTYPE_WDS); 2996 ADD_CONST(NL80211_IFTYPE_MONITOR); 2997 ADD_CONST(NL80211_IFTYPE_MESH_POINT); 2998 ADD_CONST(NL80211_IFTYPE_P2P_CLIENT); 2999 ADD_CONST(NL80211_IFTYPE_P2P_GO); 3000 ADD_CONST(NL80211_IFTYPE_P2P_DEVICE); 3001 ADD_CONST(NL80211_IFTYPE_OCB); 3002 3003 ucv_object_add(scope, "const", c); 3004 }; 3005 3006 static const uc_function_list_t global_fns[] = { 3007 { "error", uc_nl_error }, 3008 { "request", uc_nl_request }, 3009 { "waitfor", uc_nl_waitfor }, 3010 { "listener", uc_nl_listener }, 3011 }; 3012 3013 3014 static const uc_function_list_t listener_fns[] = { 3015 { "set_commands", uc_nl_listener_set_commands }, 3016 { "request", uc_nl_listener_request }, 3017 { "close", uc_nl_listener_close }, 3018 }; 3019 3020 void uc_module_init(uc_vm_t *vm, uc_value_t *scope) 3021 { 3022 uc_function_list_register(scope, global_fns); 3023 3024 listener_type = uc_type_declare(vm, "nl80211.listener", listener_fns, uc_nl_listener_free); 3025 listener_registry = ucv_array_new(vm); 3026 3027 uc_vm_registry_set(vm, "nl80211.registry", listener_registry); 3028 3029 register_constants(vm, scope); 3030 } 3031
This page was automatically generated by LXR 0.3.1. • OpenWrt