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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt