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