1 /* 2 Copyright 2021 Jo-Philipp Wich <jo@mein.io> 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #include <stdio.h> 18 #include <stdint.h> 19 #include <stdbool.h> 20 #include <stdarg.h> 21 #include <unistd.h> 22 #include <errno.h> 23 #include <string.h> 24 #include <limits.h> 25 #include <math.h> 26 #include <assert.h> 27 #include <endian.h> 28 #include <fcntl.h> 29 #include <poll.h> 30 31 #include <net/if.h> 32 #include <netinet/ether.h> 33 #include <arpa/inet.h> 34 #include <netlink/msg.h> 35 #include <netlink/attr.h> 36 #include <netlink/socket.h> 37 #include <netlink/genl/genl.h> 38 #include <netlink/genl/family.h> 39 #include <netlink/genl/ctrl.h> 40 41 #include <linux/nl80211.h> 42 #include <linux/ieee80211.h> 43 #include <libubox/uloop.h> 44 45 #include "ucode/module.h" 46 47 #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) 48 49 #define err_return(code, ...) do { set_error(code, __VA_ARGS__); return NULL; } while(0) 50 51 /* Modified downstream nl80211.h headers may disable certain unsupported 52 * attributes by setting the corresponding defines to 0x10000 without having 53 * to patch the attribute dictionaries within this file. */ 54 55 #define NL80211_ATTR_NOT_IMPLEMENTED 0x10000 56 57 #define NL80211_CMDS_BITMAP_SIZE DIV_ROUND_UP(NL80211_CMD_MAX + 1, 32) 58 59 static struct { 60 int code; 61 char *msg; 62 } last_error; 63 64 __attribute__((format(printf, 2, 3))) static void 65 set_error(int errcode, const char *fmt, ...) { 66 va_list ap; 67 68 free(last_error.msg); 69 70 last_error.code = errcode; 71 last_error.msg = NULL; 72 73 if (fmt) { 74 va_start(ap, fmt); 75 xvasprintf(&last_error.msg, fmt, ap); 76 va_end(ap); 77 } 78 } 79 80 static uc_resource_type_t *listener_type; 81 static uc_value_t *listener_registry; 82 static uc_vm_t *listener_vm; 83 84 typedef struct { 85 uint32_t cmds[NL80211_CMDS_BITMAP_SIZE]; 86 size_t index; 87 } uc_nl_listener_t; 88 89 static bool 90 uc_nl_parse_u32(uc_value_t *val, uint32_t *n) 91 { 92 uint64_t u; 93 94 u = ucv_to_unsigned(val); 95 96 if (errno != 0 || u > UINT32_MAX) 97 return false; 98 99 *n = (uint32_t)u; 100 101 return true; 102 } 103 104 static bool 105 uc_nl_parse_s32(uc_value_t *val, uint32_t *n) 106 { 107 int64_t i; 108 109 i = ucv_to_integer(val); 110 111 if (errno != 0 || i < INT32_MIN || i > INT32_MAX) 112 return false; 113 114 *n = (uint32_t)i; 115 116 return true; 117 } 118 119 static bool 120 uc_nl_parse_u64(uc_value_t *val, uint64_t *n) 121 { 122 *n = ucv_to_unsigned(val); 123 124 return (errno == 0); 125 } 126 127 static bool 128 uc_nl_parse_ipaddr(uc_vm_t *vm, uc_value_t *val, struct in_addr *in) 129 { 130 char *s = ucv_to_string(vm, val); 131 bool valid = true; 132 133 if (!s) 134 return false; 135 136 valid = (inet_pton(AF_INET, s, in) == 1); 137 138 free(s); 139 140 return valid; 141 } 142 143 typedef enum { 144 DT_FLAG, 145 DT_BOOL, 146 DT_U8, 147 DT_S8, 148 DT_U16, 149 DT_U32, 150 DT_S32, 151 DT_U64, 152 DT_STRING, 153 DT_NETDEV, 154 DT_LLADDR, 155 DT_INADDR, 156 DT_NESTED, 157 DT_HT_MCS, 158 DT_HT_CAP, 159 DT_VHT_MCS, 160 DT_HE_MCS, 161 DT_IE, 162 } uc_nl_attr_datatype_t; 163 164 enum { 165 DF_NO_SET = (1 << 0), 166 DF_MULTIPLE = (1 << 1), 167 DF_AUTOIDX = (1 << 2), 168 DF_TYPEIDX = (1 << 3), 169 DF_OFFSET1 = (1 << 4), 170 DF_ARRAY = (1 << 5), 171 DF_BINARY = (1 << 6), 172 }; 173 174 typedef struct uc_nl_attr_spec { 175 size_t attr; 176 const char *key; 177 uc_nl_attr_datatype_t type; 178 uint32_t flags; 179 const void *auxdata; 180 } uc_nl_attr_spec_t; 181 182 typedef struct uc_nl_nested_spec { 183 size_t headsize; 184 size_t nattrs; 185 const uc_nl_attr_spec_t attrs[]; 186 } uc_nl_nested_spec_t; 187 188 #define SIZE(type) (void *)(uintptr_t)sizeof(struct type) 189 #define MEMBER(type, field) (void *)(uintptr_t)offsetof(struct type, field) 190 191 static const uc_nl_nested_spec_t nl80211_cqm_nla = { 192 .headsize = 0, 193 .nattrs = 5, 194 .attrs = { 195 { NL80211_ATTR_CQM_PKT_LOSS_EVENT, "cqm_pkt_loss_event", DT_U32, 0, NULL }, 196 { NL80211_ATTR_CQM_RSSI_HYST, "cqm_rssi_hyst", DT_U32, 0, NULL }, 197 { NL80211_ATTR_CQM_RSSI_LEVEL, "cqm_rssi_level", DT_S32, 0, NULL }, 198 { NL80211_ATTR_CQM_RSSI_THOLD, "cqm_rssi_thold", DT_U32, 0, NULL }, 199 { NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, "cqm_rssi_threshold_event", DT_U32, 0, NULL }, 200 } 201 }; 202 203 static const uc_nl_nested_spec_t nl80211_ftm_responder_stats_nla = { 204 .headsize = 0, 205 .nattrs = 9, 206 .attrs = { 207 { NL80211_FTM_STATS_SUCCESS_NUM, "success_num", DT_U32, 0, NULL }, 208 { NL80211_FTM_STATS_PARTIAL_NUM, "partial_num", DT_U32, 0, NULL }, 209 { NL80211_FTM_STATS_FAILED_NUM, "failed_num", DT_U32, 0, NULL }, 210 { NL80211_FTM_STATS_ASAP_NUM, "asap_num", DT_U32, 0, NULL }, 211 { NL80211_FTM_STATS_NON_ASAP_NUM, "non_asap_num", DT_U32, 0, NULL }, 212 { NL80211_FTM_STATS_TOTAL_DURATION_MSEC, "total_duration_msec", DT_U64, 0, NULL }, 213 { NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM, "unknown_triggers_num", DT_U32, 0, NULL }, 214 { NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM, "reschedule_requests_num", DT_U32, 0, NULL }, 215 { NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM, "out_of_window_triggers_num", DT_U32, 0, NULL }, 216 } 217 }; 218 219 static const uc_nl_nested_spec_t nl80211_ifcomb_limit_types_nla = { 220 .headsize = 0, 221 .nattrs = 12, 222 .attrs = { 223 { 1, "ibss", DT_FLAG, 0, NULL }, 224 { 2, "managed", DT_FLAG, 0, NULL }, 225 { 3, "ap", DT_FLAG, 0, NULL }, 226 { 4, "ap_vlan", DT_FLAG, 0, NULL }, 227 { 5, "wds", DT_FLAG, 0, NULL }, 228 { 6, "monitor", DT_FLAG, 0, NULL }, 229 { 7, "mesh_point", DT_FLAG, 0, NULL }, 230 { 8, "p2p_client", DT_FLAG, 0, NULL }, 231 { 9, "p2p_go", DT_FLAG, 0, NULL }, 232 { 10, "p2p_device", DT_FLAG, 0, NULL }, 233 { 11, "outside_bss_context", DT_FLAG, 0, NULL }, 234 { 12, "nan", DT_FLAG, 0, NULL }, 235 } 236 }; 237 238 static const uc_nl_nested_spec_t nl80211_ifcomb_limits_nla = { 239 .headsize = 0, 240 .nattrs = 2, 241 .attrs = { 242 { NL80211_IFACE_LIMIT_TYPES, "types", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla }, 243 { NL80211_IFACE_LIMIT_MAX, "max", DT_U32, 0, NULL }, 244 } 245 }; 246 247 static const uc_nl_nested_spec_t nl80211_ifcomb_nla = { 248 .headsize = 0, 249 .nattrs = 5, 250 .attrs = { 251 { NL80211_IFACE_COMB_LIMITS, "limits", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_ifcomb_limits_nla }, 252 { NL80211_IFACE_COMB_MAXNUM, "maxnum", DT_U32, 0, NULL }, 253 { NL80211_IFACE_COMB_STA_AP_BI_MATCH, "sta_ap_bi_match", DT_FLAG, 0, NULL }, 254 { NL80211_IFACE_COMB_NUM_CHANNELS, "num_channels", DT_U32, 0, NULL }, 255 { NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, "radar_detect_widths", DT_U32, 0, NULL }, 256 } 257 }; 258 259 static const uc_nl_nested_spec_t nl80211_ftm_responder_nla = { 260 .headsize = 0, 261 .nattrs = 3, 262 .attrs = { 263 { NL80211_FTM_RESP_ATTR_ENABLED, "enabled", DT_FLAG, 0, NULL }, 264 { NL80211_FTM_RESP_ATTR_LCI, "lci", DT_STRING, DF_BINARY, NULL }, 265 { NL80211_FTM_RESP_ATTR_CIVICLOC, "civicloc", DT_STRING, DF_BINARY, NULL }, 266 } 267 }; 268 269 static const uc_nl_nested_spec_t nl80211_keys_nla = { 270 .headsize = 0, 271 .nattrs = 4, 272 .attrs = { 273 { NL80211_KEY_DEFAULT, "default", DT_FLAG, 0, NULL }, 274 { NL80211_KEY_IDX, "idx", DT_U8, 0, NULL }, 275 { NL80211_KEY_CIPHER, "cipher", DT_U32, 0, NULL }, 276 { NL80211_KEY_DATA, "data", DT_STRING, DF_BINARY, NULL }, 277 } 278 }; 279 280 static const uc_nl_nested_spec_t nl80211_mesh_params_nla = { 281 .headsize = 0, 282 .nattrs = 29, 283 .attrs = { 284 { NL80211_MESHCONF_RETRY_TIMEOUT, "retry_timeout", DT_U16, 0, NULL }, 285 { NL80211_MESHCONF_CONFIRM_TIMEOUT, "confirm_timeout", DT_U16, 0, NULL }, 286 { NL80211_MESHCONF_HOLDING_TIMEOUT, "holding_timeout", DT_U16, 0, NULL }, 287 { NL80211_MESHCONF_MAX_PEER_LINKS, "max_peer_links", DT_U16, 0, NULL }, 288 { NL80211_MESHCONF_MAX_RETRIES, "max_retries", DT_U8, 0, NULL }, 289 { NL80211_MESHCONF_TTL, "ttl", DT_U8, 0, NULL }, 290 { NL80211_MESHCONF_ELEMENT_TTL, "element_ttl", DT_U8, 0, NULL }, 291 { NL80211_MESHCONF_AUTO_OPEN_PLINKS, "auto_open_plinks", DT_BOOL, 0, NULL }, 292 { NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, "hwmp_max_preq_retries", DT_U8, 0, NULL }, 293 { NL80211_MESHCONF_PATH_REFRESH_TIME, "path_refresh_time", DT_U32, 0, NULL }, 294 { NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, "min_discovery_timeout", DT_U16, 0, NULL }, 295 { NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, "hwmp_active_path_timeout", DT_U32, 0, NULL }, 296 { NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, "hwmp_preq_min_interval", DT_U16, 0, NULL }, 297 { NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, "hwmp_net_diam_trvs_time", DT_U16, 0, NULL }, 298 { NL80211_MESHCONF_HWMP_ROOTMODE, "hwmp_rootmode", DT_U8, 0, NULL }, 299 { NL80211_MESHCONF_HWMP_RANN_INTERVAL, "hwmp_rann_interval", DT_U16, 0, NULL }, 300 { NL80211_MESHCONF_GATE_ANNOUNCEMENTS, "gate_announcements", DT_U8, 0, NULL }, 301 { NL80211_MESHCONF_FORWARDING, "forwarding", DT_BOOL, 0, NULL }, 302 { NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, "sync_offset_max_neighbor", DT_U32, 0, NULL }, 303 { NL80211_MESHCONF_RSSI_THRESHOLD, "rssi_threshold", DT_S32, 0, NULL }, 304 { NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, "hwmp_path_to_root_timeout", DT_U32, 0, NULL }, 305 { NL80211_MESHCONF_HWMP_ROOT_INTERVAL, "hwmp_root_interval", DT_U16, 0, NULL }, 306 { NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, "hwmp_confirmation_interval", DT_U16, 0, NULL }, 307 { NL80211_MESHCONF_POWER_MODE, "power_mode", DT_U32, 0, NULL }, 308 { NL80211_MESHCONF_AWAKE_WINDOW, "awake_window", DT_U16, 0, NULL }, 309 { NL80211_MESHCONF_PLINK_TIMEOUT, "plink_timeout", DT_U32, 0, NULL }, 310 { NL80211_MESHCONF_CONNECTED_TO_GATE, "connected_to_gate", DT_BOOL, 0, NULL }, 311 { NL80211_MESHCONF_NOLEARN, "nolearn", DT_BOOL, 0, NULL }, 312 { NL80211_MESHCONF_CONNECTED_TO_AS, "connected_to_as", DT_BOOL, 0, NULL }, 313 } 314 }; 315 316 static const uc_nl_nested_spec_t nl80211_mesh_setup_nla = { 317 .headsize = 0, 318 .nattrs = 1, 319 .attrs = { 320 { NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, "enable_vendor_sync", DT_BOOL, 0, NULL }, 321 } 322 }; 323 324 static const uc_nl_nested_spec_t nl80211_mntr_flags_nla = { 325 .headsize = 0, 326 .nattrs = 6, 327 .attrs = { 328 { NL80211_MNTR_FLAG_FCSFAIL, "fcsfail", DT_FLAG, 0, NULL }, 329 { NL80211_MNTR_FLAG_PLCPFAIL, "plcpfail", DT_FLAG, 0, NULL }, 330 { NL80211_MNTR_FLAG_CONTROL, "control", DT_FLAG, 0, NULL }, 331 { NL80211_MNTR_FLAG_OTHER_BSS, "other_bss", DT_FLAG, 0, NULL }, 332 { NL80211_MNTR_FLAG_COOK_FRAMES, "cook_frames", DT_FLAG, 0, NULL }, 333 { NL80211_MNTR_FLAG_ACTIVE, "active", DT_FLAG, 0, NULL }, 334 } 335 }; 336 337 static const uc_nl_nested_spec_t nl80211_nan_func_srf_nla = { 338 .headsize = 0, 339 .nattrs = 4, 340 .attrs = { 341 { NL80211_NAN_SRF_INCLUDE, "include", DT_FLAG, 0, NULL }, 342 { NL80211_NAN_SRF_BF_IDX, "bf_idx", DT_U8, 0, NULL }, 343 { NL80211_NAN_SRF_BF, "bf", DT_STRING, DF_BINARY, NULL }, 344 { NL80211_NAN_SRF_MAC_ADDRS, "mac_addrs", DT_LLADDR, DF_MULTIPLE|DF_AUTOIDX, NULL }, 345 } 346 }; 347 348 static const uc_nl_nested_spec_t nl80211_nan_func_nla = { 349 .headsize = 0, 350 .nattrs = 16, 351 .attrs = { 352 { NL80211_NAN_FUNC_TYPE, "type", DT_U8, 0, NULL }, 353 { NL80211_NAN_FUNC_SERVICE_ID, "service_id", DT_STRING, DF_BINARY, NULL }, 354 { NL80211_NAN_FUNC_PUBLISH_TYPE, "publish_type", DT_U8, 0, NULL }, 355 { NL80211_NAN_FUNC_PUBLISH_BCAST, "publish_bcast", DT_FLAG, 0, NULL }, 356 { NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE, "subscribe_active", DT_FLAG, 0, NULL }, 357 { NL80211_NAN_FUNC_FOLLOW_UP_ID, "follow_up_id", DT_U8, 0, NULL }, 358 { NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID, "follow_up_req_id", DT_U8, 0, NULL }, 359 { NL80211_NAN_FUNC_FOLLOW_UP_DEST, "follow_up_dest", DT_LLADDR, 0, NULL }, 360 { NL80211_NAN_FUNC_CLOSE_RANGE, "close_range", DT_FLAG, 0, NULL }, 361 { NL80211_NAN_FUNC_TTL, "ttl", DT_U32, 0, NULL }, 362 { NL80211_NAN_FUNC_SERVICE_INFO, "service_info", DT_STRING, 0, NULL }, 363 { NL80211_NAN_FUNC_SRF, "srf", DT_NESTED, 0, &nl80211_nan_func_srf_nla }, 364 { NL80211_NAN_FUNC_RX_MATCH_FILTER, "rx_match_filter", DT_STRING, DF_MULTIPLE|DF_AUTOIDX, NULL }, 365 { NL80211_NAN_FUNC_TX_MATCH_FILTER, "tx_match_filter", DT_STRING, DF_MULTIPLE|DF_AUTOIDX, NULL }, 366 { NL80211_NAN_FUNC_INSTANCE_ID, "instance_id", DT_U8, 0, NULL }, 367 { NL80211_NAN_FUNC_TERM_REASON, "term_reason", DT_U8, 0, NULL }, 368 } 369 }; 370 371 static const uc_nl_nested_spec_t nl80211_peer_measurements_peers_req_data_ftm_nla = { 372 .headsize = 0, 373 .nattrs = 13, 374 .attrs = { 375 { NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP, "num_bursts_exp", DT_U8, 0, NULL }, 376 { NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD, "burst_period", DT_U16, 0, NULL }, 377 { NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES, "num_ftmr_retries", DT_U8, 0, NULL }, 378 { NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION, "burst_duration", DT_U8, 0, NULL }, 379 { NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST, "ftms_per_burst", DT_U8, 0, NULL }, 380 { NL80211_PMSR_FTM_REQ_ATTR_ASAP, "asap", DT_FLAG, 0, NULL }, 381 { NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC, "request_civicloc", DT_FLAG, 0, NULL }, 382 { NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI, "request_lci", DT_FLAG, 0, NULL }, 383 { NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED, "trigger_based", DT_FLAG, 0, NULL }, 384 { NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE, "preamble", DT_U32, 0, NULL }, 385 { NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED, "non_trigger_based", DT_FLAG, 0, NULL }, 386 { NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK, "lmr_feedback", DT_FLAG, 0, NULL }, 387 { NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR, "bss_color", DT_U8, 0, NULL }, 388 } 389 }; 390 391 static const uc_nl_nested_spec_t nl80211_peer_measurements_peers_req_data_nla = { 392 .headsize = 0, 393 .nattrs = 2, 394 .attrs = { 395 { NL80211_PMSR_TYPE_FTM, "ftm", DT_NESTED, 0, &nl80211_peer_measurements_peers_req_data_ftm_nla }, 396 { NL80211_PMSR_REQ_ATTR_GET_AP_TSF, "get_ap_tsf", DT_FLAG, 0, NULL }, 397 } 398 }; 399 400 static const uc_nl_nested_spec_t nl80211_peer_measurements_peers_req_nla = { 401 .headsize = 0, 402 .nattrs = 1, 403 .attrs = { 404 { NL80211_PMSR_REQ_ATTR_DATA, "data", DT_NESTED, 0, &nl80211_peer_measurements_peers_req_data_nla }, 405 } 406 }; 407 408 static const uc_nl_nested_spec_t nl80211_peer_measurements_peers_chan_nla = { 409 .headsize = 0, 410 .nattrs = 4, 411 .attrs = { 412 { NL80211_ATTR_WIPHY_FREQ, "freq", DT_U32, 0, NULL }, 413 { NL80211_ATTR_CENTER_FREQ1, "center_freq1", DT_U32, 0, NULL }, 414 { NL80211_ATTR_CENTER_FREQ2, "center_freq2", DT_U32, 0, NULL }, 415 { NL80211_ATTR_CHANNEL_WIDTH, "channel_width", DT_U32, 0, NULL }, 416 } 417 }; 418 419 static const uc_nl_nested_spec_t nl80211_peer_measurements_peers_nla = { 420 .headsize = 0, 421 .nattrs = 3, 422 .attrs = { 423 { NL80211_PMSR_PEER_ATTR_ADDR, "addr", DT_LLADDR, 0, NULL }, 424 { NL80211_PMSR_PEER_ATTR_REQ, "req", DT_NESTED, 0, &nl80211_peer_measurements_peers_req_nla }, 425 { NL80211_PMSR_PEER_ATTR_CHAN, "chan", DT_NESTED, 0, &nl80211_peer_measurements_peers_chan_nla } 426 } 427 }; 428 429 static const uc_nl_nested_spec_t nl80211_peer_measurements_nla = { 430 .headsize = 0, 431 .nattrs = 1, 432 .attrs = { 433 { NL80211_PMSR_ATTR_PEERS, "peers", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_peer_measurements_peers_nla }, 434 } 435 }; 436 437 static const uc_nl_nested_spec_t nl80211_reg_rules_nla = { 438 .headsize = 0, 439 .nattrs = 7, 440 .attrs = { 441 { NL80211_ATTR_REG_RULE_FLAGS, "reg_rule_flags", DT_U32, 0, NULL }, 442 { NL80211_ATTR_FREQ_RANGE_START, "freq_range_start", DT_U32, 0, NULL }, 443 { NL80211_ATTR_FREQ_RANGE_END, "freq_range_end", DT_U32, 0, NULL }, 444 { NL80211_ATTR_FREQ_RANGE_MAX_BW, "freq_range_max_bw", DT_U32, 0, NULL }, 445 { NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, "power_rule_max_ant_gain", DT_U32, 0, NULL }, 446 { NL80211_ATTR_POWER_RULE_MAX_EIRP, "power_rule_max_eirp", DT_U32, 0, NULL }, 447 { NL80211_ATTR_DFS_CAC_TIME, "dfs_cac_time", DT_U32, 0, NULL }, 448 } 449 }; 450 451 static const uc_nl_nested_spec_t nl80211_frame_types_nla = { 452 .headsize = 0, 453 .nattrs = 12, 454 .attrs = { 455 { 1, "ibss", DT_U16, DF_MULTIPLE, NULL }, 456 { 2, "managed", DT_U16, DF_MULTIPLE, NULL }, 457 { 3, "ap", DT_U16, DF_MULTIPLE, NULL }, 458 { 4, "ap_vlan", DT_U16, DF_MULTIPLE, NULL }, 459 { 5, "wds", DT_U16, DF_MULTIPLE, NULL }, 460 { 6, "monitor", DT_U16, DF_MULTIPLE, NULL }, 461 { 7, "mesh_point", DT_U16, DF_MULTIPLE, NULL }, 462 { 8, "p2p_client", DT_U16, DF_MULTIPLE, NULL }, 463 { 9, "p2p_go", DT_U16, DF_MULTIPLE, NULL }, 464 { 10, "p2p_device", DT_U16, DF_MULTIPLE, NULL }, 465 { 11, "outside_bss_context", DT_U16, DF_MULTIPLE, NULL }, 466 { 12, "nan", DT_U16, DF_MULTIPLE, NULL }, 467 } 468 }; 469 470 static const uc_nl_nested_spec_t nl80211_sched_scan_match_nla = { 471 .headsize = 0, 472 .nattrs = 1, 473 .attrs = { 474 { NL80211_SCHED_SCAN_MATCH_ATTR_SSID, "ssid", DT_STRING, DF_BINARY, NULL }, 475 } 476 }; 477 478 static const uc_nl_nested_spec_t nl80211_sched_scan_plan_nla = { 479 .headsize = 0, 480 .nattrs = 2, 481 .attrs = { 482 { NL80211_SCHED_SCAN_PLAN_INTERVAL, "interval", DT_U32, 0, NULL }, 483 { NL80211_SCHED_SCAN_PLAN_ITERATIONS, "iterations", DT_U32, 0, NULL }, 484 } 485 }; 486 487 enum { 488 HWSIM_TM_ATTR_CMD = 1, 489 HWSIM_TM_ATTR_PS = 2, 490 }; 491 492 static const uc_nl_nested_spec_t nl80211_testdata_nla = { 493 .headsize = 0, 494 .nattrs = 2, 495 .attrs = { 496 { HWSIM_TM_ATTR_CMD, "cmd", DT_U32, 0, NULL }, 497 { HWSIM_TM_ATTR_PS, "ps", DT_U32, 0, NULL }, 498 } 499 }; 500 501 static const uc_nl_nested_spec_t nl80211_tid_config_nla = { 502 .headsize = 0, 503 .nattrs = 1, 504 .attrs = { 505 { NL80211_TID_CONFIG_ATTR_TIDS, "tids", DT_U16, 0, NULL }, 506 } 507 }; 508 509 static const uc_nl_nested_spec_t nl80211_wiphy_bands_freqs_wmm_nla = { 510 .headsize = 0, 511 .nattrs = 4, 512 .attrs = { 513 { NL80211_WMMR_CW_MIN, "cw_min", DT_U16, 0, NULL }, 514 { NL80211_WMMR_CW_MAX, "cw_max", DT_U16, 0, NULL }, 515 { NL80211_WMMR_AIFSN, "aifsn", DT_U8, 0, NULL }, 516 { NL80211_WMMR_TXOP, "txop", DT_U16, 0, NULL }, 517 } 518 }; 519 520 static const uc_nl_nested_spec_t nl80211_wiphy_bands_freqs_nla = { 521 .headsize = 0, 522 .nattrs = 25, 523 .attrs = { 524 { NL80211_FREQUENCY_ATTR_FREQ, "freq", DT_U32, 0, NULL }, 525 { NL80211_FREQUENCY_ATTR_DISABLED, "disabled", DT_FLAG, 0, NULL }, 526 { NL80211_FREQUENCY_ATTR_NO_IR, "no_ir", DT_FLAG, 0, NULL }, 527 { __NL80211_FREQUENCY_ATTR_NO_IBSS, "no_ibss", DT_FLAG, 0, NULL }, 528 { NL80211_FREQUENCY_ATTR_RADAR, "radar", DT_FLAG, 0, NULL }, 529 { NL80211_FREQUENCY_ATTR_MAX_TX_POWER, "max_tx_power", DT_U32, 0, NULL }, 530 { NL80211_FREQUENCY_ATTR_DFS_STATE, "dfs_state", DT_U32, 0, NULL }, 531 { NL80211_FREQUENCY_ATTR_DFS_TIME, "dfs_time", DT_U32, 0, NULL }, 532 { NL80211_FREQUENCY_ATTR_NO_HT40_MINUS, "no_ht40_minus", DT_FLAG, 0, NULL }, 533 { NL80211_FREQUENCY_ATTR_NO_HT40_PLUS, "no_ht40_plus", DT_FLAG, 0, NULL }, 534 { NL80211_FREQUENCY_ATTR_NO_80MHZ, "no_80mhz", DT_FLAG, 0, NULL }, 535 { NL80211_FREQUENCY_ATTR_NO_160MHZ, "no_160mhz", DT_FLAG, 0, NULL }, 536 { NL80211_FREQUENCY_ATTR_DFS_CAC_TIME, "dfs_cac_time", DT_FLAG, 0, NULL }, 537 { NL80211_FREQUENCY_ATTR_INDOOR_ONLY, "indoor_only", DT_FLAG, 0, NULL }, 538 { NL80211_FREQUENCY_ATTR_IR_CONCURRENT, "ir_concurrent", DT_FLAG, 0, NULL }, 539 { NL80211_FREQUENCY_ATTR_NO_20MHZ, "no_20mhz", DT_FLAG, 0, NULL }, 540 { NL80211_FREQUENCY_ATTR_NO_10MHZ, "no_10mhz", DT_FLAG, 0, NULL }, 541 { NL80211_FREQUENCY_ATTR_WMM, "wmm", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_wiphy_bands_freqs_wmm_nla }, 542 { NL80211_FREQUENCY_ATTR_NO_HE, "no_he", DT_FLAG, 0, NULL }, 543 { NL80211_FREQUENCY_ATTR_OFFSET, "offset", DT_U32, 0, NULL }, 544 { NL80211_FREQUENCY_ATTR_1MHZ, "1mhz", DT_FLAG, 0, NULL }, 545 { NL80211_FREQUENCY_ATTR_2MHZ, "2mhz", DT_FLAG, 0, NULL }, 546 { NL80211_FREQUENCY_ATTR_4MHZ, "4mhz", DT_FLAG, 0, NULL }, 547 { NL80211_FREQUENCY_ATTR_8MHZ, "8mhz", DT_FLAG, 0, NULL }, 548 { NL80211_FREQUENCY_ATTR_16MHZ, "16mhz", DT_FLAG, 0, NULL }, 549 } 550 }; 551 552 static const uc_nl_nested_spec_t nl80211_wiphy_bands_rates_nla = { 553 .headsize = 0, 554 .nattrs = 2, 555 .attrs = { 556 { NL80211_BITRATE_ATTR_RATE, "rate", DT_U32, 0, NULL }, 557 { NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE, "2ghz_shortpreamble", DT_FLAG, 0, NULL }, 558 } 559 }; 560 561 static const uc_nl_nested_spec_t nl80211_wiphy_bands_iftype_data_nla = { 562 .headsize = 0, 563 .nattrs = 7, 564 .attrs = { 565 { NL80211_BAND_IFTYPE_ATTR_IFTYPES, "iftypes", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla }, 566 { NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC, "he_cap_mac", DT_U16, DF_ARRAY, NULL }, 567 { NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY, "he_cap_phy", DT_U16, DF_ARRAY, NULL }, 568 { NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, "he_cap_mcs_set", DT_HE_MCS, 0, NULL }, 569 { NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE, "he_cap_ppe", DT_U8, DF_ARRAY, NULL }, 570 { NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA, "he_6ghz_capa", DT_U16, 0, NULL }, 571 { NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS, "vendor_elems", DT_STRING, DF_BINARY, NULL }, 572 } 573 }; 574 575 static const uc_nl_nested_spec_t nl80211_wiphy_bands_nla = { 576 .headsize = 0, 577 .nattrs = 11, 578 .attrs = { 579 { NL80211_BAND_ATTR_FREQS, "freqs", DT_NESTED, DF_MULTIPLE|DF_TYPEIDX, &nl80211_wiphy_bands_freqs_nla }, 580 { NL80211_BAND_ATTR_RATES, "rates", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_wiphy_bands_rates_nla }, 581 { NL80211_BAND_ATTR_HT_MCS_SET, "ht_mcs_set", DT_HT_MCS, 0, NULL }, 582 { NL80211_BAND_ATTR_HT_CAPA, "ht_capa", DT_U16, 0, NULL }, 583 { NL80211_BAND_ATTR_HT_AMPDU_FACTOR, "ht_ampdu_factor", DT_U8, 0, NULL }, 584 { NL80211_BAND_ATTR_HT_AMPDU_DENSITY, "ht_ampdu_density", DT_U8, 0, NULL }, 585 { NL80211_BAND_ATTR_VHT_MCS_SET, "vht_mcs_set", DT_VHT_MCS, 0, NULL }, 586 { NL80211_BAND_ATTR_VHT_CAPA, "vht_capa", DT_U32, 0, NULL }, 587 { NL80211_BAND_ATTR_IFTYPE_DATA, "iftype_data", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_wiphy_bands_iftype_data_nla }, 588 { NL80211_BAND_ATTR_EDMG_CHANNELS, "edmg_channels", DT_U8, 0, NULL }, 589 { NL80211_BAND_ATTR_EDMG_BW_CONFIG, "edmg_bw_config", DT_U8, 0, NULL }, 590 } 591 }; 592 593 static const uc_nl_nested_spec_t nl80211_wowlan_triggers_tcp_nla = { 594 .headsize = 0, 595 .nattrs = 11, 596 .attrs = { 597 { NL80211_WOWLAN_TCP_SRC_IPV4, "src_ipv4", DT_INADDR, 0, NULL }, 598 { NL80211_WOWLAN_TCP_SRC_PORT, "src_port", DT_U16, 0, NULL }, 599 { NL80211_WOWLAN_TCP_DST_IPV4, "dst_ipv4", DT_INADDR, 0, NULL }, 600 { NL80211_WOWLAN_TCP_DST_PORT, "dst_port", DT_U16, 0, NULL }, 601 { NL80211_WOWLAN_TCP_DST_MAC, "dst_mac", DT_LLADDR, 0, NULL }, 602 { NL80211_WOWLAN_TCP_DATA_PAYLOAD, "data_payload", DT_STRING, DF_BINARY, NULL }, 603 { NL80211_WOWLAN_TCP_DATA_INTERVAL, "data_interval", DT_U32, 0, NULL }, 604 { NL80211_WOWLAN_TCP_WAKE_MASK, "wake_mask", DT_STRING, DF_BINARY, NULL }, 605 { NL80211_WOWLAN_TCP_WAKE_PAYLOAD, "wake_payload", DT_STRING, DF_BINARY, NULL }, 606 { NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ, "data_payload_seq", DT_U32, DF_ARRAY, NULL }, 607 { NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, "data_payload_token", DT_STRING, DF_BINARY, NULL }, /* XXX: struct nl80211_wowlan_tcp_data_token */ 608 } 609 }; 610 611 static const uc_nl_nested_spec_t nl80211_pkt_pattern_nla = { 612 .headsize = 0, 613 .nattrs = 3, 614 .attrs = { 615 { NL80211_PKTPAT_MASK, "mask", DT_STRING, DF_BINARY, NULL }, 616 { NL80211_PKTPAT_PATTERN, "pattern", DT_STRING, DF_BINARY, NULL }, 617 { NL80211_PKTPAT_OFFSET, "offset", DT_U32, 0, NULL }, 618 } 619 }; 620 621 static const uc_nl_nested_spec_t nl80211_wowlan_triggers_nla = { 622 .headsize = 0, 623 .nattrs = 9, 624 .attrs = { 625 { NL80211_WOWLAN_TRIG_ANY, "any", DT_FLAG, 0, NULL }, 626 { NL80211_WOWLAN_TRIG_DISCONNECT, "disconnect", DT_FLAG, 0, NULL }, 627 { NL80211_WOWLAN_TRIG_MAGIC_PKT, "magic_pkt", DT_FLAG, 0, NULL }, 628 { NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE, "gtk_rekey_failure", DT_FLAG, 0, NULL }, 629 { NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST, "eap_ident_request", DT_FLAG, 0, NULL }, 630 { NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE, "4way_handshake", DT_FLAG, 0, NULL }, 631 { NL80211_WOWLAN_TRIG_RFKILL_RELEASE, "rfkill_release", DT_FLAG, 0, NULL }, 632 { NL80211_WOWLAN_TRIG_TCP_CONNECTION, "tcp_connection", DT_NESTED, 0, &nl80211_wowlan_triggers_tcp_nla }, 633 { NL80211_WOWLAN_TRIG_PKT_PATTERN, "pkt_pattern", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX|DF_OFFSET1, &nl80211_pkt_pattern_nla }, 634 } 635 }; 636 637 static const uc_nl_nested_spec_t nl80211_coalesce_rule_nla = { 638 .headsize = 0, 639 .nattrs = 3, 640 .attrs = { 641 { NL80211_ATTR_COALESCE_RULE_CONDITION, "coalesce_rule_condition", DT_U32, 0, NULL }, 642 { NL80211_ATTR_COALESCE_RULE_DELAY, "coalesce_rule_delay", DT_U32, 0, NULL }, 643 { NL80211_ATTR_COALESCE_RULE_PKT_PATTERN, "coalesce_rule_pkt_pattern", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX|DF_OFFSET1, &nl80211_pkt_pattern_nla }, 644 } 645 }; 646 647 static const uc_nl_nested_spec_t nl80211_bss_nla = { 648 .headsize = 0, 649 .nattrs = 12, 650 .attrs = { 651 { NL80211_BSS_BSSID, "bssid", DT_LLADDR, 0, NULL }, 652 { NL80211_BSS_STATUS, "status", DT_U32, 0, NULL }, 653 { NL80211_BSS_LAST_SEEN_BOOTTIME, "last_seen_boottime", DT_U64, 0, NULL }, 654 { NL80211_BSS_TSF, "tsf", DT_U64, 0, NULL }, 655 { NL80211_BSS_FREQUENCY, "frequency", DT_U32, 0, NULL }, 656 { NL80211_BSS_BEACON_INTERVAL, "beacon_interval", DT_U16, 0, NULL }, 657 { NL80211_BSS_CAPABILITY, "capability", DT_U16, 0, NULL }, 658 { NL80211_BSS_SIGNAL_MBM, "signal_mbm", DT_S32, 0, NULL }, 659 { NL80211_BSS_SIGNAL_UNSPEC, "signal_unspec", DT_U8, 0, NULL }, 660 { NL80211_BSS_SEEN_MS_AGO, "seen_ms_ago", DT_S32, 0, NULL }, 661 { NL80211_BSS_INFORMATION_ELEMENTS, "information_elements", DT_IE, 0, NULL }, 662 { NL80211_BSS_BEACON_IES, "beacon_ies", DT_IE, 0, NULL }, 663 } 664 }; 665 666 static const uc_nl_nested_spec_t nl80211_sta_info_bitrate_nla = { 667 .headsize = 0, 668 .nattrs = 18, 669 .attrs = { 670 { NL80211_RATE_INFO_BITRATE, "bitrate", DT_U16, 0, NULL }, 671 { NL80211_RATE_INFO_BITRATE32, "bitrate32", DT_U32, 0, NULL }, 672 { NL80211_RATE_INFO_MCS, "mcs", DT_U8, 0, NULL }, 673 { NL80211_RATE_INFO_40_MHZ_WIDTH, "40_mhz_width", DT_FLAG, 0, NULL }, 674 { NL80211_RATE_INFO_SHORT_GI, "short_gi", DT_FLAG, 0, NULL }, 675 { NL80211_RATE_INFO_VHT_MCS, "vht_mcs", DT_U8, 0, NULL }, 676 { NL80211_RATE_INFO_VHT_NSS, "vht_nss", DT_U8, 0, NULL }, 677 { NL80211_RATE_INFO_HE_MCS, "he_mcs", DT_U8, 0, NULL }, 678 { NL80211_RATE_INFO_HE_NSS, "he_nss", DT_U8, 0, NULL }, 679 { NL80211_RATE_INFO_HE_GI, "he_gi", DT_U8, 0, NULL }, 680 { NL80211_RATE_INFO_HE_DCM, "he_dcm", DT_U8, 0, NULL }, 681 { NL80211_RATE_INFO_HE_RU_ALLOC, "he_ru_alloc", DT_U8, 0, NULL }, 682 { NL80211_RATE_INFO_40_MHZ_WIDTH, "width_40", DT_FLAG, 0, NULL }, 683 { NL80211_RATE_INFO_80_MHZ_WIDTH, "width_80", DT_FLAG, 0, NULL }, 684 { NL80211_RATE_INFO_80P80_MHZ_WIDTH, "width_80p80", DT_FLAG, 0, NULL }, 685 { NL80211_RATE_INFO_160_MHZ_WIDTH, "width_160", DT_FLAG, 0, NULL }, 686 { NL80211_RATE_INFO_10_MHZ_WIDTH, "width_10", DT_FLAG, 0, NULL }, 687 { NL80211_RATE_INFO_5_MHZ_WIDTH, "width_5", DT_FLAG, 0, NULL }, 688 } 689 }; 690 691 static const uc_nl_nested_spec_t nl80211_tid_txq_stats_nla = { 692 .headsize = 0, 693 .nattrs = 9, 694 .attrs = { 695 { NL80211_TXQ_STATS_BACKLOG_BYTES, "backlog_bytes", DT_U32, 0, NULL }, 696 { NL80211_TXQ_STATS_BACKLOG_PACKETS, "backlog_packets", DT_U32, 0, NULL }, 697 { NL80211_TXQ_STATS_FLOWS, "flows", DT_U32, 0, NULL }, 698 { NL80211_TXQ_STATS_DROPS, "drops", DT_U32, 0, NULL }, 699 { NL80211_TXQ_STATS_ECN_MARKS, "ecn_marks", DT_U32, 0, NULL }, 700 { NL80211_TXQ_STATS_OVERLIMIT, "overlimit", DT_U32, 0, NULL }, 701 { NL80211_TXQ_STATS_COLLISIONS, "collisions", DT_U32, 0, NULL }, 702 { NL80211_TXQ_STATS_TX_BYTES, "tx_bytes", DT_U32, 0, NULL }, 703 { NL80211_TXQ_STATS_TX_PACKETS, "tx_packets", DT_U32, 0, NULL }, 704 } 705 }; 706 707 static const uc_nl_nested_spec_t nl80211_tid_stats_nla = { 708 .headsize = 0, 709 .nattrs = 5, 710 .attrs = { 711 { NL80211_TID_STATS_RX_MSDU, "rx_msdu", DT_U64, 0, NULL }, 712 { NL80211_TID_STATS_TX_MSDU, "tx_msdu", DT_U64, 0, NULL }, 713 { NL80211_TID_STATS_TX_MSDU_RETRIES, "tx_msdu_retries", DT_U64, 0, NULL }, 714 { NL80211_TID_STATS_TX_MSDU_FAILED, "tx_msdu_failed", DT_U64, 0, NULL }, 715 { NL80211_TID_STATS_TXQ_STATS, "txq_stats", DT_NESTED, 0, &nl80211_tid_txq_stats_nla }, 716 } 717 }; 718 719 static const uc_nl_nested_spec_t nl80211_bss_param_nla = { 720 .headsize = 0, 721 .nattrs = 5, 722 .attrs = { 723 { NL80211_STA_BSS_PARAM_CTS_PROT, "cts_prot", DT_FLAG, 0, NULL }, 724 { NL80211_STA_BSS_PARAM_SHORT_PREAMBLE, "short_preamble", DT_FLAG, 0, NULL }, 725 { NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME, "short_slot_time", DT_FLAG, 0, NULL }, 726 { NL80211_STA_BSS_PARAM_DTIM_PERIOD, "dtim_period", DT_U8, 0, NULL }, 727 { NL80211_STA_BSS_PARAM_BEACON_INTERVAL, "beacon_interval", DT_U16, 0, NULL }, 728 } 729 }; 730 731 static const uc_nl_nested_spec_t nl80211_sta_info_nla = { 732 .headsize = 0, 733 .nattrs = 40, 734 .attrs = { 735 { NL80211_STA_INFO_INACTIVE_TIME, "inactive_time", DT_U32, 0, NULL }, 736 { NL80211_STA_INFO_RX_BYTES, "rx_bytes", DT_U32, 0, NULL }, 737 { NL80211_STA_INFO_TX_BYTES, "tx_bytes", DT_U32, 0, NULL }, 738 { NL80211_STA_INFO_RX_BYTES64, "rx_bytes64", DT_U64, 0, NULL }, 739 { NL80211_STA_INFO_TX_BYTES64, "tx_bytes64", DT_U64, 0, NULL }, 740 { NL80211_STA_INFO_RX_PACKETS, "rx_packets", DT_U32, 0, NULL }, 741 { NL80211_STA_INFO_TX_PACKETS, "tx_packets", DT_U32, 0, NULL }, 742 { NL80211_STA_INFO_BEACON_RX, "beacon_rx", DT_U64, 0, NULL }, 743 { NL80211_STA_INFO_SIGNAL, "signal", DT_S8, 0, NULL }, 744 { NL80211_STA_INFO_T_OFFSET, "t_offset", DT_U64, 0, NULL }, 745 { NL80211_STA_INFO_TX_BITRATE, "tx_bitrate", DT_NESTED, 0, &nl80211_sta_info_bitrate_nla }, 746 { NL80211_STA_INFO_RX_BITRATE, "rx_bitrate", DT_NESTED, 0, &nl80211_sta_info_bitrate_nla }, 747 { NL80211_STA_INFO_LLID, "llid", DT_U16, 0, NULL }, 748 { NL80211_STA_INFO_PLID, "plid", DT_U16, 0, NULL }, 749 { NL80211_STA_INFO_PLINK_STATE, "plink_state", DT_U8, 0, NULL }, 750 { NL80211_STA_INFO_TX_RETRIES, "tx_retries", DT_U32, 0, NULL }, 751 { NL80211_STA_INFO_TX_FAILED, "tx_failed", DT_U32, 0, NULL }, 752 { NL80211_STA_INFO_BEACON_LOSS, "beacon_loss", DT_U32, 0, NULL }, 753 { NL80211_STA_INFO_RX_DROP_MISC, "rx_drop_misc", DT_U64, 0, NULL }, 754 { NL80211_STA_INFO_STA_FLAGS, "sta_flags", DT_U32, DF_ARRAY, NULL }, 755 { NL80211_STA_INFO_LOCAL_PM, "local_pm", DT_U32, 0, NULL }, 756 { NL80211_STA_INFO_PEER_PM, "peer_pm", DT_U32, 0, NULL }, 757 { NL80211_STA_INFO_NONPEER_PM, "nonpeer_pm", DT_U32, 0, NULL }, 758 { NL80211_STA_INFO_CHAIN_SIGNAL, "chain_signal", DT_S8, DF_MULTIPLE|DF_AUTOIDX, NULL }, 759 { NL80211_STA_INFO_CHAIN_SIGNAL_AVG, "chain_signal_avg", DT_S8, DF_MULTIPLE|DF_AUTOIDX, NULL }, 760 { NL80211_STA_INFO_TID_STATS, "tid_stats", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_tid_stats_nla }, 761 { NL80211_STA_INFO_BSS_PARAM, "bss_param", DT_NESTED, 0, &nl80211_bss_param_nla }, 762 { NL80211_STA_INFO_RX_DURATION, "rx_duration", DT_U64, 0, NULL }, 763 { NL80211_STA_INFO_TX_DURATION, "tx_duration", DT_U64, 0, NULL }, 764 { NL80211_STA_INFO_ACK_SIGNAL, "ack_signal", DT_S8, 0, NULL }, 765 { NL80211_STA_INFO_ACK_SIGNAL_AVG, "ack_signal_avg", DT_S8, 0, NULL }, 766 { NL80211_STA_INFO_AIRTIME_LINK_METRIC, "airtime_link_metric", DT_U32, 0, NULL }, 767 { NL80211_STA_INFO_AIRTIME_WEIGHT, "airtime_weight", DT_U16, 0, NULL }, 768 { NL80211_STA_INFO_CONNECTED_TO_AS, "connected_to_as", DT_BOOL, 0, NULL }, 769 { NL80211_STA_INFO_CONNECTED_TO_GATE, "connected_to_gate", DT_BOOL, 0, NULL }, 770 { NL80211_STA_INFO_CONNECTED_TIME, "connected_time", DT_U32, 0, NULL }, 771 { NL80211_STA_INFO_ASSOC_AT_BOOTTIME, "assoc_at_boottime", DT_U64, 0, NULL }, 772 { NL80211_STA_INFO_BEACON_SIGNAL_AVG, "beacon_signal_avg", DT_S8, 0, NULL }, 773 { NL80211_STA_INFO_EXPECTED_THROUGHPUT, "expected_throughput", DT_U32, 0, NULL }, 774 { NL80211_STA_INFO_SIGNAL_AVG, "signal_avg", DT_S8, 0, NULL }, 775 } 776 }; 777 778 static const uc_nl_nested_spec_t nl80211_survey_info_nla = { 779 .headsize = 0, 780 .nattrs = 8, 781 .attrs = { 782 { NL80211_SURVEY_INFO_FREQUENCY, "frequency", DT_U32, 0, NULL }, 783 { NL80211_SURVEY_INFO_TIME, "time", DT_U64, 0, NULL }, 784 { NL80211_SURVEY_INFO_TIME_TX, "time_tx", DT_U64, 0, NULL }, 785 { NL80211_SURVEY_INFO_TIME_RX, "time_rx", DT_U64, 0, NULL }, 786 { NL80211_SURVEY_INFO_TIME_BUSY, "busy", DT_U64, 0, NULL }, 787 { NL80211_SURVEY_INFO_TIME_EXT_BUSY, "ext_busy", DT_U64, 0, NULL }, 788 { NL80211_SURVEY_INFO_TIME_SCAN, "scan", DT_U64, 0, NULL }, 789 { NL80211_SURVEY_INFO_NOISE, "noise", DT_S8, 0, NULL }, 790 } 791 }; 792 793 static const uc_nl_nested_spec_t nl80211_mpath_info_nla = { 794 .headsize = 0, 795 .nattrs = 8, 796 .attrs = { 797 { NL80211_MPATH_INFO_SN, "sn", DT_U32, 0, NULL }, 798 { NL80211_MPATH_INFO_METRIC, "metric", DT_U32, 0, NULL }, 799 { NL80211_MPATH_INFO_EXPTIME, "expire", DT_U32, 0, NULL }, 800 { NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, "discovery_timeout", DT_U32, 0, NULL }, 801 { NL80211_MPATH_INFO_DISCOVERY_RETRIES, "discovery_retries", DT_U8, 0, NULL }, 802 { NL80211_MPATH_INFO_FLAGS, "flags", DT_U8, 0, NULL }, 803 { NL80211_MPATH_INFO_HOP_COUNT, "hop_count", DT_U8, 0, NULL }, 804 { NL80211_MPATH_INFO_PATH_CHANGE, "path_change", DT_U32, 0, NULL }, 805 } 806 }; 807 808 static const uc_nl_nested_spec_t nl80211_msg = { 809 .headsize = 0, 810 .nattrs = 127, 811 .attrs = { 812 { NL80211_ATTR_4ADDR, "4addr", DT_U8, 0, NULL }, 813 { NL80211_ATTR_AIRTIME_WEIGHT, "airtime_weight", DT_U16, 0, NULL }, 814 { NL80211_ATTR_AKM_SUITES, "akm_suites", DT_U32, 0, NULL }, 815 { NL80211_ATTR_AUTH_TYPE, "auth_type", DT_U32, 0, NULL }, 816 { NL80211_ATTR_BANDS, "bands", DT_U32, 0, NULL }, 817 { NL80211_ATTR_BEACON_HEAD, "beacon_head", DT_STRING, DF_BINARY, NULL }, 818 { NL80211_ATTR_BEACON_INTERVAL, "beacon_interval", DT_U32, 0, NULL }, 819 { NL80211_ATTR_BEACON_TAIL, "beacon_tail", DT_STRING, DF_BINARY, NULL }, 820 { NL80211_ATTR_BSS, "bss", DT_NESTED, 0, &nl80211_bss_nla }, 821 { NL80211_ATTR_BSS_BASIC_RATES, "bss_basic_rates", DT_U32, DF_ARRAY, NULL }, 822 { NL80211_ATTR_CENTER_FREQ1, "center_freq1", DT_U32, 0, NULL }, 823 { NL80211_ATTR_CENTER_FREQ2, "center_freq2", DT_U32, 0, NULL }, 824 { NL80211_ATTR_CHANNEL_WIDTH, "channel_width", DT_U32, 0, NULL }, 825 { NL80211_ATTR_CH_SWITCH_BLOCK_TX, "ch_switch_block_tx", DT_FLAG, 0, NULL }, 826 { NL80211_ATTR_CH_SWITCH_COUNT, "ch_switch_count", DT_U32, 0, NULL }, 827 { NL80211_ATTR_CIPHER_SUITES, "cipher_suites", DT_U32, DF_ARRAY, NULL }, 828 { NL80211_ATTR_CIPHER_SUITES_PAIRWISE, "cipher_suites_pairwise", DT_U32, 0, NULL }, 829 { NL80211_ATTR_CIPHER_SUITE_GROUP, "cipher_suite_group", DT_U32, 0, NULL }, 830 { NL80211_ATTR_COALESCE_RULE, "coalesce_rule", DT_NESTED, 0, &nl80211_coalesce_rule_nla }, 831 { NL80211_ATTR_COOKIE, "cookie", DT_U64, 0, NULL }, 832 { NL80211_ATTR_CQM, "cqm", DT_NESTED, 0, &nl80211_cqm_nla }, 833 { NL80211_ATTR_DFS_CAC_TIME, "dfs_cac_time", DT_U32, 0, NULL }, 834 { NL80211_ATTR_DFS_REGION, "dfs_region", DT_U8, 0, NULL }, 835 { NL80211_ATTR_DTIM_PERIOD, "dtim_period", DT_U32, 0, NULL }, 836 { NL80211_ATTR_DURATION, "duration", DT_U32, 0, NULL }, 837 { NL80211_ATTR_FEATURE_FLAGS, "feature_flags", DT_U32, 0, NULL }, 838 { NL80211_ATTR_FRAME, "frame", DT_STRING, DF_BINARY, NULL }, 839 { NL80211_ATTR_FRAME_MATCH, "frame_match", DT_STRING, DF_BINARY, NULL }, 840 { NL80211_ATTR_FRAME_TYPE, "frame_type", DT_U16, 0, NULL }, 841 { NL80211_ATTR_FREQ_FIXED, "freq_fixed", DT_FLAG, 0, NULL }, 842 { NL80211_ATTR_FTM_RESPONDER, "ftm_responder", DT_NESTED, 0, &nl80211_ftm_responder_nla }, 843 { NL80211_ATTR_FTM_RESPONDER_STATS, "ftm_responder_stats", DT_NESTED, 0, &nl80211_ftm_responder_stats_nla }, 844 { NL80211_ATTR_HIDDEN_SSID, "hidden_ssid", DT_U32, 0, NULL }, 845 { NL80211_ATTR_HT_CAPABILITY_MASK, "ht_capability_mask", DT_HT_CAP, 0, NULL }, 846 { NL80211_ATTR_IE, "ie", DT_IE, 0, NULL }, 847 { NL80211_ATTR_IFINDEX, "dev", DT_NETDEV, 0, NULL }, 848 { NL80211_ATTR_IFNAME, "ifname", DT_STRING, 0, NULL }, 849 { NL80211_ATTR_IFTYPE, "iftype", DT_U32, 0, NULL }, 850 { NL80211_ATTR_INACTIVITY_TIMEOUT, "inactivity_timeout", DT_U16, 0, NULL }, 851 { NL80211_ATTR_INTERFACE_COMBINATIONS, "interface_combinations", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_ifcomb_nla }, 852 { NL80211_ATTR_KEYS, "keys", DT_NESTED, DF_AUTOIDX, &nl80211_keys_nla }, 853 { NL80211_ATTR_KEY_SEQ, "key_seq", DT_STRING, DF_BINARY, NULL }, 854 { NL80211_ATTR_KEY_TYPE, "key_type", DT_U32, 0, NULL }, 855 { NL80211_ATTR_LOCAL_MESH_POWER_MODE, "local_mesh_power_mode", DT_U32, 0, NULL }, 856 { NL80211_ATTR_MAC, "mac", DT_LLADDR, 0, NULL }, 857 { NL80211_ATTR_MAC_MASK, "mac_mask", DT_LLADDR, 0, NULL }, 858 { NL80211_ATTR_MCAST_RATE, "mcast_rate", DT_U32, 0, NULL }, 859 { NL80211_ATTR_MEASUREMENT_DURATION, "measurement_duration", DT_U16, 0, NULL }, 860 { NL80211_ATTR_MESH_ID, "mesh_id", DT_STRING, 0, NULL }, 861 { NL80211_ATTR_MESH_PARAMS, "mesh_params", DT_NESTED, 0, &nl80211_mesh_params_nla }, 862 { NL80211_ATTR_MESH_SETUP, "mesh_setup", DT_NESTED, 0, &nl80211_mesh_setup_nla }, 863 { NL80211_ATTR_MGMT_SUBTYPE, "mgmt_subtype", DT_U8, 0, NULL }, 864 { NL80211_ATTR_MNTR_FLAGS, "mntr_flags", DT_NESTED, 0, &nl80211_mntr_flags_nla }, 865 { NL80211_ATTR_MPATH_NEXT_HOP, "mpath_next_hop", DT_LLADDR, 0, NULL }, 866 { NL80211_ATTR_MPATH_INFO, "mpath_info", DT_NESTED, 0, &nl80211_mpath_info_nla }, 867 { NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR, "mu_mimo_follow_mac_addr", DT_LLADDR, 0, NULL }, 868 { NL80211_ATTR_NAN_FUNC, "nan_func", DT_NESTED, 0, &nl80211_nan_func_nla }, 869 { NL80211_ATTR_NAN_MASTER_PREF, "nan_master_pref", DT_U8, 0, NULL }, 870 { NL80211_ATTR_NETNS_FD, "netns_fd", DT_U32, 0, NULL }, 871 { NL80211_ATTR_NOACK_MAP, "noack_map", DT_U16, 0, NULL }, 872 { NL80211_ATTR_NSS, "nss", DT_U8, 0, NULL }, 873 { NL80211_ATTR_PEER_MEASUREMENTS, "peer_measurements", DT_NESTED, 0, &nl80211_peer_measurements_nla }, 874 { NL80211_ATTR_PID, "pid", DT_U32, 0, NULL }, 875 { NL80211_ATTR_PMK, "pmk", DT_STRING, DF_BINARY, NULL }, 876 { NL80211_ATTR_PRIVACY, "privacy", DT_FLAG, 0, NULL }, 877 { NL80211_ATTR_PROTOCOL_FEATURES, "protocol_features", DT_U32, 0, NULL }, 878 { NL80211_ATTR_PS_STATE, "ps_state", DT_U32, 0, NULL }, 879 { NL80211_ATTR_RADAR_EVENT, "radar_event", DT_U32, 0, NULL }, 880 { NL80211_ATTR_REASON_CODE, "reason_code", DT_U16, 0, NULL }, 881 { NL80211_ATTR_REG_ALPHA2, "reg_alpha2", DT_STRING, 0, NULL }, 882 { NL80211_ATTR_REG_INITIATOR, "reg_initiator", DT_U32, 0, NULL }, 883 { NL80211_ATTR_REG_RULES, "reg_rules", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_reg_rules_nla }, 884 { NL80211_ATTR_REG_TYPE, "reg_type", DT_U8, 0, NULL }, 885 { NL80211_ATTR_RX_FRAME_TYPES, "rx_frame_types", DT_NESTED, 0, &nl80211_frame_types_nla }, 886 { NL80211_ATTR_RX_SIGNAL_DBM, "rx_signal_dbm", DT_U32, 0, NULL }, 887 { NL80211_ATTR_SCAN_FLAGS, "scan_flags", DT_U32, 0, NULL }, 888 { NL80211_ATTR_SCAN_FREQUENCIES, "scan_frequencies", DT_U32, DF_MULTIPLE|DF_AUTOIDX, NULL }, 889 { NL80211_ATTR_SCAN_SSIDS, "scan_ssids", DT_STRING, DF_MULTIPLE|DF_AUTOIDX, NULL }, 890 { NL80211_ATTR_SCHED_SCAN_DELAY, "sched_scan_delay", DT_U32, 0, NULL }, 891 { NL80211_ATTR_SCHED_SCAN_INTERVAL, "sched_scan_interval", DT_U32, 0, NULL }, 892 { NL80211_ATTR_SCHED_SCAN_MATCH, "sched_scan_match", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_sched_scan_match_nla }, 893 { NL80211_ATTR_SCHED_SCAN_PLANS, "sched_scan_plans", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX|DF_OFFSET1, &nl80211_sched_scan_plan_nla }, 894 { NL80211_ATTR_SMPS_MODE, "smps_mode", DT_U8, 0, NULL }, 895 { NL80211_ATTR_SPLIT_WIPHY_DUMP, "split_wiphy_dump", DT_FLAG, 0, NULL }, 896 { NL80211_ATTR_SSID, "ssid", DT_STRING, DF_BINARY, NULL }, 897 { NL80211_ATTR_STATUS_CODE, "status_code", DT_U16, 0, NULL }, 898 { NL80211_ATTR_STA_INFO, "sta_info", DT_NESTED, 0, &nl80211_sta_info_nla }, 899 { NL80211_ATTR_STA_PLINK_ACTION, "sta_plink_action", DT_U8, 0, NULL }, 900 { NL80211_ATTR_STA_TX_POWER, "sta_tx_power", DT_U16, 0, NULL }, 901 { NL80211_ATTR_STA_TX_POWER_SETTING, "sta_tx_power_setting", DT_U8, 0, NULL }, 902 { NL80211_ATTR_STA_VLAN, "sta_vlan", DT_U32, 0, NULL }, 903 { NL80211_ATTR_SUPPORTED_COMMANDS, "supported_commands", DT_U32, DF_NO_SET|DF_MULTIPLE|DF_AUTOIDX, NULL }, 904 { NL80211_ATTR_TESTDATA, "testdata", DT_NESTED, 0, &nl80211_testdata_nla }, 905 { NL80211_ATTR_TID_CONFIG, "tid_config", DT_NESTED, DF_MULTIPLE, &nl80211_tid_config_nla }, 906 { NL80211_ATTR_TIMEOUT, "timeout", DT_U32, 0, NULL }, 907 { NL80211_ATTR_TXQ_LIMIT, "txq_limit", DT_U32, 0, NULL }, 908 { NL80211_ATTR_TXQ_MEMORY_LIMIT, "txq_memory_limit", DT_U32, 0, NULL }, 909 { NL80211_ATTR_TXQ_QUANTUM, "txq_quantum", DT_U32, 0, NULL }, 910 { NL80211_ATTR_TX_FRAME_TYPES, "tx_frame_types", DT_NESTED, 0, &nl80211_frame_types_nla }, 911 { NL80211_ATTR_USE_MFP, "use_mfp", DT_U32, 0, NULL }, 912 { NL80211_ATTR_VENDOR_DATA, "vendor_data", DT_STRING, DF_BINARY, NULL }, 913 { NL80211_ATTR_VENDOR_ID, "vendor_id", DT_U32, 0, NULL }, 914 { NL80211_ATTR_VENDOR_SUBCMD, "vendor_subcmd", DT_U32, 0, NULL }, 915 { NL80211_ATTR_WDEV, "wdev", DT_U64, 0, NULL }, 916 { NL80211_ATTR_WIPHY, "wiphy", DT_U32, 0, NULL }, 917 { NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, "wiphy_antenna_avail_rx", DT_U32, 0, NULL }, 918 { NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, "wiphy_antenna_avail_tx", DT_U32, 0, NULL }, 919 { NL80211_ATTR_WIPHY_ANTENNA_RX, "wiphy_antenna_rx", DT_U32, 0, NULL }, 920 { NL80211_ATTR_WIPHY_ANTENNA_TX, "wiphy_antenna_tx", DT_U32, 0, NULL }, 921 { NL80211_ATTR_WIPHY_BANDS, "wiphy_bands", DT_NESTED, DF_NO_SET|DF_MULTIPLE|DF_TYPEIDX, &nl80211_wiphy_bands_nla }, 922 { NL80211_ATTR_WIPHY_CHANNEL_TYPE, "wiphy_channel_type", DT_U32, 0, NULL }, 923 { NL80211_ATTR_WIPHY_COVERAGE_CLASS, "wiphy_coverage_class", DT_U8, 0, NULL }, 924 { NL80211_ATTR_WIPHY_DYN_ACK, "wiphy_dyn_ack", DT_FLAG, 0, NULL }, 925 { NL80211_ATTR_WIPHY_FRAG_THRESHOLD, "wiphy_frag_threshold", DT_S32, 0, NULL }, 926 { NL80211_ATTR_WIPHY_FREQ, "wiphy_freq", DT_U32, 0, NULL }, 927 { NL80211_ATTR_WIPHY_NAME, "wiphy_name", DT_STRING, 0, NULL }, 928 { NL80211_ATTR_WIPHY_RETRY_LONG, "wiphy_retry_long", DT_U8, 0, NULL }, 929 { NL80211_ATTR_WIPHY_RETRY_SHORT, "wiphy_retry_short", DT_U8, 0, NULL }, 930 { NL80211_ATTR_WIPHY_RTS_THRESHOLD, "wiphy_rts_threshold", DT_S32, 0, NULL }, 931 { NL80211_ATTR_WIPHY_TX_POWER_LEVEL, "wiphy_tx_power_level", DT_U32, 0, NULL }, 932 { NL80211_ATTR_WIPHY_TX_POWER_SETTING, "wiphy_tx_power_setting", DT_U32, 0, NULL }, 933 { NL80211_ATTR_WOWLAN_TRIGGERS, "wowlan_triggers", DT_NESTED, 0, &nl80211_wowlan_triggers_nla }, 934 { NL80211_ATTR_WPA_VERSIONS, "wpa_versions", DT_U32, 0, NULL }, 935 { NL80211_ATTR_SUPPORTED_IFTYPES, "supported_iftypes", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla }, 936 { NL80211_ATTR_SOFTWARE_IFTYPES, "software_iftypes", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla }, 937 { NL80211_ATTR_MAX_AP_ASSOC_STA, "max_ap_assoc", DT_U16, 0, NULL }, 938 { NL80211_ATTR_SURVEY_INFO, "survey_info", DT_NESTED, 0, &nl80211_survey_info_nla }, 939 } 940 }; 941 942 943 static bool 944 nla_check_len(struct nlattr *nla, size_t sz) 945 { 946 return (nla && nla_len(nla) >= (ssize_t)sz); 947 } 948 949 static bool 950 nla_parse_error(const uc_nl_attr_spec_t *spec, uc_vm_t *vm, uc_value_t *v, const char *msg) 951 { 952 char *s; 953 954 s = ucv_to_string(vm, v); 955 956 set_error(NLE_INVAL, "%s `%s` has invalid value `%s`: %s", 957 spec->attr ? "attribute" : "field", 958 spec->key, 959 s, 960 msg); 961 962 free(s); 963 964 return false; 965 } 966 967 static void 968 uc_nl_put_struct_member(char *base, const void *offset, size_t datalen, void *data) 969 { 970 memcpy(base + (uintptr_t)offset, data, datalen); 971 } 972 973 static void 974 uc_nl_put_struct_member_u8(char *base, const void *offset, uint8_t u8) 975 { 976 base[(uintptr_t)offset] = u8; 977 } 978 979 static void 980 uc_nl_put_struct_member_u32(char *base, const void *offset, uint32_t u32) 981 { 982 uc_nl_put_struct_member(base, offset, sizeof(u32), &u32); 983 } 984 985 static void * 986 uc_nl_get_struct_member(char *base, const void *offset, size_t datalen, void *data) 987 { 988 memcpy(data, base + (uintptr_t)offset, datalen); 989 990 return data; 991 } 992 993 static uint8_t 994 uc_nl_get_struct_member_u8(char *base, const void *offset) 995 { 996 return (uint8_t)base[(uintptr_t)offset]; 997 } 998 999 static uint32_t 1000 uc_nl_get_struct_member_u32(char *base, const void *offset) 1001 { 1002 uint32_t u32; 1003 1004 uc_nl_get_struct_member(base, offset, sizeof(u32), &u32); 1005 1006 return u32; 1007 } 1008 1009 static void 1010 uc_nl_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len) 1011 { 1012 struct nlattr *nla; 1013 int rem; 1014 1015 memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); 1016 1017 nla_for_each_attr(nla, head, len, rem) { 1018 int type = nla_type(nla); 1019 1020 if (type <= maxtype) 1021 tb[type] = nla; 1022 } 1023 1024 if (rem > 0) 1025 fprintf(stderr, "netlink: %d bytes leftover after parsing attributes.\n", rem); 1026 } 1027 1028 1029 static bool 1030 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); 1031 1032 static uc_value_t * 1033 uc_nl_convert_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, struct nlattr **tb, uc_vm_t *vm); 1034 1035 static bool 1036 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) 1037 { 1038 struct nlattr **tb, *nla, *nla_nest; 1039 size_t i, type, maxattr = 0; 1040 uc_value_t *v, *arr; 1041 int rem; 1042 1043 for (i = 0; i < nattrs; i++) 1044 if (attrs[i].attr > maxattr) 1045 maxattr = attrs[i].attr; 1046 1047 tb = calloc(maxattr + 1, sizeof(struct nlattr *)); 1048 1049 if (!tb) 1050 return false; 1051 1052 uc_nl_nla_parse(tb, maxattr, buf + headsize, buflen - headsize); 1053 1054 nla_for_each_attr(nla, buf + headsize, buflen - headsize, rem) { 1055 type = nla_type(nla); 1056 1057 if (type <= maxattr) 1058 tb[type] = nla; 1059 } 1060 1061 for (i = 0; i < nattrs; i++) { 1062 if (attrs[i].attr != 0 && !tb[attrs[i].attr]) 1063 continue; 1064 1065 if (attrs[i].flags & DF_MULTIPLE) { 1066 arr = ucv_array_new(vm); 1067 nla_nest = tb[attrs[i].attr]; 1068 1069 nla_for_each_attr(nla, nla_data(nla_nest), nla_len(nla_nest), rem) { 1070 if (!(attrs[i].flags & (DF_AUTOIDX|DF_TYPEIDX)) && 1071 attrs[i].auxdata && nla_type(nla) != (intptr_t)attrs[i].auxdata) 1072 continue; 1073 1074 tb[attrs[i].attr] = nla; 1075 1076 v = uc_nl_convert_attr(&attrs[i], msg, (char *)buf, tb, vm); 1077 1078 if (!v) 1079 continue; 1080 1081 if (attrs[i].flags & DF_TYPEIDX) 1082 ucv_array_set(arr, nla_type(nla) - !!(attrs[i].flags & DF_OFFSET1), v); 1083 else 1084 ucv_array_push(arr, v); 1085 } 1086 1087 if (!ucv_array_length(arr)) { 1088 ucv_put(arr); 1089 1090 continue; 1091 } 1092 1093 v = arr; 1094 } 1095 else { 1096 v = uc_nl_convert_attr(&attrs[i], msg, (char *)buf, tb, vm); 1097 1098 if (!v) 1099 continue; 1100 } 1101 1102 ucv_object_add(obj, attrs[i].key, v); 1103 } 1104 1105 free(tb); 1106 1107 return true; 1108 } 1109 1110 static bool 1111 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) 1112 { 1113 struct nlattr *nla_nest = NULL; 1114 uc_value_t *v, *item; 1115 size_t i, j, idx; 1116 bool exists; 1117 1118 for (i = 0; i < nattrs; i++) { 1119 if (attrs[i].attr == NL80211_ATTR_NOT_IMPLEMENTED) 1120 continue; 1121 1122 v = ucv_object_get(obj, attrs[i].key, &exists); 1123 1124 if (!exists) 1125 continue; 1126 1127 if (attrs[i].flags & DF_MULTIPLE) { 1128 nla_nest = nla_nest_start(msg, attrs[i].attr); 1129 1130 if (ucv_type(v) == UC_ARRAY) { 1131 for (j = 0; j < ucv_array_length(v); j++) { 1132 item = ucv_array_get(v, j); 1133 1134 if (!item && (attrs[i].flags & DF_TYPEIDX)) 1135 continue; 1136 1137 if (!attrs[i].auxdata || (attrs[i].flags & (DF_AUTOIDX|DF_TYPEIDX))) 1138 idx = j + !!(attrs[i].flags & DF_OFFSET1); 1139 else 1140 idx = (uintptr_t)attrs[i].auxdata; 1141 1142 if (!uc_nl_parse_attr(&attrs[i], msg, base, vm, item, idx)) 1143 return false; 1144 } 1145 } 1146 else { 1147 if (!attrs[i].auxdata || (attrs[i].flags & (DF_AUTOIDX|DF_TYPEIDX))) 1148 idx = !!(attrs[i].flags & DF_OFFSET1); 1149 else 1150 idx = (uintptr_t)attrs[i].auxdata; 1151 1152 if (!uc_nl_parse_attr(&attrs[i], msg, base, vm, v, idx)) 1153 return false; 1154 } 1155 1156 nla_nest_end(msg, nla_nest); 1157 } 1158 else if (!uc_nl_parse_attr(&attrs[i], msg, base, vm, v, 0)) { 1159 return false; 1160 } 1161 } 1162 1163 return true; 1164 } 1165 1166 static bool 1167 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) 1168 { 1169 const uc_nl_nested_spec_t *nest = spec->auxdata; 1170 struct nlattr *nested_nla; 1171 1172 if (!nest) 1173 return false; 1174 1175 nested_nla = nla_reserve(msg, spec->attr, nest->headsize); 1176 1177 if (!uc_nl_parse_attrs(msg, nla_data(nested_nla), nest->attrs, nest->nattrs, vm, val)) 1178 return false; 1179 1180 nla_nest_end(msg, nested_nla); 1181 1182 return true; 1183 } 1184 1185 static uc_value_t * 1186 uc_nl_convert_rta_nested(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 1187 { 1188 const uc_nl_nested_spec_t *nest = spec->auxdata; 1189 uc_value_t *nested_obj; 1190 bool rv; 1191 1192 if (!nest) 1193 return NULL; 1194 1195 if (!nla_check_len(tb[spec->attr], nest->headsize)) 1196 return NULL; 1197 1198 nested_obj = ucv_object_new(vm); 1199 1200 rv = uc_nl_convert_attrs(msg, 1201 nla_data(tb[spec->attr]), nla_len(tb[spec->attr]), nest->headsize, 1202 nest->attrs, nest->nattrs, 1203 vm, nested_obj); 1204 1205 if (!rv) { 1206 ucv_put(nested_obj); 1207 1208 return NULL; 1209 } 1210 1211 return nested_obj; 1212 } 1213 1214 static uc_value_t * 1215 uc_nl_convert_rta_ht_mcs(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 1216 { 1217 uc_value_t *mcs_obj, *mcs_idx; 1218 uint16_t max_rate = 0; 1219 uint8_t *mcs; 1220 size_t i; 1221 1222 if (!nla_check_len(tb[spec->attr], 16)) 1223 return NULL; 1224 1225 mcs = nla_data(tb[spec->attr]); 1226 mcs_obj = ucv_object_new(vm); 1227 1228 max_rate = (mcs[10] | ((mcs[11] & 0x3) << 8)); 1229 1230 if (max_rate) 1231 ucv_object_add(mcs_obj, "rx_highest_data_rate", ucv_uint64_new(max_rate)); 1232 1233 mcs_idx = ucv_array_new(vm); 1234 1235 for (i = 0; i <= 76; i++) 1236 if (mcs[i / 8] & (1 << (i % 8))) 1237 ucv_array_push(mcs_idx, ucv_uint64_new(i)); 1238 1239 ucv_object_add(mcs_obj, "rx_mcs_indexes", mcs_idx); 1240 1241 ucv_object_add(mcs_obj, "tx_mcs_set_defined", ucv_boolean_new(mcs[12] & (1 << 0))); 1242 ucv_object_add(mcs_obj, "tx_rx_mcs_set_equal", ucv_boolean_new(!(mcs[12] & (1 << 1)))); 1243 ucv_object_add(mcs_obj, "tx_max_spatial_streams", ucv_uint64_new(((mcs[12] >> 2) & 3) + 1)); 1244 ucv_object_add(mcs_obj, "tx_unequal_modulation", ucv_boolean_new(mcs[12] & (1 << 4))); 1245 1246 return mcs_obj; 1247 } 1248 1249 static uc_value_t * 1250 uc_nl_convert_rta_ht_cap(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 1251 { 1252 uc_value_t *cap_obj, *mcs_obj, *rx_mask; 1253 struct ieee80211_ht_cap *cap; 1254 size_t i; 1255 1256 if (!nla_check_len(tb[spec->attr], sizeof(*cap))) 1257 return NULL; 1258 1259 cap = nla_data(tb[spec->attr]); 1260 cap_obj = ucv_object_new(vm); 1261 1262 ucv_object_add(cap_obj, "cap_info", ucv_uint64_new(le16toh(cap->cap_info))); 1263 ucv_object_add(cap_obj, "ampdu_params_info", ucv_uint64_new(cap->ampdu_params_info)); 1264 ucv_object_add(cap_obj, "extended_ht_cap_info", ucv_uint64_new(le16toh(cap->extended_ht_cap_info))); 1265 ucv_object_add(cap_obj, "tx_BF_cap_info", ucv_uint64_new(le32toh(cap->tx_BF_cap_info))); 1266 ucv_object_add(cap_obj, "antenna_selection_info", ucv_uint64_new(cap->antenna_selection_info)); 1267 1268 mcs_obj = ucv_object_new(vm); 1269 rx_mask = ucv_array_new_length(vm, sizeof(cap->mcs.rx_mask)); 1270 1271 for (i = 0; i < sizeof(cap->mcs.rx_mask); i++) 1272 ucv_array_push(rx_mask, ucv_uint64_new(cap->mcs.rx_mask[i])); 1273 1274 ucv_object_add(mcs_obj, "rx_mask", rx_mask); 1275 ucv_object_add(mcs_obj, "rx_highest", ucv_uint64_new(le16toh(cap->mcs.rx_highest))); 1276 ucv_object_add(mcs_obj, "tx_params", ucv_uint64_new(cap->mcs.tx_params)); 1277 1278 ucv_object_add(cap_obj, "mcs", mcs_obj); 1279 1280 return cap_obj; 1281 } 1282 1283 static uc_value_t * 1284 uc_nl_convert_rta_vht_mcs(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 1285 { 1286 uc_value_t *mcs_obj, *mcs_set, *mcs_entry, *mcs_idx; 1287 size_t i, j, max_idx; 1288 uint16_t u16; 1289 uint8_t *mcs; 1290 1291 if (!nla_check_len(tb[spec->attr], 16)) 1292 return NULL; 1293 1294 mcs = nla_data(tb[spec->attr]); 1295 mcs_obj = ucv_object_new(vm); 1296 1297 u16 = mcs[0] | (mcs[1] << 8); 1298 mcs_set = ucv_array_new(vm); 1299 1300 for (i = 1; i <= 8; i++) { 1301 switch ((u16 >> ((i - 1) * 2)) & 3) { 1302 case 0: max_idx = 7; break; 1303 case 1: max_idx = 8; break; 1304 case 2: max_idx = 9; break; 1305 case 3: continue; 1306 } 1307 1308 mcs_idx = ucv_array_new_length(vm, max_idx + 1); 1309 1310 for (j = 0; j <= max_idx; j++) 1311 ucv_array_push(mcs_idx, ucv_uint64_new(j)); 1312 1313 mcs_entry = ucv_object_new(vm); 1314 1315 ucv_object_add(mcs_entry, "streams", ucv_uint64_new(i)); 1316 ucv_object_add(mcs_entry, "mcs_indexes", mcs_idx); 1317 1318 ucv_array_push(mcs_set, mcs_entry); 1319 } 1320 1321 ucv_object_add(mcs_obj, "rx_mcs_set", mcs_set); 1322 ucv_object_add(mcs_obj, "rx_highest_data_rate", ucv_uint64_new((mcs[2] | (mcs[3] << 8)) & 0x1fff)); 1323 1324 u16 = mcs[4] | (mcs[5] << 8); 1325 mcs_set = ucv_array_new(vm); 1326 1327 for (i = 1; i <= 8; i++) { 1328 switch ((u16 >> ((i - 1) * 2)) & 3) { 1329 case 0: max_idx = 7; break; 1330 case 1: max_idx = 8; break; 1331 case 2: max_idx = 9; break; 1332 case 3: continue; 1333 } 1334 1335 mcs_idx = ucv_array_new_length(vm, max_idx + 1); 1336 1337 for (j = 0; j <= max_idx; j++) 1338 ucv_array_push(mcs_idx, ucv_uint64_new(j)); 1339 1340 mcs_entry = ucv_object_new(vm); 1341 1342 ucv_object_add(mcs_entry, "streams", ucv_uint64_new(i)); 1343 ucv_object_add(mcs_entry, "mcs_indexes", mcs_idx); 1344 1345 ucv_array_push(mcs_set, mcs_entry); 1346 } 1347 1348 ucv_object_add(mcs_obj, "tx_mcs_set", mcs_set); 1349 ucv_object_add(mcs_obj, "tx_highest_data_rate", ucv_uint64_new((mcs[6] | (mcs[7] << 8)) & 0x1fff)); 1350 1351 return mcs_obj; 1352 } 1353 1354 static uc_value_t * 1355 uc_nl_convert_rta_he_mcs(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 1356 { 1357 uint8_t bw_support_mask[] = { (1 << 1) | (1 << 2), (1 << 3), (1 << 4) }; 1358 uc_value_t *mcs_set, *mcs_bw, *mcs_dir, *mcs_entry, *mcs_idx; 1359 uint16_t bw[] = { 80, 160, 8080 }, mcs[16]; 1360 uint16_t u16, phy_cap_0 = 0; 1361 size_t i, j, k, l, max_idx; 1362 1363 if (!nla_check_len(tb[spec->attr], sizeof(mcs))) 1364 return NULL; 1365 1366 if (nla_check_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY], sizeof(phy_cap_0))) 1367 phy_cap_0 = nla_get_u16(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]); 1368 1369 memcpy(mcs, nla_data(tb[spec->attr]), sizeof(mcs)); 1370 1371 mcs_set = ucv_array_new_length(vm, 3); 1372 1373 for (i = 0; i < ARRAY_SIZE(bw); i++) { 1374 if (!(phy_cap_0 & (bw_support_mask[i] << 8))) 1375 continue; 1376 1377 mcs_bw = ucv_object_new(vm); 1378 1379 for (j = 0; j < 2; j++) { 1380 mcs_dir = ucv_array_new_length(vm, 8); 1381 1382 for (k = 0; k < 8; k++) { 1383 u16 = mcs[(i * 2) + k]; 1384 u16 >>= k * 2; 1385 u16 &= 0x3; 1386 1387 switch (u16) { 1388 case 0: max_idx = 7; break; 1389 case 1: max_idx = 8; break; 1390 case 2: max_idx = 9; break; 1391 case 3: continue; 1392 } 1393 1394 mcs_idx = ucv_array_new_length(vm, max_idx + 1); 1395 1396 for (l = 0; l <= max_idx; l++) 1397 ucv_array_push(mcs_idx, ucv_uint64_new(l)); 1398 1399 mcs_entry = ucv_object_new(vm); 1400 1401 ucv_object_add(mcs_entry, "streams", ucv_uint64_new(k + 1)); 1402 ucv_object_add(mcs_entry, "mcs_indexes", mcs_idx); 1403 1404 ucv_array_push(mcs_dir, mcs_entry); 1405 } 1406 1407 if (ucv_array_length(mcs_dir)) 1408 ucv_object_add(mcs_bw, j ? "tx_mcs_set" : "rx_mcs_set", mcs_dir); 1409 else 1410 ucv_put(mcs_dir); 1411 } 1412 1413 if (ucv_object_length(mcs_bw)) { 1414 ucv_object_add(mcs_bw, "bandwidth", ucv_uint64_new(bw[i])); 1415 ucv_array_push(mcs_set, mcs_bw); 1416 } 1417 else { 1418 ucv_put(mcs_bw); 1419 } 1420 } 1421 1422 return mcs_set; 1423 } 1424 1425 static uc_value_t * 1426 uc_nl_convert_rta_ie(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, struct nlattr **tb, uc_vm_t *vm) 1427 { 1428 uc_value_t *ie_arr, *ie_obj; 1429 uint8_t *ie; 1430 size_t len; 1431 1432 len = nla_len(tb[spec->attr]); 1433 ie = nla_data(tb[spec->attr]); 1434 1435 if (len < 2) 1436 return NULL; 1437 1438 ie_arr = ucv_array_new(vm); 1439 1440 while (len >= 2 && len - 2 >= ie[1]) { 1441 ie_obj = ucv_object_new(vm); 1442 1443 ucv_object_add(ie_obj, "type", ucv_uint64_new(ie[0])); 1444 ucv_object_add(ie_obj, "data", ucv_string_new_length((char *)&ie[2], ie[1])); 1445 1446 ucv_array_push(ie_arr, ie_obj); 1447 1448 len -= ie[1] + 2; 1449 ie += ie[1] + 2; 1450 } 1451 1452 return ie_arr; 1453 } 1454 1455 1456 static bool 1457 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) 1458 { 1459 uint64_t u64; 1460 uint32_t u32; 1461 uint16_t u16; 1462 uint8_t u8; 1463 1464 switch (spec->type) { 1465 case DT_U8: 1466 if (!uc_nl_parse_u32(val, &u32) || u32 > 255) 1467 return nla_parse_error(spec, vm, val, "not an integer or out of range 0-255"); 1468 1469 u8 = (uint8_t)u32; 1470 1471 memcpy(dst, &u8, sizeof(u8)); 1472 break; 1473 1474 case DT_U16: 1475 if (!uc_nl_parse_u32(val, &u32) || u32 > 65535) 1476 return nla_parse_error(spec, vm, val, "not an integer or out of range 0-65535"); 1477 1478 u16 = (uint16_t)u32; 1479 1480 memcpy(dst, &u16, sizeof(u16)); 1481 break; 1482 1483 case DT_S32: 1484 case DT_U32: 1485 if (spec->type == DT_S32 && !uc_nl_parse_s32(val, &u32)) 1486 return nla_parse_error(spec, vm, val, "not an integer or out of range -2147483648-2147483647"); 1487 else if (spec->type == DT_U32 && !uc_nl_parse_u32(val, &u32)) 1488 return nla_parse_error(spec, vm, val, "not an integer or out of range 0-4294967295"); 1489 1490 memcpy(dst, &u32, sizeof(u32)); 1491 break; 1492 1493 case DT_U64: 1494 if (!uc_nl_parse_u64(val, &u64)) 1495 return nla_parse_error(spec, vm, val, "not an integer or negative"); 1496 1497 memcpy(dst, &u64, sizeof(u64)); 1498 break; 1499 1500 default: 1501 return false; 1502 } 1503 1504 return true; 1505 } 1506 1507 static const uint8_t dt_sizes[] = { 1508 [DT_U8] = sizeof(uint8_t), 1509 [DT_S8] = sizeof(int8_t), 1510 [DT_U16] = sizeof(uint16_t), 1511 [DT_U32] = sizeof(uint32_t), 1512 [DT_S32] = sizeof(int32_t), 1513 [DT_U64] = sizeof(uint64_t), 1514 }; 1515 1516 static bool 1517 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) 1518 { 1519 char buf[sizeof(uint64_t)]; 1520 struct in_addr in = { 0 }; 1521 struct ether_addr *ea; 1522 struct nlattr *nla; 1523 uc_value_t *item; 1524 size_t attr, i; 1525 uint32_t u32; 1526 char *s; 1527 1528 if (spec->flags & DF_MULTIPLE) 1529 attr = idx; 1530 else 1531 attr = spec->attr; 1532 1533 switch (spec->type) { 1534 case DT_U8: 1535 case DT_U16: 1536 case DT_U32: 1537 case DT_S32: 1538 case DT_U64: 1539 if (spec->flags & DF_ARRAY) { 1540 assert(spec->attr != 0); 1541 1542 if (ucv_type(val) != UC_ARRAY) 1543 return nla_parse_error(spec, vm, val, "not an array"); 1544 1545 nla = nla_reserve(msg, spec->attr, ucv_array_length(val) * dt_sizes[spec->type]); 1546 s = nla_data(nla); 1547 1548 for (i = 0; i < ucv_array_length(val); i++) { 1549 item = ucv_array_get(val, i); 1550 1551 if (!uc_nl_parse_numval(spec, msg, base, vm, item, buf)) 1552 return false; 1553 1554 memcpy(s, buf, dt_sizes[spec->type]); 1555 1556 s += dt_sizes[spec->type]; 1557 } 1558 } 1559 else { 1560 if (!uc_nl_parse_numval(spec, msg, base, vm, val, buf)) 1561 return false; 1562 1563 if (spec->attr == 0) 1564 uc_nl_put_struct_member(base, spec->auxdata, dt_sizes[spec->type], buf); 1565 else 1566 nla_put(msg, attr, dt_sizes[spec->type], buf); 1567 } 1568 1569 break; 1570 1571 case DT_BOOL: 1572 u32 = (uint32_t)ucv_is_truish(val); 1573 1574 if (spec->attr == 0) 1575 uc_nl_put_struct_member_u8(base, spec->auxdata, u32); 1576 else 1577 nla_put_u8(msg, attr, u32); 1578 1579 break; 1580 1581 case DT_FLAG: 1582 u32 = (uint32_t)ucv_is_truish(val); 1583 1584 if (spec->attr == 0) 1585 uc_nl_put_struct_member_u8(base, spec->auxdata, u32); 1586 else if (u32 == 1) 1587 nla_put_flag(msg, attr); 1588 1589 break; 1590 1591 case DT_STRING: 1592 assert(spec->attr != 0); 1593 1594 s = ucv_to_string(vm, val); 1595 1596 if (!s) 1597 return nla_parse_error(spec, vm, val, "out of memory"); 1598 1599 nla_put_string(msg, attr, s); 1600 free(s); 1601 1602 break; 1603 1604 case DT_NETDEV: 1605 if (ucv_type(val) == UC_INTEGER) { 1606 if (ucv_int64_get(val) < 0 || 1607 ucv_int64_get(val) > UINT32_MAX) 1608 return nla_parse_error(spec, vm, val, "interface index out of range 0-4294967295"); 1609 1610 u32 = (uint32_t)ucv_int64_get(val); 1611 } 1612 else { 1613 s = ucv_to_string(vm, val); 1614 1615 if (!s) 1616 return nla_parse_error(spec, vm, val, "out of memory"); 1617 1618 u32 = if_nametoindex(s); 1619 1620 free(s); 1621 } 1622 1623 if (spec->attr == 0) 1624 uc_nl_put_struct_member_u32(base, spec->auxdata, u32); 1625 else 1626 nla_put_u32(msg, attr, u32); 1627 1628 break; 1629 1630 case DT_LLADDR: 1631 assert(spec->attr != 0); 1632 1633 s = ucv_to_string(vm, val); 1634 1635 if (!s) 1636 return nla_parse_error(spec, vm, val, "out of memory"); 1637 1638 ea = ether_aton(s); 1639 1640 free(s); 1641 1642 if (!ea) 1643 return nla_parse_error(spec, vm, val, "invalid MAC address"); 1644 1645 nla_put(msg, attr, sizeof(*ea), ea); 1646 1647 break; 1648 1649 case DT_INADDR: 1650 assert(spec->attr != 0); 1651 1652 if (!uc_nl_parse_ipaddr(vm, val, &in)) 1653 return nla_parse_error(spec, vm, val, "invalid IP address"); 1654 1655 nla_put(msg, attr, sizeof(in), &in); 1656 1657 break; 1658 1659 case DT_NESTED: 1660 if (!uc_nl_parse_rta_nested(spec, msg, base, vm, val)) 1661 return false; 1662 1663 break; 1664 1665 default: 1666 assert(0); 1667 } 1668 1669 return true; 1670 } 1671 1672 static uc_value_t * 1673 uc_nl_convert_numval(const uc_nl_attr_spec_t *spec, char *base) 1674 { 1675 union { uint8_t *u8; uint16_t *u16; uint32_t *u32; uint64_t *u64; char *base; } t = { .base = base }; 1676 1677 switch (spec->type) { 1678 case DT_U8: 1679 return ucv_uint64_new(t.u8[0]); 1680 1681 case DT_S8: 1682 return ucv_int64_new((int8_t)t.u8[0]); 1683 1684 case DT_U16: 1685 return ucv_uint64_new(t.u16[0]); 1686 1687 case DT_U32: 1688 return ucv_uint64_new(t.u32[0]); 1689 1690 case DT_S32: 1691 return ucv_int64_new((int32_t)t.u32[0]); 1692 1693 case DT_U64: 1694 return ucv_uint64_new(t.u64[0]); 1695 1696 default: 1697 return NULL; 1698 } 1699 } 1700 1701 static uc_value_t * 1702 uc_nl_convert_attr(const uc_nl_attr_spec_t *spec, struct nl_msg *msg, char *base, struct nlattr **tb, uc_vm_t *vm) 1703 { 1704 union { uint8_t u8; uint16_t u16; uint32_t u32; uint64_t u64; size_t sz; } t = { 0 }; 1705 char buf[sizeof("FF:FF:FF:FF:FF:FF")]; 1706 struct ether_addr *ea; 1707 uc_value_t *v; 1708 int i; 1709 1710 switch (spec->type) { 1711 case DT_U8: 1712 case DT_S8: 1713 case DT_U16: 1714 case DT_U32: 1715 case DT_S32: 1716 case DT_U64: 1717 if (spec->flags & DF_ARRAY) { 1718 assert(spec->attr != 0); 1719 assert((nla_len(tb[spec->attr]) % dt_sizes[spec->type]) == 0); 1720 1721 v = ucv_array_new_length(vm, nla_len(tb[spec->attr]) / dt_sizes[spec->type]); 1722 1723 for (i = 0; i < nla_len(tb[spec->attr]); i += dt_sizes[spec->type]) 1724 ucv_array_push(v, uc_nl_convert_numval(spec, nla_data(tb[spec->attr]) + i)); 1725 1726 return v; 1727 } 1728 else if (nla_check_len(tb[spec->attr], dt_sizes[spec->type])) { 1729 return uc_nl_convert_numval(spec, nla_data(tb[spec->attr])); 1730 } 1731 1732 return NULL; 1733 1734 case DT_BOOL: 1735 if (spec->attr == 0) 1736 t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata); 1737 else if (nla_check_len(tb[spec->attr], sizeof(t.u8))) 1738 t.u8 = nla_get_u8(tb[spec->attr]); 1739 1740 return ucv_boolean_new(t.u8 != 0); 1741 1742 case DT_FLAG: 1743 if (spec->attr == 0) 1744 t.u8 = uc_nl_get_struct_member_u8(base, spec->auxdata); 1745 else if (tb[spec->attr] != NULL) 1746 t.u8 = 1; 1747 1748 return ucv_boolean_new(t.u8 != 0); 1749 1750 case DT_STRING: 1751 assert(spec->attr != 0); 1752 1753 if (!nla_check_len(tb[spec->attr], 1)) 1754 return NULL; 1755 1756 t.sz = nla_len(tb[spec->attr]); 1757 1758 if (!(spec->flags & DF_BINARY)) 1759 t.sz -= 1; 1760 1761 return ucv_string_new_length(nla_data(tb[spec->attr]), t.sz); 1762 1763 case DT_NETDEV: 1764 if (spec->attr == 0) 1765 t.u32 = uc_nl_get_struct_member_u32(base, spec->auxdata); 1766 else if (nla_check_len(tb[spec->attr], sizeof(t.u32))) 1767 t.u32 = nla_get_u32(tb[spec->attr]); 1768 1769 if (if_indextoname(t.u32, buf)) 1770 return ucv_string_new(buf); 1771 1772 return NULL; 1773 1774 case DT_LLADDR: 1775 assert(spec->attr != 0); 1776 1777 if (!nla_check_len(tb[spec->attr], sizeof(*ea))) 1778 return NULL; 1779 1780 ea = nla_data(tb[spec->attr]); 1781 1782 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", 1783 ea->ether_addr_octet[0], ea->ether_addr_octet[1], 1784 ea->ether_addr_octet[2], ea->ether_addr_octet[3], 1785 ea->ether_addr_octet[4], ea->ether_addr_octet[5]); 1786 1787 return ucv_string_new(buf); 1788 1789 case DT_INADDR: 1790 assert(spec->attr != 0); 1791 1792 if (!nla_check_len(tb[spec->attr], sizeof(struct in_addr)) || 1793 !inet_ntop(AF_INET, nla_data(tb[spec->attr]), buf, sizeof(buf))) 1794 return NULL; 1795 1796 return ucv_string_new(buf); 1797 1798 case DT_NESTED: 1799 return uc_nl_convert_rta_nested(spec, msg, tb, vm); 1800 1801 case DT_HT_MCS: 1802 return uc_nl_convert_rta_ht_mcs(spec, msg, tb, vm); 1803 1804 case DT_HT_CAP: 1805 return uc_nl_convert_rta_ht_cap(spec, msg, tb, vm); 1806 1807 case DT_VHT_MCS: 1808 return uc_nl_convert_rta_vht_mcs(spec, msg, tb, vm); 1809 1810 case DT_HE_MCS: 1811 return uc_nl_convert_rta_he_mcs(spec, msg, tb, vm); 1812 1813 case DT_IE: 1814 return uc_nl_convert_rta_ie(spec, msg, tb, vm); 1815 1816 default: 1817 assert(0); 1818 } 1819 1820 return NULL; 1821 } 1822 1823 1824 static struct { 1825 struct nl_sock *sock; 1826 struct nl_sock *evsock; 1827 struct nl_cache *cache; 1828 struct genl_family *nl80211; 1829 struct genl_family *nlctrl; 1830 struct uloop_fd evsock_fd; 1831 struct nl_cb *evsock_cb; 1832 } nl80211_conn; 1833 1834 typedef enum { 1835 STATE_UNREPLIED, 1836 STATE_CONTINUE, 1837 STATE_REPLIED, 1838 STATE_ERROR 1839 } reply_state_t; 1840 1841 typedef struct { 1842 reply_state_t state; 1843 uc_vm_t *vm; 1844 uc_value_t *res; 1845 bool merge; 1846 } request_state_t; 1847 1848 1849 static uc_value_t * 1850 uc_nl_error(uc_vm_t *vm, size_t nargs) 1851 { 1852 uc_stringbuf_t *buf; 1853 const char *s; 1854 1855 if (last_error.code == 0) 1856 return NULL; 1857 1858 buf = ucv_stringbuf_new(); 1859 1860 if (last_error.code == NLE_FAILURE && last_error.msg) { 1861 ucv_stringbuf_addstr(buf, last_error.msg, strlen(last_error.msg)); 1862 } 1863 else { 1864 s = nl_geterror(last_error.code); 1865 1866 ucv_stringbuf_addstr(buf, s, strlen(s)); 1867 1868 if (last_error.msg) 1869 ucv_stringbuf_printf(buf, ": %s", last_error.msg); 1870 } 1871 1872 set_error(0, NULL); 1873 1874 return ucv_stringbuf_finish(buf); 1875 } 1876 1877 static int 1878 cb_done(struct nl_msg *msg, void *arg) 1879 { 1880 request_state_t *s = arg; 1881 1882 s->state = STATE_REPLIED; 1883 1884 return NL_STOP; 1885 } 1886 1887 static void 1888 deep_merge_array(uc_value_t *dest, uc_value_t *src); 1889 1890 static void 1891 deep_merge_object(uc_value_t *dest, uc_value_t *src); 1892 1893 static void 1894 deep_merge_array(uc_value_t *dest, uc_value_t *src) 1895 { 1896 uc_value_t *e, *v; 1897 size_t i; 1898 1899 if (ucv_type(dest) == UC_ARRAY && ucv_type(src) == UC_ARRAY) { 1900 for (i = 0; i < ucv_array_length(src); i++) { 1901 e = ucv_array_get(dest, i); 1902 v = ucv_array_get(src, i); 1903 1904 if (!e) 1905 ucv_array_set(dest, i, ucv_get(v)); 1906 else if (ucv_type(v) == UC_ARRAY) 1907 deep_merge_array(e, v); 1908 else if (ucv_type(v) == UC_OBJECT) 1909 deep_merge_object(e, v); 1910 } 1911 } 1912 } 1913 1914 static void 1915 deep_merge_object(uc_value_t *dest, uc_value_t *src) 1916 { 1917 uc_value_t *e; 1918 bool exists; 1919 1920 if (ucv_type(dest) == UC_OBJECT && ucv_type(src) == UC_OBJECT) { 1921 ucv_object_foreach(src, k, v) { 1922 e = ucv_object_get(dest, k, &exists); 1923 1924 if (!exists) 1925 ucv_object_add(dest, k, ucv_get(v)); 1926 else if (ucv_type(v) == UC_ARRAY) 1927 deep_merge_array(e, v); 1928 else if (ucv_type(v) == UC_OBJECT) 1929 deep_merge_object(e, v); 1930 } 1931 } 1932 } 1933 1934 static int 1935 cb_reply(struct nl_msg *msg, void *arg) 1936 { 1937 struct nlmsghdr *hdr = nlmsg_hdr(msg); 1938 struct genlmsghdr *gnlh = nlmsg_data(hdr); 1939 request_state_t *s = arg; 1940 uc_value_t *o, *idx; 1941 int64_t i; 1942 bool rv; 1943 1944 o = ucv_object_new(s->vm); 1945 1946 rv = uc_nl_convert_attrs(msg, 1947 genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), 1948 0, nl80211_msg.attrs, nl80211_msg.nattrs, s->vm, o); 1949 1950 if (rv) { 1951 if (hdr->nlmsg_flags & NLM_F_MULTI) { 1952 if (!s->res) 1953 s->res = ucv_array_new(s->vm); 1954 1955 if (s->merge) { 1956 idx = ucv_object_get(o, "wiphy", NULL); 1957 i = idx ? ucv_int64_get(idx) : -1; 1958 1959 if (i >= 0) { 1960 idx = ucv_array_get(s->res, i); 1961 1962 if (idx) { 1963 deep_merge_object(idx, o); 1964 ucv_put(o); 1965 } 1966 else { 1967 ucv_array_set(s->res, i, o); 1968 } 1969 } 1970 } 1971 else { 1972 ucv_array_push(s->res, o); 1973 } 1974 } 1975 else { 1976 s->res = o; 1977 } 1978 } 1979 else { 1980 ucv_put(o); 1981 } 1982 1983 s->state = STATE_CONTINUE; 1984 1985 return NL_SKIP; 1986 } 1987 1988 static bool 1989 uc_nl_connect_sock(struct nl_sock **sk, bool nonblocking) 1990 { 1991 int err, fd; 1992 1993 if (*sk) 1994 return true; 1995 1996 *sk = nl_socket_alloc(); 1997 1998 if (!*sk) { 1999 set_error(NLE_NOMEM, NULL); 2000 goto err; 2001 } 2002 2003 err = genl_connect(*sk); 2004 2005 if (err != 0) { 2006 set_error(err, NULL); 2007 goto err; 2008 } 2009 2010 fd = nl_socket_get_fd(*sk); 2011 2012 if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0) { 2013 set_error(NLE_FAILURE, "unable to set FD_CLOEXEC flag on socket: %s", strerror(errno)); 2014 goto err; 2015 } 2016 2017 if (nonblocking) { 2018 err = nl_socket_set_nonblocking(*sk); 2019 2020 if (err != 0) { 2021 set_error(err, NULL); 2022 goto err; 2023 } 2024 } 2025 2026 return true; 2027 2028 err: 2029 if (*sk) { 2030 nl_socket_free(*sk); 2031 *sk = NULL; 2032 } 2033 2034 return false; 2035 } 2036 2037 static int 2038 uc_nl_find_family_id(const char *name) 2039 { 2040 struct genl_family *fam; 2041 2042 if (!nl80211_conn.cache && genl_ctrl_alloc_cache(nl80211_conn.sock, &nl80211_conn.cache)) 2043 return -NLE_NOMEM; 2044 2045 fam = genl_ctrl_search_by_name(nl80211_conn.cache, name); 2046 2047 if (!fam) 2048 return -NLE_OBJ_NOTFOUND; 2049 2050 return genl_family_get_id(fam); 2051 } 2052 2053 static int 2054 cb_errno(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) 2055 { 2056 int *ret = arg; 2057 2058 *ret = err->error; 2059 2060 return NL_STOP; 2061 } 2062 2063 static int 2064 cb_ack(struct nl_msg *msg, void *arg) 2065 { 2066 int *ret = arg; 2067 2068 *ret = 0; 2069 2070 return NL_STOP; 2071 } 2072 2073 static int 2074 cb_subscribe(struct nl_msg *msg, void *arg) 2075 { 2076 struct nlattr *nla, *tb[CTRL_ATTR_MAX + 1], *grp[CTRL_ATTR_MCAST_GRP_MAX + 1]; 2077 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 2078 struct { int id; const char *group; } *ret = arg; 2079 int rem; 2080 2081 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); 2082 2083 if (!tb[CTRL_ATTR_MCAST_GROUPS]) 2084 return NL_SKIP; 2085 2086 nla_for_each_nested(nla, tb[CTRL_ATTR_MCAST_GROUPS], rem) { 2087 nla_parse(grp, CTRL_ATTR_MCAST_GRP_MAX, nla_data(nla), nla_len(nla), NULL); 2088 2089 if (!grp[CTRL_ATTR_MCAST_GRP_NAME] || !grp[CTRL_ATTR_MCAST_GRP_ID]) 2090 continue; 2091 2092 if (strncmp(nla_data(grp[CTRL_ATTR_MCAST_GRP_NAME]), 2093 ret->group, nla_len(grp[CTRL_ATTR_MCAST_GRP_NAME]))) 2094 continue; 2095 2096 ret->id = nla_get_u32(grp[CTRL_ATTR_MCAST_GRP_ID]); 2097 2098 break; 2099 } 2100 2101 return NL_SKIP; 2102 } 2103 2104 static bool 2105 uc_nl_subscribe(struct nl_sock *sk, const char *family, const char *group) 2106 { 2107 struct { int id; const char *group; } grp = { -NLE_OBJ_NOTFOUND, group }; 2108 struct nl_msg *msg; 2109 struct nl_cb *cb; 2110 int id, ret; 2111 2112 if (!uc_nl_connect_sock(&nl80211_conn.sock, false)) 2113 return NULL; 2114 2115 msg = nlmsg_alloc(); 2116 2117 if (!msg) 2118 err_return(NLE_NOMEM, NULL); 2119 2120 id = uc_nl_find_family_id("nlctrl"); 2121 2122 if (id < 0) 2123 err_return(-id, NULL); 2124 2125 genlmsg_put(msg, 0, 0, id, 0, 0, CTRL_CMD_GETFAMILY, 0); 2126 nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family); 2127 2128 cb = nl_cb_alloc(NL_CB_DEFAULT); 2129 2130 if (!cb) { 2131 nlmsg_free(msg); 2132 err_return(NLE_NOMEM, NULL); 2133 } 2134 2135 nl_send_auto_complete(nl80211_conn.sock, msg); 2136 2137 ret = 1; 2138 2139 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, cb_ack, &ret); 2140 nl_cb_err(cb, NL_CB_CUSTOM, cb_errno, &ret); 2141 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_subscribe, &grp); 2142 2143 while (ret > 0) 2144 nl_recvmsgs(nl80211_conn.sock, cb); 2145 2146 nlmsg_free(msg); 2147 nl_cb_put(cb); 2148 2149 if (ret < 0) 2150 err_return(ret, NULL); 2151 2152 if (grp.id < 0) 2153 err_return(grp.id, NULL); 2154 2155 ret = nl_socket_add_membership(sk, grp.id); 2156 2157 if (ret != 0) 2158 err_return(ret, NULL); 2159 2160 return true; 2161 } 2162 2163 2164 struct waitfor_ctx { 2165 uint8_t cmd; 2166 uc_vm_t *vm; 2167 uc_value_t *res; 2168 uint32_t cmds[NL80211_CMDS_BITMAP_SIZE]; 2169 }; 2170 2171 static uc_value_t * 2172 uc_nl_prepare_event(uc_vm_t *vm, struct nl_msg *msg) 2173 { 2174 struct nlmsghdr *hdr = nlmsg_hdr(msg); 2175 struct genlmsghdr *gnlh = nlmsg_data(hdr); 2176 uc_value_t *o = ucv_object_new(vm); 2177 2178 if (!uc_nl_convert_attrs(msg, genlmsg_attrdata(gnlh, 0), 2179 genlmsg_attrlen(gnlh, 0), 0, 2180 nl80211_msg.attrs, nl80211_msg.nattrs, vm, o)) { 2181 ucv_put(o); 2182 return NULL; 2183 } 2184 2185 return o; 2186 } 2187 2188 static int 2189 cb_listener_event(struct nl_msg *msg, void *arg) 2190 { 2191 struct nlmsghdr *hdr = nlmsg_hdr(msg); 2192 struct genlmsghdr *gnlh = nlmsg_data(hdr); 2193 uc_vm_t *vm = listener_vm; 2194 2195 if (!nl80211_conn.evsock_fd.registered || !vm) 2196 return NL_SKIP; 2197 2198 for (size_t i = 0; i < ucv_array_length(listener_registry); i += 2) { 2199 uc_value_t *this = ucv_array_get(listener_registry, i); 2200 uc_value_t *func = ucv_array_get(listener_registry, i + 1); 2201 uc_nl_listener_t *l; 2202 uc_value_t *o, *data; 2203 2204 l = ucv_resource_data(this, "nl80211.listener"); 2205 if (!l) 2206 continue; 2207 2208 if (gnlh->cmd > NL80211_CMD_MAX || 2209 !(l->cmds[gnlh->cmd / 32] & (1 << (gnlh->cmd % 32)))) 2210 continue; 2211 2212 if (!ucv_is_callable(func)) 2213 continue; 2214 2215 data = uc_nl_prepare_event(vm, msg); 2216 if (!data) 2217 return NL_SKIP; 2218 2219 o = ucv_object_new(vm); 2220 ucv_object_add(o, "cmd", ucv_int64_new(gnlh->cmd)); 2221 ucv_object_add(o, "msg", data); 2222 2223 uc_vm_stack_push(vm, ucv_get(this)); 2224 uc_vm_stack_push(vm, ucv_get(func)); 2225 uc_vm_stack_push(vm, o); 2226 2227 if (uc_vm_call(vm, true, 1) != EXCEPTION_NONE) { 2228 uloop_end(); 2229 return NL_STOP; 2230 } 2231 2232 ucv_put(uc_vm_stack_pop(vm)); 2233 } 2234 2235 return NL_SKIP; 2236 } 2237 2238 static int 2239 cb_event(struct nl_msg *msg, void *arg) 2240 { 2241 struct nlmsghdr *hdr = nlmsg_hdr(msg); 2242 struct genlmsghdr *gnlh = nlmsg_data(hdr); 2243 struct waitfor_ctx *s = arg; 2244 uc_value_t *o; 2245 2246 cb_listener_event(msg, arg); 2247 2248 if (gnlh->cmd > NL80211_CMD_MAX || 2249 !(s->cmds[gnlh->cmd / 32] & (1 << (gnlh->cmd % 32)))) 2250 return NL_SKIP; 2251 2252 o = uc_nl_prepare_event(s->vm, msg); 2253 if (o) 2254 s->res = o; 2255 2256 s->cmd = gnlh->cmd; 2257 2258 return NL_SKIP; 2259 } 2260 2261 static int 2262 cb_seq(struct nl_msg *msg, void *arg) 2263 { 2264 return NL_OK; 2265 } 2266 2267 static bool 2268 uc_nl_fill_cmds(uint32_t *cmd_bits, uc_value_t *cmds) 2269 { 2270 if (ucv_type(cmds) == UC_ARRAY) { 2271 for (size_t i = 0; i < ucv_array_length(cmds); i++) { 2272 int64_t n = ucv_int64_get(ucv_array_get(cmds, i)); 2273 2274 if (errno || n < 0 || n > NL80211_CMD_MAX) 2275 return false; 2276 2277 cmd_bits[n / 32] |= (1 << (n % 32)); 2278 } 2279 } 2280 else if (ucv_type(cmds) == UC_INTEGER) { 2281 int64_t n = ucv_int64_get(cmds); 2282 2283 if (errno || n < 0 || n > 255) 2284 return false; 2285 2286 cmd_bits[n / 32] |= (1 << (n % 32)); 2287 } 2288 else if (!cmds) 2289 memset(cmd_bits, 0xff, NL80211_CMDS_BITMAP_SIZE * sizeof(*cmd_bits)); 2290 else 2291 return false; 2292 2293 return true; 2294 } 2295 2296 static bool 2297 uc_nl_evsock_init(void) 2298 { 2299 if (nl80211_conn.evsock) 2300 return true; 2301 2302 if (!uc_nl_connect_sock(&nl80211_conn.evsock, true)) 2303 return false; 2304 2305 if (!uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "config") || 2306 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "scan") || 2307 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "regulatory") || 2308 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "mlme") || 2309 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "vendor") || 2310 !uc_nl_subscribe(nl80211_conn.evsock, "nl80211", "nan")) { 2311 nl_socket_free(nl80211_conn.evsock); 2312 nl80211_conn.evsock = NULL; 2313 return false; 2314 } 2315 2316 return true; 2317 } 2318 2319 static uc_value_t * 2320 uc_nl_waitfor(uc_vm_t *vm, size_t nargs) 2321 { 2322 struct pollfd pfd = { .events = POLLIN }; 2323 uc_value_t *cmds = uc_fn_arg(0); 2324 uc_value_t *timeout = uc_fn_arg(1); 2325 uc_value_t *rv = NULL; 2326 struct waitfor_ctx ctx = { .vm = vm }; 2327 struct nl_cb *cb; 2328 int ms = -1, err; 2329 2330 if (timeout) { 2331 int64_t n = ucv_int64_get(timeout); 2332 2333 if (ucv_type(timeout) != UC_INTEGER || n < INT32_MIN || n > INT32_MAX) 2334 err_return(NLE_INVAL, "Invalid timeout specified"); 2335 2336 ms = (int)n; 2337 } 2338 2339 if (!uc_nl_fill_cmds(ctx.cmds, cmds)) 2340 err_return(NLE_INVAL, "Invalid command ID specified"); 2341 2342 if (!uc_nl_evsock_init()) 2343 return NULL; 2344 2345 cb = nl_cb_alloc(NL_CB_DEFAULT); 2346 2347 if (!cb) 2348 err_return(NLE_NOMEM, NULL); 2349 2350 err = 0; 2351 2352 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, cb_seq, NULL); 2353 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_event, &ctx); 2354 nl_cb_err(cb, NL_CB_CUSTOM, cb_errno, &err); 2355 2356 pfd.fd = nl_socket_get_fd(nl80211_conn.evsock); 2357 2358 if (poll(&pfd, 1, ms) == 1) { 2359 while (err == 0 && ctx.cmd == 0) 2360 nl_recvmsgs(nl80211_conn.evsock, cb); 2361 } 2362 2363 nl_cb_put(cb); 2364 2365 if (ctx.cmd) { 2366 rv = ucv_object_new(vm); 2367 2368 ucv_object_add(rv, "cmd", ucv_int64_new(ctx.cmd)); 2369 ucv_object_add(rv, "msg", ctx.res); 2370 2371 return rv; 2372 } 2373 else if (err) { 2374 err_return(err, NULL); 2375 } 2376 else { 2377 err_return(NLE_FAILURE, "No event received"); 2378 } 2379 } 2380 2381 static uc_value_t * 2382 uc_nl_request(uc_vm_t *vm, size_t nargs) 2383 { 2384 request_state_t st = { .vm = vm }; 2385 uc_value_t *cmd = uc_fn_arg(0); 2386 uc_value_t *flags = uc_fn_arg(1); 2387 uc_value_t *payload = uc_fn_arg(2); 2388 uint16_t flagval = 0; 2389 struct nl_msg *msg; 2390 struct nl_cb *cb; 2391 int ret, id; 2392 2393 if (ucv_type(cmd) != UC_INTEGER || ucv_int64_get(cmd) < 0 || 2394 (flags != NULL && ucv_type(flags) != UC_INTEGER) || 2395 (payload != NULL && ucv_type(payload) != UC_OBJECT)) 2396 err_return(NLE_INVAL, NULL); 2397 2398 if (flags) { 2399 if (ucv_int64_get(flags) < 0 || ucv_int64_get(flags) > 0xffff) 2400 err_return(NLE_INVAL, NULL); 2401 else 2402 flagval = (uint16_t)ucv_int64_get(flags); 2403 } 2404 2405 if (!uc_nl_connect_sock(&nl80211_conn.sock, false)) 2406 return NULL; 2407 2408 msg = nlmsg_alloc(); 2409 2410 if (!msg) 2411 err_return(NLE_NOMEM, NULL); 2412 2413 id = uc_nl_find_family_id("nl80211"); 2414 2415 if (id < 0) 2416 err_return(-id, NULL); 2417 2418 genlmsg_put(msg, 0, 0, id, 0, flagval, ucv_int64_get(cmd), 0); 2419 2420 if (!uc_nl_parse_attrs(msg, nlmsg_data(nlmsg_hdr(msg)), nl80211_msg.attrs, nl80211_msg.nattrs, vm, payload)) { 2421 nlmsg_free(msg); 2422 2423 return NULL; 2424 } 2425 2426 switch (ucv_int64_get(cmd)) { 2427 case NL80211_CMD_GET_WIPHY: 2428 st.merge = true; 2429 break; 2430 } 2431 2432 cb = nl_cb_alloc(NL_CB_DEFAULT); 2433 2434 if (!cb) { 2435 nlmsg_free(msg); 2436 err_return(NLE_NOMEM, NULL); 2437 } 2438 2439 ret = 1; 2440 2441 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_reply, &st); 2442 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_done, &st); 2443 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, cb_done, &st); 2444 nl_cb_err(cb, NL_CB_CUSTOM, cb_errno, &ret); 2445 2446 nl_send_auto_complete(nl80211_conn.sock, msg); 2447 2448 while (ret > 0 && st.state < STATE_REPLIED) 2449 nl_recvmsgs(nl80211_conn.sock, cb); 2450 2451 nlmsg_free(msg); 2452 nl_cb_put(cb); 2453 2454 if (ret < 0) 2455 err_return(nl_syserr2nlerr(ret), NULL); 2456 2457 switch (st.state) { 2458 case STATE_REPLIED: 2459 return st.res; 2460 2461 case STATE_UNREPLIED: 2462 return ucv_boolean_new(true); 2463 2464 default: 2465 set_error(NLE_FAILURE, "Interrupted reply"); 2466 2467 return ucv_boolean_new(false); 2468 } 2469 } 2470 2471 static void 2472 uc_nl_listener_cb(struct uloop_fd *fd, unsigned int events) 2473 { 2474 nl_recvmsgs(nl80211_conn.evsock, nl80211_conn.evsock_cb); 2475 } 2476 2477 static uc_value_t * 2478 uc_nl_listener(uc_vm_t *vm, size_t nargs) 2479 { 2480 struct uloop_fd *fd = &nl80211_conn.evsock_fd; 2481 uc_nl_listener_t *l; 2482 uc_value_t *cb_func = uc_fn_arg(0); 2483 uc_value_t *cmds = uc_fn_arg(1); 2484 uc_value_t *rv; 2485 size_t i; 2486 2487 if (!ucv_is_callable(cb_func)) { 2488 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid callback"); 2489 return NULL; 2490 } 2491 2492 if (!uc_nl_evsock_init()) 2493 return NULL; 2494 2495 if (!fd->registered) { 2496 fd->fd = nl_socket_get_fd(nl80211_conn.evsock); 2497 fd->cb = uc_nl_listener_cb; 2498 uloop_fd_add(fd, ULOOP_READ); 2499 } 2500 2501 if (!nl80211_conn.evsock_cb) { 2502 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT); 2503 2504 if (!cb) 2505 err_return(NLE_NOMEM, NULL); 2506 2507 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, cb_seq, NULL); 2508 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_listener_event, NULL); 2509 nl80211_conn.evsock_cb = cb; 2510 } 2511 2512 for (i = 0; i < ucv_array_length(listener_registry); i += 2) { 2513 if (!ucv_array_get(listener_registry, i)) 2514 break; 2515 } 2516 2517 ucv_array_set(listener_registry, i + 1, ucv_get(cb_func)); 2518 l = xalloc(sizeof(*l)); 2519 l->index = i; 2520 if (!uc_nl_fill_cmds(l->cmds, cmds)) { 2521 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid command ID"); 2522 free(l); 2523 return NULL; 2524 } 2525 2526 rv = uc_resource_new(listener_type, l); 2527 ucv_array_set(listener_registry, i, ucv_get(rv)); 2528 listener_vm = vm; 2529 2530 return rv; 2531 } 2532 2533 static void 2534 uc_nl_listener_free(void *arg) 2535 { 2536 uc_nl_listener_t *l = arg; 2537 2538 ucv_array_set(listener_registry, l->index, NULL); 2539 ucv_array_set(listener_registry, l->index + 1, NULL); 2540 free(l); 2541 } 2542 2543 static uc_value_t * 2544 uc_nl_listener_set_commands(uc_vm_t *vm, size_t nargs) 2545 { 2546 uc_nl_listener_t *l = uc_fn_thisval("nl80211.listener"); 2547 uc_value_t *cmds = uc_fn_arg(0); 2548 2549 if (!l) 2550 return NULL; 2551 2552 memset(l->cmds, 0, sizeof(l->cmds)); 2553 if (!uc_nl_fill_cmds(l->cmds, cmds)) 2554 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid command ID"); 2555 2556 return NULL; 2557 } 2558 2559 static uc_value_t * 2560 uc_nl_listener_close(uc_vm_t *vm, size_t nargs) 2561 { 2562 uc_nl_listener_t **lptr = uc_fn_this("nl80211.listener"); 2563 uc_nl_listener_t *l; 2564 2565 if (!lptr) 2566 return NULL; 2567 2568 l = *lptr; 2569 if (!l) 2570 return NULL; 2571 2572 *lptr = NULL; 2573 uc_nl_listener_free(l); 2574 2575 return NULL; 2576 } 2577 2578 2579 static void 2580 register_constants(uc_vm_t *vm, uc_value_t *scope) 2581 { 2582 uc_value_t *c = ucv_object_new(vm); 2583 2584 #define ADD_CONST(x) ucv_object_add(c, #x, ucv_int64_new(x)) 2585 2586 ADD_CONST(NLM_F_ACK); 2587 ADD_CONST(NLM_F_ACK_TLVS); 2588 ADD_CONST(NLM_F_APPEND); 2589 ADD_CONST(NLM_F_ATOMIC); 2590 ADD_CONST(NLM_F_CAPPED); 2591 ADD_CONST(NLM_F_CREATE); 2592 ADD_CONST(NLM_F_DUMP); 2593 ADD_CONST(NLM_F_DUMP_FILTERED); 2594 ADD_CONST(NLM_F_DUMP_INTR); 2595 ADD_CONST(NLM_F_ECHO); 2596 ADD_CONST(NLM_F_EXCL); 2597 ADD_CONST(NLM_F_MATCH); 2598 ADD_CONST(NLM_F_MULTI); 2599 ADD_CONST(NLM_F_NONREC); 2600 ADD_CONST(NLM_F_REPLACE); 2601 ADD_CONST(NLM_F_REQUEST); 2602 ADD_CONST(NLM_F_ROOT); 2603 2604 ADD_CONST(NL80211_CMD_GET_WIPHY); 2605 ADD_CONST(NL80211_CMD_SET_WIPHY); 2606 ADD_CONST(NL80211_CMD_NEW_WIPHY); 2607 ADD_CONST(NL80211_CMD_DEL_WIPHY); 2608 ADD_CONST(NL80211_CMD_GET_INTERFACE); 2609 ADD_CONST(NL80211_CMD_SET_INTERFACE); 2610 ADD_CONST(NL80211_CMD_NEW_INTERFACE); 2611 ADD_CONST(NL80211_CMD_DEL_INTERFACE); 2612 ADD_CONST(NL80211_CMD_GET_KEY); 2613 ADD_CONST(NL80211_CMD_SET_KEY); 2614 ADD_CONST(NL80211_CMD_NEW_KEY); 2615 ADD_CONST(NL80211_CMD_DEL_KEY); 2616 ADD_CONST(NL80211_CMD_GET_BEACON); 2617 ADD_CONST(NL80211_CMD_SET_BEACON); 2618 ADD_CONST(NL80211_CMD_START_AP); 2619 ADD_CONST(NL80211_CMD_NEW_BEACON); 2620 ADD_CONST(NL80211_CMD_STOP_AP); 2621 ADD_CONST(NL80211_CMD_DEL_BEACON); 2622 ADD_CONST(NL80211_CMD_GET_STATION); 2623 ADD_CONST(NL80211_CMD_SET_STATION); 2624 ADD_CONST(NL80211_CMD_NEW_STATION); 2625 ADD_CONST(NL80211_CMD_DEL_STATION); 2626 ADD_CONST(NL80211_CMD_GET_MPATH); 2627 ADD_CONST(NL80211_CMD_SET_MPATH); 2628 ADD_CONST(NL80211_CMD_NEW_MPATH); 2629 ADD_CONST(NL80211_CMD_DEL_MPATH); 2630 ADD_CONST(NL80211_CMD_SET_BSS); 2631 ADD_CONST(NL80211_CMD_SET_REG); 2632 ADD_CONST(NL80211_CMD_REQ_SET_REG); 2633 ADD_CONST(NL80211_CMD_GET_MESH_CONFIG); 2634 ADD_CONST(NL80211_CMD_SET_MESH_CONFIG); 2635 ADD_CONST(NL80211_CMD_GET_REG); 2636 ADD_CONST(NL80211_CMD_GET_SCAN); 2637 ADD_CONST(NL80211_CMD_TRIGGER_SCAN); 2638 ADD_CONST(NL80211_CMD_NEW_SCAN_RESULTS); 2639 ADD_CONST(NL80211_CMD_SCAN_ABORTED); 2640 ADD_CONST(NL80211_CMD_REG_CHANGE); 2641 ADD_CONST(NL80211_CMD_AUTHENTICATE); 2642 ADD_CONST(NL80211_CMD_ASSOCIATE); 2643 ADD_CONST(NL80211_CMD_DEAUTHENTICATE); 2644 ADD_CONST(NL80211_CMD_DISASSOCIATE); 2645 ADD_CONST(NL80211_CMD_MICHAEL_MIC_FAILURE); 2646 ADD_CONST(NL80211_CMD_REG_BEACON_HINT); 2647 ADD_CONST(NL80211_CMD_JOIN_IBSS); 2648 ADD_CONST(NL80211_CMD_LEAVE_IBSS); 2649 ADD_CONST(NL80211_CMD_TESTMODE); 2650 ADD_CONST(NL80211_CMD_CONNECT); 2651 ADD_CONST(NL80211_CMD_ROAM); 2652 ADD_CONST(NL80211_CMD_DISCONNECT); 2653 ADD_CONST(NL80211_CMD_SET_WIPHY_NETNS); 2654 ADD_CONST(NL80211_CMD_GET_SURVEY); 2655 ADD_CONST(NL80211_CMD_NEW_SURVEY_RESULTS); 2656 ADD_CONST(NL80211_CMD_SET_PMKSA); 2657 ADD_CONST(NL80211_CMD_DEL_PMKSA); 2658 ADD_CONST(NL80211_CMD_FLUSH_PMKSA); 2659 ADD_CONST(NL80211_CMD_REMAIN_ON_CHANNEL); 2660 ADD_CONST(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL); 2661 ADD_CONST(NL80211_CMD_SET_TX_BITRATE_MASK); 2662 ADD_CONST(NL80211_CMD_REGISTER_FRAME); 2663 ADD_CONST(NL80211_CMD_REGISTER_ACTION); 2664 ADD_CONST(NL80211_CMD_FRAME); 2665 ADD_CONST(NL80211_CMD_ACTION); 2666 ADD_CONST(NL80211_CMD_FRAME_TX_STATUS); 2667 ADD_CONST(NL80211_CMD_ACTION_TX_STATUS); 2668 ADD_CONST(NL80211_CMD_SET_POWER_SAVE); 2669 ADD_CONST(NL80211_CMD_GET_POWER_SAVE); 2670 ADD_CONST(NL80211_CMD_SET_CQM); 2671 ADD_CONST(NL80211_CMD_NOTIFY_CQM); 2672 ADD_CONST(NL80211_CMD_SET_CHANNEL); 2673 ADD_CONST(NL80211_CMD_SET_WDS_PEER); 2674 ADD_CONST(NL80211_CMD_FRAME_WAIT_CANCEL); 2675 ADD_CONST(NL80211_CMD_JOIN_MESH); 2676 ADD_CONST(NL80211_CMD_LEAVE_MESH); 2677 ADD_CONST(NL80211_CMD_UNPROT_DEAUTHENTICATE); 2678 ADD_CONST(NL80211_CMD_UNPROT_DISASSOCIATE); 2679 ADD_CONST(NL80211_CMD_NEW_PEER_CANDIDATE); 2680 ADD_CONST(NL80211_CMD_GET_WOWLAN); 2681 ADD_CONST(NL80211_CMD_SET_WOWLAN); 2682 ADD_CONST(NL80211_CMD_START_SCHED_SCAN); 2683 ADD_CONST(NL80211_CMD_STOP_SCHED_SCAN); 2684 ADD_CONST(NL80211_CMD_SCHED_SCAN_RESULTS); 2685 ADD_CONST(NL80211_CMD_SCHED_SCAN_STOPPED); 2686 ADD_CONST(NL80211_CMD_SET_REKEY_OFFLOAD); 2687 ADD_CONST(NL80211_CMD_PMKSA_CANDIDATE); 2688 ADD_CONST(NL80211_CMD_TDLS_OPER); 2689 ADD_CONST(NL80211_CMD_TDLS_MGMT); 2690 ADD_CONST(NL80211_CMD_UNEXPECTED_FRAME); 2691 ADD_CONST(NL80211_CMD_PROBE_CLIENT); 2692 ADD_CONST(NL80211_CMD_REGISTER_BEACONS); 2693 ADD_CONST(NL80211_CMD_UNEXPECTED_4ADDR_FRAME); 2694 ADD_CONST(NL80211_CMD_SET_NOACK_MAP); 2695 ADD_CONST(NL80211_CMD_CH_SWITCH_NOTIFY); 2696 ADD_CONST(NL80211_CMD_START_P2P_DEVICE); 2697 ADD_CONST(NL80211_CMD_STOP_P2P_DEVICE); 2698 ADD_CONST(NL80211_CMD_CONN_FAILED); 2699 ADD_CONST(NL80211_CMD_SET_MCAST_RATE); 2700 ADD_CONST(NL80211_CMD_SET_MAC_ACL); 2701 ADD_CONST(NL80211_CMD_RADAR_DETECT); 2702 ADD_CONST(NL80211_CMD_GET_PROTOCOL_FEATURES); 2703 ADD_CONST(NL80211_CMD_UPDATE_FT_IES); 2704 ADD_CONST(NL80211_CMD_FT_EVENT); 2705 ADD_CONST(NL80211_CMD_CRIT_PROTOCOL_START); 2706 ADD_CONST(NL80211_CMD_CRIT_PROTOCOL_STOP); 2707 ADD_CONST(NL80211_CMD_GET_COALESCE); 2708 ADD_CONST(NL80211_CMD_SET_COALESCE); 2709 ADD_CONST(NL80211_CMD_CHANNEL_SWITCH); 2710 ADD_CONST(NL80211_CMD_VENDOR); 2711 ADD_CONST(NL80211_CMD_SET_QOS_MAP); 2712 ADD_CONST(NL80211_CMD_ADD_TX_TS); 2713 ADD_CONST(NL80211_CMD_DEL_TX_TS); 2714 ADD_CONST(NL80211_CMD_GET_MPP); 2715 ADD_CONST(NL80211_CMD_JOIN_OCB); 2716 ADD_CONST(NL80211_CMD_LEAVE_OCB); 2717 ADD_CONST(NL80211_CMD_CH_SWITCH_STARTED_NOTIFY); 2718 ADD_CONST(NL80211_CMD_TDLS_CHANNEL_SWITCH); 2719 ADD_CONST(NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH); 2720 2721 ADD_CONST(NL80211_IFTYPE_ADHOC); 2722 ADD_CONST(NL80211_IFTYPE_STATION); 2723 ADD_CONST(NL80211_IFTYPE_AP); 2724 ADD_CONST(NL80211_IFTYPE_AP_VLAN); 2725 ADD_CONST(NL80211_IFTYPE_WDS); 2726 ADD_CONST(NL80211_IFTYPE_MONITOR); 2727 ADD_CONST(NL80211_IFTYPE_MESH_POINT); 2728 ADD_CONST(NL80211_IFTYPE_P2P_CLIENT); 2729 ADD_CONST(NL80211_IFTYPE_P2P_GO); 2730 ADD_CONST(NL80211_IFTYPE_P2P_DEVICE); 2731 ADD_CONST(NL80211_IFTYPE_OCB); 2732 2733 ucv_object_add(scope, "const", c); 2734 }; 2735 2736 static const uc_function_list_t global_fns[] = { 2737 { "error", uc_nl_error }, 2738 { "request", uc_nl_request }, 2739 { "waitfor", uc_nl_waitfor }, 2740 { "listener", uc_nl_listener }, 2741 }; 2742 2743 2744 static const uc_function_list_t listener_fns[] = { 2745 { "set_commands", uc_nl_listener_set_commands }, 2746 { "close", uc_nl_listener_close }, 2747 }; 2748 2749 void uc_module_init(uc_vm_t *vm, uc_value_t *scope) 2750 { 2751 uc_function_list_register(scope, global_fns); 2752 2753 listener_type = uc_type_declare(vm, "nl80211.listener", listener_fns, uc_nl_listener_free); 2754 listener_registry = ucv_array_new(vm); 2755 2756 uc_vm_registry_set(vm, "nl80211.registry", listener_registry); 2757 2758 register_constants(vm, scope); 2759 } 2760
This page was automatically generated by LXR 0.3.1. • OpenWrt