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