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