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