• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/lib/nl80211.c

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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt