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