blob: 1385edb2e5f64a84b82b63a9037b803e457128ef [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * Driver interaction with Linux nl80211/cfg80211
Dmitry Shmidt807291d2015-01-27 13:40:23 -08003 * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 * Copyright (c) 2003-2004, Instant802 Networks, Inc.
5 * Copyright (c) 2005-2006, Devicescape Software, Inc.
6 * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
7 * Copyright (c) 2009-2010, Atheros Communications
8 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009 * This software may be distributed under the terms of the BSD license.
10 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011 */
12
13#include "includes.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014#include <sys/types.h>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070015#include <fcntl.h>
16#include <net/if.h>
17#include <netlink/genl/genl.h>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070018#include <netlink/genl/ctrl.h>
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070019#ifdef CONFIG_LIBNL3_ROUTE
20#include <netlink/route/neighbour.h>
21#endif /* CONFIG_LIBNL3_ROUTE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070022#include <linux/rtnetlink.h>
23#include <netpacket/packet.h>
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080024#include <linux/errqueue.h>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070025
26#include "common.h"
27#include "eloop.h"
Dmitry Shmidtcf32e602014-01-28 10:57:39 -080028#include "common/qca-vendor.h"
Dmitry Shmidt7832adb2014-04-29 10:53:02 -070029#include "common/qca-vendor-attr.h"
Hai Shalomc1a21442022-02-04 13:43:00 -080030#include "common/brcm_vendor.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070031#include "common/ieee802_11_defs.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080032#include "common/ieee802_11_common.h"
Paul Stewart092955c2017-02-06 09:13:09 -080033#include "common/wpa_common.h"
Sunil Ravi89eba102022-09-13 21:04:37 -070034#include "crypto/sha256.h"
35#include "crypto/sha384.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070036#include "netlink.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080037#include "linux_defines.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070038#include "linux_ioctl.h"
39#include "radiotap.h"
40#include "radiotap_iter.h"
41#include "rfkill.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080042#include "driver_nl80211.h"
Andy Kuoaba17c12022-04-14 16:05:31 +080043#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Ajay Davanagerib921bb82020-09-16 12:49:08 +053044#include "common/brcm_vendor.h"
Andy Kuoaba17c12022-04-14 16:05:31 +080045#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080046
Hai Shalom74f70d42019-02-11 14:42:39 -080047#ifndef NETLINK_CAP_ACK
48#define NETLINK_CAP_ACK 10
49#endif /* NETLINK_CAP_ACK */
Hai Shalom39ba6fc2019-01-22 12:40:38 -080050/* support for extack if compilation headers are too old */
51#ifndef NETLINK_EXT_ACK
52#define NETLINK_EXT_ACK 11
53enum nlmsgerr_attrs {
54 NLMSGERR_ATTR_UNUSED,
55 NLMSGERR_ATTR_MSG,
56 NLMSGERR_ATTR_OFFS,
57 NLMSGERR_ATTR_COOKIE,
58
59 __NLMSGERR_ATTR_MAX,
60 NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
61};
62#endif
63#ifndef NLM_F_CAPPED
64#define NLM_F_CAPPED 0x100
65#endif
66#ifndef NLM_F_ACK_TLVS
67#define NLM_F_ACK_TLVS 0x200
68#endif
69#ifndef SOL_NETLINK
70#define SOL_NETLINK 270
71#endif
72
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070073
Dmitry Shmidt54605472013-11-08 11:10:19 -080074#ifdef ANDROID
75/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
Dmitry Shmidt54605472013-11-08 11:10:19 -080076#undef nl_socket_set_nonblocking
77#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080078
Dmitry Shmidt54605472013-11-08 11:10:19 -080079#endif /* ANDROID */
80
81
Hai Shalomfdcde762020-04-02 11:19:20 -070082static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080083{
Hai Shalomfdcde762020-04-02 11:19:20 -070084 struct nl_sock *handle;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080085
Hai Shalomfdcde762020-04-02 11:19:20 -070086 handle = nl_socket_alloc_cb(cb);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080087 if (handle == NULL) {
88 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
89 "callbacks (%s)", dbg);
90 return NULL;
91 }
92
93 if (genl_connect(handle)) {
94 wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
95 "netlink (%s)", dbg);
Hai Shalomfdcde762020-04-02 11:19:20 -070096 nl_socket_free(handle);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080097 return NULL;
98 }
99
100 return handle;
101}
102
103
Hai Shalomfdcde762020-04-02 11:19:20 -0700104static void nl_destroy_handles(struct nl_sock **handle)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800105{
106 if (*handle == NULL)
107 return;
Hai Shalomfdcde762020-04-02 11:19:20 -0700108 nl_socket_free(*handle);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800109 *handle = NULL;
110}
111
112
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700113#if __WORDSIZE == 64
114#define ELOOP_SOCKET_INVALID (intptr_t) 0x8888888888888889ULL
115#else
116#define ELOOP_SOCKET_INVALID (intptr_t) 0x88888889ULL
117#endif
118
Hai Shalomfdcde762020-04-02 11:19:20 -0700119static void nl80211_register_eloop_read(struct nl_sock **handle,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700120 eloop_sock_handler handler,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700121 void *eloop_data, int persist)
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700122{
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800123 /*
124 * libnl uses a pretty small buffer (32 kB that gets converted to 64 kB)
125 * by default. It is possible to hit that limit in some cases where
126 * operations are blocked, e.g., with a burst of Deauthentication frames
127 * to hostapd and STA entry deletion. Try to increase the buffer to make
128 * this less likely to occur.
129 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700130 int err;
131
132 err = nl_socket_set_buffer_size(*handle, 262144, 0);
133 if (err < 0) {
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800134 wpa_printf(MSG_DEBUG,
135 "nl80211: Could not set nl_socket RX buffer size: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -0700136 nl_geterror(err));
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800137 /* continue anyway with the default (smaller) buffer */
138 }
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800139
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700140 nl_socket_set_nonblocking(*handle);
141 eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
142 eloop_data, *handle);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700143 if (!persist)
144 *handle = (void *) (((intptr_t) *handle) ^
145 ELOOP_SOCKET_INVALID);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700146}
147
148
Hai Shalomfdcde762020-04-02 11:19:20 -0700149static void nl80211_destroy_eloop_handle(struct nl_sock **handle, int persist)
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700150{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700151 if (!persist)
152 *handle = (void *) (((intptr_t) *handle) ^
153 ELOOP_SOCKET_INVALID);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700154 eloop_unregister_read_sock(nl_socket_get_fd(*handle));
155 nl_destroy_handles(handle);
156}
157
158
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800159static void nl80211_global_deinit(void *priv);
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800160static void nl80211_check_global(struct nl80211_global *global);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800161
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800162static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -0700163static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
164 struct hostapd_freq_params *freq);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -0700165
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700166static int
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800167wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800168 const u8 *set_addr, int first,
169 const char *driver_params);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800170static int nl80211_send_frame_cmd(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700171 unsigned int freq, unsigned int wait,
Hai Shalomfdcde762020-04-02 11:19:20 -0700172 const u8 *buf, size_t buf_len,
173 int save_cookie,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800174 int no_cck, int no_ack, int offchanok,
175 const u16 *csa_offs, size_t csa_offs_len);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800176static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
177 int report);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700178
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800179#define IFIDX_ANY -1
180
181static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
182 int ifidx_reason);
183static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
184 int ifidx_reason);
185static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
186 int ifidx_reason);
Dmitry Shmidt738a26e2011-07-07 14:22:14 -0700187
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700188static int nl80211_set_channel(struct i802_bss *bss,
189 struct hostapd_freq_params *freq, int set_chan);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700190static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
191 int ifindex, int disabled);
192
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800193static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
194 int reset_mode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800195
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700196static int i802_set_iface_flags(struct i802_bss *bss, int up);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800197static int nl80211_set_param(void *priv, const char *param);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -0700198#ifdef CONFIG_MESH
199static int nl80211_put_mesh_config(struct nl_msg *msg,
200 struct wpa_driver_mesh_bss_params *params);
201#endif /* CONFIG_MESH */
Dmitry Shmidt29333592017-01-09 12:27:11 -0800202static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -0700203 u16 reason);
Vinayak Yadawade62409f2022-01-20 12:32:07 +0530204#ifdef CONFIG_DRIVER_NL80211_BRCM
205static int nl80211_set_td_policy(void *priv, u32 td_policy);
206#endif /* CONFIG_DRIVER_NL80211_BRCM */
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700207
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800208/* Converts nl80211_chan_width to a common format */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800209enum chan_width convert2width(int width)
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800210{
211 switch (width) {
212 case NL80211_CHAN_WIDTH_20_NOHT:
213 return CHAN_WIDTH_20_NOHT;
214 case NL80211_CHAN_WIDTH_20:
215 return CHAN_WIDTH_20;
216 case NL80211_CHAN_WIDTH_40:
217 return CHAN_WIDTH_40;
218 case NL80211_CHAN_WIDTH_80:
219 return CHAN_WIDTH_80;
220 case NL80211_CHAN_WIDTH_80P80:
221 return CHAN_WIDTH_80P80;
222 case NL80211_CHAN_WIDTH_160:
223 return CHAN_WIDTH_160;
Sunil8cd6f4d2022-06-28 18:40:46 +0000224 case NL80211_CHAN_WIDTH_320:
225 return CHAN_WIDTH_320;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800226 }
227 return CHAN_WIDTH_UNKNOWN;
228}
229
230
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800231int is_ap_interface(enum nl80211_iftype nlmode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800232{
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700233 return nlmode == NL80211_IFTYPE_AP ||
234 nlmode == NL80211_IFTYPE_P2P_GO;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800235}
236
237
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800238int is_sta_interface(enum nl80211_iftype nlmode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800239{
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700240 return nlmode == NL80211_IFTYPE_STATION ||
241 nlmode == NL80211_IFTYPE_P2P_CLIENT;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800242}
243
244
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700245static int is_p2p_net_interface(enum nl80211_iftype nlmode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800246{
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700247 return nlmode == NL80211_IFTYPE_P2P_CLIENT ||
248 nlmode == NL80211_IFTYPE_P2P_GO;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800249}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700250
251
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800252struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
253 int ifindex)
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -0700254{
255 struct i802_bss *bss;
256
257 for (bss = drv->first_bss; bss; bss = bss->next) {
258 if (bss->ifindex == ifindex)
259 return bss;
260 }
261
262 return NULL;
263}
264
265
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800266static int is_mesh_interface(enum nl80211_iftype nlmode)
267{
268 return nlmode == NL80211_IFTYPE_MESH_POINT;
269}
270
271
272void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
Dmitry Shmidt8bae4132013-06-06 11:25:10 -0700273{
274 if (drv->associated)
275 os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
276 drv->associated = 0;
Sunil Ravi89eba102022-09-13 21:04:37 -0700277 drv->sta_mlo_info.valid_links = 0;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -0700278 os_memset(drv->bssid, 0, ETH_ALEN);
Hai Shalom5f92bc92019-04-18 11:54:11 -0700279 drv->first_bss->freq = 0;
Sunil Ravi89eba102022-09-13 21:04:37 -0700280#ifdef CONFIG_DRIVER_NL80211_QCA
281 os_free(drv->pending_roam_data);
282 drv->pending_roam_data = NULL;
283#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt8bae4132013-06-06 11:25:10 -0700284}
285
286
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700287/* nl80211 code */
288static int ack_handler(struct nl_msg *msg, void *arg)
289{
290 int *err = arg;
291 *err = 0;
292 return NL_STOP;
293}
294
Hai Shalom899fcc72020-10-19 14:38:18 -0700295
296struct nl80211_ack_ext_arg {
297 int *err;
298 void *ext_data;
299};
300
301
302static int ack_handler_cookie(struct nl_msg *msg, void *arg)
303{
304 struct nl80211_ack_ext_arg *ext_arg = arg;
305 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
306 u64 *cookie = ext_arg->ext_data;
307 struct nlattr *attrs;
308 size_t ack_len, attr_len;
309
310 *ext_arg->err = 0;
311 ack_len = sizeof(struct nlmsghdr) + sizeof(int) +
312 sizeof(struct nlmsghdr);
313 attrs = (struct nlattr *)
314 ((u8 *) nlmsg_data(nlmsg_hdr(msg)) + sizeof(struct nlmsghdr) +
315 sizeof(int));
316 if (nlmsg_hdr(msg)->nlmsg_len <= ack_len)
317 return NL_STOP;
318
319 attr_len = nlmsg_hdr(msg)->nlmsg_len - ack_len;
320
321 if(!(nlmsg_hdr(msg)->nlmsg_flags & NLM_F_ACK_TLVS))
322 return NL_STOP;
323
324 nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, attr_len, NULL);
325 if (tb[NLMSGERR_ATTR_COOKIE])
326 *cookie = nla_get_u64(tb[NLMSGERR_ATTR_COOKIE]);
327
328 return NL_STOP;
329}
330
331
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700332static int finish_handler(struct nl_msg *msg, void *arg)
333{
334 int *ret = arg;
335 *ret = 0;
336 return NL_SKIP;
337}
338
339static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
340 void *arg)
341{
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800342 struct nlmsghdr *nlh = (struct nlmsghdr *) err - 1;
343 int len = nlh->nlmsg_len;
344 struct nlattr *attrs;
345 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700346 int *ret = arg;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800347 int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh);
348
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700349 *ret = err->error;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800350
351 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
352 return NL_SKIP;
353
354 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
355 ack_len += err->msg.nlmsg_len - sizeof(*nlh);
356
357 if (len <= ack_len)
358 return NL_STOP;
359
360 attrs = (void *) ((unsigned char *) nlh + ack_len);
361 len -= ack_len;
362
363 nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, len, NULL);
364 if (tb[NLMSGERR_ATTR_MSG]) {
365 len = strnlen((char *) nla_data(tb[NLMSGERR_ATTR_MSG]),
366 nla_len(tb[NLMSGERR_ATTR_MSG]));
367 wpa_printf(MSG_ERROR, "nl80211: kernel reports: %*s",
368 len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG]));
369 }
370
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700371 return NL_SKIP;
372}
373
374
375static int no_seq_check(struct nl_msg *msg, void *arg)
376{
377 return NL_OK;
378}
379
380
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800381static void nl80211_nlmsg_clear(struct nl_msg *msg)
382{
383 /*
384 * Clear nlmsg data, e.g., to make sure key material is not left in
385 * heap memory for unnecessarily long time.
386 */
387 if (msg) {
388 struct nlmsghdr *hdr = nlmsg_hdr(msg);
389 void *data = nlmsg_data(hdr);
390 /*
391 * This would use nlmsg_datalen() or the older nlmsg_len() if
392 * only libnl were to maintain a stable API.. Neither will work
393 * with all released versions, so just calculate the length
394 * here.
395 */
396 int len = hdr->nlmsg_len - NLMSG_HDRLEN;
397
398 os_memset(data, 0, len);
399 }
400}
401
402
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800403static int send_and_recv(struct nl80211_global *global,
Hai Shalomfdcde762020-04-02 11:19:20 -0700404 struct nl_sock *nl_handle, struct nl_msg *msg,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700405 int (*valid_handler)(struct nl_msg *, void *),
Hai Shalom899fcc72020-10-19 14:38:18 -0700406 void *valid_data,
407 int (*ack_handler_custom)(struct nl_msg *, void *),
408 void *ack_data)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700409{
410 struct nl_cb *cb;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800411 int err = -ENOMEM, opt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700412
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800413 if (!msg)
414 return -ENOMEM;
415
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800416 cb = nl_cb_clone(global->nl_cb);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700417 if (!cb)
418 goto out;
419
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800420 /* try to set NETLINK_EXT_ACK to 1, ignoring errors */
421 opt = 1;
422 setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
423 NETLINK_EXT_ACK, &opt, sizeof(opt));
424
Hai Shalom74f70d42019-02-11 14:42:39 -0800425 /* try to set NETLINK_CAP_ACK to 1, ignoring errors */
426 opt = 1;
427 setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
428 NETLINK_CAP_ACK, &opt, sizeof(opt));
429
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700430 err = nl_send_auto_complete(nl_handle, msg);
Hai Shalomfdcde762020-04-02 11:19:20 -0700431 if (err < 0) {
432 wpa_printf(MSG_INFO,
433 "nl80211: nl_send_auto_complete() failed: %s",
434 nl_geterror(err));
435 /* Need to convert libnl error code to an errno value. For now,
436 * just hardcode this to EBADF; the real error reason is shown
437 * in that error print above. */
438 err = -EBADF;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700439 goto out;
Hai Shalomfdcde762020-04-02 11:19:20 -0700440 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700441
442 err = 1;
443
444 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
445 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
Hai Shalom899fcc72020-10-19 14:38:18 -0700446 if (ack_handler_custom) {
447 struct nl80211_ack_ext_arg *ext_arg = ack_data;
448
449 ext_arg->err = &err;
450 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM,
451 ack_handler_custom, ack_data);
452 } else {
453 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
454 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700455
456 if (valid_handler)
457 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
458 valid_handler, valid_data);
459
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700460 while (err > 0) {
461 int res = nl_recvmsgs(nl_handle, cb);
Hai Shalomfdcde762020-04-02 11:19:20 -0700462
463 if (res == -NLE_DUMP_INTR) {
464 /* Most likely one of the nl80211 dump routines hit a
465 * case where internal results changed while the dump
466 * was being sent. The most common known case for this
467 * is scan results fetching while associated were every
468 * received Beacon frame from the AP may end up
469 * incrementing bss_generation. This
470 * NL80211_CMD_GET_SCAN case tries again in the caller;
471 * other cases (of which there are no known common ones)
472 * will stop and return an error. */
473 wpa_printf(MSG_DEBUG, "nl80211: %s; convert to -EAGAIN",
474 nl_geterror(res));
475 err = -EAGAIN;
476 } else if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700477 wpa_printf(MSG_INFO,
Hai Shalomfdcde762020-04-02 11:19:20 -0700478 "nl80211: %s->nl_recvmsgs failed: %d (%s)",
479 __func__, res, nl_geterror(res));
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700480 }
481 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700482 out:
483 nl_cb_put(cb);
Hai Shalom60840252021-02-19 19:02:11 -0800484 /* Always clear the message as it can potentially contain keys */
485 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700486 nlmsg_free(msg);
487 return err;
488}
489
490
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800491int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
492 struct nl_msg *msg,
493 int (*valid_handler)(struct nl_msg *, void *),
Hai Shalom899fcc72020-10-19 14:38:18 -0700494 void *valid_data,
495 int (*ack_handler_custom)(struct nl_msg *, void *),
496 void *ack_data)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700497{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800498 return send_and_recv(drv->global, drv->global->nl, msg,
Hai Shalom899fcc72020-10-19 14:38:18 -0700499 valid_handler, valid_data,
500 ack_handler_custom, ack_data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700501}
502
503
Hai Shalomb755a2a2020-04-23 21:49:02 -0700504/* Use this method to mark that it is necessary to own the connection/interface
505 * for this operation.
506 * handle may be set to NULL, to get the same behavior as send_and_recv_msgs().
507 * set_owner can be used to mark this socket for receiving control port frames.
508 */
509static int send_and_recv_msgs_owner(struct wpa_driver_nl80211_data *drv,
510 struct nl_msg *msg,
511 struct nl_sock *handle, int set_owner,
512 int (*valid_handler)(struct nl_msg *,
513 void *),
Hai Shalom899fcc72020-10-19 14:38:18 -0700514 void *valid_data,
515 int (*ack_handler_custom)(struct nl_msg *,
516 void *),
517 void *ack_data)
Hai Shalomb755a2a2020-04-23 21:49:02 -0700518{
Hai Shalom60840252021-02-19 19:02:11 -0800519 if (!msg)
520 return -ENOMEM;
521
Hai Shalomb755a2a2020-04-23 21:49:02 -0700522 /* Control port over nl80211 needs the flags and attributes below.
523 *
524 * The Linux kernel has initial checks for them (in nl80211.c) like:
525 * validate_pae_over_nl80211(...)
526 * or final checks like:
527 * dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid
528 *
529 * Final operations (e.g., disassociate) don't need to set these
530 * attributes, but they have to be performed on the socket, which has
531 * the connection owner property set in the kernel.
532 */
533 if ((drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) &&
534 handle && set_owner &&
535 (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) ||
536 nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER) ||
537 nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
538 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_PREAUTH)))
539 return -1;
540
541 return send_and_recv(drv->global, handle ? handle : drv->global->nl,
Hai Shalom899fcc72020-10-19 14:38:18 -0700542 msg, valid_handler, valid_data,
543 ack_handler_custom, ack_data);
Hai Shalomb755a2a2020-04-23 21:49:02 -0700544}
545
546
Hai Shalomc1a21442022-02-04 13:43:00 -0800547static int
548send_and_recv_msgs_connect_handle(struct wpa_driver_nl80211_data *drv,
549 struct nl_msg *msg, struct i802_bss *bss,
550 int set_owner)
551{
552 struct nl_sock *nl_connect = get_connect_handle(bss);
553
554 if (nl_connect)
555 return send_and_recv_msgs_owner(drv, msg, nl_connect, set_owner,
556 process_bss_event, bss, NULL,
557 NULL);
558 else
559 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
560}
561
562
Hai Shalomb755a2a2020-04-23 21:49:02 -0700563struct nl_sock * get_connect_handle(struct i802_bss *bss)
564{
565 if ((bss->drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) ||
566 bss->use_nl_connect)
567 return bss->nl_connect;
568
569 return NULL;
570}
571
572
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700573struct family_data {
574 const char *group;
575 int id;
576};
577
578
579static int family_handler(struct nl_msg *msg, void *arg)
580{
581 struct family_data *res = arg;
582 struct nlattr *tb[CTRL_ATTR_MAX + 1];
583 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
584 struct nlattr *mcgrp;
585 int i;
586
587 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
588 genlmsg_attrlen(gnlh, 0), NULL);
589 if (!tb[CTRL_ATTR_MCAST_GROUPS])
590 return NL_SKIP;
591
592 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
593 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
594 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
595 nla_len(mcgrp), NULL);
596 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
597 !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
598 os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
599 res->group,
600 nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
601 continue;
602 res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
603 break;
604 };
605
606 return NL_SKIP;
607}
608
609
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800610static int nl_get_multicast_id(struct nl80211_global *global,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700611 const char *family, const char *group)
612{
613 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800614 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700615 struct family_data res = { group, -ENOENT };
616
617 msg = nlmsg_alloc();
618 if (!msg)
619 return -ENOMEM;
Hai Shalomc1a21442022-02-04 13:43:00 -0800620 if (!genlmsg_put(msg, 0, 0, global->nlctrl_id,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800621 0, 0, CTRL_CMD_GETFAMILY, 0) ||
622 nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family)) {
623 nlmsg_free(msg);
624 return -1;
625 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700626
Hai Shalom899fcc72020-10-19 14:38:18 -0700627 ret = send_and_recv(global, global->nl, msg, family_handler, &res,
628 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700629 if (ret == 0)
630 ret = res.id;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700631 return ret;
632}
633
634
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800635void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
636 struct nl_msg *msg, int flags, uint8_t cmd)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800637{
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700638 if (TEST_FAIL())
639 return NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800640 return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
641 0, flags, cmd, 0);
642}
643
644
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800645static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
646{
647 if (bss->wdev_id_set)
648 return nla_put_u64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
649 return nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
650}
651
652
653struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd)
654{
655 struct nl_msg *msg;
656
657 msg = nlmsg_alloc();
658 if (!msg)
659 return NULL;
660
661 if (!nl80211_cmd(bss->drv, msg, flags, cmd) ||
662 nl80211_set_iface_id(msg, bss) < 0) {
663 nlmsg_free(msg);
664 return NULL;
665 }
666
667 return msg;
668}
669
670
671static struct nl_msg *
Hai Shalomc1a21442022-02-04 13:43:00 -0800672nl80211_ifindex_msg_build(struct wpa_driver_nl80211_data *drv,
673 struct nl_msg *msg, int ifindex, int flags,
674 uint8_t cmd)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800675{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800676 if (!msg)
677 return NULL;
678
679 if (!nl80211_cmd(drv, msg, flags, cmd) ||
680 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
681 nlmsg_free(msg);
682 return NULL;
683 }
684
685 return msg;
686}
687
688
Hai Shalomc1a21442022-02-04 13:43:00 -0800689static struct nl_msg *
690nl80211_ifindex_msg(struct wpa_driver_nl80211_data *drv, int ifindex,
691 int flags, uint8_t cmd)
692{
693 return nl80211_ifindex_msg_build(drv, nlmsg_alloc(), ifindex, flags,
694 cmd);
695}
696
697
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800698struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
699 uint8_t cmd)
700{
701 return nl80211_ifindex_msg(drv, drv->ifindex, flags, cmd);
702}
703
704
705struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd)
706{
707 return nl80211_ifindex_msg(bss->drv, bss->ifindex, flags, cmd);
708}
709
710
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800711struct wiphy_idx_data {
712 int wiphy_idx;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700713 enum nl80211_iftype nlmode;
714 u8 *macaddr;
Hai Shalom60840252021-02-19 19:02:11 -0800715 u8 use_4addr;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800716};
717
718
719static int netdev_info_handler(struct nl_msg *msg, void *arg)
720{
721 struct nlattr *tb[NL80211_ATTR_MAX + 1];
722 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
723 struct wiphy_idx_data *info = arg;
724
725 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
726 genlmsg_attrlen(gnlh, 0), NULL);
727
728 if (tb[NL80211_ATTR_WIPHY])
729 info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
730
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700731 if (tb[NL80211_ATTR_IFTYPE])
732 info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]);
733
734 if (tb[NL80211_ATTR_MAC] && info->macaddr)
735 os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
736 ETH_ALEN);
737
Hai Shalom60840252021-02-19 19:02:11 -0800738 if (tb[NL80211_ATTR_4ADDR])
739 info->use_4addr = nla_get_u8(tb[NL80211_ATTR_4ADDR]);
740
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800741 return NL_SKIP;
742}
743
744
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800745int nl80211_get_wiphy_index(struct i802_bss *bss)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800746{
747 struct nl_msg *msg;
748 struct wiphy_idx_data data = {
749 .wiphy_idx = -1,
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700750 .macaddr = NULL,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800751 };
752
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800753 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
754 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800755
Hai Shalom899fcc72020-10-19 14:38:18 -0700756 if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
757 NULL, NULL) == 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800758 return data.wiphy_idx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800759 return -1;
760}
761
762
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700763static enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
764{
765 struct nl_msg *msg;
766 struct wiphy_idx_data data = {
767 .nlmode = NL80211_IFTYPE_UNSPECIFIED,
768 .macaddr = NULL,
769 };
770
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800771 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
772 return NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700773
Hai Shalom899fcc72020-10-19 14:38:18 -0700774 if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
775 NULL, NULL) == 0)
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700776 return data.nlmode;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700777 return NL80211_IFTYPE_UNSPECIFIED;
778}
779
780
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700781static int nl80211_get_macaddr(struct i802_bss *bss)
782{
783 struct nl_msg *msg;
784 struct wiphy_idx_data data = {
785 .macaddr = bss->addr,
786 };
787
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800788 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
789 return -1;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700790
Hai Shalom899fcc72020-10-19 14:38:18 -0700791 return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
792 NULL, NULL);
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700793}
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700794
795
Hai Shalom60840252021-02-19 19:02:11 -0800796static int nl80211_get_4addr(struct i802_bss *bss)
797{
798 struct nl_msg *msg;
799 struct wiphy_idx_data data = {
800 .use_4addr = 0,
801 };
802
803 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)) ||
804 send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
805 NULL, NULL))
806 return -1;
807 return data.use_4addr;
808}
809
810
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800811static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
812 struct nl80211_wiphy_data *w)
813{
814 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800815 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800816
817 msg = nlmsg_alloc();
818 if (!msg)
819 return -1;
820
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800821 if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS) ||
822 nla_put_u32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx)) {
823 nlmsg_free(msg);
824 return -1;
825 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800826
Hai Shalom899fcc72020-10-19 14:38:18 -0700827 ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL,
828 NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800829 if (ret) {
830 wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
831 "failed: ret=%d (%s)",
832 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800833 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800834 return ret;
835}
836
837
838static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
839{
840 struct nl80211_wiphy_data *w = eloop_ctx;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700841 int res;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800842
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800843 wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800844
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700845 res = nl_recvmsgs(handle, w->nl_cb);
Dmitry Shmidt71757432014-06-02 13:50:35 -0700846 if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700847 wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
848 __func__, res);
849 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800850}
851
852
853static int process_beacon_event(struct nl_msg *msg, void *arg)
854{
855 struct nl80211_wiphy_data *w = arg;
856 struct wpa_driver_nl80211_data *drv;
857 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
858 struct nlattr *tb[NL80211_ATTR_MAX + 1];
859 union wpa_event_data event;
860
861 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
862 genlmsg_attrlen(gnlh, 0), NULL);
863
864 if (gnlh->cmd != NL80211_CMD_FRAME) {
865 wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
866 gnlh->cmd);
867 return NL_SKIP;
868 }
869
870 if (!tb[NL80211_ATTR_FRAME])
871 return NL_SKIP;
872
873 dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
874 wiphy_list) {
875 os_memset(&event, 0, sizeof(event));
876 event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
877 event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
878 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
879 }
880
881 return NL_SKIP;
882}
883
884
885static struct nl80211_wiphy_data *
886nl80211_get_wiphy_data_ap(struct i802_bss *bss)
887{
888 static DEFINE_DL_LIST(nl80211_wiphys);
889 struct nl80211_wiphy_data *w;
890 int wiphy_idx, found = 0;
891 struct i802_bss *tmp_bss;
Paul Stewart092955c2017-02-06 09:13:09 -0800892 u8 channel;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800893
894 if (bss->wiphy_data != NULL)
895 return bss->wiphy_data;
896
897 wiphy_idx = nl80211_get_wiphy_index(bss);
898
899 dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
900 if (w->wiphy_idx == wiphy_idx)
901 goto add;
902 }
903
904 /* alloc new one */
905 w = os_zalloc(sizeof(*w));
906 if (w == NULL)
907 return NULL;
908 w->wiphy_idx = wiphy_idx;
909 dl_list_init(&w->bsss);
910 dl_list_init(&w->drvs);
911
Paul Stewart092955c2017-02-06 09:13:09 -0800912 /* Beacon frames not supported in IEEE 802.11ad */
913 if (ieee80211_freq_to_chan(bss->freq, &channel) !=
914 HOSTAPD_MODE_IEEE80211AD) {
915 w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
916 if (!w->nl_cb) {
917 os_free(w);
918 return NULL;
919 }
920 nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
921 no_seq_check, NULL);
922 nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
923 process_beacon_event, w);
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000924
Paul Stewart092955c2017-02-06 09:13:09 -0800925 w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
926 "wiphy beacons");
927 if (w->nl_beacons == NULL) {
928 os_free(w);
929 return NULL;
930 }
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000931
Paul Stewart092955c2017-02-06 09:13:09 -0800932 if (nl80211_register_beacons(bss->drv, w)) {
933 nl_destroy_handles(&w->nl_beacons);
934 os_free(w);
935 return NULL;
936 }
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000937
Paul Stewart092955c2017-02-06 09:13:09 -0800938 nl80211_register_eloop_read(&w->nl_beacons,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700939 nl80211_recv_beacons, w, 0);
Paul Stewart092955c2017-02-06 09:13:09 -0800940 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800941
942 dl_list_add(&nl80211_wiphys, &w->list);
943
944add:
945 /* drv entry for this bss already there? */
946 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
947 if (tmp_bss->drv == bss->drv) {
948 found = 1;
949 break;
950 }
951 }
952 /* if not add it */
953 if (!found)
954 dl_list_add(&w->drvs, &bss->drv->wiphy_list);
955
956 dl_list_add(&w->bsss, &bss->wiphy_list);
957 bss->wiphy_data = w;
958 return w;
959}
960
961
962static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
963{
964 struct nl80211_wiphy_data *w = bss->wiphy_data;
965 struct i802_bss *tmp_bss;
966 int found = 0;
967
968 if (w == NULL)
969 return;
970 bss->wiphy_data = NULL;
971 dl_list_del(&bss->wiphy_list);
972
973 /* still any for this drv present? */
974 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
975 if (tmp_bss->drv == bss->drv) {
976 found = 1;
977 break;
978 }
979 }
980 /* if not remove it */
981 if (!found)
982 dl_list_del(&bss->drv->wiphy_list);
983
984 if (!dl_list_empty(&w->bsss))
985 return;
986
Paul Stewart092955c2017-02-06 09:13:09 -0800987 if (w->nl_beacons)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700988 nl80211_destroy_eloop_handle(&w->nl_beacons, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800989
990 nl_cb_put(w->nl_cb);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800991 dl_list_del(&w->list);
992 os_free(w);
993}
994
995
Dmitry Shmidte4663042016-04-04 10:07:49 -0700996static unsigned int nl80211_get_ifindex(void *priv)
997{
998 struct i802_bss *bss = priv;
999 struct wpa_driver_nl80211_data *drv = bss->drv;
1000
1001 return drv->ifindex;
1002}
1003
1004
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001005static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
1006{
1007 struct i802_bss *bss = priv;
1008 struct wpa_driver_nl80211_data *drv = bss->drv;
1009 if (!drv->associated)
1010 return -1;
1011 os_memcpy(bssid, drv->bssid, ETH_ALEN);
1012 return 0;
1013}
1014
1015
1016static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
1017{
1018 struct i802_bss *bss = priv;
1019 struct wpa_driver_nl80211_data *drv = bss->drv;
1020 if (!drv->associated)
1021 return -1;
1022 os_memcpy(ssid, drv->ssid, drv->ssid_len);
1023 return drv->ssid_len;
1024}
1025
1026
Sunil Ravi89eba102022-09-13 21:04:37 -07001027static int nl80211_get_sta_mlo_info(void *priv,
1028 struct driver_sta_mlo_info *mlo_info)
1029{
1030 struct i802_bss *bss = priv;
1031 struct wpa_driver_nl80211_data *drv = bss->drv;
1032
1033 if (!drv->associated)
1034 return -1;
1035
1036 os_memcpy(mlo_info, &drv->sta_mlo_info, sizeof(*mlo_info));
1037 return 0;
1038}
1039
1040
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001041static void wpa_driver_nl80211_event_newlink(
Dmitry Shmidte4663042016-04-04 10:07:49 -07001042 struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
1043 int ifindex, const char *ifname)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001044{
1045 union wpa_event_data event;
1046
Dmitry Shmidte4663042016-04-04 10:07:49 -07001047 if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001048 if (if_nametoindex(drv->first_bss->ifname) == 0) {
1049 wpa_printf(MSG_DEBUG, "nl80211: Interface %s does not exist - ignore RTM_NEWLINK",
1050 drv->first_bss->ifname);
1051 return;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001052 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001053 if (!drv->if_removed)
1054 return;
1055 wpa_printf(MSG_DEBUG, "nl80211: Mark if_removed=0 for %s based on RTM_NEWLINK event",
1056 drv->first_bss->ifname);
1057 drv->if_removed = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001058 }
1059
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001060 os_memset(&event, 0, sizeof(event));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001061 event.interface_status.ifindex = ifindex;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001062 os_strlcpy(event.interface_status.ifname, ifname,
1063 sizeof(event.interface_status.ifname));
1064 event.interface_status.ievent = EVENT_INTERFACE_ADDED;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001065 if (drv)
1066 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
1067 else
1068 wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
1069 &event);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001070}
1071
1072
1073static void wpa_driver_nl80211_event_dellink(
Dmitry Shmidte4663042016-04-04 10:07:49 -07001074 struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
1075 int ifindex, const char *ifname)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001076{
1077 union wpa_event_data event;
1078
Dmitry Shmidte4663042016-04-04 10:07:49 -07001079 if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001080 if (drv->if_removed) {
1081 wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s",
1082 ifname);
1083 return;
1084 }
1085 wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed - mark if_removed=1",
1086 ifname);
1087 drv->if_removed = 1;
1088 } else {
1089 wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed",
1090 ifname);
1091 }
1092
1093 os_memset(&event, 0, sizeof(event));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001094 event.interface_status.ifindex = ifindex;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001095 os_strlcpy(event.interface_status.ifname, ifname,
1096 sizeof(event.interface_status.ifname));
1097 event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001098 if (drv)
1099 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
1100 else
1101 wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
1102 &event);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001103}
1104
1105
1106static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
1107 u8 *buf, size_t len)
1108{
1109 int attrlen, rta_len;
1110 struct rtattr *attr;
1111
1112 attrlen = len;
1113 attr = (struct rtattr *) buf;
1114
1115 rta_len = RTA_ALIGN(sizeof(struct rtattr));
1116 while (RTA_OK(attr, attrlen)) {
1117 if (attr->rta_type == IFLA_IFNAME) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001118 if (os_strcmp(((char *) attr) + rta_len,
1119 drv->first_bss->ifname) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001120 return 1;
1121 else
1122 break;
1123 }
1124 attr = RTA_NEXT(attr, attrlen);
1125 }
1126
1127 return 0;
1128}
1129
1130
1131static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
1132 int ifindex, u8 *buf, size_t len)
1133{
1134 if (drv->ifindex == ifindex)
1135 return 1;
1136
1137 if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001138 nl80211_check_global(drv->global);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001139 wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
1140 "interface");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001141 if (wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL) < 0)
1142 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001143 return 1;
1144 }
1145
1146 return 0;
1147}
1148
1149
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001150static struct wpa_driver_nl80211_data *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001151nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len,
1152 int *init_failed)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001153{
1154 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001155 int res;
1156
1157 if (init_failed)
1158 *init_failed = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001159 dl_list_for_each(drv, &global->interfaces,
1160 struct wpa_driver_nl80211_data, list) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001161 res = wpa_driver_nl80211_own_ifindex(drv, idx, buf, len);
1162 if (res < 0) {
1163 wpa_printf(MSG_DEBUG,
1164 "nl80211: Found matching own interface, but failed to complete reinitialization");
1165 if (init_failed)
1166 *init_failed = 1;
1167 return drv;
1168 }
1169 if (res > 0 || have_ifidx(drv, idx, IFIDX_ANY))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001170 return drv;
1171 }
1172 return NULL;
1173}
1174
1175
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001176static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001177 int ifindex, int notify)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001178{
1179 struct i802_bss *bss;
1180 u8 addr[ETH_ALEN];
1181
1182 bss = get_bss_ifindex(drv, ifindex);
1183 if (bss &&
1184 linux_get_ifhwaddr(drv->global->ioctl_sock,
1185 bss->ifname, addr) < 0) {
1186 wpa_printf(MSG_DEBUG,
1187 "nl80211: %s: failed to re-read MAC address",
1188 bss->ifname);
1189 } else if (bss && os_memcmp(addr, bss->addr, ETH_ALEN) != 0) {
1190 wpa_printf(MSG_DEBUG,
1191 "nl80211: Own MAC address on ifindex %d (%s) changed from "
1192 MACSTR " to " MACSTR,
1193 ifindex, bss->ifname,
1194 MAC2STR(bss->addr), MAC2STR(addr));
1195 os_memcpy(bss->addr, addr, ETH_ALEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001196 if (notify)
1197 wpa_supplicant_event(drv->ctx,
1198 EVENT_INTERFACE_MAC_CHANGED, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001199 }
1200}
1201
1202
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001203static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
1204 struct ifinfomsg *ifi,
1205 u8 *buf, size_t len)
1206{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001207 struct nl80211_global *global = ctx;
1208 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001209 int attrlen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001210 struct rtattr *attr;
1211 u32 brid = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001212 char namebuf[IFNAMSIZ];
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001213 char ifname[IFNAMSIZ + 1];
1214 char extra[100], *pos, *end;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001215 int init_failed;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001216
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001217 extra[0] = '\0';
1218 pos = extra;
1219 end = pos + sizeof(extra);
1220 ifname[0] = '\0';
1221
1222 attrlen = len;
1223 attr = (struct rtattr *) buf;
1224 while (RTA_OK(attr, attrlen)) {
1225 switch (attr->rta_type) {
1226 case IFLA_IFNAME:
Hai Shalomfdcde762020-04-02 11:19:20 -07001227 if (RTA_PAYLOAD(attr) > IFNAMSIZ)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001228 break;
1229 os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
1230 ifname[RTA_PAYLOAD(attr)] = '\0';
1231 break;
1232 case IFLA_MASTER:
1233 brid = nla_get_u32((struct nlattr *) attr);
1234 pos += os_snprintf(pos, end - pos, " master=%u", brid);
1235 break;
1236 case IFLA_WIRELESS:
1237 pos += os_snprintf(pos, end - pos, " wext");
1238 break;
1239 case IFLA_OPERSTATE:
1240 pos += os_snprintf(pos, end - pos, " operstate=%u",
1241 nla_get_u32((struct nlattr *) attr));
1242 break;
1243 case IFLA_LINKMODE:
1244 pos += os_snprintf(pos, end - pos, " linkmode=%u",
1245 nla_get_u32((struct nlattr *) attr));
1246 break;
1247 }
1248 attr = RTA_NEXT(attr, attrlen);
1249 }
1250 extra[sizeof(extra) - 1] = '\0';
1251
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001252 wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
1253 ifi->ifi_index, ifname, extra, ifi->ifi_family,
1254 ifi->ifi_flags,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001255 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
1256 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
1257 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
1258 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
1259
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001260 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, &init_failed);
Dmitry Shmidte4663042016-04-04 10:07:49 -07001261 if (!drv)
1262 goto event_newlink;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001263 if (init_failed)
1264 return; /* do not update interface state */
Dmitry Shmidte4663042016-04-04 10:07:49 -07001265
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001266 if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001267 namebuf[0] = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001268 if (if_indextoname(ifi->ifi_index, namebuf) &&
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001269 linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001270 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
1271 "event since interface %s is up", namebuf);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001272 drv->ignore_if_down_event = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001273 /* Re-read MAC address as it may have changed */
1274 nl80211_refresh_mac(drv, ifi->ifi_index, 1);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001275 return;
1276 }
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001277 wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
1278 namebuf, ifname);
1279 if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
1280 wpa_printf(MSG_DEBUG,
1281 "nl80211: Not the main interface (%s) - do not indicate interface down",
1282 drv->first_bss->ifname);
1283 } else if (drv->ignore_if_down_event) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001284 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
1285 "event generated by mode change");
1286 drv->ignore_if_down_event = 0;
1287 } else {
1288 drv->if_disabled = 1;
1289 wpa_supplicant_event(drv->ctx,
1290 EVENT_INTERFACE_DISABLED, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08001291
1292 /*
1293 * Try to get drv again, since it may be removed as
1294 * part of the EVENT_INTERFACE_DISABLED handling for
1295 * dynamic interfaces
1296 */
1297 drv = nl80211_find_drv(global, ifi->ifi_index,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001298 buf, len, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08001299 if (!drv)
1300 return;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001301 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001302 }
1303
1304 if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
Hai Shalomc9e41a12018-07-31 14:41:42 -07001305 namebuf[0] = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001306 if (if_indextoname(ifi->ifi_index, namebuf) &&
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001307 linux_iface_up(drv->global->ioctl_sock, namebuf) == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001308 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1309 "event since interface %s is down",
1310 namebuf);
Hai Shalomc9e41a12018-07-31 14:41:42 -07001311 return;
1312 }
1313 wpa_printf(MSG_DEBUG, "nl80211: Interface up (%s/%s)",
1314 namebuf, ifname);
1315 if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
1316 wpa_printf(MSG_DEBUG,
1317 "nl80211: Not the main interface (%s) - do not indicate interface up",
1318 drv->first_bss->ifname);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001319 } else if (if_nametoindex(drv->first_bss->ifname) == 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001320 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1321 "event since interface %s does not exist",
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001322 drv->first_bss->ifname);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001323 } else if (drv->if_removed) {
1324 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1325 "event since interface %s is marked "
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001326 "removed", drv->first_bss->ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001327 } else {
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07001328 /* Re-read MAC address as it may have changed */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001329 nl80211_refresh_mac(drv, ifi->ifi_index, 0);
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07001330
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001331 drv->if_disabled = 0;
1332 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
1333 NULL);
1334 }
Sunil Ravi90775442020-09-24 11:53:19 -07001335 } else if (ifi->ifi_flags & IFF_UP) {
1336 /* Re-read MAC address as it may have changed */
1337 nl80211_refresh_mac(drv, ifi->ifi_index, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001338 }
1339
1340 /*
1341 * Some drivers send the association event before the operup event--in
1342 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
1343 * fails. This will hit us when wpa_supplicant does not need to do
1344 * IEEE 802.1X authentication
1345 */
1346 if (drv->operstate == 1 &&
1347 (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001348 !(ifi->ifi_flags & IFF_RUNNING)) {
1349 wpa_printf(MSG_DEBUG, "nl80211: Set IF_OPER_UP again based on ifi_flags and expected operstate");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001350 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001351 -1, IF_OPER_UP);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001352 }
1353
Dmitry Shmidte4663042016-04-04 10:07:49 -07001354event_newlink:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001355 if (ifname[0])
Dmitry Shmidte4663042016-04-04 10:07:49 -07001356 wpa_driver_nl80211_event_newlink(global, drv, ifi->ifi_index,
1357 ifname);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001358
Dmitry Shmidte4663042016-04-04 10:07:49 -07001359 if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001360 struct i802_bss *bss;
1361
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001362 /* device has been added to bridge */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001363 if (!if_indextoname(brid, namebuf)) {
1364 wpa_printf(MSG_DEBUG,
1365 "nl80211: Could not find bridge ifname for ifindex %u",
1366 brid);
1367 return;
1368 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001369 wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
1370 brid, namebuf);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001371 add_ifidx(drv, brid, ifi->ifi_index);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001372
1373 for (bss = drv->first_bss; bss; bss = bss->next) {
1374 if (os_strcmp(ifname, bss->ifname) == 0) {
1375 os_strlcpy(bss->brname, namebuf, IFNAMSIZ);
1376 break;
1377 }
1378 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001379 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001380}
1381
1382
1383static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
1384 struct ifinfomsg *ifi,
1385 u8 *buf, size_t len)
1386{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001387 struct nl80211_global *global = ctx;
1388 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001389 int attrlen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001390 struct rtattr *attr;
1391 u32 brid = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001392 char ifname[IFNAMSIZ + 1];
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001393 char extra[100], *pos, *end;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001394
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001395 extra[0] = '\0';
1396 pos = extra;
1397 end = pos + sizeof(extra);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001398 ifname[0] = '\0';
1399
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001400 attrlen = len;
1401 attr = (struct rtattr *) buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001402 while (RTA_OK(attr, attrlen)) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001403 switch (attr->rta_type) {
1404 case IFLA_IFNAME:
Hai Shalomfdcde762020-04-02 11:19:20 -07001405 if (RTA_PAYLOAD(attr) > IFNAMSIZ)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001406 break;
1407 os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
1408 ifname[RTA_PAYLOAD(attr)] = '\0';
1409 break;
1410 case IFLA_MASTER:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001411 brid = nla_get_u32((struct nlattr *) attr);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001412 pos += os_snprintf(pos, end - pos, " master=%u", brid);
1413 break;
1414 case IFLA_OPERSTATE:
1415 pos += os_snprintf(pos, end - pos, " operstate=%u",
1416 nla_get_u32((struct nlattr *) attr));
1417 break;
1418 case IFLA_LINKMODE:
1419 pos += os_snprintf(pos, end - pos, " linkmode=%u",
1420 nla_get_u32((struct nlattr *) attr));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001421 break;
1422 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001423 attr = RTA_NEXT(attr, attrlen);
1424 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001425 extra[sizeof(extra) - 1] = '\0';
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001426
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001427 wpa_printf(MSG_DEBUG, "RTM_DELLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
1428 ifi->ifi_index, ifname, extra, ifi->ifi_family,
1429 ifi->ifi_flags,
1430 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
1431 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
1432 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
1433 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
1434
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001435 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001436
Dmitry Shmidte4663042016-04-04 10:07:49 -07001437 if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001438 /* device has been removed from bridge */
1439 char namebuf[IFNAMSIZ];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001440
1441 if (!if_indextoname(brid, namebuf)) {
1442 wpa_printf(MSG_DEBUG,
1443 "nl80211: Could not find bridge ifname for ifindex %u",
1444 brid);
1445 } else {
1446 wpa_printf(MSG_DEBUG,
1447 "nl80211: Remove ifindex %u for bridge %s",
1448 brid, namebuf);
1449 }
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001450 del_ifidx(drv, brid, ifi->ifi_index);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001451 }
Dmitry Shmidte4663042016-04-04 10:07:49 -07001452
1453 if (ifi->ifi_family != AF_BRIDGE || !brid)
1454 wpa_driver_nl80211_event_dellink(global, drv, ifi->ifi_index,
1455 ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001456}
1457
1458
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001459struct nl80211_get_assoc_freq_arg {
1460 struct wpa_driver_nl80211_data *drv;
1461 unsigned int assoc_freq;
1462 unsigned int ibss_freq;
1463 u8 assoc_bssid[ETH_ALEN];
1464 u8 assoc_ssid[SSID_MAX_LEN];
1465 u8 assoc_ssid_len;
Sunil Ravi89eba102022-09-13 21:04:37 -07001466 u8 bssid[MAX_NUM_MLD_LINKS][ETH_ALEN];
1467 unsigned int freq[MAX_NUM_MLD_LINKS];
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001468};
1469
1470static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg)
1471{
1472 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1473 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1474 struct nlattr *bss[NL80211_BSS_MAX + 1];
1475 static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
1476 [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
1477 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
1478 [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
1479 [NL80211_BSS_STATUS] = { .type = NLA_U32 },
Sunil Ravi89eba102022-09-13 21:04:37 -07001480 [NL80211_BSS_MLO_LINK_ID] = { .type = NLA_U8 },
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001481 };
1482 struct nl80211_get_assoc_freq_arg *ctx = arg;
1483 enum nl80211_bss_status status;
Sunil Ravi89eba102022-09-13 21:04:37 -07001484 struct wpa_driver_nl80211_data *drv = ctx->drv;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001485
1486 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1487 genlmsg_attrlen(gnlh, 0), NULL);
1488 if (!tb[NL80211_ATTR_BSS] ||
1489 nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
1490 bss_policy) ||
1491 !bss[NL80211_BSS_STATUS])
1492 return NL_SKIP;
1493
1494 status = nla_get_u32(bss[NL80211_BSS_STATUS]);
1495 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1496 bss[NL80211_BSS_FREQUENCY]) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001497 int link_id = -1;
1498 u32 freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
1499
1500 if (bss[NL80211_BSS_MLO_LINK_ID])
1501 link_id = nla_get_u8(bss[NL80211_BSS_MLO_LINK_ID]);
1502
1503 if (link_id >= 0 && link_id < MAX_NUM_MLD_LINKS) {
1504 ctx->freq[link_id] = freq;
1505 wpa_printf(MSG_DEBUG,
1506 "nl80211: MLO link %d associated on %u MHz",
1507 link_id, ctx->freq[link_id]);
1508 }
1509
1510 if (!drv->sta_mlo_info.valid_links ||
1511 drv->mlo_assoc_link_id == link_id) {
1512 ctx->assoc_freq = freq;
1513 wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
1514 ctx->assoc_freq);
1515 }
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001516 }
1517 if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
1518 bss[NL80211_BSS_FREQUENCY]) {
1519 ctx->ibss_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
1520 wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
1521 ctx->ibss_freq);
1522 }
1523 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1524 bss[NL80211_BSS_BSSID]) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001525 int link_id = -1;
1526 const u8 *bssid = nla_data(bss[NL80211_BSS_BSSID]);
1527
1528 if (bss[NL80211_BSS_MLO_LINK_ID])
1529 link_id = nla_get_u8(bss[NL80211_BSS_MLO_LINK_ID]);
1530
1531 if (link_id >= 0 && link_id < MAX_NUM_MLD_LINKS) {
1532 os_memcpy(ctx->bssid[link_id], bssid, ETH_ALEN);
1533 wpa_printf(MSG_DEBUG,
1534 "nl80211: MLO link %d associated with "
1535 MACSTR, link_id, MAC2STR(bssid));
1536 }
1537
1538 if (!drv->sta_mlo_info.valid_links ||
1539 drv->mlo_assoc_link_id == link_id) {
1540 os_memcpy(ctx->assoc_bssid, bssid, ETH_ALEN);
1541 wpa_printf(MSG_DEBUG, "nl80211: Associated with "
1542 MACSTR, MAC2STR(bssid));
1543 }
1544
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001545 }
1546
1547 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1548 bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
1549 const u8 *ie, *ssid;
1550 size_t ie_len;
1551
1552 ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1553 ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1554 ssid = get_ie(ie, ie_len, WLAN_EID_SSID);
1555 if (ssid && ssid[1] > 0 && ssid[1] <= SSID_MAX_LEN) {
1556 ctx->assoc_ssid_len = ssid[1];
1557 os_memcpy(ctx->assoc_ssid, ssid + 2, ssid[1]);
1558 }
1559 }
1560
1561 return NL_SKIP;
1562}
1563
1564
1565int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid)
Jouni Malinen87fd2792011-05-16 18:35:42 +03001566{
1567 struct nl_msg *msg;
1568 int ret;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001569 struct nl80211_get_assoc_freq_arg arg;
Hai Shalomfdcde762020-04-02 11:19:20 -07001570 int count = 0;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001571
Hai Shalomfdcde762020-04-02 11:19:20 -07001572try_again:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001573 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
Jouni Malinen87fd2792011-05-16 18:35:42 +03001574 os_memset(&arg, 0, sizeof(arg));
Jouni Malinen87fd2792011-05-16 18:35:42 +03001575 arg.drv = drv;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001576 ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
Hai Shalom899fcc72020-10-19 14:38:18 -07001577 &arg, NULL, NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -07001578 if (ret == -EAGAIN) {
1579 count++;
1580 if (count >= 10) {
1581 wpa_printf(MSG_INFO,
1582 "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid");
1583 } else {
1584 wpa_printf(MSG_DEBUG,
1585 "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid - try again");
1586 goto try_again;
1587 }
1588 }
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001589 if (ret == 0) {
1590 os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len);
1591 return arg.assoc_ssid_len;
1592 }
1593 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d (%s)",
1594 ret, strerror(-ret));
1595 return ret;
1596}
1597
1598
1599unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
1600{
1601 struct nl_msg *msg;
1602 int ret;
1603 struct nl80211_get_assoc_freq_arg arg;
Hai Shalomfdcde762020-04-02 11:19:20 -07001604 int count = 0;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001605
Hai Shalomfdcde762020-04-02 11:19:20 -07001606try_again:
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001607 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
1608 os_memset(&arg, 0, sizeof(arg));
1609 arg.drv = drv;
1610 ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
Hai Shalom899fcc72020-10-19 14:38:18 -07001611 &arg, NULL, NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -07001612 if (ret == -EAGAIN) {
1613 count++;
1614 if (count >= 10) {
1615 wpa_printf(MSG_INFO,
1616 "nl80211: Failed to receive consistent scan result dump for get_assoc_freq");
1617 } else {
1618 wpa_printf(MSG_DEBUG,
1619 "nl80211: Failed to receive consistent scan result dump for get_assoc_freq - try again");
1620 goto try_again;
1621 }
1622 }
Jouni Malinen87fd2792011-05-16 18:35:42 +03001623 if (ret == 0) {
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07001624 unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
1625 arg.ibss_freq : arg.assoc_freq;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001626 wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07001627 "associated BSS from scan results: %u MHz", freq);
1628 if (freq)
1629 drv->assoc_freq = freq;
Sunil Ravi89eba102022-09-13 21:04:37 -07001630
1631 if (drv->sta_mlo_info.valid_links) {
1632 int i;
1633
1634 for (i = 0; i < MAX_NUM_MLD_LINKS; i++)
1635 drv->sta_mlo_info.links[i].freq = arg.freq[i];
1636 }
1637
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001638 return drv->assoc_freq;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001639 }
1640 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
1641 "(%s)", ret, strerror(-ret));
Jouni Malinen87fd2792011-05-16 18:35:42 +03001642 return drv->assoc_freq;
1643}
1644
1645
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001646static int get_link_signal(struct nl_msg *msg, void *arg)
1647{
1648 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1649 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1650 struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
1651 static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
1652 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
Dmitry Shmidt34af3062013-07-11 10:46:32 -07001653 [NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07001654 [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001655 };
1656 struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
1657 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
1658 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
1659 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
1660 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
1661 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
1662 };
1663 struct wpa_signal_info *sig_change = arg;
1664
1665 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1666 genlmsg_attrlen(gnlh, 0), NULL);
1667 if (!tb[NL80211_ATTR_STA_INFO] ||
1668 nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
1669 tb[NL80211_ATTR_STA_INFO], policy))
1670 return NL_SKIP;
1671 if (!sinfo[NL80211_STA_INFO_SIGNAL])
1672 return NL_SKIP;
1673
1674 sig_change->current_signal =
1675 (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
1676
Dmitry Shmidt34af3062013-07-11 10:46:32 -07001677 if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
1678 sig_change->avg_signal =
1679 (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
1680 else
1681 sig_change->avg_signal = 0;
1682
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07001683 if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG])
1684 sig_change->avg_beacon_signal =
1685 (s8)
1686 nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
1687 else
1688 sig_change->avg_beacon_signal = 0;
1689
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001690 if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
1691 if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
1692 sinfo[NL80211_STA_INFO_TX_BITRATE],
1693 rate_policy)) {
1694 sig_change->current_txrate = 0;
1695 } else {
1696 if (rinfo[NL80211_RATE_INFO_BITRATE]) {
1697 sig_change->current_txrate =
1698 nla_get_u16(rinfo[
1699 NL80211_RATE_INFO_BITRATE]) * 100;
1700 }
1701 }
1702 }
1703
1704 return NL_SKIP;
1705}
1706
1707
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001708int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
Sunil Ravi89eba102022-09-13 21:04:37 -07001709 const u8 *bssid, struct wpa_signal_info *sig)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001710{
1711 struct nl_msg *msg;
1712
Hai Shalom74f70d42019-02-11 14:42:39 -08001713 sig->current_signal = -WPA_INVALID_NOISE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001714 sig->current_txrate = 0;
1715
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001716 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
Sunil Ravi89eba102022-09-13 21:04:37 -07001717 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001718 nlmsg_free(msg);
1719 return -ENOBUFS;
1720 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001721
Hai Shalom899fcc72020-10-19 14:38:18 -07001722 return send_and_recv_msgs(drv, msg, get_link_signal, sig, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001723}
1724
1725
1726static int get_link_noise(struct nl_msg *msg, void *arg)
1727{
1728 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1729 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1730 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
1731 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
1732 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
1733 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
1734 };
1735 struct wpa_signal_info *sig_change = arg;
1736
1737 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1738 genlmsg_attrlen(gnlh, 0), NULL);
1739
1740 if (!tb[NL80211_ATTR_SURVEY_INFO]) {
1741 wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
1742 return NL_SKIP;
1743 }
1744
1745 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
1746 tb[NL80211_ATTR_SURVEY_INFO],
1747 survey_policy)) {
1748 wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested "
1749 "attributes!");
1750 return NL_SKIP;
1751 }
1752
1753 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
1754 return NL_SKIP;
1755
1756 if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
1757 sig_change->frequency)
1758 return NL_SKIP;
1759
1760 if (!sinfo[NL80211_SURVEY_INFO_NOISE])
1761 return NL_SKIP;
1762
1763 sig_change->current_noise =
1764 (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
1765
1766 return NL_SKIP;
1767}
1768
1769
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001770int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
1771 struct wpa_signal_info *sig_change)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001772{
1773 struct nl_msg *msg;
1774
Hai Shalom74f70d42019-02-11 14:42:39 -08001775 sig_change->current_noise = WPA_INVALID_NOISE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001776 sig_change->frequency = drv->assoc_freq;
1777
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001778 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
Hai Shalom899fcc72020-10-19 14:38:18 -07001779 return send_and_recv_msgs(drv, msg, get_link_noise, sig_change,
1780 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001781}
1782
1783
Hai Shalom74f70d42019-02-11 14:42:39 -08001784static int get_channel_info(struct nl_msg *msg, void *arg)
1785{
1786 struct nlattr *tb[NL80211_ATTR_MAX + 1] = { 0 };
1787 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1788 struct wpa_channel_info *chan_info = arg;
1789
1790 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1791 genlmsg_attrlen(gnlh, 0), NULL);
1792
1793 os_memset(chan_info, 0, sizeof(struct wpa_channel_info));
1794 chan_info->chanwidth = CHAN_WIDTH_UNKNOWN;
1795
1796 if (tb[NL80211_ATTR_WIPHY_FREQ])
1797 chan_info->frequency =
1798 nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
1799 if (tb[NL80211_ATTR_CHANNEL_WIDTH])
1800 chan_info->chanwidth = convert2width(
1801 nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
1802 if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
1803 enum nl80211_channel_type ct =
1804 nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
1805
1806 switch (ct) {
1807 case NL80211_CHAN_HT40MINUS:
1808 chan_info->sec_channel = -1;
1809 break;
1810 case NL80211_CHAN_HT40PLUS:
1811 chan_info->sec_channel = 1;
1812 break;
1813 default:
1814 chan_info->sec_channel = 0;
1815 break;
1816 }
1817 }
1818 if (tb[NL80211_ATTR_CENTER_FREQ1])
1819 chan_info->center_frq1 =
1820 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
1821 if (tb[NL80211_ATTR_CENTER_FREQ2])
1822 chan_info->center_frq2 =
1823 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
1824
1825 if (chan_info->center_frq2) {
1826 u8 seg1_idx = 0;
1827
1828 if (ieee80211_freq_to_chan(chan_info->center_frq2, &seg1_idx) !=
1829 NUM_HOSTAPD_MODES)
1830 chan_info->seg1_idx = seg1_idx;
1831 }
1832
1833 return NL_SKIP;
1834}
1835
1836
1837static int nl80211_channel_info(void *priv, struct wpa_channel_info *ci)
1838{
1839 struct i802_bss *bss = priv;
1840 struct wpa_driver_nl80211_data *drv = bss->drv;
1841 struct nl_msg *msg;
1842
1843 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
Hai Shalom899fcc72020-10-19 14:38:18 -07001844 return send_and_recv_msgs(drv, msg, get_channel_info, ci, NULL, NULL);
Hai Shalom74f70d42019-02-11 14:42:39 -08001845}
1846
1847
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001848static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
1849 void *handle)
1850{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001851 struct nl_cb *cb = eloop_ctx;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001852 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001853
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07001854 wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001855
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001856 res = nl_recvmsgs(handle, cb);
Dmitry Shmidt71757432014-06-02 13:50:35 -07001857 if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001858 wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
1859 __func__, res);
1860 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001861}
1862
1863
1864/**
1865 * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
1866 * @priv: driver_nl80211 private data
1867 * @alpha2_arg: country to which to switch to
1868 * Returns: 0 on success, -1 on failure
1869 *
1870 * This asks nl80211 to set the regulatory domain for given
1871 * country ISO / IEC alpha2.
1872 */
1873static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
1874{
1875 struct i802_bss *bss = priv;
1876 struct wpa_driver_nl80211_data *drv = bss->drv;
1877 char alpha2[3];
1878 struct nl_msg *msg;
1879
1880 msg = nlmsg_alloc();
1881 if (!msg)
1882 return -ENOMEM;
1883
1884 alpha2[0] = alpha2_arg[0];
1885 alpha2[1] = alpha2_arg[1];
1886 alpha2[2] = '\0';
1887
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001888 if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG) ||
1889 nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, alpha2)) {
1890 nlmsg_free(msg);
1891 return -EINVAL;
1892 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001893 if (send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001894 return -EINVAL;
1895 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001896}
1897
1898
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001899static int nl80211_get_country(struct nl_msg *msg, void *arg)
1900{
1901 char *alpha2 = arg;
1902 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
1903 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1904
1905 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1906 genlmsg_attrlen(gnlh, 0), NULL);
1907 if (!tb_msg[NL80211_ATTR_REG_ALPHA2]) {
1908 wpa_printf(MSG_DEBUG, "nl80211: No country information available");
1909 return NL_SKIP;
1910 }
1911 os_strlcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3);
1912 return NL_SKIP;
1913}
1914
1915
1916static int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
1917{
1918 struct i802_bss *bss = priv;
1919 struct wpa_driver_nl80211_data *drv = bss->drv;
1920 struct nl_msg *msg;
1921 int ret;
1922
1923 msg = nlmsg_alloc();
1924 if (!msg)
1925 return -ENOMEM;
1926
1927 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
1928 alpha2[0] = '\0';
Hai Shalom899fcc72020-10-19 14:38:18 -07001929 ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2,
1930 NULL, NULL);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001931 if (!alpha2[0])
1932 ret = -1;
1933
1934 return ret;
1935}
1936
1937
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001938static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001939{
1940 int ret;
1941
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001942 global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
1943 if (global->nl_cb == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001944 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
1945 "callbacks");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001946 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001947 }
1948
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001949 global->nl = nl_create_handle(global->nl_cb, "nl");
1950 if (global->nl == NULL)
1951 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001952
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001953 global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
1954 if (global->nl80211_id < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001955 wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
1956 "found");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001957 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001958 }
1959
Hai Shalomc1a21442022-02-04 13:43:00 -08001960 global->nlctrl_id = genl_ctrl_resolve(global->nl, "nlctrl");
1961 if (global->nlctrl_id < 0) {
1962 wpa_printf(MSG_ERROR,
1963 "nl80211: 'nlctrl' generic netlink not found");
1964 goto err;
1965 }
1966
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001967 global->nl_event = nl_create_handle(global->nl_cb, "event");
1968 if (global->nl_event == NULL)
1969 goto err;
1970
1971 ret = nl_get_multicast_id(global, "nl80211", "scan");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001972 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001973 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001974 if (ret < 0) {
1975 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
1976 "membership for scan events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001977 ret, nl_geterror(ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001978 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001979 }
1980
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001981 ret = nl_get_multicast_id(global, "nl80211", "mlme");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001982 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001983 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001984 if (ret < 0) {
1985 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
1986 "membership for mlme events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001987 ret, nl_geterror(ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001988 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001989 }
1990
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001991 ret = nl_get_multicast_id(global, "nl80211", "regulatory");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001992 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001993 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001994 if (ret < 0) {
1995 wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
1996 "membership for regulatory events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001997 ret, nl_geterror(ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001998 /* Continue without regulatory events */
1999 }
2000
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002001 ret = nl_get_multicast_id(global, "nl80211", "vendor");
2002 if (ret >= 0)
2003 ret = nl_socket_add_membership(global->nl_event, ret);
2004 if (ret < 0) {
2005 wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
2006 "membership for vendor events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07002007 ret, nl_geterror(ret));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002008 /* Continue without vendor events */
2009 }
2010
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002011 nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
2012 no_seq_check, NULL);
2013 nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
2014 process_global_event, global);
2015
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002016 nl80211_register_eloop_read(&global->nl_event,
2017 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002018 global->nl_cb, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002019
2020 return 0;
2021
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002022err:
2023 nl_destroy_handles(&global->nl_event);
2024 nl_destroy_handles(&global->nl);
2025 nl_cb_put(global->nl_cb);
2026 global->nl_cb = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002027 return -1;
2028}
2029
2030
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002031static void nl80211_check_global(struct nl80211_global *global)
2032{
Hai Shalomfdcde762020-04-02 11:19:20 -07002033 struct nl_sock *handle;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002034 const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL };
2035 int ret;
2036 unsigned int i;
2037
2038 /*
2039 * Try to re-add memberships to handle case of cfg80211 getting reloaded
2040 * and all registration having been cleared.
2041 */
2042 handle = (void *) (((intptr_t) global->nl_event) ^
2043 ELOOP_SOCKET_INVALID);
2044
2045 for (i = 0; groups[i]; i++) {
2046 ret = nl_get_multicast_id(global, "nl80211", groups[i]);
2047 if (ret >= 0)
2048 ret = nl_socket_add_membership(handle, ret);
2049 if (ret < 0) {
2050 wpa_printf(MSG_INFO,
2051 "nl80211: Could not re-add multicast membership for %s events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07002052 groups[i], ret, nl_geterror(ret));
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002053 }
2054 }
2055}
2056
2057
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002058static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
2059{
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002060 struct wpa_driver_nl80211_data *drv = ctx;
2061
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002062 wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002063
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002064 /*
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002065 * rtnetlink ifdown handler will report interfaces other than the P2P
2066 * Device interface as disabled.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002067 */
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002068 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
2069 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002070}
2071
2072
2073static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
2074{
2075 struct wpa_driver_nl80211_data *drv = ctx;
2076 wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002077 if (i802_set_iface_flags(drv->first_bss, 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002078 wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
2079 "after rfkill unblock");
2080 return;
2081 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002082
2083 if (is_p2p_net_interface(drv->nlmode))
2084 nl80211_disable_11b_rates(drv, drv->ifindex, 1);
2085
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002086 /*
2087 * rtnetlink ifup handler will report interfaces other than the P2P
2088 * Device interface as enabled.
2089 */
2090 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
2091 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002092}
2093
2094
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002095static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
2096 void *eloop_ctx,
2097 void *handle)
2098{
2099 struct wpa_driver_nl80211_data *drv = eloop_ctx;
2100 u8 data[2048];
2101 struct msghdr msg;
2102 struct iovec entry;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002103 u8 control[512];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002104 struct cmsghdr *cmsg;
2105 int res, found_ee = 0, found_wifi = 0, acked = 0;
2106 union wpa_event_data event;
2107
2108 memset(&msg, 0, sizeof(msg));
2109 msg.msg_iov = &entry;
2110 msg.msg_iovlen = 1;
2111 entry.iov_base = data;
2112 entry.iov_len = sizeof(data);
2113 msg.msg_control = &control;
2114 msg.msg_controllen = sizeof(control);
2115
2116 res = recvmsg(sock, &msg, MSG_ERRQUEUE);
2117 /* if error or not fitting 802.3 header, return */
2118 if (res < 14)
2119 return;
2120
2121 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
2122 {
2123 if (cmsg->cmsg_level == SOL_SOCKET &&
2124 cmsg->cmsg_type == SCM_WIFI_STATUS) {
2125 int *ack;
2126
2127 found_wifi = 1;
2128 ack = (void *)CMSG_DATA(cmsg);
2129 acked = *ack;
2130 }
2131
2132 if (cmsg->cmsg_level == SOL_PACKET &&
2133 cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
2134 struct sock_extended_err *err =
2135 (struct sock_extended_err *)CMSG_DATA(cmsg);
2136
2137 if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
2138 found_ee = 1;
2139 }
2140 }
2141
2142 if (!found_ee || !found_wifi)
2143 return;
2144
2145 memset(&event, 0, sizeof(event));
2146 event.eapol_tx_status.dst = data;
2147 event.eapol_tx_status.data = data + 14;
2148 event.eapol_tx_status.data_len = res - 14;
2149 event.eapol_tx_status.ack = acked;
2150 wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
2151}
2152
2153
Hai Shalomb755a2a2020-04-23 21:49:02 -07002154static int nl80211_init_connect_handle(struct i802_bss *bss)
2155{
2156 if (bss->nl_connect) {
2157 wpa_printf(MSG_DEBUG,
2158 "nl80211: Connect handle already created (nl_connect=%p)",
2159 bss->nl_connect);
2160 return -1;
2161 }
2162
2163 bss->nl_connect = nl_create_handle(bss->nl_cb, "connect");
2164 if (!bss->nl_connect)
2165 return -1;
2166 nl80211_register_eloop_read(&bss->nl_connect,
2167 wpa_driver_nl80211_event_receive,
2168 bss->nl_cb, 1);
2169 return 0;
2170}
2171
2172
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002173static int nl80211_init_bss(struct i802_bss *bss)
2174{
2175 bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
2176 if (!bss->nl_cb)
2177 return -1;
2178
2179 nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
2180 no_seq_check, NULL);
2181 nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
2182 process_bss_event, bss);
2183
Hai Shalomb755a2a2020-04-23 21:49:02 -07002184 nl80211_init_connect_handle(bss);
2185
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002186 return 0;
2187}
2188
2189
2190static void nl80211_destroy_bss(struct i802_bss *bss)
2191{
2192 nl_cb_put(bss->nl_cb);
2193 bss->nl_cb = NULL;
Hai Shalomb755a2a2020-04-23 21:49:02 -07002194
2195 if (bss->nl_connect)
2196 nl80211_destroy_eloop_handle(&bss->nl_connect, 1);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002197}
2198
2199
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002200static void
2201wpa_driver_nl80211_drv_init_rfkill(struct wpa_driver_nl80211_data *drv)
2202{
2203 struct rfkill_config *rcfg;
2204
2205 if (drv->rfkill)
2206 return;
2207
2208 rcfg = os_zalloc(sizeof(*rcfg));
2209 if (!rcfg)
2210 return;
2211
2212 rcfg->ctx = drv;
2213
2214 /* rfkill uses netdev sysfs for initialization. However, P2P Device is
2215 * not associated with a netdev, so use the name of some other interface
2216 * sharing the same wiphy as the P2P Device interface.
2217 *
2218 * Note: This is valid, as a P2P Device interface is always dynamically
2219 * created and is created only once another wpa_s interface was added.
2220 */
2221 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
2222 struct nl80211_global *global = drv->global;
2223 struct wpa_driver_nl80211_data *tmp1;
2224
2225 dl_list_for_each(tmp1, &global->interfaces,
2226 struct wpa_driver_nl80211_data, list) {
2227 if (drv == tmp1 || drv->wiphy_idx != tmp1->wiphy_idx ||
2228 !tmp1->rfkill)
2229 continue;
2230
2231 wpa_printf(MSG_DEBUG,
2232 "nl80211: Use (%s) to initialize P2P Device rfkill",
2233 tmp1->first_bss->ifname);
2234 os_strlcpy(rcfg->ifname, tmp1->first_bss->ifname,
2235 sizeof(rcfg->ifname));
2236 break;
2237 }
2238 } else {
2239 os_strlcpy(rcfg->ifname, drv->first_bss->ifname,
2240 sizeof(rcfg->ifname));
2241 }
2242
2243 rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
2244 rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
2245 drv->rfkill = rfkill_init(rcfg);
2246 if (!drv->rfkill) {
2247 wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
2248 os_free(rcfg);
2249 }
2250}
2251
2252
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002253static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
2254 void *global_priv, int hostapd,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002255 const u8 *set_addr,
2256 const char *driver_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002257{
2258 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002259 struct i802_bss *bss;
2260
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002261 if (global_priv == NULL)
2262 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002263 drv = os_zalloc(sizeof(*drv));
2264 if (drv == NULL)
2265 return NULL;
2266 drv->global = global_priv;
2267 drv->ctx = ctx;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002268 drv->hostapd = !!hostapd;
2269 drv->eapol_sock = -1;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002270
2271 /*
2272 * There is no driver capability flag for this, so assume it is
2273 * supported and disable this on first attempt to use if the driver
2274 * rejects the command due to missing support.
2275 */
2276 drv->set_rekey_offload = 1;
2277
Hai Shalom81f62d82019-07-22 12:10:00 -07002278 drv->num_if_indices = ARRAY_SIZE(drv->default_if_indices);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002279 drv->if_indices = drv->default_if_indices;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002280
2281 drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
2282 if (!drv->first_bss) {
2283 os_free(drv);
2284 return NULL;
2285 }
2286 bss = drv->first_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002287 bss->drv = drv;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002288 bss->ctx = ctx;
2289
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002290 os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
2291 drv->monitor_ifidx = -1;
2292 drv->monitor_sock = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002293 drv->eapol_tx_sock = -1;
2294 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002295
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002296 if (nl80211_init_bss(bss))
2297 goto failed;
2298
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002299 if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002300 goto failed;
2301
Hai Shalom899fcc72020-10-19 14:38:18 -07002302 if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS) {
2303 drv->control_port_ap = 1;
2304 goto skip_wifi_status;
2305 }
2306
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002307 drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
2308 if (drv->eapol_tx_sock < 0)
2309 goto failed;
2310
2311 if (drv->data_tx_status) {
2312 int enabled = 1;
2313
2314 if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
2315 &enabled, sizeof(enabled)) < 0) {
2316 wpa_printf(MSG_DEBUG,
Hai Shalom899fcc72020-10-19 14:38:18 -07002317 "nl80211: wifi status sockopt failed: %s",
2318 strerror(errno));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002319 drv->data_tx_status = 0;
2320 if (!drv->use_monitor)
2321 drv->capa.flags &=
2322 ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
2323 } else {
Hai Shalom899fcc72020-10-19 14:38:18 -07002324 eloop_register_read_sock(
2325 drv->eapol_tx_sock,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002326 wpa_driver_nl80211_handle_eapol_tx_status,
2327 drv, NULL);
2328 }
2329 }
Hai Shalom899fcc72020-10-19 14:38:18 -07002330skip_wifi_status:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002331
2332 if (drv->global) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002333 nl80211_check_global(drv->global);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002334 dl_list_add(&drv->global->interfaces, &drv->list);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002335 drv->in_interface_list = 1;
2336 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002337
2338 return bss;
2339
2340failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002341 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002342 return NULL;
2343}
2344
2345
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002346/**
2347 * wpa_driver_nl80211_init - Initialize nl80211 driver interface
2348 * @ctx: context to be used when calling wpa_supplicant functions,
2349 * e.g., wpa_supplicant_event()
2350 * @ifname: interface name, e.g., wlan0
2351 * @global_priv: private driver global data from global_init()
2352 * Returns: Pointer to private data, %NULL on failure
2353 */
2354static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
2355 void *global_priv)
2356{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002357 return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL,
2358 NULL);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002359}
2360
2361
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002362static int nl80211_register_frame(struct i802_bss *bss,
Hai Shalomfdcde762020-04-02 11:19:20 -07002363 struct nl_sock *nl_handle,
Hai Shalome21d4e82020-04-29 16:34:06 -07002364 u16 type, const u8 *match, size_t match_len,
2365 bool multicast)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002366{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002367 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002368 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002369 int ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002370 char buf[30];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002371
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002372 buf[0] = '\0';
2373 wpa_snprintf_hex(buf, sizeof(buf), match, match_len);
Hai Shalome21d4e82020-04-29 16:34:06 -07002374 wpa_printf(MSG_DEBUG,
2375 "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s multicast=%d",
2376 type, fc2str(type), nl_handle, buf, multicast);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002377
Hai Shalomfdcde762020-04-02 11:19:20 -07002378 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_FRAME)) ||
Hai Shalome21d4e82020-04-29 16:34:06 -07002379 (multicast && nla_put_flag(msg, NL80211_ATTR_RECEIVE_MULTICAST)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002380 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type) ||
2381 nla_put(msg, NL80211_ATTR_FRAME_MATCH, match_len, match)) {
2382 nlmsg_free(msg);
2383 return -1;
2384 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002385
Hai Shalom899fcc72020-10-19 14:38:18 -07002386 ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL,
2387 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002388 if (ret) {
2389 wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
2390 "failed (type=%u): ret=%d (%s)",
2391 type, ret, strerror(-ret));
2392 wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
2393 match, match_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002394 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002395 return ret;
2396}
2397
2398
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002399static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
2400{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002401 if (bss->nl_mgmt) {
2402 wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
2403 "already on! (nl_mgmt=%p)", bss->nl_mgmt);
2404 return -1;
2405 }
2406
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002407 bss->nl_mgmt = nl_create_handle(bss->nl_cb, "mgmt");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002408 if (bss->nl_mgmt == NULL)
2409 return -1;
2410
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002411 return 0;
2412}
2413
2414
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002415static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss)
2416{
2417 nl80211_register_eloop_read(&bss->nl_mgmt,
2418 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002419 bss->nl_cb, 0);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002420}
2421
2422
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002423static int nl80211_register_action_frame(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002424 const u8 *match, size_t match_len)
2425{
2426 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002427 return nl80211_register_frame(bss, bss->nl_mgmt,
Hai Shalome21d4e82020-04-29 16:34:06 -07002428 type, match, match_len, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002429}
2430
2431
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002432static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002433{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002434 struct wpa_driver_nl80211_data *drv = bss->drv;
Hai Shalomfdcde762020-04-02 11:19:20 -07002435 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002436 int ret = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002437
2438 if (nl80211_alloc_mgmt_handle(bss))
2439 return -1;
2440 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
2441 "handle %p", bss->nl_mgmt);
2442
Hai Shalomfdcde762020-04-02 11:19:20 -07002443 if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002444 /* register for any AUTH message */
Hai Shalome21d4e82020-04-29 16:34:06 -07002445 nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0, false);
Hai Shalomfdcde762020-04-02 11:19:20 -07002446 } else if ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
2447 !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
2448 /* register for SAE Authentication frames */
2449 nl80211_register_frame(bss, bss->nl_mgmt, type,
Hai Shalome21d4e82020-04-29 16:34:06 -07002450 (u8 *) "\x03\x00", 2, false);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002451 }
2452
Hai Shalom60840252021-02-19 19:02:11 -08002453#ifdef CONFIG_PASN
2454 /* register for PASN Authentication frames */
Sunil Ravi89eba102022-09-13 21:04:37 -07002455 if (nl80211_register_frame(bss, bss->nl_mgmt, type,
Hai Shalom60840252021-02-19 19:02:11 -08002456 (u8 *) "\x07\x00", 2, false))
2457 ret = -1;
2458#endif /* CONFIG_PASN */
2459
Dmitry Shmidt051af732013-10-22 13:52:46 -07002460#ifdef CONFIG_INTERWORKING
2461 /* QoS Map Configure */
2462 if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002463 ret = -1;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002464#endif /* CONFIG_INTERWORKING */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002465#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002466 /* GAS Initial Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002467 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002468 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002469 /* GAS Initial Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002470 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002471 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002472 /* GAS Comeback Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002473 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002474 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002475 /* GAS Comeback Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002476 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002477 ret = -1;
Dmitry Shmidt18463232014-01-24 12:29:41 -08002478 /* Protected GAS Initial Request */
2479 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0a", 2) < 0)
2480 ret = -1;
2481 /* Protected GAS Initial Response */
2482 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0b", 2) < 0)
2483 ret = -1;
2484 /* Protected GAS Comeback Request */
2485 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0c", 2) < 0)
2486 ret = -1;
2487 /* Protected GAS Comeback Response */
2488 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0d", 2) < 0)
2489 ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002490#endif /* CONFIG_P2P || CONFIG_INTERWORKING || CONFIG_DPP */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002491#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002492 /* P2P Public Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002493 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002494 (u8 *) "\x04\x09\x50\x6f\x9a\x09",
2495 6) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002496 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002497 /* P2P Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002498 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002499 (u8 *) "\x7f\x50\x6f\x9a\x09",
2500 5) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002501 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002502#endif /* CONFIG_P2P */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002503#ifdef CONFIG_DPP
2504 /* DPP Public Action */
2505 if (nl80211_register_action_frame(bss,
2506 (u8 *) "\x04\x09\x50\x6f\x9a\x1a",
2507 6) < 0)
2508 ret = -1;
2509#endif /* CONFIG_DPP */
Hai Shalom74f70d42019-02-11 14:42:39 -08002510#ifdef CONFIG_OCV
2511 /* SA Query Request */
2512 if (nl80211_register_action_frame(bss, (u8 *) "\x08\x00", 2) < 0)
2513 ret = -1;
2514#endif /* CONFIG_OCV */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002515 /* SA Query Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002516 if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002517 ret = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002518#ifdef CONFIG_TDLS
2519 if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
2520 /* TDLS Discovery Response */
2521 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
2522 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002523 ret = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002524 }
2525#endif /* CONFIG_TDLS */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002526#ifdef CONFIG_FST
2527 /* FST Action frames */
2528 if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
2529 ret = -1;
2530#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002531
2532 /* FT Action frames */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002533 if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002534 ret = -1;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002535 else if (!drv->has_driver_key_mgmt) {
2536 int i;
2537
2538 /* Update supported AKMs only if the driver doesn't advertize
2539 * any AKM capabilities. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002540 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
2541 WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
2542
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002543 /* Update per interface supported AKMs */
2544 for (i = 0; i < WPA_IF_MAX; i++)
2545 drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt;
2546 }
2547
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002548 /* WNM - BSS Transition Management Request */
2549 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002550 ret = -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002551 /* WNM-Sleep Mode Response */
2552 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002553 ret = -1;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08002554#ifdef CONFIG_WNM
2555 /* WNM - Collocated Interference Request */
2556 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x0b", 2) < 0)
2557 ret = -1;
2558#endif /* CONFIG_WNM */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002559
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002560#ifdef CONFIG_HS20
2561 /* WNM-Notification */
2562 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x1a", 2) < 0)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002563 ret = -1;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002564#endif /* CONFIG_HS20 */
2565
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002566 /* WMM-AC ADDTS Response */
2567 if (nl80211_register_action_frame(bss, (u8 *) "\x11\x01", 2) < 0)
2568 ret = -1;
2569
2570 /* WMM-AC DELTS */
2571 if (nl80211_register_action_frame(bss, (u8 *) "\x11\x02", 2) < 0)
2572 ret = -1;
2573
2574 /* Radio Measurement - Neighbor Report Response */
2575 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
2576 ret = -1;
2577
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002578 /* Radio Measurement - Radio Measurement Request */
Hai Shalom899fcc72020-10-19 14:38:18 -07002579 if (!drv->no_rrm &&
2580 nl80211_register_action_frame(bss, (u8 *) "\x05\x00", 2) < 0)
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002581 ret = -1;
2582
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002583 /* Radio Measurement - Link Measurement Request */
2584 if ((drv->capa.rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) &&
2585 (nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
2586 ret = -1;
2587
Hai Shalomc1a21442022-02-04 13:43:00 -08002588 /* Robust AV SCS Response */
2589 if (nl80211_register_action_frame(bss, (u8 *) "\x13\x01", 2) < 0)
2590 ret = -1;
2591
Hai Shalom899fcc72020-10-19 14:38:18 -07002592 /* Robust AV MSCS Response */
2593 if (nl80211_register_action_frame(bss, (u8 *) "\x13\x05", 2) < 0)
2594 ret = -1;
2595
Hai Shalomc1a21442022-02-04 13:43:00 -08002596 /* Protected QoS Management Action frame */
2597 if (nl80211_register_action_frame(bss, (u8 *) "\x7e\x50\x6f\x9a\x1a",
2598 5) < 0)
2599 ret = -1;
2600
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002601 nl80211_mgmt_handle_register_eloop(bss);
2602
2603 return ret;
2604}
2605
2606
2607static int nl80211_mgmt_subscribe_mesh(struct i802_bss *bss)
2608{
2609 int ret = 0;
2610
2611 if (nl80211_alloc_mgmt_handle(bss))
2612 return -1;
2613
2614 wpa_printf(MSG_DEBUG,
2615 "nl80211: Subscribe to mgmt frames with mesh handle %p",
2616 bss->nl_mgmt);
2617
2618 /* Auth frames for mesh SAE */
2619 if (nl80211_register_frame(bss, bss->nl_mgmt,
2620 (WLAN_FC_TYPE_MGMT << 2) |
2621 (WLAN_FC_STYPE_AUTH << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07002622 NULL, 0, false) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002623 ret = -1;
2624
2625 /* Mesh peering open */
2626 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x01", 2) < 0)
2627 ret = -1;
2628 /* Mesh peering confirm */
2629 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x02", 2) < 0)
2630 ret = -1;
2631 /* Mesh peering close */
2632 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x03", 2) < 0)
2633 ret = -1;
2634
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002635 nl80211_mgmt_handle_register_eloop(bss);
2636
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002637 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002638}
2639
2640
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002641static int nl80211_register_spurious_class3(struct i802_bss *bss)
2642{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002643 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002644 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002645
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002646 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
Hai Shalom899fcc72020-10-19 14:38:18 -07002647 ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL,
2648 NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002649 if (ret) {
2650 wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
2651 "failed: ret=%d (%s)",
2652 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002653 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002654 return ret;
2655}
2656
2657
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002658static int nl80211_action_subscribe_ap(struct i802_bss *bss)
2659{
2660 int ret = 0;
2661
2662 /* Public Action frames */
2663 if (nl80211_register_action_frame(bss, (u8 *) "\x04", 1) < 0)
2664 ret = -1;
2665 /* RRM Measurement Report */
2666 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x01", 2) < 0)
2667 ret = -1;
Paul Stewart092955c2017-02-06 09:13:09 -08002668 /* RRM Link Measurement Report */
2669 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x03", 2) < 0)
2670 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002671 /* RRM Neighbor Report Request */
2672 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x04", 2) < 0)
2673 ret = -1;
2674 /* FT Action frames */
2675 if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
2676 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002677 /* SA Query */
2678 if (nl80211_register_action_frame(bss, (u8 *) "\x08", 1) < 0)
2679 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002680 /* Protected Dual of Public Action */
2681 if (nl80211_register_action_frame(bss, (u8 *) "\x09", 1) < 0)
2682 ret = -1;
2683 /* WNM */
2684 if (nl80211_register_action_frame(bss, (u8 *) "\x0a", 1) < 0)
2685 ret = -1;
2686 /* WMM */
2687 if (nl80211_register_action_frame(bss, (u8 *) "\x11", 1) < 0)
2688 ret = -1;
2689#ifdef CONFIG_FST
2690 /* FST Action frames */
2691 if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
2692 ret = -1;
2693#endif /* CONFIG_FST */
2694 /* Vendor-specific */
2695 if (nl80211_register_action_frame(bss, (u8 *) "\x7f", 1) < 0)
2696 ret = -1;
2697
2698 return ret;
2699}
2700
2701
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002702static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
2703{
2704 static const int stypes[] = {
2705 WLAN_FC_STYPE_AUTH,
2706 WLAN_FC_STYPE_ASSOC_REQ,
2707 WLAN_FC_STYPE_REASSOC_REQ,
2708 WLAN_FC_STYPE_DISASSOC,
2709 WLAN_FC_STYPE_DEAUTH,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002710 WLAN_FC_STYPE_PROBE_REQ,
2711/* Beacon doesn't work as mac80211 doesn't currently allow
2712 * it, but it wouldn't really be the right thing anyway as
2713 * it isn't per interface ... maybe just dump the scan
2714 * results periodically for OLBC?
2715 */
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002716 /* WLAN_FC_STYPE_BEACON, */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002717 };
2718 unsigned int i;
2719
2720 if (nl80211_alloc_mgmt_handle(bss))
2721 return -1;
2722 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
2723 "handle %p", bss->nl_mgmt);
2724
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002725 for (i = 0; i < ARRAY_SIZE(stypes); i++) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002726 if (nl80211_register_frame(bss, bss->nl_mgmt,
2727 (WLAN_FC_TYPE_MGMT << 2) |
2728 (stypes[i] << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07002729 NULL, 0, false) < 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002730 goto out_err;
2731 }
2732 }
2733
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002734 if (nl80211_action_subscribe_ap(bss))
2735 goto out_err;
2736
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002737 if (nl80211_register_spurious_class3(bss))
2738 goto out_err;
2739
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002740 nl80211_mgmt_handle_register_eloop(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002741 return 0;
2742
2743out_err:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002744 nl_destroy_handles(&bss->nl_mgmt);
2745 return -1;
2746}
2747
2748
2749static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
2750{
2751 if (nl80211_alloc_mgmt_handle(bss))
2752 return -1;
2753 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
2754 "handle %p (device SME)", bss->nl_mgmt);
2755
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002756 if (nl80211_action_subscribe_ap(bss))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002757 goto out_err;
2758
Hai Shalom5f92bc92019-04-18 11:54:11 -07002759 if (bss->drv->device_ap_sme) {
2760 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
2761
2762 /* Register for all Authentication frames */
Hai Shalome21d4e82020-04-29 16:34:06 -07002763 if (nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0,
2764 false) < 0)
Hai Shalom5f92bc92019-04-18 11:54:11 -07002765 wpa_printf(MSG_DEBUG,
2766 "nl80211: Failed to subscribe to handle Authentication frames - SAE offload may not work");
2767 }
2768
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002769 nl80211_mgmt_handle_register_eloop(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002770 return 0;
2771
2772out_err:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002773 nl_destroy_handles(&bss->nl_mgmt);
2774 return -1;
2775}
2776
2777
2778static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
2779{
2780 if (bss->nl_mgmt == NULL)
2781 return;
2782 wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
2783 "(%s)", bss->nl_mgmt, reason);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002784 nl80211_destroy_eloop_handle(&bss->nl_mgmt, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002785
2786 nl80211_put_wiphy_data_ap(bss);
2787}
2788
2789
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002790static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
2791{
2792 wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
2793}
2794
2795
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002796static void nl80211_del_p2pdev(struct i802_bss *bss)
2797{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002798 struct nl_msg *msg;
2799 int ret;
2800
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002801 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
Hai Shalom899fcc72020-10-19 14:38:18 -07002802 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002803
2804 wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
2805 bss->ifname, (long long unsigned int) bss->wdev_id,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002806 strerror(-ret));
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002807}
2808
2809
2810static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
2811{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002812 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002813 int ret;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002814
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002815 msg = nl80211_cmd_msg(bss, 0, start ? NL80211_CMD_START_P2P_DEVICE :
2816 NL80211_CMD_STOP_P2P_DEVICE);
Hai Shalom899fcc72020-10-19 14:38:18 -07002817 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002818
2819 wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
2820 start ? "Start" : "Stop",
2821 bss->ifname, (long long unsigned int) bss->wdev_id,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002822 strerror(-ret));
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002823 return ret;
2824}
2825
2826
2827static int i802_set_iface_flags(struct i802_bss *bss, int up)
2828{
2829 enum nl80211_iftype nlmode;
2830
2831 nlmode = nl80211_get_ifmode(bss);
2832 if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
2833 return linux_set_iface_flags(bss->drv->global->ioctl_sock,
2834 bss->ifname, up);
2835 }
2836
2837 /* P2P Device has start/stop which is equivalent */
2838 return nl80211_set_p2pdev(bss, up);
2839}
2840
2841
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002842#ifdef CONFIG_TESTING_OPTIONS
2843static int qca_vendor_test_cmd_handler(struct nl_msg *msg, void *arg)
2844{
2845 /* struct wpa_driver_nl80211_data *drv = arg; */
2846 struct nlattr *tb[NL80211_ATTR_MAX + 1];
2847 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2848
2849
2850 wpa_printf(MSG_DEBUG,
2851 "nl80211: QCA vendor test command response received");
2852
2853 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2854 genlmsg_attrlen(gnlh, 0), NULL);
2855 if (!tb[NL80211_ATTR_VENDOR_DATA]) {
2856 wpa_printf(MSG_DEBUG, "nl80211: No vendor data attribute");
2857 return NL_SKIP;
2858 }
2859
2860 wpa_hexdump(MSG_DEBUG,
2861 "nl80211: Received QCA vendor test command response",
2862 nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
2863 nla_len(tb[NL80211_ATTR_VENDOR_DATA]));
2864
2865 return NL_SKIP;
2866}
2867#endif /* CONFIG_TESTING_OPTIONS */
2868
2869
2870static void qca_vendor_test(struct wpa_driver_nl80211_data *drv)
2871{
2872#ifdef CONFIG_TESTING_OPTIONS
2873 struct nl_msg *msg;
2874 struct nlattr *params;
2875 int ret;
2876
2877 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
2878 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
2879 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
2880 QCA_NL80211_VENDOR_SUBCMD_TEST) ||
2881 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
2882 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TEST, 123)) {
2883 nlmsg_free(msg);
2884 return;
2885 }
2886 nla_nest_end(msg, params);
2887
Hai Shalom899fcc72020-10-19 14:38:18 -07002888 ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv,
2889 NULL, NULL);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002890 wpa_printf(MSG_DEBUG,
2891 "nl80211: QCA vendor test command returned %d (%s)",
2892 ret, strerror(-ret));
2893#endif /* CONFIG_TESTING_OPTIONS */
2894}
2895
2896
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002897static int
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002898wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002899 const u8 *set_addr, int first,
2900 const char *driver_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002901{
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002902 struct i802_bss *bss = drv->first_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002903 int send_rfkill_event = 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002904 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002905
2906 drv->ifindex = if_nametoindex(bss->ifname);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002907 bss->ifindex = drv->ifindex;
2908 bss->wdev_id = drv->global->if_add_wdevid;
2909 bss->wdev_id_set = drv->global->if_add_wdevid_set;
2910
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002911 bss->if_dynamic = drv->ifindex == drv->global->if_add_ifindex;
2912 bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002913 drv->global->if_add_wdevid_set = 0;
2914
Dmitry Shmidt03658832014-08-13 11:03:49 -07002915 if (!bss->if_dynamic && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
2916 bss->static_ap = 1;
2917
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08002918 if (first &&
2919 nl80211_get_ifmode(bss) != NL80211_IFTYPE_P2P_DEVICE &&
2920 linux_iface_up(drv->global->ioctl_sock, bss->ifname) > 0)
2921 drv->start_iface_up = 1;
2922
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002923 if (wpa_driver_nl80211_capa(drv))
2924 return -1;
2925
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002926 if (driver_params && nl80211_set_param(bss, driver_params) < 0)
2927 return -1;
2928
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002929 wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
2930 bss->ifname, drv->phyname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002931
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002932 if (set_addr &&
2933 (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) ||
2934 linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
2935 set_addr)))
2936 return -1;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002937
Hai Shalomc1a21442022-02-04 13:43:00 -08002938 if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_STATION)
2939 drv->start_mode_sta = 1;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002940
Dmitry Shmidt03658832014-08-13 11:03:49 -07002941 if (drv->hostapd || bss->static_ap)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002942 nlmode = NL80211_IFTYPE_AP;
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07002943 else if (bss->if_dynamic ||
2944 nl80211_get_ifmode(bss) == NL80211_IFTYPE_MESH_POINT)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002945 nlmode = nl80211_get_ifmode(bss);
2946 else
2947 nlmode = NL80211_IFTYPE_STATION;
2948
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002949 if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002950 wpa_printf(MSG_ERROR, "nl80211: Could not configure driver mode");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002951 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002952 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002953
Dmitry Shmidt98660862014-03-11 17:26:21 -07002954 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002955 nl80211_get_macaddr(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002956
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002957 wpa_driver_nl80211_drv_init_rfkill(drv);
2958
Dmitry Shmidt98660862014-03-11 17:26:21 -07002959 if (!rfkill_is_blocked(drv->rfkill)) {
2960 int ret = i802_set_iface_flags(bss, 1);
2961 if (ret) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002962 wpa_printf(MSG_ERROR, "nl80211: Could not set "
2963 "interface '%s' UP", bss->ifname);
Dmitry Shmidt98660862014-03-11 17:26:21 -07002964 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002965 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002966
2967 if (is_p2p_net_interface(nlmode))
2968 nl80211_disable_11b_rates(bss->drv,
2969 bss->drv->ifindex, 1);
2970
Dmitry Shmidt98660862014-03-11 17:26:21 -07002971 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
2972 return ret;
2973 } else {
2974 wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
2975 "interface '%s' due to rfkill", bss->ifname);
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002976 if (nlmode != NL80211_IFTYPE_P2P_DEVICE)
2977 drv->if_disabled = 1;
2978
Dmitry Shmidt98660862014-03-11 17:26:21 -07002979 send_rfkill_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002980 }
2981
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002982 if (!drv->hostapd && nlmode != NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002983 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
2984 1, IF_OPER_DORMANT);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002985
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002986 if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
2987 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
2988 bss->addr))
2989 return -1;
2990 os_memcpy(drv->perm_addr, bss->addr, ETH_ALEN);
2991 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002992
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002993 if (send_rfkill_event) {
2994 eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
2995 drv, drv->ctx);
2996 }
2997
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002998 if (drv->vendor_cmd_test_avail)
2999 qca_vendor_test(drv);
3000
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003001 return 0;
3002}
3003
3004
Paul Stewart092955c2017-02-06 09:13:09 -08003005static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003006{
3007 struct nl_msg *msg;
Paul Stewart092955c2017-02-06 09:13:09 -08003008 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003009
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003010 wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
3011 drv->ifindex);
Sunil Ravia04bd252022-05-02 22:54:18 -07003012 bss->beacon_set = 0;
3013 bss->freq = 0;
Paul Stewart092955c2017-02-06 09:13:09 -08003014 nl80211_put_wiphy_data_ap(bss);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003015 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
Hai Shalom899fcc72020-10-19 14:38:18 -07003016 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003017}
3018
3019
3020/**
3021 * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003022 * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003023 *
3024 * Shut down driver interface and processing of driver events. Free
3025 * private data buffer if one was allocated in wpa_driver_nl80211_init().
3026 */
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003027static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003028{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003029 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07003030 unsigned int i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003031
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003032 wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
3033 bss->ifname, drv->disabled_11b_rates);
3034
Dmitry Shmidt04949592012-07-19 12:16:46 -07003035 bss->in_deinit = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003036 if (drv->data_tx_status)
3037 eloop_unregister_read_sock(drv->eapol_tx_sock);
3038 if (drv->eapol_tx_sock >= 0)
3039 close(drv->eapol_tx_sock);
3040
3041 if (bss->nl_preq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003042 wpa_driver_nl80211_probe_req_report(bss, 0);
3043 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003044 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
3045 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003046 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
3047 "interface %s from bridge %s: %s",
3048 bss->ifname, bss->brname, strerror(errno));
3049 }
Hai Shalomc9e41a12018-07-31 14:41:42 -07003050
3051 if (drv->rtnl_sk)
Hai Shalomfdcde762020-04-02 11:19:20 -07003052 nl_socket_free(drv->rtnl_sk);
Hai Shalomc9e41a12018-07-31 14:41:42 -07003053
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003054 if (bss->added_bridge) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003055 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
3056 0) < 0)
3057 wpa_printf(MSG_INFO,
3058 "nl80211: Could not set bridge %s down",
3059 bss->brname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003060 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003061 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
3062 "bridge %s: %s",
3063 bss->brname, strerror(errno));
3064 }
3065
3066 nl80211_remove_monitor_interface(drv);
3067
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003068 if (is_ap_interface(drv->nlmode))
Paul Stewart092955c2017-02-06 09:13:09 -08003069 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003070
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003071 if (drv->eapol_sock >= 0) {
3072 eloop_unregister_read_sock(drv->eapol_sock);
3073 close(drv->eapol_sock);
3074 }
3075
3076 if (drv->if_indices != drv->default_if_indices)
3077 os_free(drv->if_indices);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003078
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003079 if (drv->disabled_11b_rates)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003080 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
3081
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003082 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
3083 IF_OPER_UP);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07003084 eloop_cancel_timeout(wpa_driver_nl80211_send_rfkill, drv, drv->ctx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003085 rfkill_deinit(drv->rfkill);
3086
3087 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
3088
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003089 if (!drv->start_iface_up)
3090 (void) i802_set_iface_flags(bss, 0);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003091
3092 if (drv->addr_changed) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003093 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
3094 0) < 0) {
3095 wpa_printf(MSG_DEBUG,
3096 "nl80211: Could not set interface down to restore permanent MAC address");
3097 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003098 if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
3099 drv->perm_addr) < 0) {
3100 wpa_printf(MSG_DEBUG,
3101 "nl80211: Could not restore permanent MAC address");
3102 }
3103 }
3104
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003105 if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
Hai Shalomc1a21442022-02-04 13:43:00 -08003106 if (drv->start_mode_sta)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003107 wpa_driver_nl80211_set_mode(bss,
3108 NL80211_IFTYPE_STATION);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07003109 nl80211_mgmt_unsubscribe(bss, "deinit");
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003110 } else {
3111 nl80211_mgmt_unsubscribe(bss, "deinit");
3112 nl80211_del_p2pdev(bss);
3113 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003114
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003115 nl80211_destroy_bss(drv->first_bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003116
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003117 os_free(drv->filter_ssids);
3118
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003119 os_free(drv->auth_ie);
Hai Shalom60840252021-02-19 19:02:11 -08003120 os_free(drv->auth_data);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003121
3122 if (drv->in_interface_list)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003123 dl_list_del(&drv->list);
3124
Dmitry Shmidt444d5672013-04-01 13:08:44 -07003125 os_free(drv->extended_capa);
3126 os_free(drv->extended_capa_mask);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07003127 for (i = 0; i < drv->num_iface_ext_capa; i++) {
3128 os_free(drv->iface_ext_capa[i].ext_capa);
3129 os_free(drv->iface_ext_capa[i].ext_capa_mask);
3130 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003131 os_free(drv->first_bss);
Hai Shalom60840252021-02-19 19:02:11 -08003132#ifdef CONFIG_DRIVER_NL80211_QCA
3133 os_free(drv->pending_roam_data);
3134#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003135 os_free(drv);
3136}
3137
3138
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003139static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len)
3140{
3141 switch (alg) {
3142 case WPA_ALG_WEP:
3143 if (key_len == 5)
Paul Stewart092955c2017-02-06 09:13:09 -08003144 return RSN_CIPHER_SUITE_WEP40;
3145 return RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003146 case WPA_ALG_TKIP:
Paul Stewart092955c2017-02-06 09:13:09 -08003147 return RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003148 case WPA_ALG_CCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003149 return RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003150 case WPA_ALG_GCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003151 return RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003152 case WPA_ALG_CCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003153 return RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003154 case WPA_ALG_GCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003155 return RSN_CIPHER_SUITE_GCMP_256;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003156 case WPA_ALG_BIP_CMAC_128:
Paul Stewart092955c2017-02-06 09:13:09 -08003157 return RSN_CIPHER_SUITE_AES_128_CMAC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003158 case WPA_ALG_BIP_GMAC_128:
Paul Stewart092955c2017-02-06 09:13:09 -08003159 return RSN_CIPHER_SUITE_BIP_GMAC_128;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003160 case WPA_ALG_BIP_GMAC_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003161 return RSN_CIPHER_SUITE_BIP_GMAC_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003162 case WPA_ALG_BIP_CMAC_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003163 return RSN_CIPHER_SUITE_BIP_CMAC_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003164 case WPA_ALG_SMS4:
Paul Stewart092955c2017-02-06 09:13:09 -08003165 return RSN_CIPHER_SUITE_SMS4;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003166 case WPA_ALG_KRK:
Paul Stewart092955c2017-02-06 09:13:09 -08003167 return RSN_CIPHER_SUITE_KRK;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003168 case WPA_ALG_NONE:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003169 wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d",
3170 alg);
3171 return 0;
3172 }
3173
3174 wpa_printf(MSG_ERROR, "nl80211: Unsupported encryption algorithm %d",
3175 alg);
3176 return 0;
3177}
3178
3179
3180static u32 wpa_cipher_to_cipher_suite(unsigned int cipher)
3181{
3182 switch (cipher) {
3183 case WPA_CIPHER_CCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003184 return RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003185 case WPA_CIPHER_GCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003186 return RSN_CIPHER_SUITE_GCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003187 case WPA_CIPHER_CCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003188 return RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003189 case WPA_CIPHER_GCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003190 return RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003191 case WPA_CIPHER_TKIP:
Paul Stewart092955c2017-02-06 09:13:09 -08003192 return RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003193 case WPA_CIPHER_WEP104:
Paul Stewart092955c2017-02-06 09:13:09 -08003194 return RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003195 case WPA_CIPHER_WEP40:
Paul Stewart092955c2017-02-06 09:13:09 -08003196 return RSN_CIPHER_SUITE_WEP40;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003197 case WPA_CIPHER_GTK_NOT_USED:
Paul Stewart092955c2017-02-06 09:13:09 -08003198 return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003199 }
3200
3201 return 0;
3202}
3203
3204
3205static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[],
3206 int max_suites)
3207{
3208 int num_suites = 0;
3209
3210 if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP_256)
Paul Stewart092955c2017-02-06 09:13:09 -08003211 suites[num_suites++] = RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003212 if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP_256)
Paul Stewart092955c2017-02-06 09:13:09 -08003213 suites[num_suites++] = RSN_CIPHER_SUITE_GCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003214 if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP)
Paul Stewart092955c2017-02-06 09:13:09 -08003215 suites[num_suites++] = RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003216 if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP)
Paul Stewart092955c2017-02-06 09:13:09 -08003217 suites[num_suites++] = RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003218 if (num_suites < max_suites && ciphers & WPA_CIPHER_TKIP)
Paul Stewart092955c2017-02-06 09:13:09 -08003219 suites[num_suites++] = RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003220 if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP104)
Paul Stewart092955c2017-02-06 09:13:09 -08003221 suites[num_suites++] = RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003222 if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP40)
Paul Stewart092955c2017-02-06 09:13:09 -08003223 suites[num_suites++] = RSN_CIPHER_SUITE_WEP40;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003224
3225 return num_suites;
3226}
3227
3228
Hai Shalomfdcde762020-04-02 11:19:20 -07003229static int wpa_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
3230 int max_suites)
3231{
3232 int num_suites = 0;
3233
3234#define __AKM(a, b) \
3235 if (num_suites < max_suites && \
3236 (key_mgmt_suites & (WPA_KEY_MGMT_ ## a))) \
3237 suites[num_suites++] = (RSN_AUTH_KEY_MGMT_ ## b)
3238 __AKM(IEEE8021X, UNSPEC_802_1X);
3239 __AKM(PSK, PSK_OVER_802_1X);
3240 __AKM(FT_IEEE8021X, FT_802_1X);
3241 __AKM(FT_PSK, FT_PSK);
3242 __AKM(IEEE8021X_SHA256, 802_1X_SHA256);
3243 __AKM(PSK_SHA256, PSK_SHA256);
3244 __AKM(SAE, SAE);
Sunil Ravi89eba102022-09-13 21:04:37 -07003245 __AKM(SAE_EXT_KEY, SAE_EXT_KEY);
Hai Shalomfdcde762020-04-02 11:19:20 -07003246 __AKM(FT_SAE, FT_SAE);
Sunil Ravi89eba102022-09-13 21:04:37 -07003247 __AKM(FT_SAE_EXT_KEY, FT_SAE_EXT_KEY);
Hai Shalomfdcde762020-04-02 11:19:20 -07003248 __AKM(CCKM, CCKM);
3249 __AKM(OSEN, OSEN);
3250 __AKM(IEEE8021X_SUITE_B, 802_1X_SUITE_B);
3251 __AKM(IEEE8021X_SUITE_B_192, 802_1X_SUITE_B_192);
3252 __AKM(FILS_SHA256, FILS_SHA256);
3253 __AKM(FILS_SHA384, FILS_SHA384);
3254 __AKM(FT_FILS_SHA256, FT_FILS_SHA256);
3255 __AKM(FT_FILS_SHA384, FT_FILS_SHA384);
3256 __AKM(OWE, OWE);
3257 __AKM(DPP, DPP);
3258 __AKM(FT_IEEE8021X_SHA384, FT_802_1X_SHA384);
3259#undef __AKM
3260
3261 return num_suites;
3262}
3263
Andy Kuoaba17c12022-04-14 16:05:31 +08003264#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Hai Shalomc1a21442022-02-04 13:43:00 -08003265static int wpa_driver_do_broadcom_acs(struct wpa_driver_nl80211_data *drv,
3266 struct drv_acs_params *params)
Ajay Davanagerib921bb82020-09-16 12:49:08 +05303267{
Ajay Davanagerib921bb82020-09-16 12:49:08 +05303268 struct nl_msg *msg;
3269 struct nlattr *data;
Hai Shalomc1a21442022-02-04 13:43:00 -08003270 int freq_list_len;
3271 int ret = -1;
Ajay Davanagerib921bb82020-09-16 12:49:08 +05303272
Hai Shalomc1a21442022-02-04 13:43:00 -08003273 freq_list_len = int_array_len(params->freq_list);
3274 wpa_printf(MSG_DEBUG, "%s: freq_list_len=%d",
3275 __func__, freq_list_len);
3276
3277 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
3278 if (!msg ||
3279 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
3280 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
3281 BRCM_VENDOR_SCMD_ACS) ||
3282 !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
3283 nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HW_MODE, params->hw_mode) ||
3284 nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT_ENABLED,
3285 params->ht_enabled) ||
3286 nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED,
3287 params->ht40_enabled) ||
3288 nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED,
3289 params->vht_enabled) ||
3290 nla_put_u16(msg, BRCM_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width) ||
3291 (freq_list_len > 0 &&
3292 nla_put(msg, BRCM_VENDOR_ATTR_ACS_FREQ_LIST,
3293 sizeof(int) * freq_list_len, params->freq_list)))
3294 goto fail;
3295 nla_nest_end(msg, data);
3296
3297 wpa_printf(MSG_DEBUG,
3298 "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d",
3299 params->hw_mode, params->ht_enabled, params->ht40_enabled,
3300 params->vht_enabled, params->ch_width);
3301
3302 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
3303 if (ret) {
3304 wpa_printf(MSG_ERROR,
3305 "nl80211: BRCM Failed to invoke driver ACS function: %s",
3306 strerror(errno));
3307 }
3308
3309 msg = NULL;
3310fail:
3311 nlmsg_free(msg);
Ajay Davanagerib921bb82020-09-16 12:49:08 +05303312 return ret;
3313}
Andy Kuoaba17c12022-04-14 16:05:31 +08003314#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
Hai Shalomfdcde762020-04-02 11:19:20 -07003315
Vinayak Yadawad14709082022-03-17 14:25:11 +05303316#ifdef CONFIG_DRIVER_NL80211_BRCM
3317static int wpa_cross_akm_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
3318 int max_suites)
3319{
3320 int num_suites = 0;
3321
3322#define __AKM_TO_SUITES_ARRAY(a, b) \
3323 if (num_suites < max_suites && \
3324 (key_mgmt_suites & (WPA_KEY_MGMT_ ## a))) \
3325 suites[num_suites++] = (RSN_AUTH_KEY_MGMT_ ## b)
3326 __AKM_TO_SUITES_ARRAY(PSK, PSK_OVER_802_1X);
3327 __AKM_TO_SUITES_ARRAY(SAE, SAE);
3328#undef __AKM_TO_SUITES_ARRAY
3329
3330 return num_suites;
3331}
3332#endif /* CONFIG_DRIVER_NL80211_BRCM */
3333
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003334#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003335static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
3336 const u8 *key, size_t key_len)
3337{
3338 struct nl_msg *msg;
3339 int ret;
3340
3341 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
3342 return 0;
3343
3344 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
3345 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
3346 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
3347 QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY) ||
3348 nla_put(msg, NL80211_ATTR_VENDOR_DATA, key_len, key)) {
3349 nl80211_nlmsg_clear(msg);
3350 nlmsg_free(msg);
3351 return -1;
3352 }
Hai Shalom60840252021-02-19 19:02:11 -08003353 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003354 if (ret) {
3355 wpa_printf(MSG_DEBUG,
3356 "nl80211: Key management set key failed: ret=%d (%s)",
3357 ret, strerror(-ret));
3358 }
3359
3360 return ret;
3361}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003362#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003363
3364
Andy Kuoaba17c12022-04-14 16:05:31 +08003365#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Mir Ali677e7482020-11-12 19:49:02 +05303366static int key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
3367 const u8 *key, size_t key_len)
3368{
3369 struct nl_msg *msg;
3370 int ret;
3371 struct nlattr *params;
3372
3373 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
3374 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
3375 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
Hai Shalomc1a21442022-02-04 13:43:00 -08003376 BRCM_VENDOR_SCMD_SET_PMK) ||
Mir Ali677e7482020-11-12 19:49:02 +05303377 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
3378 nla_put(msg, BRCM_ATTR_DRIVER_KEY_PMK, key_len, key)) {
3379 nl80211_nlmsg_clear(msg);
3380 nlmsg_free(msg);
3381 return -ENOBUFS;
3382 }
3383 nla_nest_end(msg, params);
3384
3385 ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
3386 if (ret) {
3387 wpa_printf(MSG_DEBUG, "nl80211: Key mgmt set key failed: ret=%d (%s)",
3388 ret, strerror(-ret));
3389 }
3390
3391 return ret;
3392}
Andy Kuoaba17c12022-04-14 16:05:31 +08003393#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
3394
Mir Ali677e7482020-11-12 19:49:02 +05303395
Roshan Pius3a1667e2018-07-03 15:17:14 -07003396static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
3397 const u8 *key, size_t key_len,
3398 const u8 *addr)
3399{
3400 struct nl_msg *msg = NULL;
3401 int ret;
3402
3403 /*
3404 * If the authenticator address is not set, assume it is
3405 * the current BSSID.
3406 */
3407 if (!addr && drv->associated)
3408 addr = drv->bssid;
3409 else if (!addr)
3410 return -1;
3411
3412 wpa_printf(MSG_DEBUG, "nl80211: Set PMK to the driver for " MACSTR,
3413 MAC2STR(addr));
3414 wpa_hexdump_key(MSG_DEBUG, "nl80211: PMK", key, key_len);
3415 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_PMK);
3416 if (!msg ||
3417 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
3418 nla_put(msg, NL80211_ATTR_PMK, key_len, key)) {
3419 nl80211_nlmsg_clear(msg);
3420 nlmsg_free(msg);
3421 return -ENOBUFS;
3422 }
3423
Hai Shalom60840252021-02-19 19:02:11 -08003424 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003425 if (ret) {
3426 wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)",
3427 ret, strerror(-ret));
3428 }
3429
3430 return ret;
3431}
3432
3433
Hai Shalomfdcde762020-04-02 11:19:20 -07003434static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
3435 struct wpa_driver_set_key_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003436{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003437 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003438 int ifindex;
Hai Shalomc3565922019-10-28 11:58:20 -07003439 struct nl_msg *msg;
3440 struct nl_msg *key_msg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003441 int ret;
Hai Shalomfdcde762020-04-02 11:19:20 -07003442 int skip_set_key = 1;
3443 const char *ifname = params->ifname;
3444 enum wpa_alg alg = params->alg;
3445 const u8 *addr = params->addr;
3446 int key_idx = params->key_idx;
3447 int set_tx = params->set_tx;
3448 const u8 *seq = params->seq;
3449 size_t seq_len = params->seq_len;
3450 const u8 *key = params->key;
3451 size_t key_len = params->key_len;
3452 int vlan_id = params->vlan_id;
3453 enum key_flag key_flag = params->key_flag;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003454
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003455 /* Ignore for P2P Device */
3456 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
3457 return 0;
3458
3459 ifindex = if_nametoindex(ifname);
3460 wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
Hai Shalomfdcde762020-04-02 11:19:20 -07003461 "set_tx=%d seq_len=%lu key_len=%lu key_flag=0x%x",
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003462 __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
Hai Shalomfdcde762020-04-02 11:19:20 -07003463 (unsigned long) seq_len, (unsigned long) key_len, key_flag);
3464
3465 if (check_key_flag(key_flag)) {
3466 wpa_printf(MSG_DEBUG, "%s: invalid key_flag", __func__);
3467 return -EINVAL;
Dmitry Shmidtd5c075b2013-08-05 14:36:10 -07003468 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003469
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003470#ifdef CONFIG_DRIVER_NL80211_QCA
Hai Shalomfdcde762020-04-02 11:19:20 -07003471 if ((key_flag & KEY_FLAG_PMK) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003472 (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
3473 wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
3474 __func__);
3475 ret = issue_key_mgmt_set_key(drv, key, key_len);
3476 return ret;
3477 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003478#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003479
Hai Shalomfdcde762020-04-02 11:19:20 -07003480 if (key_flag & KEY_FLAG_PMK) {
3481 if (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)
3482 return nl80211_set_pmk(drv, key, key_len, addr);
Andy Kuoaba17c12022-04-14 16:05:31 +08003483#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Mir Ali677e7482020-11-12 19:49:02 +05303484 if (drv->vendor_set_pmk) {
Jay Patel731adae2021-02-17 14:55:58 -08003485 wpa_printf(MSG_INFO, "nl80211: key_mgmt_set_key with key_len %lu", (unsigned long) key_len);
Mir Ali677e7482020-11-12 19:49:02 +05303486 return key_mgmt_set_key(drv, key, key_len);
3487 }
Andy Kuoaba17c12022-04-14 16:05:31 +08003488#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
3489
Hai Shalomfdcde762020-04-02 11:19:20 -07003490 /* The driver does not have any offload mechanism for PMK, so
3491 * there is no need to configure this key. */
3492 return 0;
3493 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003494
Hai Shalomfdcde762020-04-02 11:19:20 -07003495 ret = -ENOBUFS;
Hai Shalomc3565922019-10-28 11:58:20 -07003496 key_msg = nlmsg_alloc();
3497 if (!key_msg)
Hai Shalomfdcde762020-04-02 11:19:20 -07003498 return ret;
Hai Shalomc3565922019-10-28 11:58:20 -07003499
Hai Shalomfdcde762020-04-02 11:19:20 -07003500 if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3501 KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
3502 wpa_printf(MSG_DEBUG,
3503 "nl80211: SET_KEY (pairwise RX/TX modify)");
3504 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
3505 if (!msg)
3506 goto fail2;
3507 } else if (alg == WPA_ALG_NONE && (key_flag & KEY_FLAG_RX_TX)) {
3508 wpa_printf(MSG_DEBUG, "%s: invalid key_flag to delete key",
3509 __func__);
3510 ret = -EINVAL;
3511 goto fail2;
3512 } else if (alg == WPA_ALG_NONE) {
3513 wpa_printf(MSG_DEBUG, "nl80211: DEL_KEY");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003514 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
3515 if (!msg)
Hai Shalomc3565922019-10-28 11:58:20 -07003516 goto fail2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003517 } else {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003518 u32 suite;
3519
3520 suite = wpa_alg_to_cipher_suite(alg, key_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07003521 if (!suite) {
3522 ret = -EINVAL;
Hai Shalomc3565922019-10-28 11:58:20 -07003523 goto fail2;
Hai Shalomfdcde762020-04-02 11:19:20 -07003524 }
3525 wpa_printf(MSG_DEBUG, "nl80211: NEW_KEY");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003526 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
Hai Shalomc3565922019-10-28 11:58:20 -07003527 if (!msg)
3528 goto fail2;
3529 if (nla_put(key_msg, NL80211_KEY_DATA, key_len, key) ||
3530 nla_put_u32(key_msg, NL80211_KEY_CIPHER, suite))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003531 goto fail;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003532 wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003533
Hai Shalomfdcde762020-04-02 11:19:20 -07003534 if (seq && seq_len) {
3535 if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq))
3536 goto fail;
3537 wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ",
3538 seq, seq_len);
3539 }
Dmitry Shmidt98660862014-03-11 17:26:21 -07003540 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003541
3542 if (addr && !is_broadcast_ether_addr(addr)) {
3543 wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003544 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
3545 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003546
Hai Shalomfdcde762020-04-02 11:19:20 -07003547 if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3548 KEY_FLAG_PAIRWISE_RX ||
3549 (key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3550 KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
3551 if (nla_put_u8(key_msg, NL80211_KEY_MODE,
3552 key_flag == KEY_FLAG_PAIRWISE_RX ?
3553 NL80211_KEY_NO_TX : NL80211_KEY_SET_TX))
3554 goto fail;
3555 } else if ((key_flag & KEY_FLAG_GROUP_MASK) ==
3556 KEY_FLAG_GROUP_RX) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003557 wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
Hai Shalomc3565922019-10-28 11:58:20 -07003558 if (nla_put_u32(key_msg, NL80211_KEY_TYPE,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003559 NL80211_KEYTYPE_GROUP))
3560 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003561 } else if (!(key_flag & KEY_FLAG_PAIRWISE)) {
3562 wpa_printf(MSG_DEBUG,
3563 " key_flag missing PAIRWISE when setting a pairwise key");
3564 ret = -EINVAL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003565 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003566 } else if (alg == WPA_ALG_WEP &&
3567 (key_flag & KEY_FLAG_RX_TX) == KEY_FLAG_RX_TX) {
3568 wpa_printf(MSG_DEBUG, " unicast WEP key");
3569 skip_set_key = 0;
3570 } else {
3571 wpa_printf(MSG_DEBUG, " pairwise key");
3572 }
3573 } else if ((key_flag & KEY_FLAG_PAIRWISE) ||
3574 !(key_flag & KEY_FLAG_GROUP)) {
3575 wpa_printf(MSG_DEBUG,
3576 " invalid key_flag for a broadcast key");
3577 ret = -EINVAL;
3578 goto fail;
3579 } else {
3580 wpa_printf(MSG_DEBUG, " broadcast key");
3581 if (key_flag & KEY_FLAG_DEFAULT)
3582 skip_set_key = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003583 }
Hai Shalomc3565922019-10-28 11:58:20 -07003584 if (nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
3585 nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003586 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003587 nl80211_nlmsg_clear(key_msg);
3588 nlmsg_free(key_msg);
3589 key_msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003590
Hai Shalomfdcde762020-04-02 11:19:20 -07003591 if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
3592 wpa_printf(MSG_DEBUG, "nl80211: VLAN ID %d", vlan_id);
3593 if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
3594 goto fail;
3595 }
3596
Hai Shalom60840252021-02-19 19:02:11 -08003597 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003598 if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
3599 ret = 0;
3600 if (ret)
Hai Shalomfdcde762020-04-02 11:19:20 -07003601 wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003602 ret, strerror(-ret));
3603
3604 /*
Hai Shalomfdcde762020-04-02 11:19:20 -07003605 * If we failed or don't need to set the key as default (below),
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003606 * we're done here.
3607 */
Hai Shalomfdcde762020-04-02 11:19:20 -07003608 if (ret || skip_set_key)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003609 return ret;
Hai Shalomfdcde762020-04-02 11:19:20 -07003610 wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_SET_KEY - default key");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003611
Hai Shalomfdcde762020-04-02 11:19:20 -07003612 ret = -ENOBUFS;
Hai Shalomc3565922019-10-28 11:58:20 -07003613 key_msg = nlmsg_alloc();
3614 if (!key_msg)
Hai Shalomfdcde762020-04-02 11:19:20 -07003615 return ret;
Hai Shalomc3565922019-10-28 11:58:20 -07003616
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003617 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
Hai Shalomc3565922019-10-28 11:58:20 -07003618 if (!msg)
3619 goto fail2;
3620 if (!key_msg ||
3621 nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003622 nla_put_flag(key_msg, wpa_alg_bip(alg) ?
Hai Shalomfdcde762020-04-02 11:19:20 -07003623 (key_idx == 6 || key_idx == 7 ?
3624 NL80211_KEY_DEFAULT_BEACON :
3625 NL80211_KEY_DEFAULT_MGMT) :
3626 NL80211_KEY_DEFAULT))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003627 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003628 if (addr && is_broadcast_ether_addr(addr)) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003629 struct nlattr *types;
3630
Hai Shalomc3565922019-10-28 11:58:20 -07003631 types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003632 if (!types ||
Hai Shalomc3565922019-10-28 11:58:20 -07003633 nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003634 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003635 nla_nest_end(key_msg, types);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003636 } else if (addr) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003637 struct nlattr *types;
3638
Hai Shalomc3565922019-10-28 11:58:20 -07003639 types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003640 if (!types ||
Hai Shalomc3565922019-10-28 11:58:20 -07003641 nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003642 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003643 nla_nest_end(key_msg, types);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003644 }
3645
Hai Shalomc3565922019-10-28 11:58:20 -07003646 if (nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
3647 goto fail;
3648 nl80211_nlmsg_clear(key_msg);
3649 nlmsg_free(key_msg);
3650 key_msg = NULL;
3651
Hai Shalomfdcde762020-04-02 11:19:20 -07003652 if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
3653 wpa_printf(MSG_DEBUG, "nl80211: set_key default - VLAN ID %d",
3654 vlan_id);
3655 if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
3656 goto fail;
3657 }
3658
Hai Shalom899fcc72020-10-19 14:38:18 -07003659 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003660 if (ret)
Hai Shalomfdcde762020-04-02 11:19:20 -07003661 wpa_printf(MSG_DEBUG,
3662 "nl80211: set_key default failed; err=%d %s",
3663 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003664 return ret;
3665
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003666fail:
3667 nl80211_nlmsg_clear(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003668 nlmsg_free(msg);
Hai Shalomc3565922019-10-28 11:58:20 -07003669fail2:
3670 nl80211_nlmsg_clear(key_msg);
3671 nlmsg_free(key_msg);
Hai Shalomfdcde762020-04-02 11:19:20 -07003672 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003673}
3674
3675
3676static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
3677 int key_idx, int defkey,
3678 const u8 *seq, size_t seq_len,
3679 const u8 *key, size_t key_len)
3680{
3681 struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003682 u32 suite;
3683
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003684 if (!key_attr)
3685 return -1;
3686
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003687 suite = wpa_alg_to_cipher_suite(alg, key_len);
3688 if (!suite)
3689 return -1;
3690
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003691 if (defkey && wpa_alg_bip(alg)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003692 if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT))
3693 return -1;
3694 } else if (defkey) {
3695 if (nla_put_flag(msg, NL80211_KEY_DEFAULT))
3696 return -1;
3697 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003698
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003699 if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) ||
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003700 nla_put_u32(msg, NL80211_KEY_CIPHER, suite) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003701 (seq && seq_len &&
3702 nla_put(msg, NL80211_KEY_SEQ, seq_len, seq)) ||
3703 nla_put(msg, NL80211_KEY_DATA, key_len, key))
3704 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003705
3706 nla_nest_end(msg, key_attr);
3707
3708 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003709}
3710
3711
3712static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
3713 struct nl_msg *msg)
3714{
3715 int i, privacy = 0;
3716 struct nlattr *nl_keys, *nl_key;
3717
3718 for (i = 0; i < 4; i++) {
3719 if (!params->wep_key[i])
3720 continue;
3721 privacy = 1;
3722 break;
3723 }
3724 if (params->wps == WPS_MODE_PRIVACY)
3725 privacy = 1;
3726 if (params->pairwise_suite &&
3727 params->pairwise_suite != WPA_CIPHER_NONE)
3728 privacy = 1;
3729
3730 if (!privacy)
3731 return 0;
3732
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003733 if (nla_put_flag(msg, NL80211_ATTR_PRIVACY))
3734 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003735
3736 nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
3737 if (!nl_keys)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003738 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003739
3740 for (i = 0; i < 4; i++) {
3741 if (!params->wep_key[i])
3742 continue;
3743
3744 nl_key = nla_nest_start(msg, i);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003745 if (!nl_key ||
3746 nla_put(msg, NL80211_KEY_DATA, params->wep_key_len[i],
3747 params->wep_key[i]) ||
3748 nla_put_u32(msg, NL80211_KEY_CIPHER,
3749 params->wep_key_len[i] == 5 ?
Paul Stewart092955c2017-02-06 09:13:09 -08003750 RSN_CIPHER_SUITE_WEP40 :
3751 RSN_CIPHER_SUITE_WEP104) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003752 nla_put_u8(msg, NL80211_KEY_IDX, i) ||
3753 (i == params->wep_tx_keyidx &&
3754 nla_put_flag(msg, NL80211_KEY_DEFAULT)))
3755 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003756
3757 nla_nest_end(msg, nl_key);
3758 }
3759 nla_nest_end(msg, nl_keys);
3760
3761 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003762}
3763
3764
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003765int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
3766 const u8 *addr, int cmd, u16 reason_code,
Hai Shalom74f70d42019-02-11 14:42:39 -08003767 int local_state_change,
Hai Shalomc1a21442022-02-04 13:43:00 -08003768 struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003769{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003770 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003771 struct nl_msg *msg;
Hai Shalomc1a21442022-02-04 13:43:00 -08003772 struct nl_sock *nl_connect = get_connect_handle(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003773
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003774 if (!(msg = nl80211_drv_msg(drv, 0, cmd)) ||
3775 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code) ||
3776 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
3777 (local_state_change &&
3778 nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))) {
3779 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003780 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003781 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003782
Hai Shalom74f70d42019-02-11 14:42:39 -08003783 if (nl_connect)
Hai Shalomc1a21442022-02-04 13:43:00 -08003784 ret = send_and_recv(drv->global, nl_connect, msg,
3785 process_bss_event, bss, NULL, NULL);
Hai Shalom74f70d42019-02-11 14:42:39 -08003786 else
Hai Shalom899fcc72020-10-19 14:38:18 -07003787 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003788 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003789 wpa_dbg(drv->ctx, MSG_DEBUG,
3790 "nl80211: MLME command failed: reason=%u ret=%d (%s)",
3791 reason_code, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003792 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003793 return ret;
3794}
3795
3796
3797static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
Hai Shalom81f62d82019-07-22 12:10:00 -07003798 u16 reason_code,
Hai Shalomc1a21442022-02-04 13:43:00 -08003799 struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003800{
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003801 int ret;
Hai Shalomce48b4a2018-09-05 11:41:35 -07003802 int drv_associated = drv->associated;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003803
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003804 wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003805 nl80211_mark_disconnected(drv);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003806 /* Disconnect command doesn't need BSSID - it uses cached value */
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003807 ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
Hai Shalomc1a21442022-02-04 13:43:00 -08003808 reason_code, 0, bss);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003809 /*
3810 * For locally generated disconnect, supplicant already generates a
3811 * DEAUTH event, so ignore the event from NL80211.
3812 */
Hai Shalomce48b4a2018-09-05 11:41:35 -07003813 drv->ignore_next_local_disconnect = drv_associated && (ret == 0);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003814
3815 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003816}
3817
3818
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003819static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
Hai Shalom81f62d82019-07-22 12:10:00 -07003820 const u8 *addr, u16 reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003821{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003822 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003823 int ret;
Hai Shalomce48b4a2018-09-05 11:41:35 -07003824 int drv_associated = drv->associated;
Dmitry Shmidt413dde72014-04-11 10:23:22 -07003825
3826 if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
3827 nl80211_mark_disconnected(drv);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003828 return nl80211_leave_ibss(drv, 1);
Dmitry Shmidt413dde72014-04-11 10:23:22 -07003829 }
Hai Shalom74f70d42019-02-11 14:42:39 -08003830 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
Hai Shalomc1a21442022-02-04 13:43:00 -08003831 return wpa_driver_nl80211_disconnect(drv, reason_code, bss);
Hai Shalom74f70d42019-02-11 14:42:39 -08003832 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003833 wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
3834 __func__, MAC2STR(addr), reason_code);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003835 nl80211_mark_disconnected(drv);
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003836 ret = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
Hai Shalomc1a21442022-02-04 13:43:00 -08003837 reason_code, 0, bss);
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003838 /*
3839 * For locally generated deauthenticate, supplicant already generates a
3840 * DEAUTH event, so ignore the event from NL80211.
3841 */
Hai Shalomce48b4a2018-09-05 11:41:35 -07003842 drv->ignore_next_local_deauth = drv_associated && (ret == 0);
3843
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003844 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003845}
3846
3847
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003848static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
3849 struct wpa_driver_auth_params *params)
3850{
3851 int i;
3852
3853 drv->auth_freq = params->freq;
3854 drv->auth_alg = params->auth_alg;
3855 drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
3856 drv->auth_local_state_change = params->local_state_change;
3857 drv->auth_p2p = params->p2p;
3858
3859 if (params->bssid)
3860 os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
3861 else
3862 os_memset(drv->auth_bssid_, 0, ETH_ALEN);
3863
3864 if (params->ssid) {
3865 os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
3866 drv->auth_ssid_len = params->ssid_len;
3867 } else
3868 drv->auth_ssid_len = 0;
3869
3870
3871 os_free(drv->auth_ie);
3872 drv->auth_ie = NULL;
3873 drv->auth_ie_len = 0;
3874 if (params->ie) {
3875 drv->auth_ie = os_malloc(params->ie_len);
3876 if (drv->auth_ie) {
3877 os_memcpy(drv->auth_ie, params->ie, params->ie_len);
3878 drv->auth_ie_len = params->ie_len;
3879 }
3880 }
3881
Hai Shalom60840252021-02-19 19:02:11 -08003882 os_free(drv->auth_data);
3883 drv->auth_data = NULL;
3884 drv->auth_data_len = 0;
3885 if (params->auth_data) {
3886 drv->auth_data = os_memdup(params->auth_data,
3887 params->auth_data_len);
3888 if (drv->auth_data)
3889 drv->auth_data_len = params->auth_data_len;
3890 }
3891
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003892 for (i = 0; i < 4; i++) {
3893 if (params->wep_key[i] && params->wep_key_len[i] &&
3894 params->wep_key_len[i] <= 16) {
3895 os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
3896 params->wep_key_len[i]);
3897 drv->auth_wep_key_len[i] = params->wep_key_len[i];
3898 } else
3899 drv->auth_wep_key_len[i] = 0;
3900 }
3901}
3902
3903
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003904static void nl80211_unmask_11b_rates(struct i802_bss *bss)
3905{
3906 struct wpa_driver_nl80211_data *drv = bss->drv;
3907
3908 if (is_p2p_net_interface(drv->nlmode) || !drv->disabled_11b_rates)
3909 return;
3910
3911 /*
3912 * Looks like we failed to unmask 11b rates previously. This could
3913 * happen, e.g., if the interface was down at the point in time when a
3914 * P2P group was terminated.
3915 */
3916 wpa_printf(MSG_DEBUG,
3917 "nl80211: Interface %s mode is for non-P2P, but 11b rates were disabled - re-enable them",
3918 bss->ifname);
3919 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
3920}
3921
3922
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003923static enum nl80211_auth_type get_nl_auth_type(int wpa_auth_alg)
3924{
3925 if (wpa_auth_alg & WPA_AUTH_ALG_OPEN)
3926 return NL80211_AUTHTYPE_OPEN_SYSTEM;
3927 if (wpa_auth_alg & WPA_AUTH_ALG_SHARED)
3928 return NL80211_AUTHTYPE_SHARED_KEY;
3929 if (wpa_auth_alg & WPA_AUTH_ALG_LEAP)
3930 return NL80211_AUTHTYPE_NETWORK_EAP;
3931 if (wpa_auth_alg & WPA_AUTH_ALG_FT)
3932 return NL80211_AUTHTYPE_FT;
3933 if (wpa_auth_alg & WPA_AUTH_ALG_SAE)
3934 return NL80211_AUTHTYPE_SAE;
3935 if (wpa_auth_alg & WPA_AUTH_ALG_FILS)
3936 return NL80211_AUTHTYPE_FILS_SK;
3937 if (wpa_auth_alg & WPA_AUTH_ALG_FILS_SK_PFS)
3938 return NL80211_AUTHTYPE_FILS_SK_PFS;
3939
3940 return NL80211_AUTHTYPE_MAX;
3941}
3942
3943
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003944static int wpa_driver_nl80211_authenticate(
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003945 struct i802_bss *bss, struct wpa_driver_auth_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003946{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003947 struct wpa_driver_nl80211_data *drv = bss->drv;
3948 int ret = -1, i;
3949 struct nl_msg *msg;
3950 enum nl80211_auth_type type;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003951 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003952 int count = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003953 int is_retry;
Hai Shalomfdcde762020-04-02 11:19:20 -07003954 struct wpa_driver_set_key_params p;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003955
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003956 nl80211_unmask_11b_rates(bss);
3957
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003958 is_retry = drv->retry_auth;
3959 drv->retry_auth = 0;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003960 drv->ignore_deauth_event = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003961
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003962 nl80211_mark_disconnected(drv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003963 os_memset(drv->auth_bssid, 0, ETH_ALEN);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003964 if (params->bssid)
3965 os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
3966 else
3967 os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003968 /* FIX: IBSS mode */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003969 nlmode = params->p2p ?
3970 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
3971 if (drv->nlmode != nlmode &&
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003972 wpa_driver_nl80211_set_mode(bss, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003973 return -1;
3974
3975retry:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003976 wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
3977 drv->ifindex);
3978
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003979 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_AUTHENTICATE);
3980 if (!msg)
3981 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003982
Hai Shalomfdcde762020-04-02 11:19:20 -07003983 os_memset(&p, 0, sizeof(p));
3984 p.ifname = bss->ifname;
3985 p.alg = WPA_ALG_WEP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003986 for (i = 0; i < 4; i++) {
3987 if (!params->wep_key[i])
3988 continue;
Hai Shalomfdcde762020-04-02 11:19:20 -07003989 p.key_idx = i;
3990 p.set_tx = i == params->wep_tx_keyidx;
3991 p.key = params->wep_key[i];
3992 p.key_len = params->wep_key_len[i];
3993 p.key_flag = i == params->wep_tx_keyidx ?
3994 KEY_FLAG_GROUP_RX_TX_DEFAULT :
3995 KEY_FLAG_GROUP_RX_TX;
3996 wpa_driver_nl80211_set_key(bss, &p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003997 if (params->wep_tx_keyidx != i)
3998 continue;
3999 if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004000 params->wep_key[i], params->wep_key_len[i]))
4001 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004002 }
4003
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004004 if (params->bssid) {
4005 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
4006 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004007 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
4008 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004009 }
4010 if (params->freq) {
4011 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004012 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
4013 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004014 }
4015 if (params->ssid) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004016 wpa_printf(MSG_DEBUG, " * SSID=%s",
4017 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004018 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
4019 params->ssid))
4020 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004021 }
4022 wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004023 if (params->ie &&
4024 nla_put(msg, NL80211_ATTR_IE, params->ie_len, params->ie))
4025 goto fail;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004026 if (params->auth_data) {
4027 wpa_hexdump(MSG_DEBUG, " * auth_data", params->auth_data,
4028 params->auth_data_len);
4029 if (nla_put(msg, NL80211_ATTR_SAE_DATA, params->auth_data_len,
4030 params->auth_data))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004031 goto fail;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004032 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004033 type = get_nl_auth_type(params->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004034 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004035 if (type == NL80211_AUTHTYPE_MAX ||
4036 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004037 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004038 if (params->local_state_change) {
4039 wpa_printf(MSG_DEBUG, " * Local state change only");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004040 if (nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))
4041 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004042 }
4043
Hai Shalom899fcc72020-10-19 14:38:18 -07004044 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004045 msg = NULL;
4046 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004047 wpa_dbg(drv->ctx, MSG_DEBUG,
Roshan Pius3a1667e2018-07-03 15:17:14 -07004048 "nl80211: MLME command failed (auth): count=%d ret=%d (%s)",
4049 count, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004050 count++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004051 if ((ret == -EALREADY || ret == -EEXIST) && count == 1 &&
4052 params->bssid && !params->local_state_change) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004053 /*
4054 * mac80211 does not currently accept new
4055 * authentication if we are already authenticated. As a
4056 * workaround, force deauthentication and try again.
4057 */
4058 wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
4059 "after forced deauthentication");
Dmitry Shmidt98660862014-03-11 17:26:21 -07004060 drv->ignore_deauth_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004061 wpa_driver_nl80211_deauthenticate(
4062 bss, params->bssid,
4063 WLAN_REASON_PREV_AUTH_NOT_VALID);
4064 nlmsg_free(msg);
4065 goto retry;
4066 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004067
4068 if (ret == -ENOENT && params->freq && !is_retry) {
4069 /*
4070 * cfg80211 has likely expired the BSS entry even
4071 * though it was previously available in our internal
4072 * BSS table. To recover quickly, start a single
4073 * channel scan on the specified channel.
4074 */
4075 struct wpa_driver_scan_params scan;
4076 int freqs[2];
4077
4078 os_memset(&scan, 0, sizeof(scan));
4079 scan.num_ssids = 1;
4080 if (params->ssid) {
4081 scan.ssids[0].ssid = params->ssid;
4082 scan.ssids[0].ssid_len = params->ssid_len;
4083 }
4084 freqs[0] = params->freq;
4085 freqs[1] = 0;
4086 scan.freqs = freqs;
4087 wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
4088 "channel scan to refresh cfg80211 BSS "
4089 "entry");
4090 ret = wpa_driver_nl80211_scan(bss, &scan);
4091 if (ret == 0) {
4092 nl80211_copy_auth_params(drv, params);
4093 drv->scan_for_auth = 1;
4094 }
4095 } else if (is_retry) {
4096 /*
4097 * Need to indicate this with an event since the return
4098 * value from the retry is not delivered to core code.
4099 */
4100 union wpa_event_data event;
4101 wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
4102 "failed");
4103 os_memset(&event, 0, sizeof(event));
4104 os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
4105 ETH_ALEN);
4106 wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
4107 &event);
4108 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004109 } else {
4110 wpa_printf(MSG_DEBUG,
4111 "nl80211: Authentication request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004112 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004113
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004114fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004115 nlmsg_free(msg);
4116 return ret;
4117}
4118
4119
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004120int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004121{
4122 struct wpa_driver_auth_params params;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08004123 struct i802_bss *bss = drv->first_bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004124 int i;
4125
4126 wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
4127
4128 os_memset(&params, 0, sizeof(params));
4129 params.freq = drv->auth_freq;
4130 params.auth_alg = drv->auth_alg;
4131 params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
4132 params.local_state_change = drv->auth_local_state_change;
4133 params.p2p = drv->auth_p2p;
4134
4135 if (!is_zero_ether_addr(drv->auth_bssid_))
4136 params.bssid = drv->auth_bssid_;
4137
4138 if (drv->auth_ssid_len) {
4139 params.ssid = drv->auth_ssid;
4140 params.ssid_len = drv->auth_ssid_len;
4141 }
4142
4143 params.ie = drv->auth_ie;
4144 params.ie_len = drv->auth_ie_len;
Hai Shalom60840252021-02-19 19:02:11 -08004145 params.auth_data = drv->auth_data;
4146 params.auth_data_len = drv->auth_data_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004147
4148 for (i = 0; i < 4; i++) {
4149 if (drv->auth_wep_key_len[i]) {
4150 params.wep_key[i] = drv->auth_wep_key[i];
4151 params.wep_key_len[i] = drv->auth_wep_key_len[i];
4152 }
4153 }
4154
4155 drv->retry_auth = 1;
4156 return wpa_driver_nl80211_authenticate(bss, &params);
4157}
4158
4159
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004160static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
4161 size_t data_len, int noack,
4162 unsigned int freq, int no_cck,
4163 int offchanok,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004164 unsigned int wait_time,
4165 const u16 *csa_offs,
Hai Shalomfdcde762020-04-02 11:19:20 -07004166 size_t csa_offs_len, int no_encrypt)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004167{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004168 struct wpa_driver_nl80211_data *drv = bss->drv;
4169 struct ieee80211_mgmt *mgmt;
Hai Shalomfdcde762020-04-02 11:19:20 -07004170 int encrypt = !no_encrypt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004171 u16 fc;
Hai Shalomfdcde762020-04-02 11:19:20 -07004172 int use_cookie = 1;
4173 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004174
4175 mgmt = (struct ieee80211_mgmt *) data;
4176 fc = le_to_host16(mgmt->frame_control);
Hai Shalomfdcde762020-04-02 11:19:20 -07004177 wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR
4178 " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u no_encrypt=%d fc=0x%x (%s) nlmode=%d",
Dmitry Shmidt2271d3f2014-06-23 12:16:31 -07004179 MAC2STR(mgmt->da), noack, freq, no_cck, offchanok, wait_time,
Hai Shalomfdcde762020-04-02 11:19:20 -07004180 no_encrypt, fc, fc2str(fc), drv->nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004181
Dmitry Shmidt34af3062013-07-11 10:46:32 -07004182 if ((is_sta_interface(drv->nlmode) ||
4183 drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004184 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4185 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
4186 /*
4187 * The use of last_mgmt_freq is a bit of a hack,
4188 * but it works due to the single-threaded nature
4189 * of wpa_supplicant.
4190 */
Dmitry Shmidt56052862013-10-04 10:23:25 -07004191 if (freq == 0) {
4192 wpa_printf(MSG_DEBUG, "nl80211: Use last_mgmt_freq=%d",
4193 drv->last_mgmt_freq);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004194 freq = drv->last_mgmt_freq;
Dmitry Shmidt56052862013-10-04 10:23:25 -07004195 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004196 wait_time = 0;
4197 use_cookie = 0;
4198 no_cck = 1;
4199 offchanok = 1;
4200 goto send_frame_cmd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004201 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004202
4203 if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
Dmitry Shmidt56052862013-10-04 10:23:25 -07004204 if (freq == 0) {
4205 wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d",
4206 bss->freq);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004207 freq = bss->freq;
Dmitry Shmidt56052862013-10-04 10:23:25 -07004208 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004209 if ((int) freq == bss->freq)
4210 wait_time = 0;
4211 goto send_frame_cmd;
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07004212 }
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07004213
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004214 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4215 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
4216 /*
4217 * Only one of the authentication frame types is encrypted.
4218 * In order for static WEP encryption to work properly (i.e.,
4219 * to not encrypt the frame), we need to tell mac80211 about
4220 * the frames that must not be encrypted.
4221 */
4222 u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
4223 u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
4224 if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
4225 encrypt = 0;
4226 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004227
Hai Shalom60840252021-02-19 19:02:11 -08004228 if (is_sta_interface(drv->nlmode) &&
Hai Shalomfdcde762020-04-02 11:19:20 -07004229 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4230 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
Hai Shalom60840252021-02-19 19:02:11 -08004231 if (freq == 0 &&
4232 (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
4233 !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
4234 freq = nl80211_get_assoc_freq(drv);
4235 wpa_printf(MSG_DEBUG,
4236 "nl80211: send_mlme - Use assoc_freq=%u for external auth",
4237 freq);
4238 }
4239
4240 /* Allow off channel for PASN authentication */
4241 if (data_len >= IEEE80211_HDRLEN + 2 &&
4242 WPA_GET_LE16(data + IEEE80211_HDRLEN) == WLAN_AUTH_PASN &&
4243 !offchanok) {
4244 wpa_printf(MSG_DEBUG,
4245 "nl80211: send_mlme: allow off channel for PASN");
4246 offchanok = 1;
4247 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004248 }
4249
Hai Shalomc1a21442022-02-04 13:43:00 -08004250#ifdef CONFIG_PASN
4251 if (is_sta_interface(drv->nlmode) &&
4252 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4253 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_DEAUTH) {
4254 wpa_printf(MSG_DEBUG,
4255 "nl80211: send_mlme: allow Deauthentication frame for PASN");
4256
4257 use_cookie = 0;
4258 offchanok = 1;
4259 goto send_frame_cmd;
4260 }
4261#endif /* CONFIG_PASN */
4262
Hai Shalomfdcde762020-04-02 11:19:20 -07004263 if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
4264 freq = nl80211_get_assoc_freq(drv);
4265 wpa_printf(MSG_DEBUG,
4266 "nl80211: send_mlme - Use assoc_freq=%u for IBSS",
4267 freq);
4268 }
4269 if (freq == 0) {
4270 wpa_printf(MSG_DEBUG, "nl80211: send_mlme - Use bss->freq=%u",
4271 bss->freq);
4272 freq = bss->freq;
4273 }
4274
Hai Shalomc1a21442022-02-04 13:43:00 -08004275 if (drv->use_monitor && is_ap_interface(drv->nlmode)) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004276 wpa_printf(MSG_DEBUG,
4277 "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
4278 freq, bss->freq);
4279 return nl80211_send_monitor(drv, data, data_len, encrypt,
4280 noack);
4281 }
4282
4283 if (noack || WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
4284 WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
4285 use_cookie = 0;
4286send_frame_cmd:
4287#ifdef CONFIG_TESTING_OPTIONS
4288 if (no_encrypt && !encrypt && !drv->use_monitor) {
4289 wpa_printf(MSG_DEBUG,
4290 "nl80211: Request to send an unencrypted frame - use a monitor interface for this");
4291 if (nl80211_create_monitor_interface(drv) < 0)
4292 return -1;
4293 res = nl80211_send_monitor(drv, data, data_len, encrypt,
4294 noack);
4295 nl80211_remove_monitor_interface(drv);
4296 return res;
4297 }
4298#endif /* CONFIG_TESTING_OPTIONS */
4299
4300 wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame_cmd");
4301 res = nl80211_send_frame_cmd(bss, freq, wait_time, data, data_len,
4302 use_cookie, no_cck, noack, offchanok,
4303 csa_offs, csa_offs_len);
4304
4305 return res;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004306}
4307
4308
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004309static int nl80211_put_basic_rates(struct nl_msg *msg, const int *basic_rates)
4310{
4311 u8 rates[NL80211_MAX_SUPP_RATES];
4312 u8 rates_len = 0;
4313 int i;
4314
4315 if (!basic_rates)
4316 return 0;
4317
4318 for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
4319 rates[rates_len++] = basic_rates[i] / 5;
4320
4321 return nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
4322}
4323
4324
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004325static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
4326 int slot, int ht_opmode, int ap_isolate,
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004327 const int *basic_rates)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004328{
4329 struct wpa_driver_nl80211_data *drv = bss->drv;
4330 struct nl_msg *msg;
4331
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004332 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_BSS)) ||
4333 (cts >= 0 &&
4334 nla_put_u8(msg, NL80211_ATTR_BSS_CTS_PROT, cts)) ||
4335 (preamble >= 0 &&
4336 nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble)) ||
4337 (slot >= 0 &&
4338 nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot)) ||
4339 (ht_opmode >= 0 &&
4340 nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) ||
4341 (ap_isolate >= 0 &&
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004342 nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)) ||
4343 nl80211_put_basic_rates(msg, basic_rates)) {
4344 nlmsg_free(msg);
4345 return -ENOBUFS;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004346 }
4347
Hai Shalom899fcc72020-10-19 14:38:18 -07004348 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004349}
4350
4351
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004352static int wpa_driver_nl80211_set_acl(void *priv,
4353 struct hostapd_acl_params *params)
4354{
4355 struct i802_bss *bss = priv;
4356 struct wpa_driver_nl80211_data *drv = bss->drv;
4357 struct nl_msg *msg;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004358 struct nl_msg *acl;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004359 unsigned int i;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004360 int ret;
Hai Shalomc1a21442022-02-04 13:43:00 -08004361 size_t acl_nla_sz, acl_nlmsg_sz, nla_sz, nlmsg_sz;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004362
4363 if (!(drv->capa.max_acl_mac_addrs))
4364 return -ENOTSUP;
4365
4366 if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
4367 return -ENOTSUP;
4368
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004369 wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
4370 params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
4371
Hai Shalomc1a21442022-02-04 13:43:00 -08004372 acl_nla_sz = nla_total_size(ETH_ALEN) * params->num_mac_acl;
4373 acl_nlmsg_sz = nlmsg_total_size(acl_nla_sz);
4374 acl = nlmsg_alloc_size(acl_nlmsg_sz);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004375 if (!acl)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004376 return -ENOMEM;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004377 for (i = 0; i < params->num_mac_acl; i++) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004378 if (nla_put(acl, i + 1, ETH_ALEN, params->mac_acl[i].addr)) {
4379 nlmsg_free(acl);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004380 return -ENOMEM;
4381 }
4382 }
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004383
Hai Shalomc1a21442022-02-04 13:43:00 -08004384 /*
4385 * genetlink message header (Length of user header is 0) +
4386 * u32 attr: NL80211_ATTR_IFINDEX +
4387 * u32 attr: NL80211_ATTR_ACL_POLICY +
4388 * nested acl attr
4389 */
4390 nla_sz = GENL_HDRLEN +
4391 nla_total_size(4) * 2 +
4392 nla_total_size(acl_nla_sz);
4393 nlmsg_sz = nlmsg_total_size(nla_sz);
4394 if (!(msg = nl80211_ifindex_msg_build(drv, nlmsg_alloc_size(nlmsg_sz),
4395 drv->ifindex, 0,
4396 NL80211_CMD_SET_MAC_ACL)) ||
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004397 nla_put_u32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
4398 NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
4399 NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED) ||
4400 nla_put_nested(msg, NL80211_ATTR_MAC_ADDRS, acl)) {
4401 nlmsg_free(msg);
4402 nlmsg_free(acl);
4403 return -ENOMEM;
4404 }
4405 nlmsg_free(acl);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004406
Hai Shalom899fcc72020-10-19 14:38:18 -07004407 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004408 if (ret) {
4409 wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
4410 ret, strerror(-ret));
4411 }
4412
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004413 return ret;
4414}
4415
4416
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004417static int nl80211_put_beacon_int(struct nl_msg *msg, int beacon_int)
4418{
4419 if (beacon_int > 0) {
4420 wpa_printf(MSG_DEBUG, " * beacon_int=%d", beacon_int);
4421 return nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
4422 beacon_int);
4423 }
4424
4425 return 0;
4426}
4427
4428
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004429static int nl80211_put_dtim_period(struct nl_msg *msg, int dtim_period)
4430{
4431 if (dtim_period > 0) {
4432 wpa_printf(MSG_DEBUG, " * dtim_period=%d", dtim_period);
4433 return nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
4434 }
4435
4436 return 0;
4437}
4438
4439
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004440#ifdef CONFIG_MESH
4441static int nl80211_set_mesh_config(void *priv,
4442 struct wpa_driver_mesh_bss_params *params)
4443{
4444 struct i802_bss *bss = priv;
4445 struct wpa_driver_nl80211_data *drv = bss->drv;
4446 struct nl_msg *msg;
4447 int ret;
4448
4449 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MESH_CONFIG);
4450 if (!msg)
4451 return -1;
4452
4453 ret = nl80211_put_mesh_config(msg, params);
4454 if (ret < 0) {
4455 nlmsg_free(msg);
4456 return ret;
4457 }
4458
Hai Shalom899fcc72020-10-19 14:38:18 -07004459 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004460 if (ret) {
4461 wpa_printf(MSG_ERROR,
4462 "nl80211: Mesh config set failed: %d (%s)",
4463 ret, strerror(-ret));
4464 return ret;
4465 }
4466 return 0;
4467}
4468#endif /* CONFIG_MESH */
4469
4470
Hai Shalom60840252021-02-19 19:02:11 -08004471static int nl80211_put_beacon_rate(struct nl_msg *msg, u64 flags, u64 flags2,
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004472 struct wpa_driver_ap_params *params)
4473{
4474 struct nlattr *bands, *band;
4475 struct nl80211_txrate_vht vht_rate;
Hai Shalom60840252021-02-19 19:02:11 -08004476 struct nl80211_txrate_he he_rate;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004477
4478 if (!params->freq ||
4479 (params->beacon_rate == 0 &&
4480 params->rate_type == BEACON_RATE_LEGACY))
4481 return 0;
4482
4483 bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
4484 if (!bands)
4485 return -1;
4486
4487 switch (params->freq->mode) {
4488 case HOSTAPD_MODE_IEEE80211B:
4489 case HOSTAPD_MODE_IEEE80211G:
4490 band = nla_nest_start(msg, NL80211_BAND_2GHZ);
4491 break;
4492 case HOSTAPD_MODE_IEEE80211A:
Hai Shalom60840252021-02-19 19:02:11 -08004493 if (is_6ghz_freq(params->freq->freq))
4494 band = nla_nest_start(msg, NL80211_BAND_6GHZ);
4495 else
4496 band = nla_nest_start(msg, NL80211_BAND_5GHZ);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004497 break;
4498 case HOSTAPD_MODE_IEEE80211AD:
4499 band = nla_nest_start(msg, NL80211_BAND_60GHZ);
4500 break;
4501 default:
4502 return 0;
4503 }
4504
4505 if (!band)
4506 return -1;
4507
4508 os_memset(&vht_rate, 0, sizeof(vht_rate));
Hai Shalom60840252021-02-19 19:02:11 -08004509 os_memset(&he_rate, 0, sizeof(he_rate));
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004510
4511 switch (params->rate_type) {
4512 case BEACON_RATE_LEGACY:
4513 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY)) {
4514 wpa_printf(MSG_INFO,
4515 "nl80211: Driver does not support setting Beacon frame rate (legacy)");
4516 return -1;
4517 }
4518
4519 if (nla_put_u8(msg, NL80211_TXRATE_LEGACY,
4520 (u8) params->beacon_rate / 5) ||
4521 nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
4522 (params->freq->vht_enabled &&
4523 nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4524 &vht_rate)))
4525 return -1;
4526
4527 wpa_printf(MSG_DEBUG, " * beacon_rate = legacy:%u (* 100 kbps)",
4528 params->beacon_rate);
4529 break;
4530 case BEACON_RATE_HT:
4531 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_HT)) {
4532 wpa_printf(MSG_INFO,
4533 "nl80211: Driver does not support setting Beacon frame rate (HT)");
4534 return -1;
4535 }
4536 if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
4537 nla_put_u8(msg, NL80211_TXRATE_HT, params->beacon_rate) ||
4538 (params->freq->vht_enabled &&
4539 nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4540 &vht_rate)))
4541 return -1;
4542 wpa_printf(MSG_DEBUG, " * beacon_rate = HT-MCS %u",
4543 params->beacon_rate);
4544 break;
4545 case BEACON_RATE_VHT:
4546 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_VHT)) {
4547 wpa_printf(MSG_INFO,
4548 "nl80211: Driver does not support setting Beacon frame rate (VHT)");
4549 return -1;
4550 }
4551 vht_rate.mcs[0] = BIT(params->beacon_rate);
4552 if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL))
4553 return -1;
4554 if (nla_put(msg, NL80211_TXRATE_HT, 0, NULL))
4555 return -1;
4556 if (nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4557 &vht_rate))
4558 return -1;
4559 wpa_printf(MSG_DEBUG, " * beacon_rate = VHT-MCS %u",
4560 params->beacon_rate);
4561 break;
Hai Shalom60840252021-02-19 19:02:11 -08004562 case BEACON_RATE_HE:
4563 if (!(flags2 & WPA_DRIVER_FLAGS2_BEACON_RATE_HE)) {
4564 wpa_printf(MSG_INFO,
4565 "nl80211: Driver does not support setting Beacon frame rate (HE)");
4566 return -1;
4567 }
4568 he_rate.mcs[0] = BIT(params->beacon_rate);
4569 if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
4570 nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
4571 nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4572 &vht_rate) ||
4573 nla_put(msg, NL80211_TXRATE_HE, sizeof(he_rate), &he_rate))
4574 return -1;
4575 wpa_printf(MSG_DEBUG, " * beacon_rate = HE-MCS %u",
4576 params->beacon_rate);
4577 break;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004578 }
4579
4580 nla_nest_end(msg, band);
4581 nla_nest_end(msg, bands);
4582
4583 return 0;
4584}
4585
4586
4587static int nl80211_set_multicast_to_unicast(struct i802_bss *bss,
4588 int multicast_to_unicast)
4589{
4590 struct wpa_driver_nl80211_data *drv = bss->drv;
4591 struct nl_msg *msg;
4592 int ret;
4593
4594 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_MULTICAST_TO_UNICAST);
4595 if (!msg ||
4596 (multicast_to_unicast &&
4597 nla_put_flag(msg, NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED))) {
4598 wpa_printf(MSG_ERROR,
4599 "nl80211: Failed to build NL80211_CMD_SET_MULTICAST_TO_UNICAST msg for %s",
4600 bss->ifname);
4601 nlmsg_free(msg);
4602 return -ENOBUFS;
4603 }
4604
Hai Shalom899fcc72020-10-19 14:38:18 -07004605 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004606
4607 switch (ret) {
4608 case 0:
4609 wpa_printf(MSG_DEBUG,
4610 "nl80211: multicast to unicast %s on interface %s",
4611 multicast_to_unicast ? "enabled" : "disabled",
4612 bss->ifname);
4613 break;
4614 case -EOPNOTSUPP:
4615 if (!multicast_to_unicast)
4616 break;
4617 wpa_printf(MSG_INFO,
4618 "nl80211: multicast to unicast not supported on interface %s",
4619 bss->ifname);
4620 break;
4621 default:
4622 wpa_printf(MSG_ERROR,
4623 "nl80211: %s multicast to unicast failed with %d (%s) on interface %s",
4624 multicast_to_unicast ? "enabling" : "disabling",
4625 ret, strerror(-ret), bss->ifname);
4626 break;
4627 }
4628
4629 return ret;
4630}
4631
4632
Hai Shalom60840252021-02-19 19:02:11 -08004633#ifdef CONFIG_SAE
4634static int nl80211_put_sae_pwe(struct nl_msg *msg, int pwe)
4635{
4636 u8 sae_pwe;
4637
4638 wpa_printf(MSG_DEBUG, "nl802111: sae_pwe=%d", pwe);
4639 if (pwe == 0)
4640 sae_pwe = NL80211_SAE_PWE_HUNT_AND_PECK;
4641 else if (pwe == 1)
4642 sae_pwe = NL80211_SAE_PWE_HASH_TO_ELEMENT;
4643 else if (pwe == 2)
4644 sae_pwe = NL80211_SAE_PWE_BOTH;
4645 else if (pwe == 3)
4646 return 0; /* special test mode */
4647 else
4648 return -1;
4649 if (nla_put_u8(msg, NL80211_ATTR_SAE_PWE, sae_pwe))
4650 return -1;
4651
4652 return 0;
4653}
4654#endif /* CONFIG_SAE */
4655
4656
4657#ifdef CONFIG_FILS
4658static int nl80211_fils_discovery(struct i802_bss *bss, struct nl_msg *msg,
4659 struct wpa_driver_ap_params *params)
4660{
4661 struct nlattr *attr;
4662
4663 if (!bss->drv->fils_discovery) {
4664 wpa_printf(MSG_ERROR,
4665 "nl80211: Driver does not support FILS Discovery frame transmission for %s",
4666 bss->ifname);
4667 return -1;
4668 }
4669
4670 attr = nla_nest_start(msg, NL80211_ATTR_FILS_DISCOVERY);
4671 if (!attr ||
4672 nla_put_u32(msg, NL80211_FILS_DISCOVERY_ATTR_INT_MIN,
4673 params->fd_min_int) ||
4674 nla_put_u32(msg, NL80211_FILS_DISCOVERY_ATTR_INT_MAX,
4675 params->fd_max_int) ||
4676 (params->fd_frame_tmpl &&
4677 nla_put(msg, NL80211_FILS_DISCOVERY_ATTR_TMPL,
4678 params->fd_frame_tmpl_len, params->fd_frame_tmpl)))
4679 return -1;
4680
4681 nla_nest_end(msg, attr);
4682 return 0;
4683}
4684#endif /* CONFIG_FILS */
4685
4686
4687#ifdef CONFIG_IEEE80211AX
4688static int nl80211_unsol_bcast_probe_resp(struct i802_bss *bss,
4689 struct nl_msg *msg,
4690 struct wpa_driver_ap_params *params)
4691{
4692 struct nlattr *attr;
4693
4694 if (!bss->drv->unsol_bcast_probe_resp) {
4695 wpa_printf(MSG_ERROR,
4696 "nl80211: Driver does not support unsolicited broadcast Probe Response frame transmission for %s",
4697 bss->ifname);
4698 return -1;
4699 }
4700
4701 wpa_printf(MSG_DEBUG,
4702 "nl80211: Unsolicited broadcast Probe Response frame interval: %u",
4703 params->unsol_bcast_probe_resp_interval);
4704 attr = nla_nest_start(msg, NL80211_ATTR_UNSOL_BCAST_PROBE_RESP);
4705 if (!attr ||
4706 nla_put_u32(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT,
4707 params->unsol_bcast_probe_resp_interval) ||
4708 (params->unsol_bcast_probe_resp_tmpl &&
4709 nla_put(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL,
4710 params->unsol_bcast_probe_resp_tmpl_len,
4711 params->unsol_bcast_probe_resp_tmpl)))
4712 return -1;
4713
4714 nla_nest_end(msg, attr);
4715 return 0;
4716}
4717#endif /* CONFIG_IEEE80211AX */
4718
4719
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004720static int wpa_driver_nl80211_set_ap(void *priv,
4721 struct wpa_driver_ap_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004722{
4723 struct i802_bss *bss = priv;
4724 struct wpa_driver_nl80211_data *drv = bss->drv;
4725 struct nl_msg *msg;
4726 u8 cmd = NL80211_CMD_NEW_BEACON;
Hai Shalom74f70d42019-02-11 14:42:39 -08004727 int ret = -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004728 int beacon_set;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004729 int num_suites;
Hai Shalomfdcde762020-04-02 11:19:20 -07004730 u32 suites[20], suite;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004731 u32 ver;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004732#ifdef CONFIG_MESH
4733 struct wpa_driver_mesh_bss_params mesh_params;
4734#endif /* CONFIG_MESH */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004735
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004736 beacon_set = params->reenable ? 0 : bss->beacon_set;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004737
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004738 wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
4739 beacon_set);
4740 if (beacon_set)
4741 cmd = NL80211_CMD_SET_BEACON;
Paul Stewart092955c2017-02-06 09:13:09 -08004742 else if (!drv->device_ap_sme && !drv->use_monitor &&
4743 !nl80211_get_wiphy_data_ap(bss))
4744 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004745
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004746 wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
4747 params->head, params->head_len);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004748 wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
4749 params->tail, params->tail_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004750 wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004751 wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004752 wpa_printf(MSG_DEBUG, "nl80211: beacon_rate=%u", params->beacon_rate);
4753 wpa_printf(MSG_DEBUG, "nl80211: rate_type=%d", params->rate_type);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004754 wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
Hai Shalom74f70d42019-02-11 14:42:39 -08004755 wpa_printf(MSG_DEBUG, "nl80211: ssid=%s",
4756 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004757 if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
4758 nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
4759 params->head) ||
4760 nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
4761 params->tail) ||
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004762 nl80211_put_beacon_int(msg, params->beacon_int) ||
Hai Shalom60840252021-02-19 19:02:11 -08004763 nl80211_put_beacon_rate(msg, drv->capa.flags, drv->capa.flags2,
4764 params) ||
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004765 nl80211_put_dtim_period(msg, params->dtim_period) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004766 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
4767 goto fail;
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004768 if (params->proberesp && params->proberesp_len) {
4769 wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
4770 params->proberesp, params->proberesp_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004771 if (nla_put(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
4772 params->proberesp))
4773 goto fail;
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004774 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004775 switch (params->hide_ssid) {
4776 case NO_SSID_HIDING:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004777 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004778 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
4779 NL80211_HIDDEN_SSID_NOT_IN_USE))
4780 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004781 break;
4782 case HIDDEN_SSID_ZERO_LEN:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004783 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004784 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
4785 NL80211_HIDDEN_SSID_ZERO_LEN))
4786 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004787 break;
4788 case HIDDEN_SSID_ZERO_CONTENTS:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004789 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004790 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
4791 NL80211_HIDDEN_SSID_ZERO_CONTENTS))
4792 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004793 break;
4794 }
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004795 wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004796 if (params->privacy &&
4797 nla_put_flag(msg, NL80211_ATTR_PRIVACY))
4798 goto fail;
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004799 wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004800 if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
4801 (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
4802 /* Leave out the attribute */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004803 } else if (params->auth_algs & WPA_AUTH_ALG_SHARED) {
4804 if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
4805 NL80211_AUTHTYPE_SHARED_KEY))
4806 goto fail;
4807 } else {
4808 if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
4809 NL80211_AUTHTYPE_OPEN_SYSTEM))
4810 goto fail;
4811 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004812
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004813 wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004814 ver = 0;
4815 if (params->wpa_version & WPA_PROTO_WPA)
4816 ver |= NL80211_WPA_VERSION_1;
4817 if (params->wpa_version & WPA_PROTO_RSN)
4818 ver |= NL80211_WPA_VERSION_2;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004819 if (ver &&
4820 nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
4821 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004822
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004823 wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
4824 params->key_mgmt_suites);
Hai Shalomfdcde762020-04-02 11:19:20 -07004825 num_suites = wpa_key_mgmt_to_suites(params->key_mgmt_suites,
4826 suites, ARRAY_SIZE(suites));
4827 if (num_suites > NL80211_MAX_NR_AKM_SUITES)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004828 wpa_printf(MSG_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07004829 "nl80211: Not enough room for all AKM suites (num_suites=%d > NL80211_MAX_NR_AKM_SUITES)",
4830 num_suites);
4831 else if (num_suites &&
4832 nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
4833 suites))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004834 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004835
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004836 if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004837 (!params->pairwise_ciphers ||
4838 params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
4839 (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
4840 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004841 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004842
Sunil Ravia04bd252022-05-02 22:54:18 -07004843 if (drv->device_ap_sme) {
4844 u32 flags = 0;
4845
Sunil Ravi89eba102022-09-13 21:04:37 -07004846 if (params->key_mgmt_suites & (WPA_KEY_MGMT_SAE |
4847 WPA_KEY_MGMT_SAE_EXT_KEY)) {
Sunil Ravia04bd252022-05-02 22:54:18 -07004848 /* Add the previously used flag attribute to support
4849 * older kernel versions and the newer flag bit for
4850 * newer kernels. */
4851 if (nla_put_flag(msg,
4852 NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
4853 goto fail;
4854 flags |= NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;
4855 }
4856
4857 flags |= NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT;
4858
4859 if (nla_put_u32(msg, NL80211_ATTR_AP_SETTINGS_FLAGS, flags))
4860 goto fail;
4861 }
Hai Shalom5f92bc92019-04-18 11:54:11 -07004862
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004863 wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
4864 params->pairwise_ciphers);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004865 num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers,
4866 suites, ARRAY_SIZE(suites));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004867 if (num_suites &&
4868 nla_put(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
4869 num_suites * sizeof(u32), suites))
4870 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004871
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004872 wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
4873 params->group_cipher);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004874 suite = wpa_cipher_to_cipher_suite(params->group_cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004875 if (suite &&
4876 nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
4877 goto fail;
4878
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004879 if (params->beacon_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004880 wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
4881 params->beacon_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004882 if (nla_put(msg, NL80211_ATTR_IE,
4883 wpabuf_len(params->beacon_ies),
4884 wpabuf_head(params->beacon_ies)))
4885 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004886 }
4887 if (params->proberesp_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004888 wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
4889 params->proberesp_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004890 if (nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
4891 wpabuf_len(params->proberesp_ies),
4892 wpabuf_head(params->proberesp_ies)))
4893 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004894 }
4895 if (params->assocresp_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004896 wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
4897 params->assocresp_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004898 if (nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
4899 wpabuf_len(params->assocresp_ies),
4900 wpabuf_head(params->assocresp_ies)))
4901 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004902 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004903
Dmitry Shmidt04949592012-07-19 12:16:46 -07004904 if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004905 wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
4906 params->ap_max_inactivity);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004907 if (nla_put_u16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
4908 params->ap_max_inactivity))
4909 goto fail;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004910 }
4911
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004912#ifdef CONFIG_P2P
4913 if (params->p2p_go_ctwindow > 0) {
4914 if (drv->p2p_go_ctwindow_supported) {
4915 wpa_printf(MSG_DEBUG, "nl80211: P2P GO ctwindow=%d",
4916 params->p2p_go_ctwindow);
4917 if (nla_put_u8(msg, NL80211_ATTR_P2P_CTWINDOW,
4918 params->p2p_go_ctwindow))
4919 goto fail;
4920 } else {
4921 wpa_printf(MSG_INFO,
4922 "nl80211: Driver does not support CTWindow configuration - ignore this parameter");
4923 }
4924 }
4925#endif /* CONFIG_P2P */
4926
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004927 if (params->pbss) {
4928 wpa_printf(MSG_DEBUG, "nl80211: PBSS");
4929 if (nla_put_flag(msg, NL80211_ATTR_PBSS))
4930 goto fail;
4931 }
4932
Hai Shalom74f70d42019-02-11 14:42:39 -08004933 if (params->ftm_responder) {
4934 struct nlattr *ftm;
4935
4936 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_FTM_RESPONDER)) {
4937 ret = -ENOTSUP;
4938 goto fail;
4939 }
4940
4941 ftm = nla_nest_start(msg, NL80211_ATTR_FTM_RESPONDER);
4942 if (!ftm ||
4943 nla_put_flag(msg, NL80211_FTM_RESP_ATTR_ENABLED) ||
4944 (params->lci &&
4945 nla_put(msg, NL80211_FTM_RESP_ATTR_LCI,
4946 wpabuf_len(params->lci),
4947 wpabuf_head(params->lci))) ||
4948 (params->civic &&
4949 nla_put(msg, NL80211_FTM_RESP_ATTR_CIVICLOC,
4950 wpabuf_len(params->civic),
4951 wpabuf_head(params->civic))))
4952 goto fail;
4953 nla_nest_end(msg, ftm);
4954 }
4955
Hai Shalomc3565922019-10-28 11:58:20 -07004956#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08004957 if (params->he_spr_ctrl) {
Hai Shalomc3565922019-10-28 11:58:20 -07004958 struct nlattr *spr;
4959
4960 spr = nla_nest_start(msg, NL80211_ATTR_HE_OBSS_PD);
Hai Shalom60840252021-02-19 19:02:11 -08004961 wpa_printf(MSG_DEBUG, "nl80211: he_spr_ctrl=0x%x",
4962 params->he_spr_ctrl);
Hai Shalomc3565922019-10-28 11:58:20 -07004963
Hai Shalomfdcde762020-04-02 11:19:20 -07004964 if (!spr ||
Hai Shalom60840252021-02-19 19:02:11 -08004965 nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_SR_CTRL,
4966 params->he_spr_ctrl) ||
4967 ((params->he_spr_ctrl &
4968 SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) &&
4969 nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET,
4970 params->he_spr_non_srg_obss_pd_max_offset)))
4971 goto fail;
4972
4973 if ((params->he_spr_ctrl &
4974 SPATIAL_REUSE_SRG_INFORMATION_PRESENT) &&
4975 (nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
4976 params->he_spr_srg_obss_pd_min_offset) ||
4977 nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
4978 params->he_spr_srg_obss_pd_max_offset) ||
4979 nla_put(msg, NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP,
4980 sizeof(params->he_spr_bss_color_bitmap),
4981 params->he_spr_bss_color_bitmap) ||
4982 nla_put(msg, NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP,
4983 sizeof(params->he_spr_partial_bssid_bitmap),
4984 params->he_spr_partial_bssid_bitmap)))
Hai Shalomc3565922019-10-28 11:58:20 -07004985 goto fail;
4986
4987 nla_nest_end(msg, spr);
4988 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004989
4990 if (params->freq && params->freq->he_enabled) {
4991 struct nlattr *bss_color;
4992
4993 bss_color = nla_nest_start(msg, NL80211_ATTR_HE_BSS_COLOR);
4994 if (!bss_color ||
4995 (params->he_bss_color_disabled &&
4996 nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_DISABLED)) ||
4997 (params->he_bss_color_partial &&
4998 nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_PARTIAL)) ||
4999 nla_put_u8(msg, NL80211_HE_BSS_COLOR_ATTR_COLOR,
5000 params->he_bss_color))
5001 goto fail;
5002 nla_nest_end(msg, bss_color);
5003 }
5004
5005 if (params->twt_responder) {
5006 wpa_printf(MSG_DEBUG, "nl80211: twt_responder=%d",
5007 params->twt_responder);
5008 if (nla_put_flag(msg, NL80211_ATTR_TWT_RESPONDER))
5009 goto fail;
5010 }
Hai Shalom60840252021-02-19 19:02:11 -08005011
5012 if (params->unsol_bcast_probe_resp_interval &&
5013 nl80211_unsol_bcast_probe_resp(bss, msg, params) < 0)
5014 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07005015#endif /* CONFIG_IEEE80211AX */
5016
Hai Shalom60840252021-02-19 19:02:11 -08005017#ifdef CONFIG_SAE
Sunil Ravi89eba102022-09-13 21:04:37 -07005018 if (wpa_key_mgmt_sae(params->key_mgmt_suites) &&
Hai Shalom60840252021-02-19 19:02:11 -08005019 nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
5020 goto fail;
5021#endif /* CONFIG_SAE */
5022
5023#ifdef CONFIG_FILS
5024 if (params->fd_max_int && nl80211_fils_discovery(bss, msg, params) < 0)
5025 goto fail;
5026#endif /* CONFIG_FILS */
5027
Hai Shalomc1a21442022-02-04 13:43:00 -08005028 ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005029 if (ret) {
5030 wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
5031 ret, strerror(-ret));
5032 } else {
5033 bss->beacon_set = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005034 nl80211_set_bss(bss, params->cts_protect, params->preamble,
5035 params->short_slot_time, params->ht_opmode,
5036 params->isolate, params->basic_rates);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08005037 nl80211_set_multicast_to_unicast(bss,
5038 params->multicast_to_unicast);
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005039 if (beacon_set && params->freq &&
5040 params->freq->bandwidth != bss->bandwidth) {
5041 wpa_printf(MSG_DEBUG,
5042 "nl80211: Update BSS %s bandwidth: %d -> %d",
5043 bss->ifname, bss->bandwidth,
5044 params->freq->bandwidth);
5045 ret = nl80211_set_channel(bss, params->freq, 1);
5046 if (ret) {
5047 wpa_printf(MSG_DEBUG,
5048 "nl80211: Frequency set failed: %d (%s)",
5049 ret, strerror(-ret));
5050 } else {
5051 wpa_printf(MSG_DEBUG,
5052 "nl80211: Frequency set succeeded for ht2040 coex");
5053 bss->bandwidth = params->freq->bandwidth;
5054 }
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005055 } else if (!beacon_set && params->freq) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005056 /*
5057 * cfg80211 updates the driver on frequence change in AP
5058 * mode only at the point when beaconing is started, so
5059 * set the initial value here.
5060 */
5061 bss->bandwidth = params->freq->bandwidth;
5062 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005063 }
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07005064
5065#ifdef CONFIG_MESH
5066 if (is_mesh_interface(drv->nlmode) && params->ht_opmode != -1) {
5067 os_memset(&mesh_params, 0, sizeof(mesh_params));
5068 mesh_params.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
5069 mesh_params.ht_opmode = params->ht_opmode;
5070 ret = nl80211_set_mesh_config(priv, &mesh_params);
5071 if (ret < 0)
5072 return ret;
5073 }
5074#endif /* CONFIG_MESH */
5075
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005076 return ret;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005077fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005078 nlmsg_free(msg);
Hai Shalom74f70d42019-02-11 14:42:39 -08005079 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005080}
5081
5082
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005083static int nl80211_put_freq_params(struct nl_msg *msg,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005084 const struct hostapd_freq_params *freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005085{
Hai Shalomc3565922019-10-28 11:58:20 -07005086 enum hostapd_hw_mode hw_mode;
5087 int is_24ghz;
5088 u8 channel;
5089
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005090 wpa_printf(MSG_DEBUG, " * freq=%d", freq->freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005091 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
5092 return -ENOBUFS;
5093
Sunil Ravia04bd252022-05-02 22:54:18 -07005094 wpa_printf(MSG_DEBUG, " * eht_enabled=%d", freq->eht_enabled);
Hai Shalom81f62d82019-07-22 12:10:00 -07005095 wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005096 wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
5097 wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
Sunil Ravia04bd252022-05-02 22:54:18 -07005098 wpa_printf(MSG_DEBUG, " * radar_background=%d",
5099 freq->radar_background);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005100
Hai Shalomc3565922019-10-28 11:58:20 -07005101 hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
5102 is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
5103 hw_mode == HOSTAPD_MODE_IEEE80211B;
5104
Sunil Ravia04bd252022-05-02 22:54:18 -07005105 if (freq->vht_enabled ||
5106 ((freq->he_enabled || freq->eht_enabled) && !is_24ghz)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005107 enum nl80211_chan_width cw;
5108
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005109 wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005110 switch (freq->bandwidth) {
5111 case 20:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005112 cw = NL80211_CHAN_WIDTH_20;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005113 break;
5114 case 40:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005115 cw = NL80211_CHAN_WIDTH_40;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005116 break;
5117 case 80:
5118 if (freq->center_freq2)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005119 cw = NL80211_CHAN_WIDTH_80P80;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005120 else
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005121 cw = NL80211_CHAN_WIDTH_80;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005122 break;
5123 case 160:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005124 cw = NL80211_CHAN_WIDTH_160;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005125 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00005126 case 320:
5127 cw = NL80211_CHAN_WIDTH_320;
5128 break;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005129 default:
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005130 return -EINVAL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005131 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005132
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005133 wpa_printf(MSG_DEBUG, " * channel_width=%d", cw);
5134 wpa_printf(MSG_DEBUG, " * center_freq1=%d",
5135 freq->center_freq1);
5136 wpa_printf(MSG_DEBUG, " * center_freq2=%d",
5137 freq->center_freq2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005138 if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) ||
5139 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1,
5140 freq->center_freq1) ||
5141 (freq->center_freq2 &&
5142 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2,
5143 freq->center_freq2)))
5144 return -ENOBUFS;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005145 } else if (freq->ht_enabled) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005146 enum nl80211_channel_type ct;
5147
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005148 wpa_printf(MSG_DEBUG, " * sec_channel_offset=%d",
5149 freq->sec_channel_offset);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005150 switch (freq->sec_channel_offset) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005151 case -1:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005152 ct = NL80211_CHAN_HT40MINUS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005153 break;
5154 case 1:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005155 ct = NL80211_CHAN_HT40PLUS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005156 break;
5157 default:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005158 ct = NL80211_CHAN_HT20;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005159 break;
5160 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005161
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005162 wpa_printf(MSG_DEBUG, " * channel_type=%d", ct);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005163 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
5164 return -ENOBUFS;
Hai Shalomc3565922019-10-28 11:58:20 -07005165 } else if (freq->edmg.channels && freq->edmg.bw_config) {
5166 wpa_printf(MSG_DEBUG,
5167 " * EDMG configuration: channels=0x%x bw_config=%d",
5168 freq->edmg.channels, freq->edmg.bw_config);
5169 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
5170 freq->edmg.channels) ||
5171 nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
5172 freq->edmg.bw_config))
5173 return -1;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005174 } else {
5175 wpa_printf(MSG_DEBUG, " * channel_type=%d",
5176 NL80211_CHAN_NO_HT);
5177 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
5178 NL80211_CHAN_NO_HT))
5179 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005180 }
Sunil8cd6f4d2022-06-28 18:40:46 +00005181 if (freq->radar_background &&
5182 nla_put_flag(msg, NL80211_ATTR_RADAR_BACKGROUND))
5183 return -ENOBUFS;
Sunil Ravia04bd252022-05-02 22:54:18 -07005184
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005185 return 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005186}
5187
5188
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005189static int nl80211_set_channel(struct i802_bss *bss,
5190 struct hostapd_freq_params *freq, int set_chan)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005191{
5192 struct wpa_driver_nl80211_data *drv = bss->drv;
5193 struct nl_msg *msg;
5194 int ret;
5195
5196 wpa_printf(MSG_DEBUG,
Sunil Ravia04bd252022-05-02 22:54:18 -07005197 "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, eht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
5198 freq->freq, freq->ht_enabled, freq->vht_enabled,
5199 freq->he_enabled, freq->eht_enabled, freq->bandwidth,
5200 freq->center_freq1, freq->center_freq2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005201
5202 msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
5203 NL80211_CMD_SET_WIPHY);
5204 if (!msg || nl80211_put_freq_params(msg, freq) < 0) {
5205 nlmsg_free(msg);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005206 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005207 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005208
Hai Shalom899fcc72020-10-19 14:38:18 -07005209 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005210 if (ret == 0) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005211 bss->freq = freq->freq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005212 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005213 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005214 wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005215 "%d (%s)", freq->freq, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005216 return -1;
5217}
5218
5219
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005220static u32 sta_flags_nl80211(int flags)
5221{
5222 u32 f = 0;
5223
5224 if (flags & WPA_STA_AUTHORIZED)
5225 f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
5226 if (flags & WPA_STA_WMM)
5227 f |= BIT(NL80211_STA_FLAG_WME);
5228 if (flags & WPA_STA_SHORT_PREAMBLE)
5229 f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
5230 if (flags & WPA_STA_MFP)
5231 f |= BIT(NL80211_STA_FLAG_MFP);
5232 if (flags & WPA_STA_TDLS_PEER)
5233 f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005234 if (flags & WPA_STA_AUTHENTICATED)
5235 f |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005236 if (flags & WPA_STA_ASSOCIATED)
5237 f |= BIT(NL80211_STA_FLAG_ASSOCIATED);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005238
5239 return f;
5240}
5241
5242
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005243#ifdef CONFIG_MESH
5244static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
5245{
5246 switch (state) {
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005247 case PLINK_IDLE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005248 return NL80211_PLINK_LISTEN;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005249 case PLINK_OPN_SNT:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005250 return NL80211_PLINK_OPN_SNT;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005251 case PLINK_OPN_RCVD:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005252 return NL80211_PLINK_OPN_RCVD;
5253 case PLINK_CNF_RCVD:
5254 return NL80211_PLINK_CNF_RCVD;
5255 case PLINK_ESTAB:
5256 return NL80211_PLINK_ESTAB;
5257 case PLINK_HOLDING:
5258 return NL80211_PLINK_HOLDING;
5259 case PLINK_BLOCKED:
5260 return NL80211_PLINK_BLOCKED;
5261 default:
5262 wpa_printf(MSG_ERROR, "nl80211: Invalid mesh plink state %d",
5263 state);
5264 }
5265 return -1;
5266}
5267#endif /* CONFIG_MESH */
5268
5269
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005270static int wpa_driver_nl80211_sta_add(void *priv,
5271 struct hostapd_sta_add_params *params)
5272{
5273 struct i802_bss *bss = priv;
5274 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005275 struct nl_msg *msg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005276 struct nl80211_sta_flag_update upd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005277 int ret = -ENOBUFS;
5278
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005279 if ((params->flags & WPA_STA_TDLS_PEER) &&
5280 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
5281 return -EOPNOTSUPP;
5282
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005283 wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
5284 params->set ? "Set" : "Add", MAC2STR(params->addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005285 msg = nl80211_bss_msg(bss, 0, params->set ? NL80211_CMD_SET_STATION :
5286 NL80211_CMD_NEW_STATION);
5287 if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
5288 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005289
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005290 /*
5291 * Set the below properties only in one of the following cases:
5292 * 1. New station is added, already associated.
5293 * 2. Set WPA_STA_TDLS_PEER station.
5294 * 3. Set an already added unassociated station, if driver supports
5295 * full AP client state. (Set these properties after station became
5296 * associated will be rejected by the driver).
5297 */
5298 if (!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
5299 (params->set && FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags) &&
5300 (params->flags & WPA_STA_ASSOCIATED))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005301 wpa_hexdump(MSG_DEBUG, " * supported rates",
5302 params->supp_rates, params->supp_rates_len);
5303 wpa_printf(MSG_DEBUG, " * capability=0x%x",
5304 params->capability);
5305 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_RATES,
5306 params->supp_rates_len, params->supp_rates) ||
5307 nla_put_u16(msg, NL80211_ATTR_STA_CAPABILITY,
5308 params->capability))
5309 goto fail;
5310
5311 if (params->ht_capabilities) {
5312 wpa_hexdump(MSG_DEBUG, " * ht_capabilities",
5313 (u8 *) params->ht_capabilities,
5314 sizeof(*params->ht_capabilities));
5315 if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY,
5316 sizeof(*params->ht_capabilities),
5317 params->ht_capabilities))
5318 goto fail;
5319 }
5320
5321 if (params->vht_capabilities) {
5322 wpa_hexdump(MSG_DEBUG, " * vht_capabilities",
5323 (u8 *) params->vht_capabilities,
5324 sizeof(*params->vht_capabilities));
5325 if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY,
5326 sizeof(*params->vht_capabilities),
5327 params->vht_capabilities))
5328 goto fail;
5329 }
5330
Hai Shalom81f62d82019-07-22 12:10:00 -07005331 if (params->he_capab) {
5332 wpa_hexdump(MSG_DEBUG, " * he_capab",
5333 params->he_capab, params->he_capab_len);
5334 if (nla_put(msg, NL80211_ATTR_HE_CAPABILITY,
5335 params->he_capab_len, params->he_capab))
5336 goto fail;
5337 }
5338
Hai Shalom60840252021-02-19 19:02:11 -08005339 if (params->he_6ghz_capab) {
5340 wpa_hexdump(MSG_DEBUG, " * he_6ghz_capab",
5341 params->he_6ghz_capab,
5342 sizeof(*params->he_6ghz_capab));
5343 if (nla_put(msg, NL80211_ATTR_HE_6GHZ_CAPABILITY,
5344 sizeof(*params->he_6ghz_capab),
5345 params->he_6ghz_capab))
5346 goto fail;
5347 }
5348
Sunil Ravia04bd252022-05-02 22:54:18 -07005349 if (params->eht_capab) {
5350 wpa_hexdump(MSG_DEBUG, " * eht_capab",
5351 params->eht_capab, params->eht_capab_len);
5352 if (nla_put(msg, NL80211_ATTR_EHT_CAPABILITY,
5353 params->eht_capab_len, params->eht_capab))
5354 goto fail;
5355 }
5356
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005357 if (params->ext_capab) {
5358 wpa_hexdump(MSG_DEBUG, " * ext_capab",
5359 params->ext_capab, params->ext_capab_len);
5360 if (nla_put(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
5361 params->ext_capab_len, params->ext_capab))
5362 goto fail;
5363 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005364
5365 if (is_ap_interface(drv->nlmode) &&
5366 nla_put_u8(msg, NL80211_ATTR_STA_SUPPORT_P2P_PS,
5367 params->support_p2p_ps ?
5368 NL80211_P2P_PS_SUPPORTED :
5369 NL80211_P2P_PS_UNSUPPORTED))
5370 goto fail;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005371 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005372 if (!params->set) {
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005373 if (params->aid) {
5374 wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005375 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid))
5376 goto fail;
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005377 } else {
5378 /*
5379 * cfg80211 validates that AID is non-zero, so we have
5380 * to make this a non-zero value for the TDLS case where
Hai Shalomc1a21442022-02-04 13:43:00 -08005381 * a stub STA entry is used for now and for a station
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005382 * that is still not associated.
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005383 */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005384 wpa_printf(MSG_DEBUG, " * aid=1 (%s workaround)",
5385 (params->flags & WPA_STA_TDLS_PEER) ?
5386 "TDLS" : "UNASSOC_STA");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005387 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, 1))
5388 goto fail;
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005389 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005390 wpa_printf(MSG_DEBUG, " * listen_interval=%u",
5391 params->listen_interval);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005392 if (nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
5393 params->listen_interval))
5394 goto fail;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07005395 } else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
5396 wpa_printf(MSG_DEBUG, " * peer_aid=%u", params->aid);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005397 if (nla_put_u16(msg, NL80211_ATTR_PEER_AID, params->aid))
5398 goto fail;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005399 } else if (FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags) &&
5400 (params->flags & WPA_STA_ASSOCIATED)) {
5401 wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
5402 wpa_printf(MSG_DEBUG, " * listen_interval=%u",
5403 params->listen_interval);
5404 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid) ||
5405 nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
5406 params->listen_interval))
5407 goto fail;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005408 }
5409
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08005410 if (params->vht_opmode_enabled) {
5411 wpa_printf(MSG_DEBUG, " * opmode=%u", params->vht_opmode);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005412 if (nla_put_u8(msg, NL80211_ATTR_OPMODE_NOTIF,
5413 params->vht_opmode))
5414 goto fail;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005415 }
5416
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005417 if (params->supp_channels) {
5418 wpa_hexdump(MSG_DEBUG, " * supported channels",
5419 params->supp_channels, params->supp_channels_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005420 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
5421 params->supp_channels_len, params->supp_channels))
5422 goto fail;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005423 }
5424
5425 if (params->supp_oper_classes) {
5426 wpa_hexdump(MSG_DEBUG, " * supported operating classes",
5427 params->supp_oper_classes,
5428 params->supp_oper_classes_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005429 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
5430 params->supp_oper_classes_len,
5431 params->supp_oper_classes))
5432 goto fail;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005433 }
5434
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005435 os_memset(&upd, 0, sizeof(upd));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005436 upd.set = sta_flags_nl80211(params->flags);
5437 upd.mask = upd.set | sta_flags_nl80211(params->flags_mask);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005438
5439 /*
5440 * If the driver doesn't support full AP client state, ignore ASSOC/AUTH
5441 * flags, as nl80211 driver moves a new station, by default, into
5442 * associated state.
5443 *
5444 * On the other hand, if the driver supports that feature and the
5445 * station is added in unauthenticated state, set the
5446 * authenticated/associated bits in the mask to prevent moving this
5447 * station to associated state before it is actually associated.
5448 *
5449 * This is irrelevant for mesh mode where the station is added to the
5450 * driver as authenticated already, and ASSOCIATED isn't part of the
5451 * nl80211 API.
5452 */
5453 if (!is_mesh_interface(drv->nlmode)) {
5454 if (!FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) {
5455 wpa_printf(MSG_DEBUG,
5456 "nl80211: Ignore ASSOC/AUTH flags since driver doesn't support full AP client state");
5457 upd.mask &= ~(BIT(NL80211_STA_FLAG_ASSOCIATED) |
5458 BIT(NL80211_STA_FLAG_AUTHENTICATED));
5459 } else if (!params->set &&
5460 !(params->flags & WPA_STA_TDLS_PEER)) {
5461 if (!(params->flags & WPA_STA_AUTHENTICATED))
5462 upd.mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
5463 if (!(params->flags & WPA_STA_ASSOCIATED))
5464 upd.mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
5465 }
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005466#ifdef CONFIG_MESH
5467 } else {
5468 if (params->plink_state == PLINK_ESTAB && params->peer_aid) {
5469 ret = nla_put_u16(msg, NL80211_ATTR_MESH_PEER_AID,
5470 params->peer_aid);
5471 if (ret)
5472 goto fail;
5473 }
5474#endif /* CONFIG_MESH */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005475 }
5476
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005477 wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x",
5478 upd.set, upd.mask);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005479 if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
5480 goto fail;
5481
5482#ifdef CONFIG_MESH
5483 if (params->plink_state &&
5484 nla_put_u8(msg, NL80211_ATTR_STA_PLINK_STATE,
5485 sta_plink_state_nl80211(params->plink_state)))
5486 goto fail;
5487#endif /* CONFIG_MESH */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005488
Hai Shalomc3565922019-10-28 11:58:20 -07005489 if ((!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
5490 FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) &&
5491 (params->flags & WPA_STA_WMM)) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005492 struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
5493
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005494 wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005495 if (!wme ||
5496 nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
5497 params->qosinfo & WMM_QOSINFO_STA_AC_MASK) ||
5498 nla_put_u8(msg, NL80211_STA_WME_MAX_SP,
5499 (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
5500 WMM_QOSINFO_STA_SP_MASK))
5501 goto fail;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005502 nla_nest_end(msg, wme);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005503 }
5504
Hai Shalom899fcc72020-10-19 14:38:18 -07005505 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005506 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005507 if (ret)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005508 wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
5509 "result: %d (%s)", params->set ? "SET" : "NEW", ret,
5510 strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005511 if (ret == -EEXIST)
5512 ret = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005513fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005514 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005515 return ret;
5516}
5517
5518
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005519static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr)
5520{
5521#ifdef CONFIG_LIBNL3_ROUTE
5522 struct wpa_driver_nl80211_data *drv = bss->drv;
5523 struct rtnl_neigh *rn;
5524 struct nl_addr *nl_addr;
5525 int err;
5526
5527 rn = rtnl_neigh_alloc();
5528 if (!rn)
5529 return;
5530
5531 rtnl_neigh_set_family(rn, AF_BRIDGE);
5532 rtnl_neigh_set_ifindex(rn, bss->ifindex);
5533 nl_addr = nl_addr_build(AF_BRIDGE, (void *) addr, ETH_ALEN);
5534 if (!nl_addr) {
5535 rtnl_neigh_put(rn);
5536 return;
5537 }
5538 rtnl_neigh_set_lladdr(rn, nl_addr);
5539
5540 err = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
5541 if (err < 0) {
5542 wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for "
5543 MACSTR " ifindex=%d failed: %s", MAC2STR(addr),
5544 bss->ifindex, nl_geterror(err));
5545 } else {
5546 wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry for "
5547 MACSTR, MAC2STR(addr));
5548 }
5549
5550 nl_addr_put(nl_addr);
5551 rtnl_neigh_put(rn);
5552#endif /* CONFIG_LIBNL3_ROUTE */
5553}
5554
5555
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005556static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
5557 int deauth, u16 reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005558{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005559 struct wpa_driver_nl80211_data *drv = bss->drv;
5560 struct nl_msg *msg;
5561 int ret;
5562
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005563 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION)) ||
5564 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
5565 (deauth == 0 &&
5566 nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
5567 WLAN_FC_STYPE_DISASSOC)) ||
5568 (deauth == 1 &&
5569 nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
5570 WLAN_FC_STYPE_DEAUTH)) ||
5571 (reason_code &&
5572 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code))) {
5573 nlmsg_free(msg);
5574 return -ENOBUFS;
5575 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005576
Hai Shalom899fcc72020-10-19 14:38:18 -07005577 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07005578 wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
5579 " --> %d (%s)",
5580 bss->ifname, MAC2STR(addr), ret, strerror(-ret));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005581
5582 if (drv->rtnl_sk)
5583 rtnl_neigh_delete_fdb_entry(bss, addr);
5584
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005585 if (ret == -ENOENT)
5586 return 0;
5587 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005588}
5589
5590
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005591void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005592{
5593 struct nl_msg *msg;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005594 struct wpa_driver_nl80211_data *drv2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005595
5596 wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
5597
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005598 /* stop listening for EAPOL on this interface */
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005599 dl_list_for_each(drv2, &drv->global->interfaces,
5600 struct wpa_driver_nl80211_data, list)
Dmitry Shmidt9c175262016-03-03 10:20:07 -08005601 {
5602 del_ifidx(drv2, ifidx, IFIDX_ANY);
5603 /* Remove all bridges learned for this iface */
5604 del_ifidx(drv2, IFIDX_ANY, ifidx);
5605 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005606
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005607 msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
Hai Shalom899fcc72020-10-19 14:38:18 -07005608 if (send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005609 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005610 wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
5611}
5612
5613
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07005614const char * nl80211_iftype_str(enum nl80211_iftype mode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005615{
5616 switch (mode) {
5617 case NL80211_IFTYPE_ADHOC:
5618 return "ADHOC";
5619 case NL80211_IFTYPE_STATION:
5620 return "STATION";
5621 case NL80211_IFTYPE_AP:
5622 return "AP";
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07005623 case NL80211_IFTYPE_AP_VLAN:
5624 return "AP_VLAN";
5625 case NL80211_IFTYPE_WDS:
5626 return "WDS";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005627 case NL80211_IFTYPE_MONITOR:
5628 return "MONITOR";
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07005629 case NL80211_IFTYPE_MESH_POINT:
5630 return "MESH_POINT";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005631 case NL80211_IFTYPE_P2P_CLIENT:
5632 return "P2P_CLIENT";
5633 case NL80211_IFTYPE_P2P_GO:
5634 return "P2P_GO";
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005635 case NL80211_IFTYPE_P2P_DEVICE:
5636 return "P2P_DEVICE";
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005637 case NL80211_IFTYPE_OCB:
5638 return "OCB";
5639 case NL80211_IFTYPE_NAN:
5640 return "NAN";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005641 default:
5642 return "unknown";
5643 }
5644}
5645
5646
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005647static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
5648 const char *ifname,
5649 enum nl80211_iftype iftype,
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005650 const u8 *addr, int wds,
5651 int (*handler)(struct nl_msg *, void *),
5652 void *arg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005653{
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005654 struct nl_msg *msg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005655 int ifidx;
5656 int ret = -ENOBUFS;
5657
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005658 wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
5659 iftype, nl80211_iftype_str(iftype));
5660
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005661 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_NEW_INTERFACE);
5662 if (!msg ||
5663 nla_put_string(msg, NL80211_ATTR_IFNAME, ifname) ||
5664 nla_put_u32(msg, NL80211_ATTR_IFTYPE, iftype))
5665 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005666
5667 if (iftype == NL80211_IFTYPE_MONITOR) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005668 struct nlattr *flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005669
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005670 flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005671 if (!flags ||
5672 nla_put_flag(msg, NL80211_MNTR_FLAG_COOK_FRAMES))
5673 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005674
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005675 nla_nest_end(msg, flags);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005676 } else if (wds) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005677 if (nla_put_u8(msg, NL80211_ATTR_4ADDR, wds))
5678 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005679 }
5680
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07005681 /*
5682 * Tell cfg80211 that the interface belongs to the socket that created
5683 * it, and the interface should be deleted when the socket is closed.
5684 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005685 if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
5686 goto fail;
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07005687
Hai Shalom60840252021-02-19 19:02:11 -08005688 if ((addr && iftype == NL80211_IFTYPE_P2P_DEVICE) &&
5689 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
5690 goto fail;
5691
Hai Shalom899fcc72020-10-19 14:38:18 -07005692 ret = send_and_recv_msgs(drv, msg, handler, arg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005693 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005694 if (ret) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005695 fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005696 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005697 wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
5698 ifname, ret, strerror(-ret));
5699 return ret;
5700 }
5701
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005702 if (iftype == NL80211_IFTYPE_P2P_DEVICE)
5703 return 0;
5704
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005705 ifidx = if_nametoindex(ifname);
5706 wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
5707 ifname, ifidx);
5708
5709 if (ifidx <= 0)
5710 return -1;
5711
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005712 /*
5713 * Some virtual interfaces need to process EAPOL packets and events on
5714 * the parent interface. This is used mainly with hostapd.
5715 */
5716 if (drv->hostapd ||
5717 iftype == NL80211_IFTYPE_AP_VLAN ||
5718 iftype == NL80211_IFTYPE_WDS ||
5719 iftype == NL80211_IFTYPE_MONITOR) {
5720 /* start listening for EAPOL on this interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08005721 add_ifidx(drv, ifidx, IFIDX_ANY);
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005722 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005723
5724 if (addr && iftype != NL80211_IFTYPE_MONITOR &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005725 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005726 nl80211_remove_iface(drv, ifidx);
5727 return -1;
5728 }
5729
5730 return ifidx;
5731}
5732
5733
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005734int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
5735 const char *ifname, enum nl80211_iftype iftype,
5736 const u8 *addr, int wds,
5737 int (*handler)(struct nl_msg *, void *),
5738 void *arg, int use_existing)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005739{
5740 int ret;
5741
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005742 ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
5743 arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005744
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005745 /* if error occurred and interface exists already */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005746 if (ret == -ENFILE && if_nametoindex(ifname)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005747 if (use_existing) {
5748 wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s",
5749 ifname);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07005750 if (addr && iftype != NL80211_IFTYPE_MONITOR &&
5751 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
5752 addr) < 0 &&
5753 (linux_set_iface_flags(drv->global->ioctl_sock,
5754 ifname, 0) < 0 ||
5755 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
5756 addr) < 0 ||
5757 linux_set_iface_flags(drv->global->ioctl_sock,
5758 ifname, 1) < 0))
5759 return -1;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005760 return -ENFILE;
5761 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005762 wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
5763
5764 /* Try to remove the interface that was already there. */
5765 nl80211_remove_iface(drv, if_nametoindex(ifname));
5766
5767 /* Try to create the interface again */
5768 ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005769 wds, handler, arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005770 }
5771
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005772 if (ret >= 0 && is_p2p_net_interface(iftype)) {
5773 wpa_printf(MSG_DEBUG,
5774 "nl80211: Interface %s created for P2P - disable 11b rates",
5775 ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005776 nl80211_disable_11b_rates(drv, ret, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005777 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005778
5779 return ret;
5780}
5781
5782
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005783static int nl80211_setup_ap(struct i802_bss *bss)
5784{
5785 struct wpa_driver_nl80211_data *drv = bss->drv;
5786
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005787 wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d use_monitor=%d",
5788 bss->ifname, drv->device_ap_sme, drv->use_monitor);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005789
5790 /*
5791 * Disable Probe Request reporting unless we need it in this way for
5792 * devices that include the AP SME, in the other case (unless using
5793 * monitor iface) we'll get it through the nl_mgmt socket instead.
5794 */
5795 if (!drv->device_ap_sme)
5796 wpa_driver_nl80211_probe_req_report(bss, 0);
5797
5798 if (!drv->device_ap_sme && !drv->use_monitor)
5799 if (nl80211_mgmt_subscribe_ap(bss))
5800 return -1;
5801
5802 if (drv->device_ap_sme && !drv->use_monitor)
5803 if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005804 wpa_printf(MSG_DEBUG,
5805 "nl80211: Failed to subscribe for mgmt frames from SME driver - trying to run without it");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005806
5807 if (!drv->device_ap_sme && drv->use_monitor &&
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005808 nl80211_create_monitor_interface(drv) &&
5809 !drv->device_ap_sme)
Dmitry Shmidt04949592012-07-19 12:16:46 -07005810 return -1;
5811
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005812 if (drv->device_ap_sme &&
5813 wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
5814 wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
5815 "Probe Request frame reporting in AP mode");
5816 /* Try to survive without this */
5817 }
5818
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005819 return 0;
5820}
5821
5822
5823static void nl80211_teardown_ap(struct i802_bss *bss)
5824{
5825 struct wpa_driver_nl80211_data *drv = bss->drv;
5826
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005827 wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d use_monitor=%d",
5828 bss->ifname, drv->device_ap_sme, drv->use_monitor);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005829 if (drv->device_ap_sme) {
5830 wpa_driver_nl80211_probe_req_report(bss, 0);
5831 if (!drv->use_monitor)
5832 nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
5833 } else if (drv->use_monitor)
5834 nl80211_remove_monitor_interface(drv);
5835 else
5836 nl80211_mgmt_unsubscribe(bss, "AP teardown");
5837
Paul Stewart092955c2017-02-06 09:13:09 -08005838 nl80211_put_wiphy_data_ap(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005839 bss->beacon_set = 0;
5840}
5841
5842
Hai Shalomfdcde762020-04-02 11:19:20 -07005843static int nl80211_tx_control_port(void *priv, const u8 *dest,
5844 u16 proto, const u8 *buf, size_t len,
5845 int no_encrypt)
5846{
Hai Shalom899fcc72020-10-19 14:38:18 -07005847 struct nl80211_ack_ext_arg ext_arg;
Hai Shalomfdcde762020-04-02 11:19:20 -07005848 struct i802_bss *bss = priv;
5849 struct nl_msg *msg;
Hai Shalom899fcc72020-10-19 14:38:18 -07005850 u64 cookie = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07005851 int ret;
5852
5853 wpa_printf(MSG_DEBUG,
5854 "nl80211: Send over control port dest=" MACSTR
5855 " proto=0x%04x len=%u no_encrypt=%d",
5856 MAC2STR(dest), proto, (unsigned int) len, no_encrypt);
5857
5858 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CONTROL_PORT_FRAME);
5859 if (!msg ||
5860 nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
5861 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dest) ||
5862 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
5863 (no_encrypt &&
5864 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) {
5865 nlmsg_free(msg);
5866 return -ENOBUFS;
5867 }
5868
Hai Shalom899fcc72020-10-19 14:38:18 -07005869 os_memset(&ext_arg, 0, sizeof(struct nl80211_ack_ext_arg));
5870 ext_arg.ext_data = &cookie;
5871 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL,
5872 ack_handler_cookie, &ext_arg);
5873 if (ret) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005874 wpa_printf(MSG_DEBUG,
5875 "nl80211: tx_control_port failed: ret=%d (%s)",
5876 ret, strerror(-ret));
Hai Shalom899fcc72020-10-19 14:38:18 -07005877 } else {
5878 struct wpa_driver_nl80211_data *drv = bss->drv;
5879
5880 wpa_printf(MSG_DEBUG,
5881 "nl80211: tx_control_port cookie=0x%llx",
5882 (long long unsigned int) cookie);
5883 drv->eapol_tx_cookie = cookie;
5884 }
Hai Shalomfdcde762020-04-02 11:19:20 -07005885
5886 return ret;
5887}
5888
5889
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005890static int nl80211_send_eapol_data(struct i802_bss *bss,
5891 const u8 *addr, const u8 *data,
5892 size_t data_len)
5893{
5894 struct sockaddr_ll ll;
5895 int ret;
5896
5897 if (bss->drv->eapol_tx_sock < 0) {
5898 wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
5899 return -1;
5900 }
5901
5902 os_memset(&ll, 0, sizeof(ll));
5903 ll.sll_family = AF_PACKET;
5904 ll.sll_ifindex = bss->ifindex;
5905 ll.sll_protocol = htons(ETH_P_PAE);
5906 ll.sll_halen = ETH_ALEN;
5907 os_memcpy(ll.sll_addr, addr, ETH_ALEN);
5908 ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
5909 (struct sockaddr *) &ll, sizeof(ll));
5910 if (ret < 0)
5911 wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
5912 strerror(errno));
5913
5914 return ret;
5915}
5916
5917
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005918static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
5919
5920static int wpa_driver_nl80211_hapd_send_eapol(
5921 void *priv, const u8 *addr, const u8 *data,
5922 size_t data_len, int encrypt, const u8 *own_addr, u32 flags)
5923{
5924 struct i802_bss *bss = priv;
5925 struct wpa_driver_nl80211_data *drv = bss->drv;
5926 struct ieee80211_hdr *hdr;
5927 size_t len;
5928 u8 *pos;
5929 int res;
5930 int qos = flags & WPA_STA_WMM;
Dmitry Shmidt641185e2013-11-06 15:17:13 -08005931
Hai Shalomb755a2a2020-04-23 21:49:02 -07005932 /* For now, disable EAPOL TX over control port in AP mode by default
5933 * since it does not provide TX status notifications. */
5934 if (drv->control_port_ap &&
5935 (drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT))
Hai Shalomfdcde762020-04-02 11:19:20 -07005936 return nl80211_tx_control_port(bss, addr, ETH_P_EAPOL,
5937 data, data_len, !encrypt);
5938
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005939 if (drv->device_ap_sme || !drv->use_monitor)
5940 return nl80211_send_eapol_data(bss, addr, data, data_len);
5941
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005942 len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
5943 data_len;
5944 hdr = os_zalloc(len);
5945 if (hdr == NULL) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005946 wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)",
5947 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005948 return -1;
5949 }
5950
5951 hdr->frame_control =
5952 IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
5953 hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
5954 if (encrypt)
5955 hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
5956 if (qos) {
5957 hdr->frame_control |=
5958 host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
5959 }
5960
5961 memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
5962 memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
5963 memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
5964 pos = (u8 *) (hdr + 1);
5965
5966 if (qos) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07005967 /* Set highest priority in QoS header */
5968 pos[0] = 7;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005969 pos[1] = 0;
5970 pos += 2;
5971 }
5972
5973 memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
5974 pos += sizeof(rfc1042_header);
5975 WPA_PUT_BE16(pos, ETH_P_PAE);
5976 pos += 2;
5977 memcpy(pos, data, data_len);
5978
Hai Shalomfdcde762020-04-02 11:19:20 -07005979 res = nl80211_send_monitor(drv, hdr, len, encrypt, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005980 if (res < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005981 wpa_printf(MSG_ERROR,
5982 "hapd_send_eapol - packet len: %lu - failed",
5983 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005984 }
5985 os_free(hdr);
5986
5987 return res;
5988}
5989
5990
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005991static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005992 unsigned int total_flags,
5993 unsigned int flags_or,
5994 unsigned int flags_and)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005995{
5996 struct i802_bss *bss = priv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005997 struct nl_msg *msg;
5998 struct nlattr *flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005999 struct nl80211_sta_flag_update upd;
6000
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07006001 wpa_printf(MSG_DEBUG, "nl80211: Set STA flags - ifname=%s addr=" MACSTR
6002 " total_flags=0x%x flags_or=0x%x flags_and=0x%x authorized=%d",
6003 bss->ifname, MAC2STR(addr), total_flags, flags_or, flags_and,
6004 !!(total_flags & WPA_STA_AUTHORIZED));
6005
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006006 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
6007 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
6008 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006009
6010 /*
6011 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
6012 * can be removed eventually.
6013 */
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07006014 flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006015 if (!flags ||
6016 ((total_flags & WPA_STA_AUTHORIZED) &&
6017 nla_put_flag(msg, NL80211_STA_FLAG_AUTHORIZED)) ||
6018 ((total_flags & WPA_STA_WMM) &&
6019 nla_put_flag(msg, NL80211_STA_FLAG_WME)) ||
6020 ((total_flags & WPA_STA_SHORT_PREAMBLE) &&
6021 nla_put_flag(msg, NL80211_STA_FLAG_SHORT_PREAMBLE)) ||
6022 ((total_flags & WPA_STA_MFP) &&
6023 nla_put_flag(msg, NL80211_STA_FLAG_MFP)) ||
6024 ((total_flags & WPA_STA_TDLS_PEER) &&
6025 nla_put_flag(msg, NL80211_STA_FLAG_TDLS_PEER)))
6026 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006027
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07006028 nla_nest_end(msg, flags);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006029
6030 os_memset(&upd, 0, sizeof(upd));
6031 upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
6032 upd.set = sta_flags_nl80211(flags_or);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006033 if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
6034 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006035
Hai Shalom899fcc72020-10-19 14:38:18 -07006036 return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006037fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006038 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006039 return -ENOBUFS;
6040}
6041
6042
Hai Shalom81f62d82019-07-22 12:10:00 -07006043static int driver_nl80211_sta_set_airtime_weight(void *priv, const u8 *addr,
6044 unsigned int weight)
6045{
6046 struct i802_bss *bss = priv;
6047 struct nl_msg *msg;
Hai Shalomc1a21442022-02-04 13:43:00 -08006048 int ret;
Hai Shalom81f62d82019-07-22 12:10:00 -07006049
6050 wpa_printf(MSG_DEBUG,
6051 "nl80211: Set STA airtime weight - ifname=%s addr=" MACSTR
6052 " weight=%u", bss->ifname, MAC2STR(addr), weight);
6053
6054 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
6055 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
6056 nla_put_u16(msg, NL80211_ATTR_AIRTIME_WEIGHT, weight))
6057 goto fail;
6058
Hai Shalomc1a21442022-02-04 13:43:00 -08006059 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
6060 if (ret) {
6061 wpa_printf(MSG_DEBUG,
6062 "nl80211: SET_STATION[AIRTIME_WEIGHT] failed: ret=%d (%s)",
6063 ret, strerror(-ret));
6064 }
6065 return ret;
Hai Shalom81f62d82019-07-22 12:10:00 -07006066fail:
6067 nlmsg_free(msg);
6068 return -ENOBUFS;
6069}
6070
6071
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006072static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
6073 struct wpa_driver_associate_params *params)
6074{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006075 enum nl80211_iftype nlmode, old_mode;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006076
6077 if (params->p2p) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006078 wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
6079 "group (GO)");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006080 nlmode = NL80211_IFTYPE_P2P_GO;
6081 } else
6082 nlmode = NL80211_IFTYPE_AP;
6083
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006084 old_mode = drv->nlmode;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006085 if (wpa_driver_nl80211_set_mode(drv->first_bss, nlmode)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006086 nl80211_remove_monitor_interface(drv);
6087 return -1;
6088 }
6089
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08006090 if (params->freq.freq &&
6091 nl80211_set_channel(drv->first_bss, &params->freq, 0)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006092 if (old_mode != nlmode)
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006093 wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006094 nl80211_remove_monitor_interface(drv);
6095 return -1;
6096 }
6097
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006098 return 0;
6099}
6100
6101
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006102static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
6103 int reset_mode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006104{
6105 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006106 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006107
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006108 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
Hai Shalomc1a21442022-02-04 13:43:00 -08006109 ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006110 if (ret) {
6111 wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
6112 "(%s)", ret, strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006113 } else {
6114 wpa_printf(MSG_DEBUG,
6115 "nl80211: Leave IBSS request sent successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006116 }
6117
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006118 if (reset_mode &&
6119 wpa_driver_nl80211_set_mode(drv->first_bss,
Dmitry Shmidt56052862013-10-04 10:23:25 -07006120 NL80211_IFTYPE_STATION)) {
6121 wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
6122 "station mode");
6123 }
6124
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006125 return ret;
6126}
6127
6128
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006129static int nl80211_ht_vht_overrides(struct nl_msg *msg,
6130 struct wpa_driver_associate_params *params)
6131{
6132 if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
6133 return -1;
6134
6135 if (params->htcaps && params->htcaps_mask) {
6136 int sz = sizeof(struct ieee80211_ht_capabilities);
6137 wpa_hexdump(MSG_DEBUG, " * htcaps", params->htcaps, sz);
6138 wpa_hexdump(MSG_DEBUG, " * htcaps_mask",
6139 params->htcaps_mask, sz);
6140 if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
6141 params->htcaps) ||
6142 nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
6143 params->htcaps_mask))
6144 return -1;
6145 }
6146
6147#ifdef CONFIG_VHT_OVERRIDES
6148 if (params->disable_vht) {
6149 wpa_printf(MSG_DEBUG, " * VHT disabled");
6150 if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
6151 return -1;
6152 }
6153
6154 if (params->vhtcaps && params->vhtcaps_mask) {
6155 int sz = sizeof(struct ieee80211_vht_capabilities);
6156 wpa_hexdump(MSG_DEBUG, " * vhtcaps", params->vhtcaps, sz);
6157 wpa_hexdump(MSG_DEBUG, " * vhtcaps_mask",
6158 params->vhtcaps_mask, sz);
6159 if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
6160 params->vhtcaps) ||
6161 nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
6162 params->vhtcaps_mask))
6163 return -1;
6164 }
6165#endif /* CONFIG_VHT_OVERRIDES */
6166
Hai Shalomc1a21442022-02-04 13:43:00 -08006167#ifdef CONFIG_HE_OVERRIDES
6168 if (params->disable_he) {
6169 wpa_printf(MSG_DEBUG, " * HE disabled");
6170 if (nla_put_flag(msg, NL80211_ATTR_DISABLE_HE))
6171 return -1;
6172 }
6173#endif /* CONFIG_HE_OVERRIDES */
6174
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006175 return 0;
6176}
6177
6178
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006179static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
6180 struct wpa_driver_associate_params *params)
6181{
6182 struct nl_msg *msg;
6183 int ret = -1;
6184 int count = 0;
6185
6186 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
6187
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006188 if (wpa_driver_nl80211_set_mode_ibss(drv->first_bss, &params->freq)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006189 wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
6190 "IBSS mode");
6191 return -1;
6192 }
6193
6194retry:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006195 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_IBSS)) ||
6196 params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
6197 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006198
Hai Shalom74f70d42019-02-11 14:42:39 -08006199 wpa_printf(MSG_DEBUG, " * SSID=%s",
6200 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006201 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
6202 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006203 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6204 drv->ssid_len = params->ssid_len;
6205
Dmitry Shmidtff787d52015-01-12 13:01:47 -08006206 if (nl80211_put_freq_params(msg, &params->freq) < 0 ||
6207 nl80211_put_beacon_int(msg, params->beacon_int))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006208 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006209
6210 ret = nl80211_set_conn_keys(params, msg);
6211 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006212 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006213
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006214 if (params->bssid && params->fixed_bssid) {
6215 wpa_printf(MSG_DEBUG, " * BSSID=" MACSTR,
6216 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006217 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
6218 goto fail;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006219 }
6220
Dmitry Shmidt7f656022015-02-25 14:36:37 -08006221 if (params->fixed_freq) {
6222 wpa_printf(MSG_DEBUG, " * fixed_freq");
6223 if (nla_put_flag(msg, NL80211_ATTR_FREQ_FIXED))
6224 goto fail;
6225 }
6226
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006227 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
6228 params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
6229 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
6230 params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006231 wpa_printf(MSG_DEBUG, " * control port");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006232 if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
6233 goto fail;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006234 }
6235
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006236 if (params->wpa_ie) {
6237 wpa_hexdump(MSG_DEBUG,
6238 " * Extra IEs for Beacon/Probe Response frames",
6239 params->wpa_ie, params->wpa_ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006240 if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
6241 params->wpa_ie))
6242 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006243 }
6244
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08006245 ret = nl80211_ht_vht_overrides(msg, params);
6246 if (ret < 0)
6247 goto fail;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006248
Hai Shalomc1a21442022-02-04 13:43:00 -08006249 ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006250 msg = NULL;
6251 if (ret) {
6252 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
6253 ret, strerror(-ret));
6254 count++;
6255 if (ret == -EALREADY && count == 1) {
6256 wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
6257 "forced leave");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006258 nl80211_leave_ibss(drv, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006259 nlmsg_free(msg);
6260 goto retry;
6261 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006262 } else {
6263 wpa_printf(MSG_DEBUG,
6264 "nl80211: Join IBSS request sent successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006265 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006266
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006267fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006268 nlmsg_free(msg);
6269 return ret;
6270}
6271
6272
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006273static int nl80211_put_fils_connect_params(struct wpa_driver_nl80211_data *drv,
6274 struct wpa_driver_associate_params *params,
6275 struct nl_msg *msg)
6276{
6277 if (params->fils_erp_username_len) {
6278 wpa_hexdump_ascii(MSG_DEBUG, " * FILS ERP EMSKname/username",
6279 params->fils_erp_username,
6280 params->fils_erp_username_len);
6281 if (nla_put(msg, NL80211_ATTR_FILS_ERP_USERNAME,
6282 params->fils_erp_username_len,
6283 params->fils_erp_username))
6284 return -1;
6285 }
6286
6287 if (params->fils_erp_realm_len) {
6288 wpa_hexdump_ascii(MSG_DEBUG, " * FILS ERP Realm",
6289 params->fils_erp_realm,
6290 params->fils_erp_realm_len);
6291 if (nla_put(msg, NL80211_ATTR_FILS_ERP_REALM,
6292 params->fils_erp_realm_len, params->fils_erp_realm))
6293 return -1;
6294 }
6295
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006296 if (params->fils_erp_rrk_len) {
Vinita S. Maloo3a5b4412020-05-19 17:43:22 +05306297 wpa_printf(MSG_DEBUG, " * FILS ERP next seq %u",
6298 params->fils_erp_next_seq_num);
6299 if (nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
6300 params->fils_erp_next_seq_num))
6301 return -1;
6302
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006303 wpa_printf(MSG_DEBUG, " * FILS ERP rRK (len=%lu)",
6304 (unsigned long) params->fils_erp_rrk_len);
6305 if (nla_put(msg, NL80211_ATTR_FILS_ERP_RRK,
6306 params->fils_erp_rrk_len, params->fils_erp_rrk))
6307 return -1;
6308 }
6309
6310 return 0;
6311}
6312
6313
Sunil Ravi89eba102022-09-13 21:04:37 -07006314static unsigned int num_bits_set(u32 val)
6315{
6316 unsigned int c;
6317
6318 for (c = 0; val; c++)
6319 val &= val - 1;
6320
6321 return c;
6322}
6323
6324
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006325static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
6326 struct wpa_driver_associate_params *params,
6327 struct nl_msg *msg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006328{
Paul Stewart092955c2017-02-06 09:13:09 -08006329 if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
6330 return -1;
6331
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006332 if (params->bssid) {
6333 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
6334 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006335 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
6336 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006337 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006338
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006339 if (params->bssid_hint) {
6340 wpa_printf(MSG_DEBUG, " * bssid_hint=" MACSTR,
6341 MAC2STR(params->bssid_hint));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006342 if (nla_put(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
6343 params->bssid_hint))
6344 return -1;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006345 }
6346
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006347 if (params->freq.freq) {
6348 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq.freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006349 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
6350 params->freq.freq))
6351 return -1;
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006352 drv->assoc_freq = params->freq.freq;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07006353 } else
6354 drv->assoc_freq = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006355
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006356 if (params->freq_hint) {
6357 wpa_printf(MSG_DEBUG, " * freq_hint=%d", params->freq_hint);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006358 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_HINT,
6359 params->freq_hint))
6360 return -1;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006361 }
6362
Hai Shalomc3565922019-10-28 11:58:20 -07006363 if (params->freq.edmg.channels && params->freq.edmg.bw_config) {
6364 wpa_printf(MSG_DEBUG,
6365 " * EDMG configuration: channels=0x%x bw_config=%d",
6366 params->freq.edmg.channels,
6367 params->freq.edmg.bw_config);
6368 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
6369 params->freq.edmg.channels) ||
6370 nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
6371 params->freq.edmg.bw_config))
6372 return -1;
6373 }
6374
Dmitry Shmidt04949592012-07-19 12:16:46 -07006375 if (params->bg_scan_period >= 0) {
6376 wpa_printf(MSG_DEBUG, " * bg scan period=%d",
6377 params->bg_scan_period);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006378 if (nla_put_u16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
6379 params->bg_scan_period))
6380 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07006381 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006382
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006383 if (params->ssid) {
Hai Shalom74f70d42019-02-11 14:42:39 -08006384 wpa_printf(MSG_DEBUG, " * SSID=%s",
6385 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006386 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
6387 params->ssid))
6388 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006389 if (params->ssid_len > sizeof(drv->ssid))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006390 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006391 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6392 drv->ssid_len = params->ssid_len;
6393 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006394
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006395 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006396 if (params->wpa_ie &&
6397 nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie))
6398 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006399
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006400 if (params->wpa_proto) {
6401 enum nl80211_wpa_versions ver = 0;
6402
6403 if (params->wpa_proto & WPA_PROTO_WPA)
6404 ver |= NL80211_WPA_VERSION_1;
6405 if (params->wpa_proto & WPA_PROTO_RSN)
6406 ver |= NL80211_WPA_VERSION_2;
6407
6408 wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006409 if (nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
6410 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006411 }
6412
6413 if (params->pairwise_suite != WPA_CIPHER_NONE) {
6414 u32 cipher = wpa_cipher_to_cipher_suite(params->pairwise_suite);
6415 wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006416 if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
6417 cipher))
6418 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006419 }
6420
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08006421 if (params->group_suite == WPA_CIPHER_GTK_NOT_USED &&
6422 !(drv->capa.enc & WPA_DRIVER_CAPA_ENC_GTK_NOT_USED)) {
6423 /*
6424 * This is likely to work even though many drivers do not
6425 * advertise support for operations without GTK.
6426 */
6427 wpa_printf(MSG_DEBUG, " * skip group cipher configuration for GTK_NOT_USED due to missing driver support advertisement");
6428 } else if (params->group_suite != WPA_CIPHER_NONE) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006429 u32 cipher = wpa_cipher_to_cipher_suite(params->group_suite);
6430 wpa_printf(MSG_DEBUG, " * group=0x%x", cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006431 if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher))
6432 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006433 }
6434
6435 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
6436 params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
6437 params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X ||
6438 params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
Dmitry Shmidt15907092014-03-25 10:42:57 -07006439 params->key_mgmt_suite == WPA_KEY_MGMT_CCKM ||
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07006440 params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
6441 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006442 params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
Hai Shalom021b0b52019-04-10 11:17:58 -07006443 params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
Sunil Ravi89eba102022-09-13 21:04:37 -07006444 params->key_mgmt_suite == WPA_KEY_MGMT_SAE_EXT_KEY ||
Hai Shalom021b0b52019-04-10 11:17:58 -07006445 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE ||
Sunil Ravi89eba102022-09-13 21:04:37 -07006446 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE_EXT_KEY ||
Dmitry Shmidt807291d2015-01-27 13:40:23 -08006447 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006448 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ||
Hai Shalom021b0b52019-04-10 11:17:58 -07006449 params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006450 params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA256 ||
6451 params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA384 ||
6452 params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA256 ||
Roshan Pius3a1667e2018-07-03 15:17:14 -07006453 params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384 ||
6454 params->key_mgmt_suite == WPA_KEY_MGMT_OWE ||
6455 params->key_mgmt_suite == WPA_KEY_MGMT_DPP) {
Sunil Ravi89eba102022-09-13 21:04:37 -07006456 u32 *mgmt;
6457 unsigned int akm_count = 1, i;
6458
6459 /*
6460 * Make sure the driver has capability to handle default AKM in
6461 * key_mgmt_suite plus allowed AKMs in allowed_key_mgmts.
6462 */
6463 if (drv->capa.max_num_akms <=
6464 num_bits_set(params->allowed_key_mgmts)) {
6465 wpa_printf(MSG_INFO,
6466 "nl80211: Not enough support for the allowed AKMs (max_num_akms=%u <= num_bits_set=%u)",
6467 drv->capa.max_num_akms,
6468 num_bits_set(params->allowed_key_mgmts));
6469 return -1;
6470 }
6471
6472 mgmt = os_malloc(sizeof(u32) * drv->capa.max_num_akms);
6473 if (!mgmt)
6474 return -1;
6475
6476 mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006477
6478 switch (params->key_mgmt_suite) {
6479 case WPA_KEY_MGMT_CCKM:
Sunil Ravi89eba102022-09-13 21:04:37 -07006480 mgmt[0] = RSN_AUTH_KEY_MGMT_CCKM;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006481 break;
6482 case WPA_KEY_MGMT_IEEE8021X:
Sunil Ravi89eba102022-09-13 21:04:37 -07006483 mgmt[0] = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006484 break;
6485 case WPA_KEY_MGMT_FT_IEEE8021X:
Sunil Ravi89eba102022-09-13 21:04:37 -07006486 mgmt[0] = RSN_AUTH_KEY_MGMT_FT_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006487 break;
6488 case WPA_KEY_MGMT_FT_PSK:
Sunil Ravi89eba102022-09-13 21:04:37 -07006489 mgmt[0] = RSN_AUTH_KEY_MGMT_FT_PSK;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006490 break;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07006491 case WPA_KEY_MGMT_IEEE8021X_SHA256:
Sunil Ravi89eba102022-09-13 21:04:37 -07006492 mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07006493 break;
6494 case WPA_KEY_MGMT_PSK_SHA256:
Sunil Ravi89eba102022-09-13 21:04:37 -07006495 mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_SHA256;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07006496 break;
Dmitry Shmidt15907092014-03-25 10:42:57 -07006497 case WPA_KEY_MGMT_OSEN:
Sunil Ravi89eba102022-09-13 21:04:37 -07006498 mgmt[0] = RSN_AUTH_KEY_MGMT_OSEN;
Dmitry Shmidt15907092014-03-25 10:42:57 -07006499 break;
Hai Shalom021b0b52019-04-10 11:17:58 -07006500 case WPA_KEY_MGMT_SAE:
Sunil Ravi89eba102022-09-13 21:04:37 -07006501 mgmt[0] = RSN_AUTH_KEY_MGMT_SAE;
6502 break;
6503 case WPA_KEY_MGMT_SAE_EXT_KEY:
6504 mgmt[0] = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY;
Hai Shalom021b0b52019-04-10 11:17:58 -07006505 break;
6506 case WPA_KEY_MGMT_FT_SAE:
Sunil Ravi89eba102022-09-13 21:04:37 -07006507 mgmt[0] = RSN_AUTH_KEY_MGMT_FT_SAE;
6508 break;
6509 case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
6510 mgmt[0] = RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY;
Hai Shalom021b0b52019-04-10 11:17:58 -07006511 break;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006512 case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
Sunil Ravi89eba102022-09-13 21:04:37 -07006513 mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006514 break;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08006515 case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
Sunil Ravi89eba102022-09-13 21:04:37 -07006516 mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08006517 break;
Hai Shalom021b0b52019-04-10 11:17:58 -07006518 case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
Sunil Ravi89eba102022-09-13 21:04:37 -07006519 mgmt[0] = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
Hai Shalom021b0b52019-04-10 11:17:58 -07006520 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006521 case WPA_KEY_MGMT_FILS_SHA256:
Sunil Ravi89eba102022-09-13 21:04:37 -07006522 mgmt[0] = RSN_AUTH_KEY_MGMT_FILS_SHA256;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006523 break;
6524 case WPA_KEY_MGMT_FILS_SHA384:
Sunil Ravi89eba102022-09-13 21:04:37 -07006525 mgmt[0] = RSN_AUTH_KEY_MGMT_FILS_SHA384;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006526 break;
6527 case WPA_KEY_MGMT_FT_FILS_SHA256:
Sunil Ravi89eba102022-09-13 21:04:37 -07006528 mgmt[0] = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006529 break;
6530 case WPA_KEY_MGMT_FT_FILS_SHA384:
Sunil Ravi89eba102022-09-13 21:04:37 -07006531 mgmt[0] = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006532 break;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006533 case WPA_KEY_MGMT_OWE:
Sunil Ravi89eba102022-09-13 21:04:37 -07006534 mgmt[0] = RSN_AUTH_KEY_MGMT_OWE;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006535 break;
6536 case WPA_KEY_MGMT_DPP:
Sunil Ravi89eba102022-09-13 21:04:37 -07006537 mgmt[0] = RSN_AUTH_KEY_MGMT_DPP;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006538 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006539 case WPA_KEY_MGMT_PSK:
6540 default:
Sunil Ravi89eba102022-09-13 21:04:37 -07006541 mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006542 break;
6543 }
Sunil Ravi89eba102022-09-13 21:04:37 -07006544
6545 if (drv->capa.max_num_akms > 1) {
6546 akm_count += wpa_key_mgmt_to_suites(
6547 params->allowed_key_mgmts, &mgmt[1],
6548 drv->capa.max_num_akms - 1);
6549 }
6550
6551 for (i = 0; i < akm_count; i++)
6552 wpa_printf(MSG_DEBUG, " * akm[%d]=0x%x", i, mgmt[i]);
6553
6554 if (nla_put(msg, NL80211_ATTR_AKM_SUITES,
6555 akm_count * sizeof(u32), mgmt)) {
6556 os_free(mgmt);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006557 return -1;
Sunil Ravi89eba102022-09-13 21:04:37 -07006558 }
6559
6560 os_free(mgmt);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006561 }
6562
Vinayak Yadawad14709082022-03-17 14:25:11 +05306563#ifdef CONFIG_DRIVER_NL80211_BRCM
6564 if (IS_CROSS_AKM_ROAM_KEY_MGMT(params->key_mgmt_suite)) {
6565 int num_suites;
6566 u32 suites[NL80211_MAX_NR_AKM_SUITES];
6567
6568 wpa_printf(MSG_INFO, "nl80211: key_mgmt_suites=0x%x",
6569 params->key_mgmt_suite);
6570 num_suites = wpa_cross_akm_key_mgmt_to_suites(params->key_mgmt_suite,
6571 suites, ARRAY_SIZE(suites));
6572 if (num_suites &&
6573 nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32), suites)) {
6574 wpa_printf(MSG_ERROR, "Updating multi akm_suite failed");
6575 return -1;
6576 }
6577 }
6578#endif /* CONFIG_DRIVER_NL80211_BRCM */
Hai Shalomc3565922019-10-28 11:58:20 -07006579 if (params->req_handshake_offload &&
Hai Shalom74f70d42019-02-11 14:42:39 -08006580 (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) {
6581 wpa_printf(MSG_DEBUG, " * WANT_1X_4WAY_HS");
6582 if (nla_put_flag(msg, NL80211_ATTR_WANT_1X_4WAY_HS))
6583 return -1;
6584 }
6585
Roshan Pius3a1667e2018-07-03 15:17:14 -07006586 /* Add PSK in case of 4-way handshake offload */
6587 if (params->psk &&
Hai Shalom74f70d42019-02-11 14:42:39 -08006588 (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006589 wpa_hexdump_key(MSG_DEBUG, " * PSK", params->psk, 32);
6590 if (nla_put(msg, NL80211_ATTR_PMK, 32, params->psk))
6591 return -1;
6592 }
6593
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006594 if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
6595 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006596
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006597 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
6598 (params->pairwise_suite == WPA_CIPHER_NONE ||
6599 params->pairwise_suite == WPA_CIPHER_WEP104 ||
6600 params->pairwise_suite == WPA_CIPHER_WEP40) &&
6601 (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
6602 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
6603 return -1;
6604
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006605 if (params->rrm_used) {
6606 u32 drv_rrm_flags = drv->capa.rrm_flags;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006607 if ((!((drv_rrm_flags &
6608 WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) &&
6609 (drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) &&
6610 !(drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006611 nla_put_flag(msg, NL80211_ATTR_USE_RRM))
6612 return -1;
6613 }
6614
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006615 if (nl80211_ht_vht_overrides(msg, params) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006616 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006617
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006618 if (params->p2p)
6619 wpa_printf(MSG_DEBUG, " * P2P group");
6620
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006621 if (params->pbss) {
6622 wpa_printf(MSG_DEBUG, " * PBSS");
6623 if (nla_put_flag(msg, NL80211_ATTR_PBSS))
6624 return -1;
6625 }
6626
Dmitry Shmidte4663042016-04-04 10:07:49 -07006627 drv->connect_reassoc = 0;
6628 if (params->prev_bssid) {
6629 wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR,
6630 MAC2STR(params->prev_bssid));
6631 if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
6632 params->prev_bssid))
6633 return -1;
6634 drv->connect_reassoc = 1;
6635 }
6636
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006637 if ((params->auth_alg & WPA_AUTH_ALG_FILS) &&
6638 nl80211_put_fils_connect_params(drv, params, msg) != 0)
6639 return -1;
6640
Vinayak Yadawad14709082022-03-17 14:25:11 +05306641#ifdef CONFIG_DRIVER_NL80211_BRCM
Sunil Ravi89eba102022-09-13 21:04:37 -07006642 if (((params->key_mgmt_suite & WPA_KEY_MGMT_SAE) ||
6643 (params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE)) &&
Vinayak Yadawad14709082022-03-17 14:25:11 +05306644#else
Sunil Ravi89eba102022-09-13 21:04:37 -07006645 if ((wpa_key_mgmt_sae(params->key_mgmt_suite) ||
6646 wpa_key_mgmt_sae(params->allowed_key_mgmts)) &&
Vinayak Yadawad14709082022-03-17 14:25:11 +05306647#endif /* CONFIG_DRIVER_NL80211_BRCM */
Roshan Pius3a1667e2018-07-03 15:17:14 -07006648 (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
6649 nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
6650 return -1;
6651
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006652 return 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006653}
6654
6655
6656static int wpa_driver_nl80211_try_connect(
6657 struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006658 struct wpa_driver_associate_params *params,
Hai Shalomc1a21442022-02-04 13:43:00 -08006659 struct i802_bss *bss)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006660{
6661 struct nl_msg *msg;
6662 enum nl80211_auth_type type;
6663 int ret;
6664 int algs;
6665
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006666#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006667 if (params->req_key_mgmt_offload && params->psk &&
Sunil Ravi89eba102022-09-13 21:04:37 -07006668 (wpa_key_mgmt_wpa_psk_no_sae(params->key_mgmt_suite) ||
6669 wpa_key_mgmt_wpa_psk_no_sae(params->allowed_key_mgmts))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006670 wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK");
6671 ret = issue_key_mgmt_set_key(drv, params->psk, 32);
6672 if (ret)
6673 return ret;
6674 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006675#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006676
6677 wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
6678 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_CONNECT);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006679 if (!msg)
6680 return -1;
6681
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006682 ret = nl80211_connect_common(drv, params, msg);
6683 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006684 goto fail;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006685
Roshan Pius3a1667e2018-07-03 15:17:14 -07006686 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
6687 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
6688 goto fail;
6689
6690 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_OPTIONAL &&
6691 (drv->capa.flags & WPA_DRIVER_FLAGS_MFP_OPTIONAL) &&
6692 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_OPTIONAL))
6693 goto fail;
6694
Hai Shalom60840252021-02-19 19:02:11 -08006695#ifdef CONFIG_SAE
Vinayak Yadawad14709082022-03-17 14:25:11 +05306696#ifdef CONFIG_DRIVER_NL80211_BRCM
Sunil Ravi89eba102022-09-13 21:04:37 -07006697 if (((params->key_mgmt_suite & WPA_KEY_MGMT_SAE) ||
6698 (params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE)) &&
Vinayak Yadawad14709082022-03-17 14:25:11 +05306699#else
Sunil Ravi89eba102022-09-13 21:04:37 -07006700 if ((wpa_key_mgmt_sae(params->key_mgmt_suite) ||
6701 wpa_key_mgmt_sae(params->allowed_key_mgmts)) &&
Vinayak Yadawad14709082022-03-17 14:25:11 +05306702#endif /* CONFIG_DRIVER_NL80211_BRCM */
Hai Shalom60840252021-02-19 19:02:11 -08006703 nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
6704 goto fail;
6705#endif /* CONFIG_SAE */
6706
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006707 algs = 0;
6708 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
6709 algs++;
6710 if (params->auth_alg & WPA_AUTH_ALG_SHARED)
6711 algs++;
6712 if (params->auth_alg & WPA_AUTH_ALG_LEAP)
6713 algs++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006714 if (params->auth_alg & WPA_AUTH_ALG_FILS)
6715 algs++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006716 if (params->auth_alg & WPA_AUTH_ALG_FT)
6717 algs++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006718 if (algs > 1) {
6719 wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic "
6720 "selection");
6721 goto skip_auth_type;
6722 }
6723
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006724 type = get_nl_auth_type(params->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006725 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006726 if (type == NL80211_AUTHTYPE_MAX ||
6727 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006728 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006729
6730skip_auth_type:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006731 ret = nl80211_set_conn_keys(params, msg);
6732 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006733 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006734
Hai Shalomc1a21442022-02-04 13:43:00 -08006735 ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006736 msg = NULL;
6737 if (ret) {
6738 wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
6739 "(%s)", ret, strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006740 } else {
Hai Shalom60840252021-02-19 19:02:11 -08006741#ifdef CONFIG_DRIVER_NL80211_QCA
6742 drv->roam_indication_done = false;
6743#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006744 wpa_printf(MSG_DEBUG,
6745 "nl80211: Connect request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006746 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006747
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006748fail:
Hai Shalom74f70d42019-02-11 14:42:39 -08006749 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006750 nlmsg_free(msg);
6751 return ret;
6752
6753}
6754
6755
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006756static int wpa_driver_nl80211_connect(
6757 struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006758 struct wpa_driver_associate_params *params,
Hai Shalomc1a21442022-02-04 13:43:00 -08006759 struct i802_bss *bss)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006760{
Jithu Jancea7c60b42014-12-03 18:54:40 +05306761 int ret;
6762
6763 /* Store the connection attempted bssid for future use */
6764 if (params->bssid)
6765 os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
6766 else
6767 os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
6768
Hai Shalomc1a21442022-02-04 13:43:00 -08006769 ret = wpa_driver_nl80211_try_connect(drv, params, bss);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006770 if (ret == -EALREADY) {
6771 /*
6772 * cfg80211 does not currently accept new connections if
6773 * we are already connected. As a workaround, force
6774 * disconnection and try again.
6775 */
6776 wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
6777 "disconnecting before reassociation "
6778 "attempt");
6779 if (wpa_driver_nl80211_disconnect(
Hai Shalomc1a21442022-02-04 13:43:00 -08006780 drv, WLAN_REASON_PREV_AUTH_NOT_VALID, bss))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006781 return -1;
Hai Shalomc1a21442022-02-04 13:43:00 -08006782 ret = wpa_driver_nl80211_try_connect(drv, params, bss);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006783 }
6784 return ret;
6785}
6786
6787
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006788static int wpa_driver_nl80211_associate(
6789 void *priv, struct wpa_driver_associate_params *params)
6790{
6791 struct i802_bss *bss = priv;
6792 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006793 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006794 struct nl_msg *msg;
6795
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006796 nl80211_unmask_11b_rates(bss);
6797
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006798 if (params->mode == IEEE80211_MODE_AP)
6799 return wpa_driver_nl80211_ap(drv, params);
6800
6801 if (params->mode == IEEE80211_MODE_IBSS)
6802 return wpa_driver_nl80211_ibss(drv, params);
6803
6804 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006805 enum nl80211_iftype nlmode = params->p2p ?
6806 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
6807
6808 if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006809 return -1;
Vinayak Yadawad14709082022-03-17 14:25:11 +05306810#ifdef CONFIG_DRIVER_NL80211_BRCM
Sunil Ravi89eba102022-09-13 21:04:37 -07006811 if ((params->key_mgmt_suite & WPA_KEY_MGMT_SAE) ||
6812 (params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE))
Vinayak Yadawad14709082022-03-17 14:25:11 +05306813#else
Sunil Ravi89eba102022-09-13 21:04:37 -07006814 if (wpa_key_mgmt_sae(params->key_mgmt_suite) ||
6815 wpa_key_mgmt_sae(params->allowed_key_mgmts))
Vinayak Yadawad14709082022-03-17 14:25:11 +05306816#endif /* CONFIG_DRIVER_NL80211_BRCM */
Hai Shalom74f70d42019-02-11 14:42:39 -08006817 bss->use_nl_connect = 1;
Hai Shalomb755a2a2020-04-23 21:49:02 -07006818 else
Hai Shalom74f70d42019-02-11 14:42:39 -08006819 bss->use_nl_connect = 0;
Hai Shalom74f70d42019-02-11 14:42:39 -08006820
Hai Shalomc1a21442022-02-04 13:43:00 -08006821 return wpa_driver_nl80211_connect(drv, params, bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006822 }
6823
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07006824 nl80211_mark_disconnected(drv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006825
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006826 wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
6827 drv->ifindex);
6828 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ASSOCIATE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006829 if (!msg)
6830 return -1;
6831
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006832 ret = nl80211_connect_common(drv, params, msg);
6833 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006834 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006835
Roshan Pius3a1667e2018-07-03 15:17:14 -07006836 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
6837 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
6838 goto fail;
6839
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006840 if (params->fils_kek) {
6841 wpa_printf(MSG_DEBUG, " * FILS KEK (len=%u)",
6842 (unsigned int) params->fils_kek_len);
6843 if (nla_put(msg, NL80211_ATTR_FILS_KEK, params->fils_kek_len,
6844 params->fils_kek))
6845 goto fail;
6846 }
6847 if (params->fils_nonces) {
6848 wpa_hexdump(MSG_DEBUG, " * FILS nonces (for AAD)",
6849 params->fils_nonces,
6850 params->fils_nonces_len);
6851 if (nla_put(msg, NL80211_ATTR_FILS_NONCES,
6852 params->fils_nonces_len, params->fils_nonces))
6853 goto fail;
6854 }
6855
Hai Shalomc1a21442022-02-04 13:43:00 -08006856 ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006857 msg = NULL;
6858 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006859 wpa_dbg(drv->ctx, MSG_DEBUG,
6860 "nl80211: MLME command failed (assoc): ret=%d (%s)",
6861 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006862 nl80211_dump_scan(drv);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006863 } else {
6864 wpa_printf(MSG_DEBUG,
6865 "nl80211: Association request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006866 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006867
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006868fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006869 nlmsg_free(msg);
6870 return ret;
6871}
6872
6873
6874static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006875 int ifindex, enum nl80211_iftype mode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006876{
6877 struct nl_msg *msg;
6878 int ret = -ENOBUFS;
6879
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006880 wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
6881 ifindex, mode, nl80211_iftype_str(mode));
6882
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006883 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
6884 if (!msg || nla_put_u32(msg, NL80211_ATTR_IFTYPE, mode))
6885 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006886
Hai Shalom899fcc72020-10-19 14:38:18 -07006887 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006888 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006889 if (!ret)
6890 return 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006891fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006892 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006893 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
6894 " %d (%s)", ifindex, mode, ret, strerror(-ret));
6895 return ret;
6896}
6897
6898
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006899static int wpa_driver_nl80211_set_mode_impl(
6900 struct i802_bss *bss,
6901 enum nl80211_iftype nlmode,
6902 struct hostapd_freq_params *desired_freq_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006903{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006904 struct wpa_driver_nl80211_data *drv = bss->drv;
6905 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006906 int i;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006907 int was_ap = is_ap_interface(drv->nlmode);
6908 int res;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006909 int mode_switch_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006910
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07006911 if (TEST_FAIL())
6912 return -1;
6913
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006914 mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
6915 if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))
6916 mode_switch_res = 0;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006917
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006918 if (mode_switch_res == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006919 drv->nlmode = nlmode;
6920 ret = 0;
6921 goto done;
6922 }
6923
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006924 if (mode_switch_res == -ENODEV)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006925 return -1;
6926
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006927 if (nlmode == drv->nlmode) {
6928 wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
6929 "requested mode - ignore error");
6930 ret = 0;
6931 goto done; /* Already in the requested mode */
6932 }
6933
6934 /* mac80211 doesn't allow mode changes while the device is up, so
6935 * take the device down, try to set the mode again, and bring the
6936 * device back up.
6937 */
6938 wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
6939 "interface down");
6940 for (i = 0; i < 10; i++) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006941 res = i802_set_iface_flags(bss, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006942 if (res == -EACCES || res == -ENODEV)
6943 break;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006944 if (res != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006945 wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
6946 "interface down");
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006947 os_sleep(0, 100000);
6948 continue;
6949 }
6950
6951 /*
6952 * Setting the mode will fail for some drivers if the phy is
6953 * on a frequency that the mode is disallowed in.
6954 */
6955 if (desired_freq_params) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006956 res = nl80211_set_channel(bss, desired_freq_params, 0);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006957 if (res) {
6958 wpa_printf(MSG_DEBUG,
6959 "nl80211: Failed to set frequency on interface");
6960 }
6961 }
6962
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006963 if (i == 0 && was_ap && !is_ap_interface(nlmode) &&
6964 bss->brname[0] &&
6965 (bss->added_if_into_bridge || bss->already_in_bridge)) {
6966 wpa_printf(MSG_DEBUG,
6967 "nl80211: Remove AP interface %s temporarily from the bridge %s to allow its mode to be set to STATION",
6968 bss->ifname, bss->brname);
6969 if (linux_br_del_if(drv->global->ioctl_sock,
6970 bss->brname, bss->ifname) < 0)
6971 wpa_printf(MSG_INFO,
6972 "nl80211: Failed to remove interface %s from bridge %s: %s",
6973 bss->ifname, bss->brname,
6974 strerror(errno));
6975 }
6976
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006977 /* Try to set the mode again while the interface is down */
6978 mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
6979 if (mode_switch_res == -EBUSY) {
6980 wpa_printf(MSG_DEBUG,
6981 "nl80211: Delaying mode set while interface going down");
6982 os_sleep(0, 100000);
6983 continue;
6984 }
6985 ret = mode_switch_res;
6986 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006987 }
6988
6989 if (!ret) {
6990 wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
6991 "interface is down");
6992 drv->nlmode = nlmode;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006993 drv->ignore_if_down_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006994 }
6995
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006996 /* Bring the interface back up */
6997 res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
6998 if (res != 0) {
6999 wpa_printf(MSG_DEBUG,
7000 "nl80211: Failed to set interface up after switching mode");
7001 ret = -1;
7002 }
7003
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007004done:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007005 if (ret) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007006 wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
7007 "from %d failed", nlmode, drv->nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007008 return ret;
7009 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007010
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007011 if (is_p2p_net_interface(nlmode)) {
7012 wpa_printf(MSG_DEBUG,
7013 "nl80211: Interface %s mode change to P2P - disable 11b rates",
7014 bss->ifname);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007015 nl80211_disable_11b_rates(drv, drv->ifindex, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007016 } else if (drv->disabled_11b_rates) {
7017 wpa_printf(MSG_DEBUG,
7018 "nl80211: Interface %s mode changed to non-P2P - re-enable 11b rates",
7019 bss->ifname);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007020 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007021 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007022
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007023 if (is_ap_interface(nlmode)) {
7024 nl80211_mgmt_unsubscribe(bss, "start AP");
7025 /* Setup additional AP mode functionality if needed */
7026 if (nl80211_setup_ap(bss))
7027 return -1;
7028 } else if (was_ap) {
7029 /* Remove additional AP mode functionality */
7030 nl80211_teardown_ap(bss);
7031 } else {
7032 nl80211_mgmt_unsubscribe(bss, "mode change");
7033 }
7034
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007035 if (is_mesh_interface(nlmode) &&
7036 nl80211_mgmt_subscribe_mesh(bss))
7037 return -1;
7038
Dmitry Shmidt04949592012-07-19 12:16:46 -07007039 if (!bss->in_deinit && !is_ap_interface(nlmode) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007040 !is_mesh_interface(nlmode) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007041 nl80211_mgmt_subscribe_non_ap(bss) < 0)
7042 wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
7043 "frame processing - ignore for now");
7044
7045 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007046}
7047
7048
Hai Shalom4fbc08f2020-05-18 12:37:00 -07007049void nl80211_restore_ap_mode(struct i802_bss *bss)
7050{
7051 struct wpa_driver_nl80211_data *drv = bss->drv;
7052 int was_ap = is_ap_interface(drv->nlmode);
leslc3979c32021-03-29 22:34:02 +08007053 int br_ifindex;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07007054
7055 wpa_driver_nl80211_set_mode(bss, drv->ap_scan_as_station);
7056 if (!was_ap && is_ap_interface(drv->ap_scan_as_station) &&
7057 bss->brname[0] &&
7058 (bss->added_if_into_bridge || bss->already_in_bridge)) {
7059 wpa_printf(MSG_DEBUG,
7060 "nl80211: Add AP interface %s back into the bridge %s",
7061 bss->ifname, bss->brname);
7062 if (linux_br_add_if(drv->global->ioctl_sock, bss->brname,
7063 bss->ifname) < 0) {
7064 wpa_printf(MSG_WARNING,
7065 "nl80211: Failed to add interface %s into bridge %s: %s",
7066 bss->ifname, bss->brname, strerror(errno));
7067 }
leslc3979c32021-03-29 22:34:02 +08007068 br_ifindex = if_nametoindex(bss->brname);
7069 add_ifidx(drv, br_ifindex, drv->ifindex);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07007070 }
7071 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
7072}
7073
7074
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007075int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
7076 enum nl80211_iftype nlmode)
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007077{
7078 return wpa_driver_nl80211_set_mode_impl(bss, nlmode, NULL);
7079}
7080
7081
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07007082static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
7083 struct hostapd_freq_params *freq)
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007084{
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007085 return wpa_driver_nl80211_set_mode_impl(bss, NL80211_IFTYPE_ADHOC,
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07007086 freq);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007087}
7088
7089
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007090static int wpa_driver_nl80211_get_capa(void *priv,
7091 struct wpa_driver_capa *capa)
7092{
7093 struct i802_bss *bss = priv;
7094 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07007095
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007096 if (!drv->has_capability)
7097 return -1;
7098 os_memcpy(capa, &drv->capa, sizeof(*capa));
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007099 if (drv->extended_capa && drv->extended_capa_mask) {
7100 capa->extended_capa = drv->extended_capa;
7101 capa->extended_capa_mask = drv->extended_capa_mask;
7102 capa->extended_capa_len = drv->extended_capa_len;
7103 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007104
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007105 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007106}
7107
7108
7109static int wpa_driver_nl80211_set_operstate(void *priv, int state)
7110{
7111 struct i802_bss *bss = priv;
7112 struct wpa_driver_nl80211_data *drv = bss->drv;
7113
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007114 wpa_printf(MSG_DEBUG, "nl80211: Set %s operstate %d->%d (%s)",
7115 bss->ifname, drv->operstate, state,
7116 state ? "UP" : "DORMANT");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007117 drv->operstate = state;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007118 return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007119 state ? IF_OPER_UP : IF_OPER_DORMANT);
7120}
7121
7122
7123static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
7124{
7125 struct i802_bss *bss = priv;
7126 struct wpa_driver_nl80211_data *drv = bss->drv;
7127 struct nl_msg *msg;
7128 struct nl80211_sta_flag_update upd;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007129 int ret;
Sunil Ravi89eba102022-09-13 21:04:37 -07007130 const u8 *connected_addr = drv->sta_mlo_info.valid_links ?
7131 drv->sta_mlo_info.ap_mld_addr : drv->bssid;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007132
Sunil Ravi89eba102022-09-13 21:04:37 -07007133 if (!drv->associated && is_zero_ether_addr(connected_addr) &&
7134 !authorized) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007135 wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated");
7136 return 0;
7137 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007138
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07007139 wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
Sunil Ravi89eba102022-09-13 21:04:37 -07007140 MACSTR, authorized ? "" : "un", MAC2STR(connected_addr));
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07007141
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007142 os_memset(&upd, 0, sizeof(upd));
7143 upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
7144 if (authorized)
7145 upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007146
7147 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
Sunil Ravi89eba102022-09-13 21:04:37 -07007148 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, connected_addr) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007149 nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd)) {
7150 nlmsg_free(msg);
7151 return -ENOBUFS;
7152 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007153
Hai Shalom899fcc72020-10-19 14:38:18 -07007154 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007155 if (!ret)
7156 return 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007157 wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)",
7158 ret, strerror(-ret));
7159 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007160}
7161
7162
Jouni Malinen75ecf522011-06-27 15:19:46 -07007163/* Set kernel driver on given frequency (MHz) */
7164static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007165{
Jouni Malinen75ecf522011-06-27 15:19:46 -07007166 struct i802_bss *bss = priv;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07007167 return nl80211_set_channel(bss, freq, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007168}
7169
7170
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007171static inline int min_int(int a, int b)
7172{
7173 if (a < b)
7174 return a;
7175 return b;
7176}
7177
7178
7179static int get_key_handler(struct nl_msg *msg, void *arg)
7180{
7181 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7182 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7183
7184 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7185 genlmsg_attrlen(gnlh, 0), NULL);
7186
7187 /*
7188 * TODO: validate the key index and mac address!
7189 * Otherwise, there's a race condition as soon as
7190 * the kernel starts sending key notifications.
7191 */
7192
7193 if (tb[NL80211_ATTR_KEY_SEQ])
7194 memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
7195 min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
Hai Shalom021b0b52019-04-10 11:17:58 -07007196 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007197 return NL_SKIP;
7198}
7199
7200
7201static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
7202 int idx, u8 *seq)
7203{
7204 struct i802_bss *bss = priv;
7205 struct wpa_driver_nl80211_data *drv = bss->drv;
7206 struct nl_msg *msg;
7207
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007208 msg = nl80211_ifindex_msg(drv, if_nametoindex(iface), 0,
7209 NL80211_CMD_GET_KEY);
7210 if (!msg ||
7211 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
7212 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, idx)) {
7213 nlmsg_free(msg);
7214 return -ENOBUFS;
7215 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007216
7217 memset(seq, 0, 6);
7218
Hai Shalom899fcc72020-10-19 14:38:18 -07007219 return send_and_recv_msgs(drv, msg, get_key_handler, seq, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007220}
7221
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007222
7223static int i802_set_rts(void *priv, int rts)
7224{
7225 struct i802_bss *bss = priv;
7226 struct wpa_driver_nl80211_data *drv = bss->drv;
7227 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007228 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007229 u32 val;
7230
Hai Shalom021b0b52019-04-10 11:17:58 -07007231 if (rts >= 2347 || rts == -1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007232 val = (u32) -1;
7233 else
7234 val = rts;
7235
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007236 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
7237 nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val)) {
7238 nlmsg_free(msg);
7239 return -ENOBUFS;
7240 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007241
Hai Shalom899fcc72020-10-19 14:38:18 -07007242 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007243 if (!ret)
7244 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007245 wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
7246 "%d (%s)", rts, ret, strerror(-ret));
7247 return ret;
7248}
7249
7250
7251static int i802_set_frag(void *priv, int frag)
7252{
7253 struct i802_bss *bss = priv;
7254 struct wpa_driver_nl80211_data *drv = bss->drv;
7255 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007256 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007257 u32 val;
7258
Hai Shalom021b0b52019-04-10 11:17:58 -07007259 if (frag >= 2346 || frag == -1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007260 val = (u32) -1;
7261 else
7262 val = frag;
7263
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007264 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
7265 nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val)) {
7266 nlmsg_free(msg);
7267 return -ENOBUFS;
7268 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007269
Hai Shalom899fcc72020-10-19 14:38:18 -07007270 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007271 if (!ret)
7272 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007273 wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
7274 "%d: %d (%s)", frag, ret, strerror(-ret));
7275 return ret;
7276}
7277
7278
7279static int i802_flush(void *priv)
7280{
7281 struct i802_bss *bss = priv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007282 struct nl_msg *msg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007283 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007284
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07007285 wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
7286 bss->ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007287
7288 /*
7289 * XXX: FIX! this needs to flush all VLANs too
7290 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007291 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
Hai Shalom899fcc72020-10-19 14:38:18 -07007292 res = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007293 if (res) {
7294 wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
7295 "(%s)", res, strerror(-res));
7296 }
7297 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007298}
7299
7300
Hai Shalom81f62d82019-07-22 12:10:00 -07007301static void get_sta_tid_stats(struct hostap_sta_driver_data *data,
7302 struct nlattr *attr)
7303{
7304 struct nlattr *tid_stats[NL80211_TID_STATS_MAX + 1], *tidattr;
7305 struct nlattr *txq_stats[NL80211_TXQ_STATS_MAX + 1];
7306 static struct nla_policy txq_stats_policy[NL80211_TXQ_STATS_MAX + 1] = {
7307 [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 },
7308 [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 },
7309 };
7310 int rem;
7311
7312 nla_for_each_nested(tidattr, attr, rem) {
7313 if (nla_parse_nested(tid_stats, NL80211_TID_STATS_MAX,
7314 tidattr, NULL) != 0 ||
7315 !tid_stats[NL80211_TID_STATS_TXQ_STATS] ||
7316 nla_parse_nested(txq_stats, NL80211_TXQ_STATS_MAX,
7317 tid_stats[NL80211_TID_STATS_TXQ_STATS],
7318 txq_stats_policy) != 0)
7319 continue;
7320 /* sum the backlogs over all TIDs for station */
7321 if (txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES])
7322 data->backlog_bytes += nla_get_u32(
7323 txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES]);
7324 if (txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS])
7325 data->backlog_bytes += nla_get_u32(
7326 txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS]);
7327 }
7328}
7329
7330
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007331static int get_sta_handler(struct nl_msg *msg, void *arg)
7332{
7333 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7334 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7335 struct hostap_sta_driver_data *data = arg;
7336 struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
7337 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
7338 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
7339 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
7340 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
7341 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
7342 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007343 [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007344 [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
7345 [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007346 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
Roshan Pius3a1667e2018-07-03 15:17:14 -07007347 [NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 },
Hai Shalom81f62d82019-07-22 12:10:00 -07007348 [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 },
7349 [NL80211_STA_INFO_TX_DURATION] = { .type = NLA_U64 },
Hai Shalomc1a21442022-02-04 13:43:00 -08007350 [NL80211_STA_INFO_CONNECTED_TIME] = { .type = NLA_U32 },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007351 };
7352 struct nlattr *rate[NL80211_RATE_INFO_MAX + 1];
7353 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
7354 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
7355 [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 },
7356 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
7357 [NL80211_RATE_INFO_VHT_MCS] = { .type = NLA_U8 },
7358 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
7359 [NL80211_RATE_INFO_VHT_NSS] = { .type = NLA_U8 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007360 };
7361
7362 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7363 genlmsg_attrlen(gnlh, 0), NULL);
7364
7365 /*
7366 * TODO: validate the interface and mac address!
7367 * Otherwise, there's a race condition as soon as
7368 * the kernel starts sending station notifications.
7369 */
7370
7371 if (!tb[NL80211_ATTR_STA_INFO]) {
7372 wpa_printf(MSG_DEBUG, "sta stats missing!");
7373 return NL_SKIP;
7374 }
7375 if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
7376 tb[NL80211_ATTR_STA_INFO],
7377 stats_policy)) {
7378 wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
7379 return NL_SKIP;
7380 }
7381
7382 if (stats[NL80211_STA_INFO_INACTIVE_TIME])
7383 data->inactive_msec =
7384 nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007385 /* For backwards compatibility, fetch the 32-bit counters first. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007386 if (stats[NL80211_STA_INFO_RX_BYTES])
7387 data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
7388 if (stats[NL80211_STA_INFO_TX_BYTES])
7389 data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007390 if (stats[NL80211_STA_INFO_RX_BYTES64] &&
7391 stats[NL80211_STA_INFO_TX_BYTES64]) {
7392 /*
7393 * The driver supports 64-bit counters, so use them to override
7394 * the 32-bit values.
7395 */
7396 data->rx_bytes =
7397 nla_get_u64(stats[NL80211_STA_INFO_RX_BYTES64]);
7398 data->tx_bytes =
7399 nla_get_u64(stats[NL80211_STA_INFO_TX_BYTES64]);
7400 data->bytes_64bit = 1;
7401 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007402 if (stats[NL80211_STA_INFO_RX_PACKETS])
7403 data->rx_packets =
7404 nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
7405 if (stats[NL80211_STA_INFO_TX_PACKETS])
7406 data->tx_packets =
7407 nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
Hai Shalom81f62d82019-07-22 12:10:00 -07007408 if (stats[NL80211_STA_INFO_RX_DURATION])
7409 data->rx_airtime =
7410 nla_get_u64(stats[NL80211_STA_INFO_RX_DURATION]);
7411 if (stats[NL80211_STA_INFO_TX_DURATION])
7412 data->tx_airtime =
7413 nla_get_u64(stats[NL80211_STA_INFO_TX_DURATION]);
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007414 if (stats[NL80211_STA_INFO_TX_FAILED])
7415 data->tx_retry_failed =
7416 nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007417 if (stats[NL80211_STA_INFO_SIGNAL])
7418 data->signal = nla_get_u8(stats[NL80211_STA_INFO_SIGNAL]);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007419 if (stats[NL80211_STA_INFO_ACK_SIGNAL]) {
7420 data->last_ack_rssi =
7421 nla_get_u8(stats[NL80211_STA_INFO_ACK_SIGNAL]);
7422 data->flags |= STA_DRV_DATA_LAST_ACK_RSSI;
7423 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007424
Hai Shalomc1a21442022-02-04 13:43:00 -08007425 if (stats[NL80211_STA_INFO_CONNECTED_TIME]) {
7426 data->connected_sec =
7427 nla_get_u32(stats[NL80211_STA_INFO_CONNECTED_TIME]);
7428 data->flags |= STA_DRV_DATA_CONN_TIME;
7429 }
7430
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007431 if (stats[NL80211_STA_INFO_TX_BITRATE] &&
7432 nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
7433 stats[NL80211_STA_INFO_TX_BITRATE],
7434 rate_policy) == 0) {
7435 if (rate[NL80211_RATE_INFO_BITRATE32])
7436 data->current_tx_rate =
7437 nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
7438 else if (rate[NL80211_RATE_INFO_BITRATE])
7439 data->current_tx_rate =
7440 nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
7441
7442 if (rate[NL80211_RATE_INFO_MCS]) {
7443 data->tx_mcs = nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
7444 data->flags |= STA_DRV_DATA_TX_MCS;
7445 }
7446 if (rate[NL80211_RATE_INFO_VHT_MCS]) {
7447 data->tx_vhtmcs =
7448 nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
7449 data->flags |= STA_DRV_DATA_TX_VHT_MCS;
7450 }
7451 if (rate[NL80211_RATE_INFO_SHORT_GI])
7452 data->flags |= STA_DRV_DATA_TX_SHORT_GI;
7453 if (rate[NL80211_RATE_INFO_VHT_NSS]) {
7454 data->tx_vht_nss =
7455 nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
7456 data->flags |= STA_DRV_DATA_TX_VHT_NSS;
7457 }
7458 }
7459
7460 if (stats[NL80211_STA_INFO_RX_BITRATE] &&
7461 nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
7462 stats[NL80211_STA_INFO_RX_BITRATE],
7463 rate_policy) == 0) {
7464 if (rate[NL80211_RATE_INFO_BITRATE32])
7465 data->current_rx_rate =
7466 nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
7467 else if (rate[NL80211_RATE_INFO_BITRATE])
7468 data->current_rx_rate =
7469 nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
7470
7471 if (rate[NL80211_RATE_INFO_MCS]) {
7472 data->rx_mcs =
7473 nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
7474 data->flags |= STA_DRV_DATA_RX_MCS;
7475 }
7476 if (rate[NL80211_RATE_INFO_VHT_MCS]) {
7477 data->rx_vhtmcs =
7478 nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
7479 data->flags |= STA_DRV_DATA_RX_VHT_MCS;
7480 }
7481 if (rate[NL80211_RATE_INFO_SHORT_GI])
7482 data->flags |= STA_DRV_DATA_RX_SHORT_GI;
7483 if (rate[NL80211_RATE_INFO_VHT_NSS]) {
7484 data->rx_vht_nss =
7485 nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
7486 data->flags |= STA_DRV_DATA_RX_VHT_NSS;
7487 }
7488 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007489
Hai Shalom81f62d82019-07-22 12:10:00 -07007490 if (stats[NL80211_STA_INFO_TID_STATS])
7491 get_sta_tid_stats(data, stats[NL80211_STA_INFO_TID_STATS]);
7492
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007493 return NL_SKIP;
7494}
7495
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007496static int i802_read_sta_data(struct i802_bss *bss,
7497 struct hostap_sta_driver_data *data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007498 const u8 *addr)
7499{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007500 struct nl_msg *msg;
7501
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007502 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_STATION)) ||
7503 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
7504 nlmsg_free(msg);
7505 return -ENOBUFS;
7506 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007507
Hai Shalom899fcc72020-10-19 14:38:18 -07007508 return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data,
7509 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007510}
7511
7512
7513static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
7514 int cw_min, int cw_max, int burst_time)
7515{
7516 struct i802_bss *bss = priv;
7517 struct wpa_driver_nl80211_data *drv = bss->drv;
7518 struct nl_msg *msg;
7519 struct nlattr *txq, *params;
Hai Shalom74f70d42019-02-11 14:42:39 -08007520 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007521
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007522 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007523 if (!msg)
7524 return -1;
7525
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007526 txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
7527 if (!txq)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007528 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007529
7530 /* We are only sending parameters for a single TXQ at a time */
7531 params = nla_nest_start(msg, 1);
7532 if (!params)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007533 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007534
7535 switch (queue) {
7536 case 0:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007537 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO))
7538 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007539 break;
7540 case 1:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007541 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI))
7542 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007543 break;
7544 case 2:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007545 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE))
7546 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007547 break;
7548 case 3:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007549 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK))
7550 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007551 break;
7552 }
7553 /* Burst time is configured in units of 0.1 msec and TXOP parameter in
7554 * 32 usec, so need to convert the value here. */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007555 if (nla_put_u16(msg, NL80211_TXQ_ATTR_TXOP,
7556 (burst_time * 100 + 16) / 32) ||
7557 nla_put_u16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min) ||
7558 nla_put_u16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max) ||
7559 nla_put_u8(msg, NL80211_TXQ_ATTR_AIFS, aifs))
7560 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007561
7562 nla_nest_end(msg, params);
7563
7564 nla_nest_end(msg, txq);
7565
Hai Shalom899fcc72020-10-19 14:38:18 -07007566 res = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalom74f70d42019-02-11 14:42:39 -08007567 wpa_printf(MSG_DEBUG,
7568 "nl80211: TX queue param set: queue=%d aifs=%d cw_min=%d cw_max=%d burst_time=%d --> res=%d",
7569 queue, aifs, cw_min, cw_max, burst_time, res);
7570 if (res == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007571 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007572 msg = NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007573fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007574 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007575 return -1;
7576}
7577
7578
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007579static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007580 const char *ifname, int vlan_id)
7581{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007582 struct wpa_driver_nl80211_data *drv = bss->drv;
7583 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007584 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007585
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007586 wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
7587 ", ifname=%s[%d], vlan_id=%d)",
7588 bss->ifname, if_nametoindex(bss->ifname),
7589 MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007590 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
7591 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Hai Shalom899fcc72020-10-19 14:38:18 -07007592 (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) &&
Hai Shalomfdcde762020-04-02 11:19:20 -07007593 nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007594 nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
7595 nlmsg_free(msg);
7596 return -ENOBUFS;
7597 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007598
Hai Shalom899fcc72020-10-19 14:38:18 -07007599 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007600 if (ret < 0) {
7601 wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
7602 MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
7603 MAC2STR(addr), ifname, vlan_id, ret,
7604 strerror(-ret));
7605 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007606 return ret;
7607}
7608
7609
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007610static int i802_get_inact_sec(void *priv, const u8 *addr)
7611{
7612 struct hostap_sta_driver_data data;
7613 int ret;
7614
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08007615 os_memset(&data, 0, sizeof(data));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007616 data.inactive_msec = (unsigned long) -1;
7617 ret = i802_read_sta_data(priv, &data, addr);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007618 if (ret == -ENOENT)
7619 return -ENOENT;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007620 if (ret || data.inactive_msec == (unsigned long) -1)
7621 return -1;
7622 return data.inactive_msec / 1000;
7623}
7624
7625
7626static int i802_sta_clear_stats(void *priv, const u8 *addr)
7627{
7628#if 0
7629 /* TODO */
7630#endif
7631 return 0;
7632}
7633
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007634
7635static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -07007636 u16 reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007637{
7638 struct i802_bss *bss = priv;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007639 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007640 struct ieee80211_mgmt mgmt;
Dmitry Shmidt29333592017-01-09 12:27:11 -08007641 u8 channel;
7642
7643 if (ieee80211_freq_to_chan(bss->freq, &channel) ==
7644 HOSTAPD_MODE_IEEE80211AD) {
7645 /* Deauthentication is not used in DMG/IEEE 802.11ad;
7646 * disassociate the STA instead. */
7647 return i802_sta_disassoc(priv, own_addr, addr, reason);
7648 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007649
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007650 if (is_mesh_interface(drv->nlmode))
7651 return -1;
7652
Dmitry Shmidt04949592012-07-19 12:16:46 -07007653 if (drv->device_ap_sme)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007654 return wpa_driver_nl80211_sta_remove(bss, addr, 1, reason);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007655
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007656 memset(&mgmt, 0, sizeof(mgmt));
7657 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
7658 WLAN_FC_STYPE_DEAUTH);
7659 memcpy(mgmt.da, addr, ETH_ALEN);
7660 memcpy(mgmt.sa, own_addr, ETH_ALEN);
7661 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
7662 mgmt.u.deauth.reason_code = host_to_le16(reason);
7663 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
7664 IEEE80211_HDRLEN +
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007665 sizeof(mgmt.u.deauth), 0, 0, 0, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -07007666 0, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007667}
7668
7669
7670static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -07007671 u16 reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007672{
7673 struct i802_bss *bss = priv;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007674 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007675 struct ieee80211_mgmt mgmt;
7676
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007677 if (is_mesh_interface(drv->nlmode))
7678 return -1;
7679
Dmitry Shmidt04949592012-07-19 12:16:46 -07007680 if (drv->device_ap_sme)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007681 return wpa_driver_nl80211_sta_remove(bss, addr, 0, reason);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007682
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007683 memset(&mgmt, 0, sizeof(mgmt));
7684 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
7685 WLAN_FC_STYPE_DISASSOC);
7686 memcpy(mgmt.da, addr, ETH_ALEN);
7687 memcpy(mgmt.sa, own_addr, ETH_ALEN);
7688 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
7689 mgmt.u.disassoc.reason_code = host_to_le16(reason);
7690 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
7691 IEEE80211_HDRLEN +
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007692 sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -07007693 0, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007694}
7695
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007696
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007697static void dump_ifidx(struct wpa_driver_nl80211_data *drv)
7698{
7699 char buf[200], *pos, *end;
7700 int i, res;
7701
7702 pos = buf;
7703 end = pos + sizeof(buf);
7704
7705 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007706 if (!drv->if_indices[i].ifindex)
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007707 continue;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007708 res = os_snprintf(pos, end - pos, " %d(%d)",
Hai Shalom81f62d82019-07-22 12:10:00 -07007709 drv->if_indices[i].ifindex,
7710 drv->if_indices[i].reason);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007711 if (os_snprintf_error(end - pos, res))
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007712 break;
7713 pos += res;
7714 }
7715 *pos = '\0';
7716
7717 wpa_printf(MSG_DEBUG, "nl80211: if_indices[%d]:%s",
7718 drv->num_if_indices, buf);
7719}
7720
7721
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007722static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
7723 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007724{
7725 int i;
Hai Shalom81f62d82019-07-22 12:10:00 -07007726 struct drv_nl80211_if_info *old;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007727
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007728 wpa_printf(MSG_DEBUG,
7729 "nl80211: Add own interface ifindex %d (ifidx_reason %d)",
7730 ifidx, ifidx_reason);
7731 if (have_ifidx(drv, ifidx, ifidx_reason)) {
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007732 wpa_printf(MSG_DEBUG, "nl80211: ifindex %d already in the list",
7733 ifidx);
7734 return;
7735 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07007736 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007737 if (drv->if_indices[i].ifindex == 0) {
7738 drv->if_indices[i].ifindex = ifidx;
7739 drv->if_indices[i].reason = ifidx_reason;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007740 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007741 return;
7742 }
7743 }
7744
7745 if (drv->if_indices != drv->default_if_indices)
7746 old = drv->if_indices;
7747 else
7748 old = NULL;
7749
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007750 drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
Hai Shalom81f62d82019-07-22 12:10:00 -07007751 sizeof(*old));
Jouni Malinen75ecf522011-06-27 15:19:46 -07007752 if (!drv->if_indices) {
7753 if (!old)
7754 drv->if_indices = drv->default_if_indices;
7755 else
7756 drv->if_indices = old;
7757 wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
7758 "interfaces");
7759 wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
7760 return;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007761 }
7762 if (!old)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007763 os_memcpy(drv->if_indices, drv->default_if_indices,
7764 sizeof(drv->default_if_indices));
Hai Shalom81f62d82019-07-22 12:10:00 -07007765 drv->if_indices[drv->num_if_indices].ifindex = ifidx;
7766 drv->if_indices[drv->num_if_indices].reason = ifidx_reason;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007767 drv->num_if_indices++;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007768 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007769}
7770
7771
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007772static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
7773 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007774{
7775 int i;
7776
7777 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007778 if ((drv->if_indices[i].ifindex == ifidx ||
7779 ifidx == IFIDX_ANY) &&
7780 (drv->if_indices[i].reason == ifidx_reason ||
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007781 ifidx_reason == IFIDX_ANY)) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007782 drv->if_indices[i].ifindex = 0;
7783 drv->if_indices[i].reason = 0;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007784 break;
7785 }
7786 }
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007787 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007788}
7789
7790
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007791static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
7792 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007793{
7794 int i;
7795
7796 for (i = 0; i < drv->num_if_indices; i++)
Hai Shalom81f62d82019-07-22 12:10:00 -07007797 if (drv->if_indices[i].ifindex == ifidx &&
7798 (drv->if_indices[i].reason == ifidx_reason ||
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007799 ifidx_reason == IFIDX_ANY))
Jouni Malinen75ecf522011-06-27 15:19:46 -07007800 return 1;
7801
7802 return 0;
7803}
7804
7805
7806static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07007807 const char *bridge_ifname, char *ifname_wds)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007808{
7809 struct i802_bss *bss = priv;
7810 struct wpa_driver_nl80211_data *drv = bss->drv;
7811 char name[IFNAMSIZ + 1];
Roshan Pius3a1667e2018-07-03 15:17:14 -07007812 union wpa_event_data event;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08007813 int ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007814
Hai Shalom39ba6fc2019-01-22 12:40:38 -08007815 ret = os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
7816 if (ret >= (int) sizeof(name))
7817 wpa_printf(MSG_WARNING,
7818 "nl80211: WDS interface name was truncated");
7819 else if (ret < 0)
7820 return ret;
7821
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07007822 if (ifname_wds)
7823 os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
7824
Jouni Malinen75ecf522011-06-27 15:19:46 -07007825 wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
7826 " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
7827 if (val) {
7828 if (!if_nametoindex(name)) {
7829 if (nl80211_create_iface(drv, name,
7830 NL80211_IFTYPE_AP_VLAN,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007831 bss->addr, 1, NULL, NULL, 0) <
7832 0)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007833 return -1;
7834 if (bridge_ifname &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007835 linux_br_add_if(drv->global->ioctl_sock,
7836 bridge_ifname, name) < 0)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007837 return -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007838
7839 os_memset(&event, 0, sizeof(event));
7840 event.wds_sta_interface.sta_addr = addr;
7841 event.wds_sta_interface.ifname = name;
7842 event.wds_sta_interface.istatus = INTERFACE_ADDED;
Hai Shalomce48b4a2018-09-05 11:41:35 -07007843 wpa_supplicant_event(bss->ctx,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007844 EVENT_WDS_STA_INTERFACE_STATUS,
7845 &event);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007846 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007847 if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
7848 wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
7849 "interface %s up", name);
7850 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07007851 return i802_set_sta_vlan(priv, addr, name, 0);
7852 } else {
Hai Shalom74f70d42019-02-11 14:42:39 -08007853 if (bridge_ifname &&
7854 linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
7855 name) < 0)
7856 wpa_printf(MSG_INFO,
7857 "nl80211: Failed to remove interface %s from bridge %s: %s",
7858 name, bridge_ifname, strerror(errno));
Dmitry Shmidtaa532512012-09-24 10:35:31 -07007859
Jouni Malinen75ecf522011-06-27 15:19:46 -07007860 i802_set_sta_vlan(priv, addr, bss->ifname, 0);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007861 nl80211_remove_iface(drv, if_nametoindex(name));
Roshan Pius3a1667e2018-07-03 15:17:14 -07007862 os_memset(&event, 0, sizeof(event));
7863 event.wds_sta_interface.sta_addr = addr;
7864 event.wds_sta_interface.ifname = name;
7865 event.wds_sta_interface.istatus = INTERFACE_REMOVED;
Hai Shalomce48b4a2018-09-05 11:41:35 -07007866 wpa_supplicant_event(bss->ctx, EVENT_WDS_STA_INTERFACE_STATUS,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007867 &event);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007868 return 0;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007869 }
7870}
7871
7872
7873static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
7874{
7875 struct wpa_driver_nl80211_data *drv = eloop_ctx;
7876 struct sockaddr_ll lladdr;
7877 unsigned char buf[3000];
7878 int len;
7879 socklen_t fromlen = sizeof(lladdr);
7880
7881 len = recvfrom(sock, buf, sizeof(buf), 0,
7882 (struct sockaddr *)&lladdr, &fromlen);
7883 if (len < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007884 wpa_printf(MSG_ERROR, "nl80211: EAPOL recv failed: %s",
7885 strerror(errno));
Jouni Malinen75ecf522011-06-27 15:19:46 -07007886 return;
7887 }
7888
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007889 if (have_ifidx(drv, lladdr.sll_ifindex, IFIDX_ANY))
Jouni Malinen75ecf522011-06-27 15:19:46 -07007890 drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
7891}
7892
7893
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007894static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
7895 struct i802_bss *bss,
7896 const char *brname, const char *ifname)
7897{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007898 int br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007899 char in_br[IFNAMSIZ];
7900
7901 os_strlcpy(bss->brname, brname, IFNAMSIZ);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007902 br_ifindex = if_nametoindex(brname);
7903 if (br_ifindex == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007904 /*
7905 * Bridge was configured, but the bridge device does
7906 * not exist. Try to add it now.
7907 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007908 if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007909 wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
7910 "bridge interface %s: %s",
7911 brname, strerror(errno));
7912 return -1;
7913 }
7914 bss->added_bridge = 1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007915 br_ifindex = if_nametoindex(brname);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007916 add_ifidx(drv, br_ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007917 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007918 bss->br_ifindex = br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007919
7920 if (linux_br_get(in_br, ifname) == 0) {
Hai Shalomc9e41a12018-07-31 14:41:42 -07007921 if (os_strcmp(in_br, brname) == 0) {
7922 bss->already_in_bridge = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007923 return 0; /* already in the bridge */
Hai Shalomc9e41a12018-07-31 14:41:42 -07007924 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007925
7926 wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
7927 "bridge %s", ifname, in_br);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007928 if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
7929 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007930 wpa_printf(MSG_ERROR, "nl80211: Failed to "
7931 "remove interface %s from bridge "
7932 "%s: %s",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007933 ifname, in_br, strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007934 return -1;
7935 }
7936 }
7937
7938 wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
7939 ifname, brname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007940 if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08007941 wpa_printf(MSG_WARNING,
7942 "nl80211: Failed to add interface %s into bridge %s: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007943 ifname, brname, strerror(errno));
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08007944 /* Try to continue without the interface being in a bridge. This
7945 * may be needed for some cases, e.g., with Open vSwitch, where
7946 * an external component will need to handle bridge
7947 * configuration. */
7948 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007949 }
7950 bss->added_if_into_bridge = 1;
7951
7952 return 0;
7953}
7954
7955
7956static void *i802_init(struct hostapd_data *hapd,
7957 struct wpa_init_params *params)
7958{
7959 struct wpa_driver_nl80211_data *drv;
7960 struct i802_bss *bss;
7961 size_t i;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007962 char master_ifname[IFNAMSIZ];
7963 int ifindex, br_ifindex = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007964 int br_added = 0;
7965
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08007966 bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
7967 params->global_priv, 1,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007968 params->bssid, params->driver_params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007969 if (bss == NULL)
7970 return NULL;
7971
7972 drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007973
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007974 if (linux_br_get(master_ifname, params->ifname) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007975 wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007976 params->ifname, master_ifname);
7977 br_ifindex = if_nametoindex(master_ifname);
7978 os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
7979 } else if ((params->num_bridge == 0 || !params->bridge[0]) &&
7980 linux_master_get(master_ifname, params->ifname) == 0) {
7981 wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in master %s",
7982 params->ifname, master_ifname);
7983 /* start listening for EAPOL on the master interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007984 add_ifidx(drv, if_nametoindex(master_ifname), drv->ifindex);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08007985
7986 /* check if master itself is under bridge */
7987 if (linux_br_get(master_ifname, master_ifname) == 0) {
7988 wpa_printf(MSG_DEBUG, "nl80211: which is in bridge %s",
7989 master_ifname);
7990 br_ifindex = if_nametoindex(master_ifname);
7991 os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
7992 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007993 } else {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007994 master_ifname[0] = '\0';
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007995 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007996
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007997 bss->br_ifindex = br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007998
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007999 for (i = 0; i < params->num_bridge; i++) {
8000 if (params->bridge[i]) {
8001 ifindex = if_nametoindex(params->bridge[i]);
8002 if (ifindex)
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008003 add_ifidx(drv, ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008004 if (ifindex == br_ifindex)
8005 br_added = 1;
8006 }
8007 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008008
8009 /* start listening for EAPOL on the default AP interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008010 add_ifidx(drv, drv->ifindex, IFIDX_ANY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008011
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008012 if (params->num_bridge && params->bridge[0]) {
8013 if (i802_check_bridge(drv, bss, params->bridge[0],
8014 params->ifname) < 0)
8015 goto failed;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008016 if (os_strcmp(params->bridge[0], master_ifname) != 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008017 br_added = 1;
8018 }
8019
8020 if (!br_added && br_ifindex &&
8021 (params->num_bridge == 0 || !params->bridge[0]))
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008022 add_ifidx(drv, br_ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008023
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07008024#ifdef CONFIG_LIBNL3_ROUTE
Hai Shalomc9e41a12018-07-31 14:41:42 -07008025 if (bss->added_if_into_bridge || bss->already_in_bridge) {
Hai Shalomfdcde762020-04-02 11:19:20 -07008026 int err;
8027
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07008028 drv->rtnl_sk = nl_socket_alloc();
8029 if (drv->rtnl_sk == NULL) {
8030 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
8031 goto failed;
8032 }
8033
Hai Shalomfdcde762020-04-02 11:19:20 -07008034 err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE);
8035 if (err) {
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07008036 wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -07008037 nl_geterror(err));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07008038 goto failed;
8039 }
8040 }
8041#endif /* CONFIG_LIBNL3_ROUTE */
8042
Hai Shalomb755a2a2020-04-23 21:49:02 -07008043 if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) {
8044 wpa_printf(MSG_DEBUG,
8045 "nl80211: Do not open EAPOL RX socket - using control port for RX");
8046 goto skip_eapol_sock;
8047 }
8048
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008049 drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
8050 if (drv->eapol_sock < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008051 wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
8052 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008053 goto failed;
8054 }
8055
8056 if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
8057 {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008058 wpa_printf(MSG_INFO, "nl80211: Could not register read socket for eapol");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008059 goto failed;
8060 }
Hai Shalomb755a2a2020-04-23 21:49:02 -07008061skip_eapol_sock:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008062
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008063 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
8064 params->own_addr))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008065 goto failed;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07008066 os_memcpy(drv->perm_addr, params->own_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008067
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008068 memcpy(bss->addr, params->own_addr, ETH_ALEN);
8069
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008070 return bss;
8071
8072failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008073 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008074 return NULL;
8075}
8076
8077
8078static void i802_deinit(void *priv)
8079{
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008080 struct i802_bss *bss = priv;
8081 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008082}
8083
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008084
8085static enum nl80211_iftype wpa_driver_nl80211_if_type(
8086 enum wpa_driver_if_type type)
8087{
8088 switch (type) {
8089 case WPA_IF_STATION:
8090 return NL80211_IFTYPE_STATION;
8091 case WPA_IF_P2P_CLIENT:
8092 case WPA_IF_P2P_GROUP:
8093 return NL80211_IFTYPE_P2P_CLIENT;
8094 case WPA_IF_AP_VLAN:
8095 return NL80211_IFTYPE_AP_VLAN;
8096 case WPA_IF_AP_BSS:
8097 return NL80211_IFTYPE_AP;
8098 case WPA_IF_P2P_GO:
8099 return NL80211_IFTYPE_P2P_GO;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008100 case WPA_IF_P2P_DEVICE:
8101 return NL80211_IFTYPE_P2P_DEVICE;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008102 case WPA_IF_MESH:
8103 return NL80211_IFTYPE_MESH_POINT;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008104 default:
8105 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008106 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008107}
8108
8109
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008110static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
8111{
8112 struct wpa_driver_nl80211_data *drv;
8113 dl_list_for_each(drv, &global->interfaces,
8114 struct wpa_driver_nl80211_data, list) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008115 if (os_memcmp(addr, drv->first_bss->addr, ETH_ALEN) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008116 return 1;
8117 }
8118 return 0;
8119}
8120
8121
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008122static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008123{
8124 unsigned int idx;
8125
8126 if (!drv->global)
8127 return -1;
8128
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008129 os_memcpy(new_addr, drv->first_bss->addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008130 for (idx = 0; idx < 64; idx++) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008131 new_addr[0] = drv->first_bss->addr[0] | 0x02;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008132 new_addr[0] ^= idx << 2;
8133 if (!nl80211_addr_in_use(drv->global, new_addr))
8134 break;
8135 }
8136 if (idx == 64)
8137 return -1;
8138
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008139 wpa_printf(MSG_DEBUG, "nl80211: Assigned new virtual interface address "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008140 MACSTR, MAC2STR(new_addr));
8141
8142 return 0;
8143}
8144
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008145
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008146struct wdev_info {
8147 u64 wdev_id;
8148 int wdev_id_set;
8149 u8 macaddr[ETH_ALEN];
8150};
8151
8152static int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
8153{
8154 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8155 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8156 struct wdev_info *wi = arg;
8157
8158 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8159 genlmsg_attrlen(gnlh, 0), NULL);
8160 if (tb[NL80211_ATTR_WDEV]) {
8161 wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
8162 wi->wdev_id_set = 1;
8163 }
8164
8165 if (tb[NL80211_ATTR_MAC])
8166 os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
8167 ETH_ALEN);
8168
8169 return NL_SKIP;
8170}
8171
8172
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008173static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
8174 const char *ifname, const u8 *addr,
8175 void *bss_ctx, void **drv_priv,
8176 char *force_ifname, u8 *if_addr,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008177 const char *bridge, int use_existing,
8178 int setup_ap)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008179{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008180 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008181 struct i802_bss *bss = priv;
8182 struct wpa_driver_nl80211_data *drv = bss->drv;
8183 int ifidx;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008184 int added = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008185
8186 if (addr)
8187 os_memcpy(if_addr, addr, ETH_ALEN);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008188 nlmode = wpa_driver_nl80211_if_type(type);
8189 if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
8190 struct wdev_info p2pdev_info;
8191
8192 os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
8193 ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
8194 0, nl80211_wdev_handler,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008195 &p2pdev_info, use_existing);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008196 if (!p2pdev_info.wdev_id_set || ifidx != 0) {
8197 wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
8198 ifname);
8199 return -1;
8200 }
8201
8202 drv->global->if_add_wdevid = p2pdev_info.wdev_id;
8203 drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
Mir Ali8a8f1002020-10-06 22:41:40 +05308204 if (!is_zero_ether_addr(p2pdev_info.macaddr)) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008205 os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
Mir Ali8a8f1002020-10-06 22:41:40 +05308206 os_memcpy(drv->global->p2p_perm_addr, p2pdev_info.macaddr, ETH_ALEN);
8207 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008208 wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
8209 ifname,
8210 (long long unsigned int) p2pdev_info.wdev_id);
8211 } else {
8212 ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008213 0, NULL, NULL, use_existing);
8214 if (use_existing && ifidx == -ENFILE) {
8215 added = 0;
8216 ifidx = if_nametoindex(ifname);
8217 } else if (ifidx < 0) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008218 return -1;
8219 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008220 }
8221
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008222 if (!addr) {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07008223 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008224 os_memcpy(if_addr, bss->addr, ETH_ALEN);
8225 else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07008226 ifname, if_addr) < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008227 if (added)
8228 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008229 return -1;
8230 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008231 }
8232
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008233 if (!addr &&
8234 (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07008235 type == WPA_IF_P2P_GO || type == WPA_IF_MESH ||
8236 type == WPA_IF_STATION)) {
8237 /* Enforce unique address */
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008238 u8 new_addr[ETH_ALEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008239
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008240 if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008241 new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07008242 if (added)
8243 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008244 return -1;
8245 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008246 if (nl80211_addr_in_use(drv->global, new_addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008247 wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07008248 "for interface %s type %d", ifname, type);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008249 if (nl80211_vif_addr(drv, new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07008250 if (added)
8251 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008252 return -1;
8253 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008254 if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008255 new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07008256 if (added)
8257 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008258 return -1;
8259 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008260 }
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008261 os_memcpy(if_addr, new_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008262 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008263
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008264 if (type == WPA_IF_AP_BSS && setup_ap) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008265 struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
8266 if (new_bss == NULL) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008267 if (added)
8268 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008269 return -1;
8270 }
8271
8272 if (bridge &&
8273 i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
8274 wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
8275 "interface %s to a bridge %s",
8276 ifname, bridge);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008277 if (added)
8278 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008279 os_free(new_bss);
8280 return -1;
8281 }
8282
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008283 if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
8284 {
Dmitry Shmidt71757432014-06-02 13:50:35 -07008285 if (added)
8286 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008287 os_free(new_bss);
8288 return -1;
8289 }
8290 os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008291 os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008292 new_bss->ifindex = ifidx;
8293 new_bss->drv = drv;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008294 new_bss->next = drv->first_bss->next;
8295 new_bss->freq = drv->first_bss->freq;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08008296 new_bss->ctx = bss_ctx;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008297 new_bss->added_if = added;
8298 drv->first_bss->next = new_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008299 if (drv_priv)
8300 *drv_priv = new_bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008301 nl80211_init_bss(new_bss);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008302
8303 /* Subscribe management frames for this WPA_IF_AP_BSS */
8304 if (nl80211_setup_ap(new_bss))
8305 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008306 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008307
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008308 if (drv->global)
8309 drv->global->if_add_ifindex = ifidx;
8310
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07008311 /*
8312 * Some virtual interfaces need to process EAPOL packets and events on
8313 * the parent interface. This is used mainly with hostapd.
8314 */
8315 if (ifidx > 0 &&
8316 (drv->hostapd ||
8317 nlmode == NL80211_IFTYPE_AP_VLAN ||
8318 nlmode == NL80211_IFTYPE_WDS ||
8319 nlmode == NL80211_IFTYPE_MONITOR))
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008320 add_ifidx(drv, ifidx, IFIDX_ANY);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008321
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008322 return 0;
8323}
8324
8325
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008326static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008327 enum wpa_driver_if_type type,
8328 const char *ifname)
8329{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008330 struct wpa_driver_nl80211_data *drv = bss->drv;
8331 int ifindex = if_nametoindex(ifname);
8332
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008333 wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
8334 __func__, type, ifname, ifindex, bss->added_if);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08008335 if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
Dmitry Shmidt051af732013-10-22 13:52:46 -07008336 nl80211_remove_iface(drv, ifindex);
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07008337 else if (ifindex > 0 && !bss->added_if) {
8338 struct wpa_driver_nl80211_data *drv2;
8339 dl_list_for_each(drv2, &drv->global->interfaces,
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008340 struct wpa_driver_nl80211_data, list) {
8341 del_ifidx(drv2, ifindex, IFIDX_ANY);
8342 del_ifidx(drv2, IFIDX_ANY, ifindex);
8343 }
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07008344 }
Dmitry Shmidtaa532512012-09-24 10:35:31 -07008345
Dmitry Shmidtaa532512012-09-24 10:35:31 -07008346 if (type != WPA_IF_AP_BSS)
8347 return 0;
8348
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008349 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008350 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
8351 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008352 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
8353 "interface %s from bridge %s: %s",
8354 bss->ifname, bss->brname, strerror(errno));
8355 }
8356 if (bss->added_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008357 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008358 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
8359 "bridge %s: %s",
8360 bss->brname, strerror(errno));
8361 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008362
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008363 if (bss != drv->first_bss) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008364 struct i802_bss *tbss;
8365
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008366 wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it");
8367 for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008368 if (tbss->next == bss) {
8369 tbss->next = bss->next;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008370 /* Unsubscribe management frames */
8371 nl80211_teardown_ap(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008372 nl80211_destroy_bss(bss);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008373 if (!bss->added_if)
8374 i802_set_iface_flags(bss, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008375 os_free(bss);
8376 bss = NULL;
8377 break;
8378 }
8379 }
8380 if (bss)
8381 wpa_printf(MSG_INFO, "nl80211: %s - could not find "
8382 "BSS %p in the list", __func__, bss);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008383 } else {
8384 wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
8385 nl80211_teardown_ap(bss);
8386 if (!bss->added_if && !drv->first_bss->next)
Paul Stewart092955c2017-02-06 09:13:09 -08008387 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008388 nl80211_destroy_bss(bss);
8389 if (!bss->added_if)
8390 i802_set_iface_flags(bss, 0);
8391 if (drv->first_bss->next) {
8392 drv->first_bss = drv->first_bss->next;
8393 drv->ctx = drv->first_bss->ctx;
8394 os_free(bss);
8395 } else {
8396 wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
8397 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008398 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008399
8400 return 0;
8401}
8402
8403
8404static int cookie_handler(struct nl_msg *msg, void *arg)
8405{
8406 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8407 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8408 u64 *cookie = arg;
8409 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8410 genlmsg_attrlen(gnlh, 0), NULL);
8411 if (tb[NL80211_ATTR_COOKIE])
8412 *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
8413 return NL_SKIP;
8414}
8415
8416
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008417static int nl80211_send_frame_cmd(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008418 unsigned int freq, unsigned int wait,
8419 const u8 *buf, size_t buf_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07008420 int save_cookie, int no_cck, int no_ack,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008421 int offchanok, const u16 *csa_offs,
8422 size_t csa_offs_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008423{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008424 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008425 struct nl_msg *msg;
8426 u64 cookie;
8427 int ret = -1;
8428
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008429 wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
Dmitry Shmidt04949592012-07-19 12:16:46 -07008430 "no_ack=%d offchanok=%d",
8431 freq, wait, no_cck, no_ack, offchanok);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07008432 wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008433
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008434 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME)) ||
8435 (freq && nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
8436 (wait && nla_put_u32(msg, NL80211_ATTR_DURATION, wait)) ||
8437 (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
8438 drv->test_use_roc_tx) &&
8439 nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) ||
8440 (no_cck && nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) ||
8441 (no_ack && nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK)) ||
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008442 (csa_offs && nla_put(msg, NL80211_ATTR_CSA_C_OFFSETS_TX,
8443 csa_offs_len * sizeof(u16), csa_offs)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008444 nla_put(msg, NL80211_ATTR_FRAME, buf_len, buf))
8445 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008446
8447 cookie = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -07008448 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008449 msg = NULL;
8450 if (ret) {
8451 wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008452 "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
8453 freq, wait);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008454 } else {
8455 wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
8456 "cookie 0x%llx", no_ack ? " (no ACK)" : "",
8457 (long long unsigned int) cookie);
8458
Hai Shalomfdcde762020-04-02 11:19:20 -07008459 if (save_cookie)
8460 drv->send_frame_cookie = no_ack ? (u64) -1 : cookie;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008461
Sunil Ravia04bd252022-05-02 22:54:18 -07008462 if (!wait) {
8463 /* There is no need to store this cookie since there
8464 * is no wait that could be canceled later. */
8465 goto fail;
8466 }
Hai Shalomfdcde762020-04-02 11:19:20 -07008467 if (drv->num_send_frame_cookies == MAX_SEND_FRAME_COOKIES) {
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008468 wpa_printf(MSG_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07008469 "nl80211: Drop oldest pending send frame cookie 0x%llx",
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008470 (long long unsigned int)
Hai Shalomfdcde762020-04-02 11:19:20 -07008471 drv->send_frame_cookies[0]);
8472 os_memmove(&drv->send_frame_cookies[0],
8473 &drv->send_frame_cookies[1],
8474 (MAX_SEND_FRAME_COOKIES - 1) *
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008475 sizeof(u64));
Hai Shalomfdcde762020-04-02 11:19:20 -07008476 drv->num_send_frame_cookies--;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008477 }
Hai Shalomfdcde762020-04-02 11:19:20 -07008478 drv->send_frame_cookies[drv->num_send_frame_cookies] = cookie;
8479 drv->num_send_frame_cookies++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008480 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008481
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008482fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008483 nlmsg_free(msg);
8484 return ret;
8485}
8486
8487
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008488static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
8489 unsigned int freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008490 unsigned int wait_time,
8491 const u8 *dst, const u8 *src,
8492 const u8 *bssid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008493 const u8 *data, size_t data_len,
8494 int no_cck)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008495{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008496 struct wpa_driver_nl80211_data *drv = bss->drv;
8497 int ret = -1;
8498 u8 *buf;
8499 struct ieee80211_hdr *hdr;
Hai Shalomfdcde762020-04-02 11:19:20 -07008500 int offchanok = 1;
8501
Hai Shalom4fbc08f2020-05-18 12:37:00 -07008502 if (is_ap_interface(drv->nlmode) && (int) freq == bss->freq &&
8503 bss->beacon_set)
Hai Shalomfdcde762020-04-02 11:19:20 -07008504 offchanok = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008505
8506 wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
Hai Shalomfdcde762020-04-02 11:19:20 -07008507 "freq=%u MHz wait=%d ms no_cck=%d offchanok=%d)",
8508 drv->ifindex, freq, wait_time, no_cck, offchanok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008509
8510 buf = os_zalloc(24 + data_len);
8511 if (buf == NULL)
8512 return ret;
8513 os_memcpy(buf + 24, data, data_len);
8514 hdr = (struct ieee80211_hdr *) buf;
8515 hdr->frame_control =
8516 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
8517 os_memcpy(hdr->addr1, dst, ETH_ALEN);
8518 os_memcpy(hdr->addr2, src, ETH_ALEN);
8519 os_memcpy(hdr->addr3, bssid, ETH_ALEN);
8520
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08008521 if (os_memcmp(bss->addr, src, ETH_ALEN) != 0) {
8522 wpa_printf(MSG_DEBUG, "nl80211: Use random TA " MACSTR,
8523 MAC2STR(src));
8524 os_memcpy(bss->rand_addr, src, ETH_ALEN);
8525 } else {
8526 os_memset(bss->rand_addr, 0, ETH_ALEN);
8527 }
8528
Hai Shalom60840252021-02-19 19:02:11 -08008529#ifdef CONFIG_MESH
8530 if (is_mesh_interface(drv->nlmode)) {
8531 struct hostapd_hw_modes *modes;
8532 u16 num_modes, flags;
8533 u8 dfs_domain;
8534 int i;
8535
8536 modes = nl80211_get_hw_feature_data(bss, &num_modes,
8537 &flags, &dfs_domain);
8538 if (dfs_domain != HOSTAPD_DFS_REGION_ETSI &&
8539 ieee80211_is_dfs(bss->freq, modes, num_modes))
8540 offchanok = 0;
8541 if (modes) {
8542 for (i = 0; i < num_modes; i++) {
8543 os_free(modes[i].channels);
8544 os_free(modes[i].rates);
8545 }
8546 os_free(modes);
8547 }
8548 }
8549#endif /* CONFIG_MESH */
8550
Dmitry Shmidt56052862013-10-04 10:23:25 -07008551 if (is_ap_interface(drv->nlmode) &&
8552 (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
8553 (int) freq == bss->freq || drv->device_ap_sme ||
8554 !drv->use_monitor))
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008555 ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07008556 0, freq, no_cck, offchanok,
8557 wait_time, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008558 else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008559 ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008560 24 + data_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07008561 1, no_cck, 0, offchanok, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008562
8563 os_free(buf);
8564 return ret;
8565}
8566
8567
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008568static void nl80211_frame_wait_cancel(struct i802_bss *bss, u64 cookie)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008569{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008570 struct wpa_driver_nl80211_data *drv = bss->drv;
8571 struct nl_msg *msg;
8572 int ret;
8573
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08008574 wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008575 (long long unsigned int) cookie);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008576 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME_WAIT_CANCEL)) ||
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008577 nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008578 nlmsg_free(msg);
8579 return;
8580 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008581
Hai Shalom899fcc72020-10-19 14:38:18 -07008582 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008583 if (ret)
8584 wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
8585 "(%s)", ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008586}
8587
8588
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008589static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
8590{
8591 struct i802_bss *bss = priv;
8592 struct wpa_driver_nl80211_data *drv = bss->drv;
8593 unsigned int i;
8594 u64 cookie;
8595
8596 /* Cancel the last pending TX cookie */
Sunil Ravia04bd252022-05-02 22:54:18 -07008597 if (drv->send_frame_cookie != (u64) -1)
8598 nl80211_frame_wait_cancel(bss, drv->send_frame_cookie);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008599
8600 /*
8601 * Cancel the other pending TX cookies, if any. This is needed since
8602 * the driver may keep a list of all pending offchannel TX operations
8603 * and free up the radio only once they have expired or cancelled.
8604 */
Hai Shalomfdcde762020-04-02 11:19:20 -07008605 for (i = drv->num_send_frame_cookies; i > 0; i--) {
8606 cookie = drv->send_frame_cookies[i - 1];
8607 if (cookie != drv->send_frame_cookie)
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008608 nl80211_frame_wait_cancel(bss, cookie);
8609 }
Hai Shalomfdcde762020-04-02 11:19:20 -07008610 drv->num_send_frame_cookies = 0;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008611}
8612
8613
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008614static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
8615 unsigned int duration)
8616{
8617 struct i802_bss *bss = priv;
8618 struct wpa_driver_nl80211_data *drv = bss->drv;
8619 struct nl_msg *msg;
8620 int ret;
8621 u64 cookie;
8622
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008623 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REMAIN_ON_CHANNEL)) ||
8624 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
8625 nla_put_u32(msg, NL80211_ATTR_DURATION, duration)) {
8626 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008627 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008628 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008629
8630 cookie = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -07008631 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008632 if (ret == 0) {
8633 wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
8634 "0x%llx for freq=%u MHz duration=%u",
8635 (long long unsigned int) cookie, freq, duration);
8636 drv->remain_on_chan_cookie = cookie;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008637 drv->pending_remain_on_chan = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008638 return 0;
8639 }
8640 wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
8641 "(freq=%d duration=%u): %d (%s)",
8642 freq, duration, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008643 return -1;
8644}
8645
8646
8647static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
8648{
8649 struct i802_bss *bss = priv;
8650 struct wpa_driver_nl80211_data *drv = bss->drv;
8651 struct nl_msg *msg;
8652 int ret;
8653
8654 if (!drv->pending_remain_on_chan) {
8655 wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
8656 "to cancel");
8657 return -1;
8658 }
8659
8660 wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
8661 "0x%llx",
8662 (long long unsigned int) drv->remain_on_chan_cookie);
8663
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008664 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
8665 if (!msg ||
8666 nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie)) {
8667 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008668 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008669 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008670
Hai Shalom899fcc72020-10-19 14:38:18 -07008671 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008672 if (ret == 0)
8673 return 0;
8674 wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
8675 "%d (%s)", ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008676 return -1;
8677}
8678
8679
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008680static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008681{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008682 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008683
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008684 if (!report) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008685 if (bss->nl_preq && drv->device_ap_sme &&
Dmitry Shmidt03658832014-08-13 11:03:49 -07008686 is_ap_interface(drv->nlmode) && !bss->in_deinit &&
8687 !bss->static_ap) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008688 /*
8689 * Do not disable Probe Request reporting that was
8690 * enabled in nl80211_setup_ap().
8691 */
8692 wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
8693 "Probe Request reporting nl_preq=%p while "
8694 "in AP mode", bss->nl_preq);
8695 } else if (bss->nl_preq) {
8696 wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
8697 "reporting nl_preq=%p", bss->nl_preq);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008698 nl80211_destroy_eloop_handle(&bss->nl_preq, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008699 }
8700 return 0;
8701 }
8702
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008703 if (bss->nl_preq) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008704 wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008705 "already on! nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008706 return 0;
8707 }
8708
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008709 bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
8710 if (bss->nl_preq == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008711 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008712 wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
8713 "reporting nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008714
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008715 if (nl80211_register_frame(bss, bss->nl_preq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008716 (WLAN_FC_TYPE_MGMT << 2) |
8717 (WLAN_FC_STYPE_PROBE_REQ << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07008718 NULL, 0, false) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008719 goto out_err;
Dmitry Shmidt497c1d52011-07-21 15:19:46 -07008720
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008721 nl80211_register_eloop_read(&bss->nl_preq,
8722 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07008723 bss->nl_cb, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008724
8725 return 0;
8726
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008727 out_err:
8728 nl_destroy_handles(&bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008729 return -1;
8730}
8731
8732
8733static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
8734 int ifindex, int disabled)
8735{
8736 struct nl_msg *msg;
8737 struct nlattr *bands, *band;
8738 int ret;
8739
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008740 wpa_printf(MSG_DEBUG,
8741 "nl80211: NL80211_CMD_SET_TX_BITRATE_MASK (ifindex=%d %s)",
8742 ifindex, disabled ? "NL80211_TXRATE_LEGACY=OFDM-only" :
8743 "no NL80211_TXRATE_LEGACY constraint");
8744
8745 msg = nl80211_ifindex_msg(drv, ifindex, 0,
8746 NL80211_CMD_SET_TX_BITRATE_MASK);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008747 if (!msg)
8748 return -1;
8749
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008750 bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
8751 if (!bands)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008752 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008753
8754 /*
8755 * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
8756 * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
8757 * rates. All 5 GHz rates are left enabled.
8758 */
8759 band = nla_nest_start(msg, NL80211_BAND_2GHZ);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008760 if (!band ||
8761 (disabled && nla_put(msg, NL80211_TXRATE_LEGACY, 8,
8762 "\x0c\x12\x18\x24\x30\x48\x60\x6c")))
8763 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008764 nla_nest_end(msg, band);
8765
8766 nla_nest_end(msg, bands);
8767
Hai Shalom899fcc72020-10-19 14:38:18 -07008768 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008769 if (ret) {
8770 wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
8771 "(%s)", ret, strerror(-ret));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008772 } else
8773 drv->disabled_11b_rates = disabled;
8774
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008775 return ret;
8776
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008777fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008778 nlmsg_free(msg);
8779 return -1;
8780}
8781
8782
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008783static int wpa_driver_nl80211_deinit_ap(void *priv)
8784{
8785 struct i802_bss *bss = priv;
8786 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008787 if (!is_ap_interface(drv->nlmode))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008788 return -1;
Paul Stewart092955c2017-02-06 09:13:09 -08008789 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008790
8791 /*
8792 * If the P2P GO interface was dynamically added, then it is
8793 * possible that the interface change to station is not possible.
8794 */
8795 if (drv->nlmode == NL80211_IFTYPE_P2P_GO && bss->if_dynamic)
8796 return 0;
8797
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008798 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008799}
8800
8801
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008802static int wpa_driver_nl80211_stop_ap(void *priv)
8803{
8804 struct i802_bss *bss = priv;
8805 struct wpa_driver_nl80211_data *drv = bss->drv;
8806 if (!is_ap_interface(drv->nlmode))
8807 return -1;
Paul Stewart092955c2017-02-06 09:13:09 -08008808 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008809 return 0;
8810}
8811
8812
Dmitry Shmidt04949592012-07-19 12:16:46 -07008813static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
8814{
8815 struct i802_bss *bss = priv;
8816 struct wpa_driver_nl80211_data *drv = bss->drv;
8817 if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
8818 return -1;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008819
8820 /*
8821 * If the P2P Client interface was dynamically added, then it is
8822 * possible that the interface change to station is not possible.
8823 */
8824 if (bss->if_dynamic)
8825 return 0;
8826
Dmitry Shmidt04949592012-07-19 12:16:46 -07008827 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
8828}
8829
8830
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008831static void wpa_driver_nl80211_resume(void *priv)
8832{
8833 struct i802_bss *bss = priv;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008834 enum nl80211_iftype nlmode = nl80211_get_ifmode(bss);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008835
8836 if (i802_set_iface_flags(bss, 1))
8837 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event");
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008838
8839 if (is_p2p_net_interface(nlmode))
8840 nl80211_disable_11b_rates(bss->drv, bss->drv->ifindex, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008841}
8842
8843
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008844static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
8845{
8846 struct i802_bss *bss = priv;
8847 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008848 struct nl_msg *msg;
8849 struct nlattr *cqm;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008850
8851 wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
8852 "hysteresis=%d", threshold, hysteresis);
8853
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008854 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_CQM)) ||
8855 !(cqm = nla_nest_start(msg, NL80211_ATTR_CQM)) ||
8856 nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold) ||
8857 nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis)) {
8858 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008859 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008860 }
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008861 nla_nest_end(msg, cqm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008862
Hai Shalom899fcc72020-10-19 14:38:18 -07008863 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008864}
8865
8866
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008867static int get_channel_width(struct nl_msg *msg, void *arg)
8868{
8869 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8870 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8871 struct wpa_signal_info *sig_change = arg;
8872
8873 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8874 genlmsg_attrlen(gnlh, 0), NULL);
8875
8876 sig_change->center_frq1 = -1;
8877 sig_change->center_frq2 = -1;
8878 sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
8879
8880 if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
8881 sig_change->chanwidth = convert2width(
8882 nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
8883 if (tb[NL80211_ATTR_CENTER_FREQ1])
8884 sig_change->center_frq1 =
8885 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
8886 if (tb[NL80211_ATTR_CENTER_FREQ2])
8887 sig_change->center_frq2 =
8888 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
8889 }
8890
8891 return NL_SKIP;
8892}
8893
8894
8895static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
8896 struct wpa_signal_info *sig)
8897{
8898 struct nl_msg *msg;
8899
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008900 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
Hai Shalom899fcc72020-10-19 14:38:18 -07008901 return send_and_recv_msgs(drv, msg, get_channel_width, sig, NULL, NULL);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008902}
8903
8904
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008905static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
8906{
8907 struct i802_bss *bss = priv;
8908 struct wpa_driver_nl80211_data *drv = bss->drv;
8909 int res;
8910
8911 os_memset(si, 0, sizeof(*si));
Sunil Ravi89eba102022-09-13 21:04:37 -07008912 res = nl80211_get_link_signal(drv, drv->bssid, si);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008913 if (res) {
8914 if (drv->nlmode != NL80211_IFTYPE_ADHOC &&
8915 drv->nlmode != NL80211_IFTYPE_MESH_POINT)
8916 return res;
8917 si->current_signal = 0;
8918 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008919
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008920 res = nl80211_get_channel_width(drv, si);
8921 if (res != 0)
8922 return res;
8923
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008924 return nl80211_get_link_noise(drv, si);
8925}
8926
8927
Sunil Ravi89eba102022-09-13 21:04:37 -07008928static int get_links_noise(struct nl_msg *msg, void *arg)
8929{
8930 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8931 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8932 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
8933 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
8934 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
8935 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
8936 };
8937 struct wpa_mlo_signal_info *mlo_sig = arg;
8938 int i;
8939
8940 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8941 genlmsg_attrlen(gnlh, 0), NULL);
8942
8943 if (!tb[NL80211_ATTR_SURVEY_INFO]) {
8944 wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
8945 return NL_SKIP;
8946 }
8947
8948 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
8949 tb[NL80211_ATTR_SURVEY_INFO],
8950 survey_policy)) {
8951 wpa_printf(MSG_DEBUG,
8952 "nl80211: Failed to parse nested attributes");
8953 return NL_SKIP;
8954 }
8955
8956 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
8957 return NL_SKIP;
8958
8959 if (!sinfo[NL80211_SURVEY_INFO_NOISE])
8960 return NL_SKIP;
8961
8962 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
8963 if (!(mlo_sig->valid_links & BIT(i)))
8964 continue;
8965
8966 if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
8967 mlo_sig->links[i].frequency)
8968 continue;
8969
8970 mlo_sig->links[i].current_noise =
8971 (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
8972 break;
8973 }
8974
8975 return NL_SKIP;
8976}
8977
8978
8979static int nl80211_get_links_noise(struct wpa_driver_nl80211_data *drv,
8980 struct wpa_mlo_signal_info *mlo_sig)
8981{
8982 struct nl_msg *msg;
8983
8984 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
8985 return send_and_recv_msgs(drv, msg, get_links_noise, mlo_sig,
8986 NULL, NULL);
8987}
8988
8989
8990static int get_links_channel_width(struct nl_msg *msg, void *arg)
8991{
8992 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8993 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8994 struct wpa_mlo_signal_info *mlo_sig = arg;
8995 struct nlattr *link;
8996 int rem_links;
8997
8998 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8999 genlmsg_attrlen(gnlh, 0), NULL);
9000
9001 if (!tb[NL80211_ATTR_MLO_LINKS])
9002 return NL_SKIP;
9003
9004 nla_for_each_nested(link, tb[NL80211_ATTR_MLO_LINKS], rem_links) {
9005 struct nlattr *tb2[NL80211_ATTR_MAX + 1];
9006 int link_id;
9007
9008 nla_parse(tb2, NL80211_ATTR_MAX, nla_data(link), nla_len(link),
9009 NULL);
9010
9011 if (!tb2[NL80211_ATTR_MLO_LINK_ID])
9012 continue;
9013
9014 link_id = nla_get_u8(tb2[NL80211_ATTR_MLO_LINK_ID]);
9015 if (link_id >= MAX_NUM_MLD_LINKS)
9016 continue;
9017
9018 if (!tb2[NL80211_ATTR_CHANNEL_WIDTH])
9019 continue;
9020 mlo_sig->links[link_id].chanwidth = convert2width(
9021 nla_get_u32(tb2[NL80211_ATTR_CHANNEL_WIDTH]));
9022 if (tb2[NL80211_ATTR_CENTER_FREQ1])
9023 mlo_sig->links[link_id].center_frq1 =
9024 nla_get_u32(tb2[NL80211_ATTR_CENTER_FREQ1]);
9025 if (tb2[NL80211_ATTR_CENTER_FREQ2])
9026 mlo_sig->links[link_id].center_frq2 =
9027 nla_get_u32(tb2[NL80211_ATTR_CENTER_FREQ2]);
9028 }
9029
9030 return NL_SKIP;
9031}
9032
9033
9034static int nl80211_get_links_channel_width(struct wpa_driver_nl80211_data *drv,
9035 struct wpa_mlo_signal_info *mlo_sig)
9036{
9037 struct nl_msg *msg;
9038
9039 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
9040 return send_and_recv_msgs(drv, msg, get_links_channel_width, mlo_sig,
9041 NULL, NULL);
9042}
9043
9044
9045static int nl80211_mlo_signal_poll(void *priv,
9046 struct wpa_mlo_signal_info *mlo_si)
9047{
9048 struct i802_bss *bss = priv;
9049 struct wpa_driver_nl80211_data *drv = bss->drv;
9050 int res;
9051 int i;
9052
9053 if (drv->nlmode != NL80211_IFTYPE_STATION ||
9054 !drv->sta_mlo_info.valid_links)
9055 return -1;
9056
9057 os_memset(mlo_si, 0, sizeof(*mlo_si));
9058 mlo_si->valid_links = drv->sta_mlo_info.valid_links;
9059
9060 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
9061 if (!(mlo_si->valid_links & BIT(i)))
9062 continue;
9063
9064 res = nl80211_get_link_signal(drv,
9065 drv->sta_mlo_info.links[i].bssid,
9066 &mlo_si->links[i]);
9067 if (res != 0)
9068 return res;
9069
9070 mlo_si->links[i].center_frq1 = -1;
9071 mlo_si->links[i].center_frq2 = -1;
9072 mlo_si->links[i].chanwidth = CHAN_WIDTH_UNKNOWN;
9073 mlo_si->links[i].current_noise = WPA_INVALID_NOISE;
9074 mlo_si->links[i].frequency = drv->sta_mlo_info.links[i].freq;
9075 }
9076
9077 res = nl80211_get_links_channel_width(drv, mlo_si);
9078 if (res != 0)
9079 return res;
9080
9081 return nl80211_get_links_noise(drv, mlo_si);
9082}
9083
9084
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009085static int nl80211_set_param(void *priv, const char *param)
9086{
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07009087 struct i802_bss *bss = priv;
9088 struct wpa_driver_nl80211_data *drv = bss->drv;
9089
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009090 if (param == NULL)
9091 return 0;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08009092 wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009093
9094#ifdef CONFIG_P2P
9095 if (os_strstr(param, "use_p2p_group_interface=1")) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009096 wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
9097 "interface");
9098 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
9099 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
9100 }
9101#endif /* CONFIG_P2P */
9102
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07009103 if (os_strstr(param, "use_monitor=1"))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009104 drv->use_monitor = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009105
9106 if (os_strstr(param, "force_connect_cmd=1")) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009107 drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07009108 drv->force_connect_cmd = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009109 }
9110
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07009111 if (os_strstr(param, "force_bss_selection=1"))
9112 drv->capa.flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
9113
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08009114 if (os_strstr(param, "no_offchannel_tx=1")) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08009115 drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
9116 drv->test_use_roc_tx = 1;
9117 }
9118
Hai Shalomb755a2a2020-04-23 21:49:02 -07009119 if (os_strstr(param, "control_port=0")) {
Hai Shalomfdcde762020-04-02 11:19:20 -07009120 drv->capa.flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
Hai Shalom899fcc72020-10-19 14:38:18 -07009121 drv->capa.flags2 &= ~(WPA_DRIVER_FLAGS2_CONTROL_PORT_RX |
9122 WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS);
9123 drv->control_port_ap = 0;
Hai Shalomb755a2a2020-04-23 21:49:02 -07009124 }
9125
9126 if (os_strstr(param, "control_port_ap=1"))
9127 drv->control_port_ap = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -07009128
Hai Shalom899fcc72020-10-19 14:38:18 -07009129 if (os_strstr(param, "control_port_ap=0")) {
9130 drv->capa.flags2 &= ~WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS;
9131 drv->control_port_ap = 0;
9132 }
9133
Hai Shalomfdcde762020-04-02 11:19:20 -07009134 if (os_strstr(param, "full_ap_client_state=0"))
9135 drv->capa.flags &= ~WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
9136
Hai Shalom899fcc72020-10-19 14:38:18 -07009137 if (os_strstr(param, "no_rrm=1")) {
9138 drv->no_rrm = 1;
9139
9140 if (!bss->in_deinit && !is_ap_interface(drv->nlmode) &&
9141 !is_mesh_interface(drv->nlmode)) {
9142 nl80211_mgmt_unsubscribe(bss, "no_rrm=1");
9143 if (nl80211_mgmt_subscribe_non_ap(bss) < 0)
9144 wpa_printf(MSG_DEBUG,
9145 "nl80211: Failed to re-register Action frame processing - ignore for now");
9146 }
9147 }
9148
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009149 return 0;
9150}
9151
9152
Dmitry Shmidte4663042016-04-04 10:07:49 -07009153static void * nl80211_global_init(void *ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009154{
9155 struct nl80211_global *global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009156 struct netlink_config *cfg;
9157
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009158 global = os_zalloc(sizeof(*global));
9159 if (global == NULL)
9160 return NULL;
Dmitry Shmidte4663042016-04-04 10:07:49 -07009161 global->ctx = ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009162 global->ioctl_sock = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009163 dl_list_init(&global->interfaces);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009164 global->if_add_ifindex = -1;
9165
9166 cfg = os_zalloc(sizeof(*cfg));
9167 if (cfg == NULL)
9168 goto err;
9169
9170 cfg->ctx = global;
9171 cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
9172 cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
9173 global->netlink = netlink_init(cfg);
9174 if (global->netlink == NULL) {
9175 os_free(cfg);
9176 goto err;
9177 }
9178
9179 if (wpa_driver_nl80211_init_nl_global(global) < 0)
9180 goto err;
9181
9182 global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
9183 if (global->ioctl_sock < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07009184 wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s",
9185 strerror(errno));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009186 goto err;
9187 }
9188
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009189 return global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009190
9191err:
9192 nl80211_global_deinit(global);
9193 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009194}
9195
9196
9197static void nl80211_global_deinit(void *priv)
9198{
9199 struct nl80211_global *global = priv;
9200 if (global == NULL)
9201 return;
9202 if (!dl_list_empty(&global->interfaces)) {
9203 wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at "
9204 "nl80211_global_deinit",
9205 dl_list_len(&global->interfaces));
9206 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009207
9208 if (global->netlink)
9209 netlink_deinit(global->netlink);
9210
9211 nl_destroy_handles(&global->nl);
9212
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07009213 if (global->nl_event)
Roshan Pius3a1667e2018-07-03 15:17:14 -07009214 nl80211_destroy_eloop_handle(&global->nl_event, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009215
9216 nl_cb_put(global->nl_cb);
9217
9218 if (global->ioctl_sock >= 0)
9219 close(global->ioctl_sock);
9220
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009221 os_free(global);
9222}
9223
9224
9225static const char * nl80211_get_radio_name(void *priv)
9226{
9227 struct i802_bss *bss = priv;
9228 struct wpa_driver_nl80211_data *drv = bss->drv;
9229 return drv->phyname;
9230}
9231
9232
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009233static int nl80211_pmkid(struct i802_bss *bss, int cmd,
9234 struct wpa_pmkid_params *params)
Jouni Malinen75ecf522011-06-27 15:19:46 -07009235{
9236 struct nl_msg *msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009237 const size_t PMK_MAX_LEN = 48; /* current cfg80211 limit */
Jouni Malinen75ecf522011-06-27 15:19:46 -07009238
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009239 if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009240 (params->pmkid &&
9241 nla_put(msg, NL80211_ATTR_PMKID, 16, params->pmkid)) ||
9242 (params->bssid &&
9243 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid)) ||
9244 (params->ssid_len &&
9245 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
9246 (params->fils_cache_id &&
9247 nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2,
9248 params->fils_cache_id)) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07009249 (params->pmk_lifetime &&
9250 nla_put_u32(msg, NL80211_ATTR_PMK_LIFETIME,
9251 params->pmk_lifetime)) ||
9252 (params->pmk_reauth_threshold &&
9253 nla_put_u8(msg, NL80211_ATTR_PMK_REAUTH_THRESHOLD,
9254 params->pmk_reauth_threshold)) ||
Hai Shalom021b0b52019-04-10 11:17:58 -07009255 (cmd != NL80211_CMD_DEL_PMKSA &&
9256 params->pmk_len && params->pmk_len <= PMK_MAX_LEN &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009257 nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
Hai Shalom74f70d42019-02-11 14:42:39 -08009258 nl80211_nlmsg_clear(msg);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009259 nlmsg_free(msg);
9260 return -ENOBUFS;
9261 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07009262
Hai Shalom60840252021-02-19 19:02:11 -08009263 return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Jouni Malinen75ecf522011-06-27 15:19:46 -07009264}
9265
9266
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009267static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params)
Jouni Malinen75ecf522011-06-27 15:19:46 -07009268{
9269 struct i802_bss *bss = priv;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009270 int ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009271
9272 if (params->bssid)
9273 wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR,
9274 MAC2STR(params->bssid));
9275 else if (params->fils_cache_id && params->ssid_len) {
9276 wpa_printf(MSG_DEBUG,
9277 "nl80211: Add PMKSA for cache id %02x%02x SSID %s",
9278 params->fils_cache_id[0], params->fils_cache_id[1],
9279 wpa_ssid_txt(params->ssid, params->ssid_len));
9280 }
9281
Roshan Pius3a1667e2018-07-03 15:17:14 -07009282 ret = nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params);
9283 if (ret < 0) {
9284 wpa_printf(MSG_DEBUG,
9285 "nl80211: NL80211_CMD_SET_PMKSA failed: %d (%s)",
9286 ret, strerror(-ret));
9287 }
9288
9289 return ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -07009290}
9291
9292
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009293static int nl80211_remove_pmkid(void *priv, struct wpa_pmkid_params *params)
Jouni Malinen75ecf522011-06-27 15:19:46 -07009294{
9295 struct i802_bss *bss = priv;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009296 int ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009297
9298 if (params->bssid)
9299 wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
9300 MAC2STR(params->bssid));
9301 else if (params->fils_cache_id && params->ssid_len) {
9302 wpa_printf(MSG_DEBUG,
9303 "nl80211: Delete PMKSA for cache id %02x%02x SSID %s",
9304 params->fils_cache_id[0], params->fils_cache_id[1],
9305 wpa_ssid_txt(params->ssid, params->ssid_len));
9306 }
9307
Roshan Pius3a1667e2018-07-03 15:17:14 -07009308 ret = nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params);
9309 if (ret < 0) {
9310 wpa_printf(MSG_DEBUG,
9311 "nl80211: NL80211_CMD_DEL_PMKSA failed: %d (%s)",
9312 ret, strerror(-ret));
9313 }
9314
9315 return ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -07009316}
9317
9318
9319static int nl80211_flush_pmkid(void *priv)
9320{
9321 struct i802_bss *bss = priv;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009322 struct nl_msg *msg;
9323
Jouni Malinen75ecf522011-06-27 15:19:46 -07009324 wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009325 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_FLUSH_PMKSA);
9326 if (!msg)
9327 return -ENOBUFS;
Hai Shalom899fcc72020-10-19 14:38:18 -07009328 return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Jouni Malinen75ecf522011-06-27 15:19:46 -07009329}
9330
9331
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009332static void clean_survey_results(struct survey_results *survey_results)
9333{
9334 struct freq_survey *survey, *tmp;
9335
9336 if (dl_list_empty(&survey_results->survey_list))
9337 return;
9338
9339 dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
9340 struct freq_survey, list) {
9341 dl_list_del(&survey->list);
9342 os_free(survey);
9343 }
9344}
9345
9346
9347static void add_survey(struct nlattr **sinfo, u32 ifidx,
9348 struct dl_list *survey_list)
9349{
9350 struct freq_survey *survey;
9351
9352 survey = os_zalloc(sizeof(struct freq_survey));
9353 if (!survey)
9354 return;
9355
9356 survey->ifidx = ifidx;
9357 survey->freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
9358 survey->filled = 0;
9359
9360 if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
9361 survey->nf = (int8_t)
9362 nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
9363 survey->filled |= SURVEY_HAS_NF;
9364 }
9365
9366 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) {
9367 survey->channel_time =
9368 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
9369 survey->filled |= SURVEY_HAS_CHAN_TIME;
9370 }
9371
9372 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
9373 survey->channel_time_busy =
9374 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
9375 survey->filled |= SURVEY_HAS_CHAN_TIME_BUSY;
9376 }
9377
9378 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) {
9379 survey->channel_time_rx =
9380 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]);
9381 survey->filled |= SURVEY_HAS_CHAN_TIME_RX;
9382 }
9383
9384 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) {
9385 survey->channel_time_tx =
9386 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]);
9387 survey->filled |= SURVEY_HAS_CHAN_TIME_TX;
9388 }
9389
9390 wpa_printf(MSG_DEBUG, "nl80211: Freq survey dump event (freq=%d MHz noise=%d channel_time=%ld busy_time=%ld tx_time=%ld rx_time=%ld filled=%04x)",
9391 survey->freq,
9392 survey->nf,
9393 (unsigned long int) survey->channel_time,
9394 (unsigned long int) survey->channel_time_busy,
9395 (unsigned long int) survey->channel_time_tx,
9396 (unsigned long int) survey->channel_time_rx,
9397 survey->filled);
9398
9399 dl_list_add_tail(survey_list, &survey->list);
9400}
9401
9402
9403static int check_survey_ok(struct nlattr **sinfo, u32 surveyed_freq,
9404 unsigned int freq_filter)
9405{
9406 if (!freq_filter)
9407 return 1;
9408
9409 return freq_filter == surveyed_freq;
9410}
9411
9412
9413static int survey_handler(struct nl_msg *msg, void *arg)
9414{
9415 struct nlattr *tb[NL80211_ATTR_MAX + 1];
9416 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
9417 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
9418 struct survey_results *survey_results;
9419 u32 surveyed_freq = 0;
9420 u32 ifidx;
9421
9422 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
9423 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
9424 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
9425 };
9426
9427 survey_results = (struct survey_results *) arg;
9428
9429 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
9430 genlmsg_attrlen(gnlh, 0), NULL);
9431
Dmitry Shmidt97672262014-02-03 13:02:54 -08009432 if (!tb[NL80211_ATTR_IFINDEX])
9433 return NL_SKIP;
9434
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009435 ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
9436
9437 if (!tb[NL80211_ATTR_SURVEY_INFO])
9438 return NL_SKIP;
9439
9440 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
9441 tb[NL80211_ATTR_SURVEY_INFO],
9442 survey_policy))
9443 return NL_SKIP;
9444
9445 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) {
9446 wpa_printf(MSG_ERROR, "nl80211: Invalid survey data");
9447 return NL_SKIP;
9448 }
9449
9450 surveyed_freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
9451
9452 if (!check_survey_ok(sinfo, surveyed_freq,
9453 survey_results->freq_filter))
9454 return NL_SKIP;
9455
9456 if (survey_results->freq_filter &&
9457 survey_results->freq_filter != surveyed_freq) {
9458 wpa_printf(MSG_EXCESSIVE, "nl80211: Ignoring survey data for freq %d MHz",
9459 surveyed_freq);
9460 return NL_SKIP;
9461 }
9462
9463 add_survey(sinfo, ifidx, &survey_results->survey_list);
9464
9465 return NL_SKIP;
9466}
9467
9468
9469static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
9470{
9471 struct i802_bss *bss = priv;
9472 struct wpa_driver_nl80211_data *drv = bss->drv;
9473 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009474 int err;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009475 union wpa_event_data data;
9476 struct survey_results *survey_results;
9477
9478 os_memset(&data, 0, sizeof(data));
9479 survey_results = &data.survey_results;
9480
9481 dl_list_init(&survey_results->survey_list);
9482
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009483 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009484 if (!msg)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009485 return -ENOBUFS;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009486
9487 if (freq)
9488 data.survey_results.freq_filter = freq;
9489
9490 do {
9491 wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
9492 err = send_and_recv_msgs(drv, msg, survey_handler,
Hai Shalom899fcc72020-10-19 14:38:18 -07009493 survey_results, NULL, NULL);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009494 } while (err > 0);
9495
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009496 if (err)
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009497 wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009498 else
9499 wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009500
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009501 clean_survey_results(survey_results);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009502 return err;
9503}
9504
9505
Dmitry Shmidt807291d2015-01-27 13:40:23 -08009506static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
9507 const u8 *kck, size_t kck_len,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009508 const u8 *replay_ctr)
9509{
9510 struct i802_bss *bss = priv;
9511 struct wpa_driver_nl80211_data *drv = bss->drv;
9512 struct nlattr *replay_nested;
9513 struct nl_msg *msg;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08009514 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009515
Dmitry Shmidtff787d52015-01-12 13:01:47 -08009516 if (!drv->set_rekey_offload)
9517 return;
9518
9519 wpa_printf(MSG_DEBUG, "nl80211: Set rekey offload");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009520 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
9521 !(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
Dmitry Shmidt807291d2015-01-27 13:40:23 -08009522 nla_put(msg, NL80211_REKEY_DATA_KEK, kek_len, kek) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009523 (kck_len && nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009524 nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
9525 replay_ctr)) {
9526 nl80211_nlmsg_clear(msg);
9527 nlmsg_free(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009528 return;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009529 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009530
9531 nla_nest_end(msg, replay_nested);
9532
Hai Shalom60840252021-02-19 19:02:11 -08009533 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08009534 if (ret == -EOPNOTSUPP) {
9535 wpa_printf(MSG_DEBUG,
9536 "nl80211: Driver does not support rekey offload");
9537 drv->set_rekey_offload = 0;
9538 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009539}
9540
9541
9542static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
9543 const u8 *addr, int qos)
9544{
9545 /* send data frame to poll STA and check whether
9546 * this frame is ACKed */
9547 struct {
9548 struct ieee80211_hdr hdr;
9549 u16 qos_ctl;
9550 } STRUCT_PACKED nulldata;
9551 size_t size;
9552
9553 /* Send data frame to poll STA and check whether this frame is ACKed */
9554
9555 os_memset(&nulldata, 0, sizeof(nulldata));
9556
9557 if (qos) {
9558 nulldata.hdr.frame_control =
9559 IEEE80211_FC(WLAN_FC_TYPE_DATA,
9560 WLAN_FC_STYPE_QOS_NULL);
9561 size = sizeof(nulldata);
9562 } else {
9563 nulldata.hdr.frame_control =
9564 IEEE80211_FC(WLAN_FC_TYPE_DATA,
9565 WLAN_FC_STYPE_NULLFUNC);
9566 size = sizeof(struct ieee80211_hdr);
9567 }
9568
9569 nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
9570 os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
9571 os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
9572 os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
9573
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009574 if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -07009575 0, 0, NULL, 0, 0) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009576 wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
9577 "send poll frame");
9578}
9579
9580static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
9581 int qos)
9582{
9583 struct i802_bss *bss = priv;
9584 struct wpa_driver_nl80211_data *drv = bss->drv;
9585 struct nl_msg *msg;
Hai Shalom5f92bc92019-04-18 11:54:11 -07009586 u64 cookie;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08009587 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009588
9589 if (!drv->poll_command_supported) {
9590 nl80211_send_null_frame(bss, own_addr, addr, qos);
9591 return;
9592 }
9593
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009594 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_PROBE_CLIENT)) ||
9595 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
9596 nlmsg_free(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009597 return;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009598 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009599
Hai Shalom899fcc72020-10-19 14:38:18 -07009600 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08009601 if (ret < 0) {
9602 wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
9603 MACSTR " failed: ret=%d (%s)",
9604 MAC2STR(addr), ret, strerror(-ret));
Hai Shalom5f92bc92019-04-18 11:54:11 -07009605 } else {
9606 wpa_printf(MSG_DEBUG,
9607 "nl80211: Client probe request addr=" MACSTR
9608 " cookie=%llu", MAC2STR(addr),
9609 (long long unsigned int) cookie);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08009610 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009611}
9612
9613
9614static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
9615{
9616 struct nl_msg *msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009617 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009618
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009619 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
9620 nla_put_u32(msg, NL80211_ATTR_PS_STATE,
9621 enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED)) {
9622 nlmsg_free(msg);
9623 return -ENOBUFS;
9624 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07009625
Hai Shalom899fcc72020-10-19 14:38:18 -07009626 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009627 if (ret < 0) {
9628 wpa_printf(MSG_DEBUG,
9629 "nl80211: Setting PS state %s failed: %d (%s)",
9630 enabled ? "enabled" : "disabled",
9631 ret, strerror(-ret));
9632 }
9633 return ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009634}
9635
9636
9637static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
9638 int ctwindow)
9639{
9640 struct i802_bss *bss = priv;
9641
9642 wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
9643 "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
9644
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08009645 if (opp_ps != -1 || ctwindow != -1) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009646#ifdef ANDROID_P2P
9647 wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08009648#else /* ANDROID_P2P */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009649 return -1; /* Not yet supported */
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08009650#endif /* ANDROID_P2P */
9651 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009652
9653 if (legacy_ps == -1)
9654 return 0;
9655 if (legacy_ps != 0 && legacy_ps != 1)
9656 return -1; /* Not yet supported */
9657
9658 return nl80211_set_power_save(bss, legacy_ps);
9659}
9660
9661
Dmitry Shmidt051af732013-10-22 13:52:46 -07009662static int nl80211_start_radar_detection(void *priv,
9663 struct hostapd_freq_params *freq)
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009664{
9665 struct i802_bss *bss = priv;
9666 struct wpa_driver_nl80211_data *drv = bss->drv;
9667 struct nl_msg *msg;
9668 int ret;
9669
Hai Shalom81f62d82019-07-22 12:10:00 -07009670 wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC) %d MHz (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
9671 freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
Dmitry Shmidt051af732013-10-22 13:52:46 -07009672 freq->bandwidth, freq->center_freq1, freq->center_freq2);
9673
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009674 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
9675 wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
9676 "detection");
9677 return -1;
9678 }
9679
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009680 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_RADAR_DETECT)) ||
9681 nl80211_put_freq_params(msg, freq) < 0) {
9682 nlmsg_free(msg);
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009683 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009684 }
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009685
Hai Shalom899fcc72020-10-19 14:38:18 -07009686 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009687 if (ret == 0)
9688 return 0;
9689 wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
9690 "%d (%s)", ret, strerror(-ret));
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009691 return -1;
9692}
9693
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009694#ifdef CONFIG_TDLS
9695
Hai Shalomc1a21442022-02-04 13:43:00 -08009696static int nl80211_add_peer_capab(struct nl_msg *msg,
9697 enum tdls_peer_capability capa)
9698{
9699 u32 peer_capab = 0;
9700
9701 if (!capa)
9702 return 0;
9703
9704 if (capa & TDLS_PEER_HT)
9705 peer_capab |= NL80211_TDLS_PEER_HT;
9706 if (capa & TDLS_PEER_VHT)
9707 peer_capab |= NL80211_TDLS_PEER_VHT;
9708 if (capa & TDLS_PEER_WMM)
9709 peer_capab |= NL80211_TDLS_PEER_WMM;
9710 if (capa & TDLS_PEER_HE)
9711 peer_capab |= NL80211_TDLS_PEER_HE;
9712
9713 return nla_put_u32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY,
9714 peer_capab);
9715}
9716
9717
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009718static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
9719 u8 dialog_token, u16 status_code,
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07009720 u32 peer_capab, int initiator, const u8 *buf,
9721 size_t len)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009722{
9723 struct i802_bss *bss = priv;
9724 struct wpa_driver_nl80211_data *drv = bss->drv;
9725 struct nl_msg *msg;
9726
9727 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
9728 return -EOPNOTSUPP;
9729
9730 if (!dst)
9731 return -EINVAL;
9732
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009733 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_MGMT)) ||
9734 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
9735 nla_put_u8(msg, NL80211_ATTR_TDLS_ACTION, action_code) ||
9736 nla_put_u8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token) ||
Hai Shalomc1a21442022-02-04 13:43:00 -08009737 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status_code) ||
9738 nl80211_add_peer_capab(msg, peer_capab) ||
9739 (initiator && nla_put_flag(msg, NL80211_ATTR_TDLS_INITIATOR)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009740 nla_put(msg, NL80211_ATTR_IE, len, buf))
9741 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009742
Hai Shalom899fcc72020-10-19 14:38:18 -07009743 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009744
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009745fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009746 nlmsg_free(msg);
9747 return -ENOBUFS;
9748}
9749
9750
9751static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
9752{
9753 struct i802_bss *bss = priv;
9754 struct wpa_driver_nl80211_data *drv = bss->drv;
9755 struct nl_msg *msg;
9756 enum nl80211_tdls_operation nl80211_oper;
Paul Stewart092955c2017-02-06 09:13:09 -08009757 int res;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009758
9759 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
9760 return -EOPNOTSUPP;
9761
9762 switch (oper) {
9763 case TDLS_DISCOVERY_REQ:
9764 nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
9765 break;
9766 case TDLS_SETUP:
9767 nl80211_oper = NL80211_TDLS_SETUP;
9768 break;
9769 case TDLS_TEARDOWN:
9770 nl80211_oper = NL80211_TDLS_TEARDOWN;
9771 break;
9772 case TDLS_ENABLE_LINK:
9773 nl80211_oper = NL80211_TDLS_ENABLE_LINK;
9774 break;
9775 case TDLS_DISABLE_LINK:
9776 nl80211_oper = NL80211_TDLS_DISABLE_LINK;
9777 break;
9778 case TDLS_ENABLE:
9779 return 0;
9780 case TDLS_DISABLE:
9781 return 0;
9782 default:
9783 return -EINVAL;
9784 }
9785
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009786 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_OPER)) ||
9787 nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper) ||
9788 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) {
9789 nlmsg_free(msg);
9790 return -ENOBUFS;
9791 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009792
Hai Shalom899fcc72020-10-19 14:38:18 -07009793 res = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Paul Stewart092955c2017-02-06 09:13:09 -08009794 wpa_printf(MSG_DEBUG, "nl80211: TDLS_OPER: oper=%d mac=" MACSTR
9795 " --> res=%d (%s)", nl80211_oper, MAC2STR(peer), res,
9796 strerror(-res));
9797 return res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009798}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009799
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009800
9801static int
9802nl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
9803 const struct hostapd_freq_params *params)
9804{
9805 struct i802_bss *bss = priv;
9806 struct wpa_driver_nl80211_data *drv = bss->drv;
9807 struct nl_msg *msg;
9808 int ret = -ENOBUFS;
9809
9810 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
9811 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
9812 return -EOPNOTSUPP;
9813
9814 wpa_printf(MSG_DEBUG, "nl80211: Enable TDLS channel switch " MACSTR
9815 " oper_class=%u freq=%u",
9816 MAC2STR(addr), oper_class, params->freq);
9817 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CHANNEL_SWITCH);
9818 if (!msg ||
9819 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
9820 nla_put_u8(msg, NL80211_ATTR_OPER_CLASS, oper_class) ||
9821 (ret = nl80211_put_freq_params(msg, params))) {
9822 nlmsg_free(msg);
9823 wpa_printf(MSG_DEBUG, "nl80211: Could not build TDLS chan switch");
9824 return ret;
9825 }
9826
Hai Shalom899fcc72020-10-19 14:38:18 -07009827 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009828}
9829
9830
9831static int
9832nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
9833{
9834 struct i802_bss *bss = priv;
9835 struct wpa_driver_nl80211_data *drv = bss->drv;
9836 struct nl_msg *msg;
9837
9838 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
9839 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
9840 return -EOPNOTSUPP;
9841
9842 wpa_printf(MSG_DEBUG, "nl80211: Disable TDLS channel switch " MACSTR,
9843 MAC2STR(addr));
9844 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH);
9845 if (!msg ||
9846 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
9847 nlmsg_free(msg);
9848 wpa_printf(MSG_DEBUG,
9849 "nl80211: Could not build TDLS cancel chan switch");
9850 return -ENOBUFS;
9851 }
9852
Hai Shalom899fcc72020-10-19 14:38:18 -07009853 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009854}
9855
9856#endif /* CONFIG TDLS */
9857
9858
Hai Shalomfdcde762020-04-02 11:19:20 -07009859static int driver_nl80211_set_key(void *priv,
9860 struct wpa_driver_set_key_params *params)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009861{
9862 struct i802_bss *bss = priv;
Hai Shalomfdcde762020-04-02 11:19:20 -07009863
9864 return wpa_driver_nl80211_set_key(bss, params);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009865}
9866
9867
9868static int driver_nl80211_scan2(void *priv,
9869 struct wpa_driver_scan_params *params)
9870{
9871 struct i802_bss *bss = priv;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009872#ifdef CONFIG_DRIVER_NL80211_QCA
9873 struct wpa_driver_nl80211_data *drv = bss->drv;
9874
9875 /*
9876 * Do a vendor specific scan if possible. If only_new_results is
9877 * set, do a normal scan since a kernel (cfg80211) BSS cache flush
9878 * cannot be achieved through a vendor scan. The below condition may
9879 * need to be modified if new scan flags are added in the future whose
9880 * functionality can only be achieved through a normal scan.
9881 */
9882 if (drv->scan_vendor_cmd_avail && !params->only_new_results)
9883 return wpa_driver_nl80211_vendor_scan(bss, params);
9884#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009885 return wpa_driver_nl80211_scan(bss, params);
9886}
9887
9888
9889static int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -07009890 u16 reason_code)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009891{
9892 struct i802_bss *bss = priv;
9893 return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
9894}
9895
9896
9897static int driver_nl80211_authenticate(void *priv,
9898 struct wpa_driver_auth_params *params)
9899{
9900 struct i802_bss *bss = priv;
9901 return wpa_driver_nl80211_authenticate(bss, params);
9902}
9903
9904
9905static void driver_nl80211_deinit(void *priv)
9906{
9907 struct i802_bss *bss = priv;
9908 wpa_driver_nl80211_deinit(bss);
9909}
9910
9911
9912static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
9913 const char *ifname)
9914{
9915 struct i802_bss *bss = priv;
9916 return wpa_driver_nl80211_if_remove(bss, type, ifname);
9917}
9918
9919
9920static int driver_nl80211_send_mlme(void *priv, const u8 *data,
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07009921 size_t data_len, int noack,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009922 unsigned int freq,
Hai Shalomfdcde762020-04-02 11:19:20 -07009923 const u16 *csa_offs, size_t csa_offs_len,
9924 int no_encrypt, unsigned int wait)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009925{
9926 struct i802_bss *bss = priv;
9927 return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
Hai Shalomfdcde762020-04-02 11:19:20 -07009928 freq, 0, 0, wait, csa_offs,
9929 csa_offs_len, no_encrypt);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009930}
9931
9932
9933static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
9934{
9935 struct i802_bss *bss = priv;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009936 return wpa_driver_nl80211_sta_remove(bss, addr, -1, 0);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009937}
9938
9939
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009940static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
9941 const char *ifname, int vlan_id)
9942{
9943 struct i802_bss *bss = priv;
9944 return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
9945}
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009946
9947
9948static int driver_nl80211_read_sta_data(void *priv,
9949 struct hostap_sta_driver_data *data,
9950 const u8 *addr)
9951{
9952 struct i802_bss *bss = priv;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08009953
9954 os_memset(data, 0, sizeof(*data));
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009955 return i802_read_sta_data(bss, data, addr);
9956}
9957
9958
9959static int driver_nl80211_send_action(void *priv, unsigned int freq,
9960 unsigned int wait_time,
9961 const u8 *dst, const u8 *src,
9962 const u8 *bssid,
9963 const u8 *data, size_t data_len,
9964 int no_cck)
9965{
9966 struct i802_bss *bss = priv;
9967 return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
9968 bssid, data, data_len, no_cck);
9969}
9970
9971
9972static int driver_nl80211_probe_req_report(void *priv, int report)
9973{
9974 struct i802_bss *bss = priv;
9975 return wpa_driver_nl80211_probe_req_report(bss, report);
9976}
9977
9978
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009979static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
9980 const u8 *ies, size_t ies_len)
9981{
9982 int ret;
9983 struct nl_msg *msg;
9984 struct i802_bss *bss = priv;
9985 struct wpa_driver_nl80211_data *drv = bss->drv;
9986 u16 mdid = WPA_GET_LE16(md);
9987
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009988 wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009989 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_FT_IES)) ||
9990 nla_put(msg, NL80211_ATTR_IE, ies_len, ies) ||
9991 nla_put_u16(msg, NL80211_ATTR_MDID, mdid)) {
9992 nlmsg_free(msg);
9993 return -ENOBUFS;
9994 }
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009995
Hai Shalom899fcc72020-10-19 14:38:18 -07009996 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009997 if (ret) {
9998 wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
9999 "err=%d (%s)", ret, strerror(-ret));
10000 }
10001
10002 return ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -070010003}
10004
10005
Hai Shalom81f62d82019-07-22 12:10:00 -070010006static int nl80211_update_dh_ie(void *priv, const u8 *peer_mac,
10007 u16 reason_code, const u8 *ie, size_t ie_len)
10008{
10009 int ret;
10010 struct nl_msg *msg;
10011 struct i802_bss *bss = priv;
10012 struct wpa_driver_nl80211_data *drv = bss->drv;
10013
10014 wpa_printf(MSG_DEBUG, "nl80211: Updating DH IE peer: " MACSTR
10015 " reason %u", MAC2STR(peer_mac), reason_code);
10016 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UPDATE_OWE_INFO)) ||
10017 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer_mac) ||
10018 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, reason_code) ||
10019 (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie))) {
10020 nlmsg_free(msg);
10021 return -ENOBUFS;
10022 }
10023
Hai Shalom899fcc72020-10-19 14:38:18 -070010024 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalom81f62d82019-07-22 12:10:00 -070010025 if (ret) {
10026 wpa_printf(MSG_DEBUG,
10027 "nl80211: update_dh_ie failed err=%d (%s)",
10028 ret, strerror(-ret));
10029 }
10030
10031 return ret;
10032}
10033
10034
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -070010035static const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
Dmitry Shmidt34af3062013-07-11 10:46:32 -070010036{
10037 struct i802_bss *bss = priv;
10038 struct wpa_driver_nl80211_data *drv = bss->drv;
10039
10040 if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
10041 return NULL;
10042
10043 return bss->addr;
10044}
10045
10046
Dmitry Shmidt56052862013-10-04 10:23:25 -070010047static const char * scan_state_str(enum scan_states scan_state)
10048{
10049 switch (scan_state) {
10050 case NO_SCAN:
10051 return "NO_SCAN";
10052 case SCAN_REQUESTED:
10053 return "SCAN_REQUESTED";
10054 case SCAN_STARTED:
10055 return "SCAN_STARTED";
10056 case SCAN_COMPLETED:
10057 return "SCAN_COMPLETED";
10058 case SCAN_ABORTED:
10059 return "SCAN_ABORTED";
10060 case SCHED_SCAN_STARTED:
10061 return "SCHED_SCAN_STARTED";
10062 case SCHED_SCAN_STOPPED:
10063 return "SCHED_SCAN_STOPPED";
10064 case SCHED_SCAN_RESULTS:
10065 return "SCHED_SCAN_RESULTS";
10066 }
10067
10068 return "??";
10069}
10070
10071
10072static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
10073{
10074 struct i802_bss *bss = priv;
10075 struct wpa_driver_nl80211_data *drv = bss->drv;
10076 int res;
10077 char *pos, *end;
Hai Shalom74f70d42019-02-11 14:42:39 -080010078 struct nl_msg *msg;
10079 char alpha2[3] = { 0, 0, 0 };
Dmitry Shmidt56052862013-10-04 10:23:25 -070010080
10081 pos = buf;
10082 end = buf + buflen;
10083
10084 res = os_snprintf(pos, end - pos,
10085 "ifindex=%d\n"
10086 "ifname=%s\n"
10087 "brname=%s\n"
10088 "addr=" MACSTR "\n"
10089 "freq=%d\n"
Hai Shalomc9e41a12018-07-31 14:41:42 -070010090 "%s%s%s%s%s%s",
Dmitry Shmidt56052862013-10-04 10:23:25 -070010091 bss->ifindex,
10092 bss->ifname,
10093 bss->brname,
10094 MAC2STR(bss->addr),
10095 bss->freq,
10096 bss->beacon_set ? "beacon_set=1\n" : "",
10097 bss->added_if_into_bridge ?
10098 "added_if_into_bridge=1\n" : "",
Hai Shalomc9e41a12018-07-31 14:41:42 -070010099 bss->already_in_bridge ? "already_in_bridge=1\n" : "",
Dmitry Shmidt56052862013-10-04 10:23:25 -070010100 bss->added_bridge ? "added_bridge=1\n" : "",
10101 bss->in_deinit ? "in_deinit=1\n" : "",
10102 bss->if_dynamic ? "if_dynamic=1\n" : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010103 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -070010104 return pos - buf;
10105 pos += res;
10106
10107 if (bss->wdev_id_set) {
10108 res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
10109 (unsigned long long) bss->wdev_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010110 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -070010111 return pos - buf;
10112 pos += res;
10113 }
10114
10115 res = os_snprintf(pos, end - pos,
10116 "phyname=%s\n"
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010117 "perm_addr=" MACSTR "\n"
Dmitry Shmidt56052862013-10-04 10:23:25 -070010118 "drv_ifindex=%d\n"
10119 "operstate=%d\n"
10120 "scan_state=%s\n"
10121 "auth_bssid=" MACSTR "\n"
10122 "auth_attempt_bssid=" MACSTR "\n"
10123 "bssid=" MACSTR "\n"
10124 "prev_bssid=" MACSTR "\n"
10125 "associated=%d\n"
10126 "assoc_freq=%u\n"
10127 "monitor_sock=%d\n"
10128 "monitor_ifidx=%d\n"
10129 "monitor_refcount=%d\n"
10130 "last_mgmt_freq=%u\n"
10131 "eapol_tx_sock=%d\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010132 "%s%s%s%s%s%s%s%s%s%s%s%s%s",
Dmitry Shmidt56052862013-10-04 10:23:25 -070010133 drv->phyname,
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010134 MAC2STR(drv->perm_addr),
Dmitry Shmidt56052862013-10-04 10:23:25 -070010135 drv->ifindex,
10136 drv->operstate,
10137 scan_state_str(drv->scan_state),
10138 MAC2STR(drv->auth_bssid),
10139 MAC2STR(drv->auth_attempt_bssid),
10140 MAC2STR(drv->bssid),
10141 MAC2STR(drv->prev_bssid),
10142 drv->associated,
10143 drv->assoc_freq,
10144 drv->monitor_sock,
10145 drv->monitor_ifidx,
10146 drv->monitor_refcount,
10147 drv->last_mgmt_freq,
10148 drv->eapol_tx_sock,
10149 drv->ignore_if_down_event ?
10150 "ignore_if_down_event=1\n" : "",
10151 drv->scan_complete_events ?
10152 "scan_complete_events=1\n" : "",
10153 drv->disabled_11b_rates ?
10154 "disabled_11b_rates=1\n" : "",
10155 drv->pending_remain_on_chan ?
10156 "pending_remain_on_chan=1\n" : "",
10157 drv->in_interface_list ? "in_interface_list=1\n" : "",
10158 drv->device_ap_sme ? "device_ap_sme=1\n" : "",
10159 drv->poll_command_supported ?
10160 "poll_command_supported=1\n" : "",
10161 drv->data_tx_status ? "data_tx_status=1\n" : "",
10162 drv->scan_for_auth ? "scan_for_auth=1\n" : "",
10163 drv->retry_auth ? "retry_auth=1\n" : "",
10164 drv->use_monitor ? "use_monitor=1\n" : "",
10165 drv->ignore_next_local_disconnect ?
10166 "ignore_next_local_disconnect=1\n" : "",
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -070010167 drv->ignore_next_local_deauth ?
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010168 "ignore_next_local_deauth=1\n" : "");
10169 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -070010170 return pos - buf;
10171 pos += res;
10172
Sunil Ravi89eba102022-09-13 21:04:37 -070010173 if (drv->sta_mlo_info.valid_links) {
10174 int i;
10175 struct driver_sta_mlo_info *mlo = &drv->sta_mlo_info;
10176
10177 res = os_snprintf(pos, end - pos,
10178 "ap_mld_addr=" MACSTR "\n",
10179 MAC2STR(mlo->ap_mld_addr));
10180 if (os_snprintf_error(end - pos, res))
10181 return pos - buf;
10182 pos += res;
10183
10184 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
10185 if (!(mlo->valid_links & BIT(i)))
10186 continue;
10187
10188 res = os_snprintf(pos, end - pos,
10189 "link_addr[%u]=" MACSTR "\n"
10190 "link_bssid[%u]=" MACSTR "\n"
10191 "link_freq[%u]=%u\n",
10192 i, MAC2STR(mlo->links[i].addr),
10193 i, MAC2STR(mlo->links[i].bssid),
10194 i, mlo->links[i].freq);
10195 if (os_snprintf_error(end - pos, res))
10196 return pos - buf;
10197 pos += res;
10198 }
10199 }
10200
Dmitry Shmidt56052862013-10-04 10:23:25 -070010201 if (drv->has_capability) {
10202 res = os_snprintf(pos, end - pos,
10203 "capa.key_mgmt=0x%x\n"
10204 "capa.enc=0x%x\n"
10205 "capa.auth=0x%x\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010206 "capa.flags=0x%llx\n"
10207 "capa.rrm_flags=0x%x\n"
Dmitry Shmidt56052862013-10-04 10:23:25 -070010208 "capa.max_scan_ssids=%d\n"
10209 "capa.max_sched_scan_ssids=%d\n"
10210 "capa.sched_scan_supported=%d\n"
10211 "capa.max_match_sets=%d\n"
10212 "capa.max_remain_on_chan=%u\n"
10213 "capa.max_stations=%u\n"
10214 "capa.probe_resp_offloads=0x%x\n"
10215 "capa.max_acl_mac_addrs=%u\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010216 "capa.num_multichan_concurrent=%u\n"
10217 "capa.mac_addr_rand_sched_scan_supported=%d\n"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010218 "capa.mac_addr_rand_scan_supported=%d\n"
10219 "capa.conc_capab=%u\n"
10220 "capa.max_conc_chan_2_4=%u\n"
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080010221 "capa.max_conc_chan_5_0=%u\n"
10222 "capa.max_sched_scan_plans=%u\n"
10223 "capa.max_sched_scan_plan_interval=%u\n"
10224 "capa.max_sched_scan_plan_iterations=%u\n",
Dmitry Shmidt56052862013-10-04 10:23:25 -070010225 drv->capa.key_mgmt,
10226 drv->capa.enc,
10227 drv->capa.auth,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010228 (unsigned long long) drv->capa.flags,
10229 drv->capa.rrm_flags,
Dmitry Shmidt56052862013-10-04 10:23:25 -070010230 drv->capa.max_scan_ssids,
10231 drv->capa.max_sched_scan_ssids,
10232 drv->capa.sched_scan_supported,
10233 drv->capa.max_match_sets,
10234 drv->capa.max_remain_on_chan,
10235 drv->capa.max_stations,
10236 drv->capa.probe_resp_offloads,
10237 drv->capa.max_acl_mac_addrs,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010238 drv->capa.num_multichan_concurrent,
10239 drv->capa.mac_addr_rand_sched_scan_supported,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010240 drv->capa.mac_addr_rand_scan_supported,
10241 drv->capa.conc_capab,
10242 drv->capa.max_conc_chan_2_4,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080010243 drv->capa.max_conc_chan_5_0,
10244 drv->capa.max_sched_scan_plans,
10245 drv->capa.max_sched_scan_plan_interval,
10246 drv->capa.max_sched_scan_plan_iterations);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010247 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -070010248 return pos - buf;
10249 pos += res;
10250 }
10251
Hai Shalom74f70d42019-02-11 14:42:39 -080010252 msg = nlmsg_alloc();
10253 if (msg &&
10254 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG) &&
10255 nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx) == 0) {
10256 if (send_and_recv_msgs(drv, msg, nl80211_get_country,
Hai Shalom899fcc72020-10-19 14:38:18 -070010257 alpha2, NULL, NULL) == 0 &&
Hai Shalom74f70d42019-02-11 14:42:39 -080010258 alpha2[0]) {
10259 res = os_snprintf(pos, end - pos, "country=%s\n",
10260 alpha2);
10261 if (os_snprintf_error(end - pos, res))
10262 return pos - buf;
10263 pos += res;
10264 }
10265 } else {
10266 nlmsg_free(msg);
10267 }
10268
Dmitry Shmidt56052862013-10-04 10:23:25 -070010269 return pos - buf;
10270}
10271
10272
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010273static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
10274{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010275 if ((settings->head &&
10276 nla_put(msg, NL80211_ATTR_BEACON_HEAD,
10277 settings->head_len, settings->head)) ||
10278 (settings->tail &&
10279 nla_put(msg, NL80211_ATTR_BEACON_TAIL,
10280 settings->tail_len, settings->tail)) ||
10281 (settings->beacon_ies &&
10282 nla_put(msg, NL80211_ATTR_IE,
10283 settings->beacon_ies_len, settings->beacon_ies)) ||
10284 (settings->proberesp_ies &&
10285 nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
10286 settings->proberesp_ies_len, settings->proberesp_ies)) ||
10287 (settings->assocresp_ies &&
10288 nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
10289 settings->assocresp_ies_len, settings->assocresp_ies)) ||
10290 (settings->probe_resp &&
10291 nla_put(msg, NL80211_ATTR_PROBE_RESP,
10292 settings->probe_resp_len, settings->probe_resp)))
10293 return -ENOBUFS;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010294
10295 return 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010296}
10297
10298
10299static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
10300{
10301 struct nl_msg *msg;
10302 struct i802_bss *bss = priv;
10303 struct wpa_driver_nl80211_data *drv = bss->drv;
10304 struct nlattr *beacon_csa;
10305 int ret = -ENOBUFS;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010306 int csa_off_len = 0;
10307 int i;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010308
Hai Shalomc1a21442022-02-04 13:43:00 -080010309 wpa_printf(MSG_DEBUG,
10310 "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d channel=%d sec_channel_offset=%d width=%d cf1=%d cf2=%d%s%s%s)",
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010311 settings->cs_count, settings->block_tx,
Hai Shalomc1a21442022-02-04 13:43:00 -080010312 settings->freq_params.freq,
10313 settings->freq_params.channel,
10314 settings->freq_params.sec_channel_offset,
10315 settings->freq_params.bandwidth,
Dmitry Shmidt04f534e2013-12-09 15:50:16 -080010316 settings->freq_params.center_freq1,
Hai Shalomc1a21442022-02-04 13:43:00 -080010317 settings->freq_params.center_freq2,
10318 settings->freq_params.ht_enabled ? " ht" : "",
10319 settings->freq_params.vht_enabled ? " vht" : "",
10320 settings->freq_params.he_enabled ? " he" : "");
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010321
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010322 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_AP_CSA)) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010323 wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
10324 return -EOPNOTSUPP;
10325 }
10326
Roshan Pius3a1667e2018-07-03 15:17:14 -070010327 if (drv->nlmode != NL80211_IFTYPE_AP &&
10328 drv->nlmode != NL80211_IFTYPE_P2P_GO &&
10329 drv->nlmode != NL80211_IFTYPE_MESH_POINT)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010330 return -EOPNOTSUPP;
10331
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010332 /*
10333 * Remove empty counters, assuming Probe Response and Beacon frame
10334 * counters match. This implementation assumes that there are only two
10335 * counters.
10336 */
10337 if (settings->counter_offset_beacon[0] &&
10338 !settings->counter_offset_beacon[1]) {
10339 csa_off_len = 1;
10340 } else if (settings->counter_offset_beacon[1] &&
10341 !settings->counter_offset_beacon[0]) {
10342 csa_off_len = 1;
10343 settings->counter_offset_beacon[0] =
10344 settings->counter_offset_beacon[1];
10345 settings->counter_offset_presp[0] =
10346 settings->counter_offset_presp[1];
10347 } else if (settings->counter_offset_beacon[1] &&
10348 settings->counter_offset_beacon[0]) {
10349 csa_off_len = 2;
10350 } else {
10351 wpa_printf(MSG_ERROR, "nl80211: No CSA counters provided");
10352 return -EINVAL;
10353 }
10354
10355 /* Check CSA counters validity */
10356 if (drv->capa.max_csa_counters &&
10357 csa_off_len > drv->capa.max_csa_counters) {
10358 wpa_printf(MSG_ERROR,
10359 "nl80211: Too many CSA counters provided");
10360 return -EINVAL;
10361 }
10362
10363 if (!settings->beacon_csa.tail)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010364 return -EINVAL;
10365
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010366 for (i = 0; i < csa_off_len; i++) {
10367 u16 csa_c_off_bcn = settings->counter_offset_beacon[i];
10368 u16 csa_c_off_presp = settings->counter_offset_presp[i];
10369
10370 if ((settings->beacon_csa.tail_len <= csa_c_off_bcn) ||
10371 (settings->beacon_csa.tail[csa_c_off_bcn] !=
10372 settings->cs_count))
10373 return -EINVAL;
10374
10375 if (settings->beacon_csa.probe_resp &&
10376 ((settings->beacon_csa.probe_resp_len <=
10377 csa_c_off_presp) ||
10378 (settings->beacon_csa.probe_resp[csa_c_off_presp] !=
10379 settings->cs_count)))
10380 return -EINVAL;
10381 }
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010382
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010383 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CHANNEL_SWITCH)) ||
10384 nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT,
10385 settings->cs_count) ||
10386 (ret = nl80211_put_freq_params(msg, &settings->freq_params)) ||
10387 (settings->block_tx &&
10388 nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)))
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010389 goto error;
10390
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010391 /* beacon_after params */
10392 ret = set_beacon_data(msg, &settings->beacon_after);
10393 if (ret)
10394 goto error;
10395
10396 /* beacon_csa params */
10397 beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
10398 if (!beacon_csa)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010399 goto fail;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010400
10401 ret = set_beacon_data(msg, &settings->beacon_csa);
10402 if (ret)
10403 goto error;
10404
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010405 if (nla_put(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
10406 csa_off_len * sizeof(u16),
10407 settings->counter_offset_beacon) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010408 (settings->beacon_csa.probe_resp &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010409 nla_put(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
10410 csa_off_len * sizeof(u16),
10411 settings->counter_offset_presp)))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010412 goto fail;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010413
10414 nla_nest_end(msg, beacon_csa);
Hai Shalom899fcc72020-10-19 14:38:18 -070010415 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010416 if (ret) {
10417 wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
10418 ret, strerror(-ret));
10419 }
10420 return ret;
10421
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010422fail:
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010423 ret = -ENOBUFS;
10424error:
10425 nlmsg_free(msg);
10426 wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request");
10427 return ret;
10428}
10429
10430
Sunil Ravia04bd252022-05-02 22:54:18 -070010431#ifdef CONFIG_IEEE80211AX
10432static int nl80211_switch_color(void *priv, struct cca_settings *settings)
10433{
10434 struct i802_bss *bss = priv;
10435 struct wpa_driver_nl80211_data *drv = bss->drv;
10436 struct nlattr *beacon_cca;
10437 struct nl_msg *msg;
10438 int ret = -ENOBUFS;
10439
10440 wpa_printf(MSG_DEBUG,
10441 "nl80211: Color change request (cca_count=%u color=%d)",
10442 settings->cca_count, settings->cca_color);
10443
10444 if (drv->nlmode != NL80211_IFTYPE_AP)
10445 return -EOPNOTSUPP;
10446
10447 if (!settings->beacon_cca.tail)
10448 return -EINVAL;
10449
10450 if (settings->beacon_cca.tail_len <= settings->counter_offset_beacon ||
10451 settings->beacon_cca.tail[settings->counter_offset_beacon] !=
10452 settings->cca_count)
10453 return -EINVAL;
10454
10455 if (settings->beacon_cca.probe_resp &&
10456 (settings->beacon_cca.probe_resp_len <=
10457 settings->counter_offset_presp ||
10458 settings->beacon_cca.probe_resp[settings->counter_offset_presp] !=
10459 settings->cca_count))
10460 return -EINVAL;
10461
10462 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_COLOR_CHANGE_REQUEST);
10463 if (!msg ||
10464 nla_put_u8(msg, NL80211_ATTR_COLOR_CHANGE_COUNT,
10465 settings->cca_count) ||
10466 nla_put_u8(msg, NL80211_ATTR_COLOR_CHANGE_COLOR,
10467 settings->cca_color))
10468 goto error;
10469
10470 /* beacon_after params */
10471 ret = set_beacon_data(msg, &settings->beacon_after);
10472 if (ret)
10473 goto error;
10474
10475 /* beacon_csa params */
10476 beacon_cca = nla_nest_start(msg, NL80211_ATTR_COLOR_CHANGE_ELEMS);
10477 if (!beacon_cca) {
10478 ret = -ENOBUFS;
10479 goto error;
10480 }
10481
10482 ret = set_beacon_data(msg, &settings->beacon_cca);
10483 if (ret)
10484 goto error;
10485
10486 if (nla_put_u16(msg, NL80211_ATTR_CNTDWN_OFFS_BEACON,
10487 settings->counter_offset_beacon) ||
10488 (settings->beacon_cca.probe_resp &&
10489 nla_put_u16(msg, NL80211_ATTR_CNTDWN_OFFS_PRESP,
10490 settings->counter_offset_presp))) {
10491 ret = -ENOBUFS;
10492 goto error;
10493 }
10494
10495 nla_nest_end(msg, beacon_cca);
10496 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
10497 if (ret) {
10498 wpa_printf(MSG_DEBUG,
10499 "nl80211: switch_color failed err=%d (%s)",
10500 ret, strerror(-ret));
10501 }
10502 return ret;
10503
10504error:
10505 nlmsg_free(msg);
10506 wpa_printf(MSG_DEBUG, "nl80211: Could not build color switch request");
10507 return ret;
10508}
10509#endif /* CONFIG_IEEE80211AX */
10510
10511
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010512static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr,
10513 u8 user_priority, u16 admitted_time)
10514{
10515 struct i802_bss *bss = priv;
10516 struct wpa_driver_nl80211_data *drv = bss->drv;
10517 struct nl_msg *msg;
10518 int ret;
10519
10520 wpa_printf(MSG_DEBUG,
10521 "nl80211: add_ts request: tsid=%u admitted_time=%u up=%d",
10522 tsid, admitted_time, user_priority);
10523
10524 if (!is_sta_interface(drv->nlmode))
10525 return -ENOTSUP;
10526
10527 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ADD_TX_TS);
10528 if (!msg ||
10529 nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
10530 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
10531 nla_put_u8(msg, NL80211_ATTR_USER_PRIO, user_priority) ||
10532 nla_put_u16(msg, NL80211_ATTR_ADMITTED_TIME, admitted_time)) {
10533 nlmsg_free(msg);
10534 return -ENOBUFS;
10535 }
10536
Hai Shalom899fcc72020-10-19 14:38:18 -070010537 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010538 if (ret)
10539 wpa_printf(MSG_DEBUG, "nl80211: add_ts failed err=%d (%s)",
10540 ret, strerror(-ret));
10541 return ret;
10542}
10543
10544
10545static int nl80211_del_ts(void *priv, u8 tsid, const u8 *addr)
10546{
10547 struct i802_bss *bss = priv;
10548 struct wpa_driver_nl80211_data *drv = bss->drv;
10549 struct nl_msg *msg;
10550 int ret;
10551
10552 wpa_printf(MSG_DEBUG, "nl80211: del_ts request: tsid=%u", tsid);
10553
10554 if (!is_sta_interface(drv->nlmode))
10555 return -ENOTSUP;
10556
10557 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_TX_TS)) ||
10558 nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
10559 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
10560 nlmsg_free(msg);
10561 return -ENOBUFS;
10562 }
10563
Hai Shalom899fcc72020-10-19 14:38:18 -070010564 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010565 if (ret)
10566 wpa_printf(MSG_DEBUG, "nl80211: del_ts failed err=%d (%s)",
10567 ret, strerror(-ret));
10568 return ret;
10569}
10570
10571
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010572#ifdef CONFIG_TESTING_OPTIONS
10573static int cmd_reply_handler(struct nl_msg *msg, void *arg)
10574{
10575 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
10576 struct wpabuf *buf = arg;
10577
10578 if (!buf)
10579 return NL_SKIP;
10580
10581 if ((size_t) genlmsg_attrlen(gnlh, 0) > wpabuf_tailroom(buf)) {
10582 wpa_printf(MSG_INFO, "nl80211: insufficient buffer space for reply");
10583 return NL_SKIP;
10584 }
10585
10586 wpabuf_put_data(buf, genlmsg_attrdata(gnlh, 0),
10587 genlmsg_attrlen(gnlh, 0));
10588
10589 return NL_SKIP;
10590}
10591#endif /* CONFIG_TESTING_OPTIONS */
10592
10593
10594static int vendor_reply_handler(struct nl_msg *msg, void *arg)
10595{
10596 struct nlattr *tb[NL80211_ATTR_MAX + 1];
10597 struct nlattr *nl_vendor_reply, *nl;
10598 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
10599 struct wpabuf *buf = arg;
10600 int rem;
10601
10602 if (!buf)
10603 return NL_SKIP;
10604
10605 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
10606 genlmsg_attrlen(gnlh, 0), NULL);
10607 nl_vendor_reply = tb[NL80211_ATTR_VENDOR_DATA];
10608
10609 if (!nl_vendor_reply)
10610 return NL_SKIP;
10611
10612 if ((size_t) nla_len(nl_vendor_reply) > wpabuf_tailroom(buf)) {
10613 wpa_printf(MSG_INFO, "nl80211: Vendor command: insufficient buffer space for reply");
10614 return NL_SKIP;
10615 }
10616
10617 nla_for_each_nested(nl, nl_vendor_reply, rem) {
10618 wpabuf_put_data(buf, nla_data(nl), nla_len(nl));
10619 }
10620
10621 return NL_SKIP;
10622}
10623
10624
Hai Shalom60840252021-02-19 19:02:11 -080010625static bool is_cmd_with_nested_attrs(unsigned int vendor_id,
10626 unsigned int subcmd)
10627{
10628 if (vendor_id != OUI_QCA)
10629 return true;
10630
10631 switch (subcmd) {
10632 case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
10633 case QCA_NL80211_VENDOR_SUBCMD_STATS_EXT:
10634 case QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI:
10635 case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY:
10636 case QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS:
10637 case QCA_NL80211_VENDOR_SUBCMD_NAN:
10638 return false;
10639 default:
10640 return true;
10641 }
10642}
10643
10644
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010645static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
10646 unsigned int subcmd, const u8 *data,
Hai Shalom60840252021-02-19 19:02:11 -080010647 size_t data_len, enum nested_attr nested_attr,
10648 struct wpabuf *buf)
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010649{
10650 struct i802_bss *bss = priv;
10651 struct wpa_driver_nl80211_data *drv = bss->drv;
10652 struct nl_msg *msg;
Hai Shalom60840252021-02-19 19:02:11 -080010653 int ret, nla_flag;
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010654
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010655#ifdef CONFIG_TESTING_OPTIONS
10656 if (vendor_id == 0xffffffff) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010657 msg = nlmsg_alloc();
10658 if (!msg)
10659 return -ENOMEM;
10660
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010661 nl80211_cmd(drv, msg, 0, subcmd);
10662 if (nlmsg_append(msg, (void *) data, data_len, NLMSG_ALIGNTO) <
10663 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010664 goto fail;
Hai Shalomb755a2a2020-04-23 21:49:02 -070010665 /* This test vendor_cmd can be used with nl80211 commands that
10666 * need the connect nl_sock, so use the owner-setting variant
10667 * of send_and_recv_msgs(). */
10668 ret = send_and_recv_msgs_owner(drv, msg,
10669 get_connect_handle(bss), 0,
Hai Shalom899fcc72020-10-19 14:38:18 -070010670 cmd_reply_handler, buf,
10671 NULL, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010672 if (ret)
10673 wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
10674 ret);
10675 return ret;
10676 }
10677#endif /* CONFIG_TESTING_OPTIONS */
10678
Hai Shalom60840252021-02-19 19:02:11 -080010679 if (nested_attr == NESTED_ATTR_USED)
10680 nla_flag = NLA_F_NESTED;
10681 else if (nested_attr == NESTED_ATTR_UNSPECIFIED &&
10682 is_cmd_with_nested_attrs(vendor_id, subcmd))
10683 nla_flag = NLA_F_NESTED;
10684 else
10685 nla_flag = 0;
10686
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010687 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
10688 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, vendor_id) ||
10689 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd) ||
10690 (data &&
Hai Shalom60840252021-02-19 19:02:11 -080010691 nla_put(msg, nla_flag | NL80211_ATTR_VENDOR_DATA,
10692 data_len, data)))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010693 goto fail;
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010694
Hai Shalom899fcc72020-10-19 14:38:18 -070010695 ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf,
10696 NULL, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010697 if (ret)
10698 wpa_printf(MSG_DEBUG, "nl80211: vendor command failed err=%d",
10699 ret);
10700 return ret;
10701
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010702fail:
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010703 nlmsg_free(msg);
10704 return -ENOBUFS;
10705}
10706
10707
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010708static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
10709 u8 qos_map_set_len)
10710{
10711 struct i802_bss *bss = priv;
10712 struct wpa_driver_nl80211_data *drv = bss->drv;
10713 struct nl_msg *msg;
10714 int ret;
10715
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010716 wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
10717 qos_map_set, qos_map_set_len);
10718
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010719 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_QOS_MAP)) ||
10720 nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) {
10721 nlmsg_free(msg);
10722 return -ENOBUFS;
10723 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010724
Hai Shalom899fcc72020-10-19 14:38:18 -070010725 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010726 if (ret)
10727 wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
10728
10729 return ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010730}
10731
10732
Hai Shalomfdcde762020-04-02 11:19:20 -070010733static int get_wowlan_handler(struct nl_msg *msg, void *arg)
10734{
10735 struct nlattr *tb[NL80211_ATTR_MAX + 1];
10736 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
10737 int *wowlan_enabled = arg;
10738
10739 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
10740 genlmsg_attrlen(gnlh, 0), NULL);
10741
10742 *wowlan_enabled = !!tb[NL80211_ATTR_WOWLAN_TRIGGERS];
10743
10744 return NL_SKIP;
10745}
10746
10747
10748static int nl80211_get_wowlan(void *priv)
10749{
10750 struct i802_bss *bss = priv;
10751 struct wpa_driver_nl80211_data *drv = bss->drv;
10752 struct nl_msg *msg;
10753 int wowlan_enabled;
10754 int ret;
10755
10756 wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status");
10757
10758 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_WOWLAN);
10759
Hai Shalom899fcc72020-10-19 14:38:18 -070010760 ret = send_and_recv_msgs(drv, msg, get_wowlan_handler, &wowlan_enabled,
10761 NULL, NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -070010762 if (ret) {
10763 wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status failed");
10764 return 0;
10765 }
10766
10767 wpa_printf(MSG_DEBUG, "nl80211: wowlan is %s",
10768 wowlan_enabled ? "enabled" : "disabled");
10769
10770 return wowlan_enabled;
10771}
10772
10773
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010774static int nl80211_set_wowlan(void *priv,
10775 const struct wowlan_triggers *triggers)
10776{
10777 struct i802_bss *bss = priv;
10778 struct wpa_driver_nl80211_data *drv = bss->drv;
10779 struct nl_msg *msg;
10780 struct nlattr *wowlan_triggers;
10781 int ret;
10782
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010783 wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
10784
Dmitry Shmidta3dc3092015-06-23 11:21:28 -070010785 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_WOWLAN)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010786 !(wowlan_triggers = nla_nest_start(msg,
10787 NL80211_ATTR_WOWLAN_TRIGGERS)) ||
10788 (triggers->any &&
10789 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
10790 (triggers->disconnect &&
10791 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
10792 (triggers->magic_pkt &&
10793 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
10794 (triggers->gtk_rekey_failure &&
10795 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
10796 (triggers->eap_identity_req &&
10797 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
10798 (triggers->four_way_handshake &&
10799 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
10800 (triggers->rfkill_release &&
10801 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) {
10802 nlmsg_free(msg);
10803 return -ENOBUFS;
10804 }
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010805
10806 nla_nest_end(msg, wowlan_triggers);
10807
Hai Shalom899fcc72020-10-19 14:38:18 -070010808 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010809 if (ret)
10810 wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
10811
10812 return ret;
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010813}
10814
10815
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010816#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010817static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
10818{
10819 struct i802_bss *bss = priv;
10820 struct wpa_driver_nl80211_data *drv = bss->drv;
10821 struct nl_msg *msg;
10822 struct nlattr *params;
10823
10824 wpa_printf(MSG_DEBUG, "nl80211: Roaming policy: allowed=%d", allowed);
10825
10826 if (!drv->roaming_vendor_cmd_avail) {
10827 wpa_printf(MSG_DEBUG,
10828 "nl80211: Ignore roaming policy change since driver does not provide command for setting it");
10829 return -1;
10830 }
10831
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010832 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10833 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10834 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10835 QCA_NL80211_VENDOR_SUBCMD_ROAMING) ||
10836 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10837 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
10838 allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
10839 QCA_ROAMING_NOT_ALLOWED) ||
10840 (bssid &&
10841 nla_put(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid))) {
10842 nlmsg_free(msg);
10843 return -1;
10844 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010845 nla_nest_end(msg, params);
10846
Hai Shalom899fcc72020-10-19 14:38:18 -070010847 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010848}
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010849
10850
Roshan Pius3a1667e2018-07-03 15:17:14 -070010851static int nl80211_disable_fils(void *priv, int disable)
10852{
10853 struct i802_bss *bss = priv;
10854 struct wpa_driver_nl80211_data *drv = bss->drv;
10855 struct nl_msg *msg;
10856 struct nlattr *params;
10857
10858 wpa_printf(MSG_DEBUG, "nl80211: Disable FILS=%d", disable);
10859
10860 if (!drv->set_wifi_conf_vendor_cmd_avail)
10861 return -1;
10862
10863 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10864 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10865 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10866 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION) ||
10867 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10868 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS,
10869 disable)) {
10870 nlmsg_free(msg);
10871 return -1;
10872 }
10873 nla_nest_end(msg, params);
10874
Hai Shalom899fcc72020-10-19 14:38:18 -070010875 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010876}
10877
10878
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010879/* Reserved QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID value for wpa_supplicant */
10880#define WPA_SUPPLICANT_CLIENT_ID 1
10881
Hai Shalom899fcc72020-10-19 14:38:18 -070010882static int nl80211_set_bssid_tmp_disallow(void *priv, unsigned int num_bssid,
10883 const u8 *bssid)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010884{
10885 struct i802_bss *bss = priv;
10886 struct wpa_driver_nl80211_data *drv = bss->drv;
10887 struct nl_msg *msg;
10888 struct nlattr *params, *nlbssids, *attr;
10889 unsigned int i;
10890
Hai Shalom899fcc72020-10-19 14:38:18 -070010891 wpa_printf(MSG_DEBUG,
10892 "nl80211: Set temporarily disallowed BSSIDs (num=%u)",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010893 num_bssid);
10894
10895 if (!drv->roam_vendor_cmd_avail)
10896 return -1;
10897
10898 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10899 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10900 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10901 QCA_NL80211_VENDOR_SUBCMD_ROAM) ||
10902 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10903 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
Hai Shalomc3565922019-10-28 11:58:20 -070010904 QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010905 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID,
10906 WPA_SUPPLICANT_CLIENT_ID) ||
10907 nla_put_u32(msg,
10908 QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID,
10909 num_bssid))
10910 goto fail;
10911
10912 nlbssids = nla_nest_start(
10913 msg, QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS);
10914 if (!nlbssids)
10915 goto fail;
10916
10917 for (i = 0; i < num_bssid; i++) {
10918 attr = nla_nest_start(msg, i);
10919 if (!attr)
10920 goto fail;
10921 if (nla_put(msg,
10922 QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID,
10923 ETH_ALEN, &bssid[i * ETH_ALEN]))
10924 goto fail;
10925 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%u]: " MACSTR, i,
10926 MAC2STR(&bssid[i * ETH_ALEN]));
10927 nla_nest_end(msg, attr);
10928 }
10929 nla_nest_end(msg, nlbssids);
10930 nla_nest_end(msg, params);
10931
Hai Shalom899fcc72020-10-19 14:38:18 -070010932 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010933
10934fail:
10935 nlmsg_free(msg);
10936 return -1;
10937}
10938
Hai Shalomc3565922019-10-28 11:58:20 -070010939
10940static int nl80211_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
10941{
10942 struct i802_bss *bss = priv;
10943 struct wpa_driver_nl80211_data *drv = bss->drv;
10944 struct nl_msg *msg;
10945 struct nlattr *params;
10946
10947 if (!drv->add_sta_node_vendor_cmd_avail)
10948 return -EOPNOTSUPP;
10949
10950 wpa_printf(MSG_DEBUG, "nl80211: Add STA node");
10951
10952 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10953 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10954 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10955 QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE) ||
10956 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10957 (addr &&
10958 nla_put(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_MAC_ADDR, ETH_ALEN,
10959 addr)) ||
10960 nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO,
10961 auth_alg)) {
10962 nlmsg_free(msg);
10963 wpa_printf(MSG_ERROR,
10964 "%s: err in adding vendor_cmd and vendor_data",
10965 __func__);
10966 return -1;
10967 }
10968 nla_nest_end(msg, params);
10969
Hai Shalom899fcc72020-10-19 14:38:18 -070010970 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalomc3565922019-10-28 11:58:20 -070010971}
10972
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010973#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010974
10975
10976static int nl80211_set_mac_addr(void *priv, const u8 *addr)
10977{
10978 struct i802_bss *bss = priv;
10979 struct wpa_driver_nl80211_data *drv = bss->drv;
10980 int new_addr = addr != NULL;
Andy Kuoaba17c12022-04-14 16:05:31 +080010981#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Mir Ali8a8f1002020-10-06 22:41:40 +053010982 struct nl_msg *msg;
10983 struct nlattr *params;
10984 int ret;
Andy Kuoaba17c12022-04-14 16:05:31 +080010985#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
Mir Ali8a8f1002020-10-06 22:41:40 +053010986 wpa_printf(MSG_DEBUG, "Enter: %s", __FUNCTION__);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010987
Dmitry Shmidt849734c2016-05-27 09:59:01 -070010988 if (TEST_FAIL())
10989 return -1;
Mir Ali8a8f1002020-10-06 22:41:40 +053010990 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
Andy Kuoaba17c12022-04-14 16:05:31 +080010991#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Mir Ali8a8f1002020-10-06 22:41:40 +053010992 if (!addr ) {
10993 addr = drv->global->p2p_perm_addr;
10994 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -070010995
Mir Ali8a8f1002020-10-06 22:41:40 +053010996 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
10997 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
10998 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
Hai Shalomc1a21442022-02-04 13:43:00 -080010999 BRCM_VENDOR_SCMD_SET_MAC) ||
Mir Ali8a8f1002020-10-06 22:41:40 +053011000 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
11001 nla_put(msg, BRCM_ATTR_DRIVER_MAC_ADDR, ETH_ALEN, addr)) {
11002 wpa_printf(MSG_ERROR, "failed to put p2p randmac");
11003 nl80211_nlmsg_clear(msg);
11004 nlmsg_free(msg);
11005 return -ENOBUFS;
11006 }
11007 nla_nest_end(msg, params);
11008
11009 ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
11010 if (ret) {
11011 wpa_printf(MSG_ERROR, "nl80211: p2p set macaddr failed: ret=%d (%s)",
11012 ret, strerror(-ret));
11013 }
11014 memcpy(bss->addr, addr, ETH_ALEN);
11015 return ret;
11016#else
11017 return -ENOTSUP;
Andy Kuoaba17c12022-04-14 16:05:31 +080011018#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
Mir Ali8a8f1002020-10-06 22:41:40 +053011019 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070011020 if (!addr)
11021 addr = drv->perm_addr;
11022
11023 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) < 0)
11024 return -1;
11025
11026 if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, addr) < 0)
11027 {
11028 wpa_printf(MSG_DEBUG,
Mir Ali8a8f1002020-10-06 22:41:40 +053011029 "nl80211: failed to set_mac_addr for %s to " MACSTR,
11030 bss->ifname, MAC2STR(addr));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070011031 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
Mir Ali8a8f1002020-10-06 22:41:40 +053011032 1) < 0) {
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070011033 wpa_printf(MSG_DEBUG,
Mir Ali8a8f1002020-10-06 22:41:40 +053011034 "nl80211: Could not restore interface UP after failed set_mac_addr");
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070011035 }
11036 return -1;
11037 }
11038
11039 wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR,
Mir Ali8a8f1002020-10-06 22:41:40 +053011040 bss->ifname, MAC2STR(addr));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070011041 drv->addr_changed = new_addr;
11042 os_memcpy(bss->addr, addr, ETH_ALEN);
11043
11044 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0)
11045 {
11046 wpa_printf(MSG_DEBUG,
Mir Ali8a8f1002020-10-06 22:41:40 +053011047 "nl80211: Could not restore interface UP after set_mac_addr");
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070011048 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070011049 return 0;
11050}
11051
11052
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011053#ifdef CONFIG_MESH
11054
11055static int wpa_driver_nl80211_init_mesh(void *priv)
11056{
11057 if (wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_MESH_POINT)) {
11058 wpa_printf(MSG_INFO,
11059 "nl80211: Failed to set interface into mesh mode");
11060 return -1;
11061 }
11062 return 0;
11063}
11064
11065
Dmitry Shmidtff787d52015-01-12 13:01:47 -080011066static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id,
11067 size_t mesh_id_len)
11068{
11069 if (mesh_id) {
Hai Shalom74f70d42019-02-11 14:42:39 -080011070 wpa_printf(MSG_DEBUG, " * Mesh ID (SSID)=%s",
11071 wpa_ssid_txt(mesh_id, mesh_id_len));
Dmitry Shmidtff787d52015-01-12 13:01:47 -080011072 return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
11073 }
11074
11075 return 0;
11076}
11077
11078
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070011079static int nl80211_put_mesh_config(struct nl_msg *msg,
11080 struct wpa_driver_mesh_bss_params *params)
11081{
11082 struct nlattr *container;
11083
11084 container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
11085 if (!container)
11086 return -1;
11087
11088 if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
Roshan Pius3a1667e2018-07-03 15:17:14 -070011089 nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
11090 params->auto_plinks)) ||
Hai Shalomc1a21442022-02-04 13:43:00 -080011091 ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_FORWARDING) &&
11092 nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
11093 params->forwarding)) ||
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070011094 ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) &&
11095 nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011096 params->max_peer_links)) ||
11097 ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD) &&
11098 nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
11099 params->rssi_threshold)))
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070011100 return -1;
11101
11102 /*
11103 * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
11104 * the timer could disconnect stations even in that case.
11105 */
11106 if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT) &&
11107 nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
11108 params->peer_link_timeout)) {
11109 wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
11110 return -1;
11111 }
11112
11113 if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE) &&
11114 nla_put_u16(msg, NL80211_MESHCONF_HT_OPMODE, params->ht_opmode)) {
11115 wpa_printf(MSG_ERROR, "nl80211: Failed to set HT_OP_MODE");
11116 return -1;
11117 }
11118
11119 nla_nest_end(msg, container);
11120
11121 return 0;
11122}
11123
11124
Dmitry Shmidt7f656022015-02-25 14:36:37 -080011125static int nl80211_join_mesh(struct i802_bss *bss,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011126 struct wpa_driver_mesh_join_params *params)
11127{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011128 struct wpa_driver_nl80211_data *drv = bss->drv;
11129 struct nl_msg *msg;
11130 struct nlattr *container;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -080011131 int ret = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011132
11133 wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
11134 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
Dmitry Shmidtff787d52015-01-12 13:01:47 -080011135 if (!msg ||
11136 nl80211_put_freq_params(msg, &params->freq) ||
11137 nl80211_put_basic_rates(msg, params->basic_rates) ||
11138 nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) ||
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070011139 nl80211_put_beacon_int(msg, params->beacon_int) ||
11140 nl80211_put_dtim_period(msg, params->dtim_period))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011141 goto fail;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011142
11143 wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags);
11144
Hai Shalom60840252021-02-19 19:02:11 -080011145 if (params->handle_dfs && nla_put_flag(msg, NL80211_ATTR_HANDLE_DFS))
11146 goto fail;
11147
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011148 container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
11149 if (!container)
11150 goto fail;
11151
11152 if (params->ies) {
11153 wpa_hexdump(MSG_DEBUG, " * IEs", params->ies, params->ie_len);
11154 if (nla_put(msg, NL80211_MESH_SETUP_IE, params->ie_len,
11155 params->ies))
11156 goto fail;
11157 }
11158 /* WPA_DRIVER_MESH_FLAG_OPEN_AUTH is treated as default by nl80211 */
11159 if (params->flags & WPA_DRIVER_MESH_FLAG_SAE_AUTH) {
11160 if (nla_put_u8(msg, NL80211_MESH_SETUP_AUTH_PROTOCOL, 0x1) ||
11161 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AUTH))
11162 goto fail;
11163 }
11164 if ((params->flags & WPA_DRIVER_MESH_FLAG_AMPE) &&
11165 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AMPE))
11166 goto fail;
11167 if ((params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) &&
11168 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_MPM))
11169 goto fail;
11170 nla_nest_end(msg, container);
11171
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070011172 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
11173 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT;
11174 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS;
11175 if (nl80211_put_mesh_config(msg, &params->conf) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011176 goto fail;
11177
Hai Shalomc1a21442022-02-04 13:43:00 -080011178 ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011179 msg = NULL;
11180 if (ret) {
11181 wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
11182 ret, strerror(-ret));
11183 goto fail;
11184 }
11185 ret = 0;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070011186 drv->assoc_freq = bss->freq = params->freq.freq;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011187 wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
11188
11189fail:
11190 nlmsg_free(msg);
11191 return ret;
11192}
11193
11194
Dmitry Shmidt7f656022015-02-25 14:36:37 -080011195static int
11196wpa_driver_nl80211_join_mesh(void *priv,
11197 struct wpa_driver_mesh_join_params *params)
11198{
11199 struct i802_bss *bss = priv;
11200 int ret, timeout;
11201
11202 timeout = params->conf.peer_link_timeout;
11203
11204 /* Disable kernel inactivity timer */
11205 if (params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM)
11206 params->conf.peer_link_timeout = 0;
11207
11208 ret = nl80211_join_mesh(bss, params);
11209 if (ret == -EINVAL && params->conf.peer_link_timeout == 0) {
11210 wpa_printf(MSG_DEBUG,
11211 "nl80211: Mesh join retry for peer_link_timeout");
11212 /*
11213 * Old kernel does not support setting
11214 * NL80211_MESHCONF_PLINK_TIMEOUT to zero, so set 60 seconds
11215 * into future from peer_link_timeout.
11216 */
11217 params->conf.peer_link_timeout = timeout + 60;
11218 ret = nl80211_join_mesh(priv, params);
11219 }
11220
11221 params->conf.peer_link_timeout = timeout;
11222 return ret;
11223}
11224
11225
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011226static int wpa_driver_nl80211_leave_mesh(void *priv)
11227{
11228 struct i802_bss *bss = priv;
11229 struct wpa_driver_nl80211_data *drv = bss->drv;
11230 struct nl_msg *msg;
11231 int ret;
11232
11233 wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
11234 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
Hai Shalomc1a21442022-02-04 13:43:00 -080011235 ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011236 if (ret) {
11237 wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
11238 ret, strerror(-ret));
11239 } else {
11240 wpa_printf(MSG_DEBUG,
11241 "nl80211: mesh leave request send successfully");
Hai Shalomc1a21442022-02-04 13:43:00 -080011242 drv->first_bss->freq = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011243 }
11244
Hai Shalomc1a21442022-02-04 13:43:00 -080011245 if (drv->start_mode_sta &&
11246 wpa_driver_nl80211_set_mode(drv->first_bss,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011247 NL80211_IFTYPE_STATION)) {
11248 wpa_printf(MSG_INFO,
11249 "nl80211: Failed to set interface into station mode");
11250 }
11251 return ret;
11252}
11253
Hai Shalom81f62d82019-07-22 12:10:00 -070011254
11255static int nl80211_probe_mesh_link(void *priv, const u8 *addr, const u8 *eth,
11256 size_t len)
11257{
11258 struct i802_bss *bss = priv;
11259 struct wpa_driver_nl80211_data *drv = bss->drv;
11260 struct nl_msg *msg;
11261 int ret;
11262
11263 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_PROBE_MESH_LINK);
11264 if (!msg ||
11265 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
11266 nla_put(msg, NL80211_ATTR_FRAME, len, eth)) {
11267 nlmsg_free(msg);
11268 return -ENOBUFS;
11269 }
11270
Hai Shalom899fcc72020-10-19 14:38:18 -070011271 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalom81f62d82019-07-22 12:10:00 -070011272 if (ret) {
11273 wpa_printf(MSG_DEBUG, "nl80211: mesh link probe to " MACSTR
11274 " failed: ret=%d (%s)",
11275 MAC2STR(addr), ret, strerror(-ret));
11276 } else {
11277 wpa_printf(MSG_DEBUG, "nl80211: Mesh link to " MACSTR
11278 " probed successfully", MAC2STR(addr));
11279 }
11280
11281 return ret;
11282}
11283
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011284#endif /* CONFIG_MESH */
11285
11286
11287static int wpa_driver_br_add_ip_neigh(void *priv, u8 version,
11288 const u8 *ipaddr, int prefixlen,
11289 const u8 *addr)
11290{
11291#ifdef CONFIG_LIBNL3_ROUTE
11292 struct i802_bss *bss = priv;
11293 struct wpa_driver_nl80211_data *drv = bss->drv;
11294 struct rtnl_neigh *rn;
11295 struct nl_addr *nl_ipaddr = NULL;
11296 struct nl_addr *nl_lladdr = NULL;
11297 int family, addrsize;
11298 int res;
11299
11300 if (!ipaddr || prefixlen == 0 || !addr)
11301 return -EINVAL;
11302
11303 if (bss->br_ifindex == 0) {
11304 wpa_printf(MSG_DEBUG,
11305 "nl80211: bridge must be set before adding an ip neigh to it");
11306 return -1;
11307 }
11308
11309 if (!drv->rtnl_sk) {
11310 wpa_printf(MSG_DEBUG,
11311 "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
11312 return -1;
11313 }
11314
11315 if (version == 4) {
11316 family = AF_INET;
11317 addrsize = 4;
11318 } else if (version == 6) {
11319 family = AF_INET6;
11320 addrsize = 16;
11321 } else {
11322 return -EINVAL;
11323 }
11324
11325 rn = rtnl_neigh_alloc();
11326 if (rn == NULL)
11327 return -ENOMEM;
11328
11329 /* set the destination ip address for neigh */
11330 nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
11331 if (nl_ipaddr == NULL) {
11332 wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
11333 res = -ENOMEM;
11334 goto errout;
11335 }
11336 nl_addr_set_prefixlen(nl_ipaddr, prefixlen);
11337 res = rtnl_neigh_set_dst(rn, nl_ipaddr);
11338 if (res) {
11339 wpa_printf(MSG_DEBUG,
11340 "nl80211: neigh set destination addr failed");
11341 goto errout;
11342 }
11343
11344 /* set the corresponding lladdr for neigh */
11345 nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN);
11346 if (nl_lladdr == NULL) {
11347 wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed");
11348 res = -ENOMEM;
11349 goto errout;
11350 }
11351 rtnl_neigh_set_lladdr(rn, nl_lladdr);
11352
11353 rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
11354 rtnl_neigh_set_state(rn, NUD_PERMANENT);
11355
11356 res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE);
11357 if (res) {
11358 wpa_printf(MSG_DEBUG,
11359 "nl80211: Adding bridge ip neigh failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070011360 nl_geterror(res));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011361 }
11362errout:
11363 if (nl_lladdr)
11364 nl_addr_put(nl_lladdr);
11365 if (nl_ipaddr)
11366 nl_addr_put(nl_ipaddr);
11367 if (rn)
11368 rtnl_neigh_put(rn);
11369 return res;
11370#else /* CONFIG_LIBNL3_ROUTE */
11371 return -1;
11372#endif /* CONFIG_LIBNL3_ROUTE */
11373}
11374
11375
11376static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version,
11377 const u8 *ipaddr)
11378{
11379#ifdef CONFIG_LIBNL3_ROUTE
11380 struct i802_bss *bss = priv;
11381 struct wpa_driver_nl80211_data *drv = bss->drv;
11382 struct rtnl_neigh *rn;
11383 struct nl_addr *nl_ipaddr;
11384 int family, addrsize;
11385 int res;
11386
11387 if (!ipaddr)
11388 return -EINVAL;
11389
11390 if (version == 4) {
11391 family = AF_INET;
11392 addrsize = 4;
11393 } else if (version == 6) {
11394 family = AF_INET6;
11395 addrsize = 16;
11396 } else {
11397 return -EINVAL;
11398 }
11399
11400 if (bss->br_ifindex == 0) {
11401 wpa_printf(MSG_DEBUG,
11402 "nl80211: bridge must be set to delete an ip neigh");
11403 return -1;
11404 }
11405
11406 if (!drv->rtnl_sk) {
11407 wpa_printf(MSG_DEBUG,
11408 "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
11409 return -1;
11410 }
11411
11412 rn = rtnl_neigh_alloc();
11413 if (rn == NULL)
11414 return -ENOMEM;
11415
11416 /* set the destination ip address for neigh */
11417 nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
11418 if (nl_ipaddr == NULL) {
11419 wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
11420 res = -ENOMEM;
11421 goto errout;
11422 }
11423 res = rtnl_neigh_set_dst(rn, nl_ipaddr);
11424 if (res) {
11425 wpa_printf(MSG_DEBUG,
11426 "nl80211: neigh set destination addr failed");
11427 goto errout;
11428 }
11429
11430 rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
11431
11432 res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
11433 if (res) {
11434 wpa_printf(MSG_DEBUG,
11435 "nl80211: Deleting bridge ip neigh failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070011436 nl_geterror(res));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011437 }
11438errout:
11439 if (nl_ipaddr)
11440 nl_addr_put(nl_ipaddr);
11441 if (rn)
11442 rtnl_neigh_put(rn);
11443 return res;
11444#else /* CONFIG_LIBNL3_ROUTE */
11445 return -1;
11446#endif /* CONFIG_LIBNL3_ROUTE */
11447}
11448
11449
11450static int linux_write_system_file(const char *path, unsigned int val)
11451{
11452 char buf[50];
11453 int fd, len;
11454
11455 len = os_snprintf(buf, sizeof(buf), "%u\n", val);
11456 if (os_snprintf_error(sizeof(buf), len))
11457 return -1;
11458
11459 fd = open(path, O_WRONLY);
11460 if (fd < 0)
11461 return -1;
11462
11463 if (write(fd, buf, len) < 0) {
11464 wpa_printf(MSG_DEBUG,
11465 "nl80211: Failed to write Linux system file: %s with the value of %d",
11466 path, val);
11467 close(fd);
11468 return -1;
11469 }
11470 close(fd);
11471
11472 return 0;
11473}
11474
11475
11476static const char * drv_br_port_attr_str(enum drv_br_port_attr attr)
11477{
11478 switch (attr) {
11479 case DRV_BR_PORT_ATTR_PROXYARP:
Dmitry Shmidt4dd28dc2015-03-10 11:21:43 -070011480 return "proxyarp_wifi";
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011481 case DRV_BR_PORT_ATTR_HAIRPIN_MODE:
11482 return "hairpin_mode";
11483 }
11484
11485 return NULL;
11486}
11487
11488
11489static int wpa_driver_br_port_set_attr(void *priv, enum drv_br_port_attr attr,
11490 unsigned int val)
11491{
11492 struct i802_bss *bss = priv;
11493 char path[128];
11494 const char *attr_txt;
11495
11496 attr_txt = drv_br_port_attr_str(attr);
11497 if (attr_txt == NULL)
11498 return -EINVAL;
11499
11500 os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/%s",
11501 bss->ifname, attr_txt);
11502
11503 if (linux_write_system_file(path, val))
11504 return -1;
11505
11506 return 0;
11507}
11508
11509
11510static const char * drv_br_net_param_str(enum drv_br_net_param param)
11511{
11512 switch (param) {
11513 case DRV_BR_NET_PARAM_GARP_ACCEPT:
11514 return "arp_accept";
Dmitry Shmidt83474442015-04-15 13:47:09 -070011515 default:
11516 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011517 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011518}
11519
11520
11521static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
11522 unsigned int val)
11523{
11524 struct i802_bss *bss = priv;
11525 char path[128];
11526 const char *param_txt;
11527 int ip_version = 4;
11528
Dmitry Shmidt83474442015-04-15 13:47:09 -070011529 if (param == DRV_BR_MULTICAST_SNOOPING) {
11530 os_snprintf(path, sizeof(path),
11531 "/sys/devices/virtual/net/%s/bridge/multicast_snooping",
11532 bss->brname);
11533 goto set_val;
11534 }
11535
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011536 param_txt = drv_br_net_param_str(param);
11537 if (param_txt == NULL)
11538 return -EINVAL;
11539
11540 switch (param) {
11541 case DRV_BR_NET_PARAM_GARP_ACCEPT:
11542 ip_version = 4;
11543 break;
11544 default:
11545 return -EINVAL;
11546 }
11547
11548 os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
11549 ip_version, bss->brname, param_txt);
11550
Dmitry Shmidt83474442015-04-15 13:47:09 -070011551set_val:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011552 if (linux_write_system_file(path, val))
11553 return -1;
11554
11555 return 0;
11556}
11557
11558
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011559#ifdef CONFIG_DRIVER_NL80211_QCA
11560
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011561static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
11562{
11563 switch (hw_mode) {
11564 case HOSTAPD_MODE_IEEE80211B:
11565 return QCA_ACS_MODE_IEEE80211B;
11566 case HOSTAPD_MODE_IEEE80211G:
11567 return QCA_ACS_MODE_IEEE80211G;
11568 case HOSTAPD_MODE_IEEE80211A:
11569 return QCA_ACS_MODE_IEEE80211A;
11570 case HOSTAPD_MODE_IEEE80211AD:
11571 return QCA_ACS_MODE_IEEE80211AD;
Dmitry Shmidtb1e52102015-05-29 12:36:29 -070011572 case HOSTAPD_MODE_IEEE80211ANY:
11573 return QCA_ACS_MODE_IEEE80211ANY;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011574 default:
11575 return -1;
11576 }
11577}
11578
11579
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080011580static int add_acs_ch_list(struct nl_msg *msg, const int *freq_list)
11581{
11582 int num_channels = 0, num_freqs;
11583 u8 *ch_list;
11584 enum hostapd_hw_mode hw_mode;
11585 int ret = 0;
11586 int i;
11587
11588 if (!freq_list)
11589 return 0;
11590
11591 num_freqs = int_array_len(freq_list);
11592 ch_list = os_malloc(sizeof(u8) * num_freqs);
11593 if (!ch_list)
11594 return -1;
11595
11596 for (i = 0; i < num_freqs; i++) {
11597 const int freq = freq_list[i];
11598
11599 if (freq == 0)
11600 break;
11601 /* Send 2.4 GHz and 5 GHz channels with
11602 * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST to maintain backwards
11603 * compatibility.
11604 */
11605 if (!(freq >= 2412 && freq <= 2484) &&
Hai Shalomc1a21442022-02-04 13:43:00 -080011606 !(freq >= 5180 && freq <= 5900) &&
11607 !(freq >= 5945 && freq <= 7115))
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080011608 continue;
11609 hw_mode = ieee80211_freq_to_chan(freq, &ch_list[num_channels]);
11610 if (hw_mode != NUM_HOSTAPD_MODES)
11611 num_channels++;
11612 }
11613
11614 if (num_channels)
11615 ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
11616 num_channels, ch_list);
11617
11618 os_free(ch_list);
11619 return ret;
11620}
11621
11622
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011623static int add_acs_freq_list(struct nl_msg *msg, const int *freq_list)
11624{
11625 int i, len, ret;
11626 u32 *freqs;
11627
11628 if (!freq_list)
11629 return 0;
11630 len = int_array_len(freq_list);
11631 freqs = os_malloc(sizeof(u32) * len);
11632 if (!freqs)
11633 return -1;
11634 for (i = 0; i < len; i++)
11635 freqs[i] = freq_list[i];
11636 ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
11637 sizeof(u32) * len, freqs);
11638 os_free(freqs);
11639 return ret;
11640}
11641
11642
Hai Shalomc1a21442022-02-04 13:43:00 -080011643static int nl80211_qca_do_acs(struct wpa_driver_nl80211_data *drv,
11644 struct drv_acs_params *params)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011645{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011646 struct nl_msg *msg;
11647 struct nlattr *data;
11648 int ret;
11649 int mode;
11650
11651 mode = hw_mode_to_qca_acs(params->hw_mode);
11652 if (mode < 0)
11653 return -1;
11654
11655 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11656 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11657 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11658 QCA_NL80211_VENDOR_SUBCMD_DO_ACS) ||
11659 !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
11660 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, mode) ||
11661 (params->ht_enabled &&
11662 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
11663 (params->ht40_enabled &&
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070011664 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) ||
11665 (params->vht_enabled &&
11666 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
Sunil Ravia04bd252022-05-02 22:54:18 -070011667 (params->eht_enabled &&
11668 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED)) ||
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070011669 nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
11670 params->ch_width) ||
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080011671 add_acs_ch_list(msg, params->freq_list) ||
Hai Shalomfdcde762020-04-02 11:19:20 -070011672 add_acs_freq_list(msg, params->freq_list) ||
11673 (params->edmg_enabled &&
11674 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011675 nlmsg_free(msg);
11676 return -ENOBUFS;
11677 }
11678 nla_nest_end(msg, data);
11679
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070011680 wpa_printf(MSG_DEBUG,
Sunil Ravia04bd252022-05-02 22:54:18 -070011681 "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d EHT: %d BW: %d EDMG: %d",
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070011682 params->hw_mode, params->ht_enabled, params->ht40_enabled,
Sunil Ravia04bd252022-05-02 22:54:18 -070011683 params->vht_enabled, params->eht_enabled, params->ch_width,
11684 params->edmg_enabled);
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070011685
Hai Shalom899fcc72020-10-19 14:38:18 -070011686 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011687 if (ret) {
11688 wpa_printf(MSG_DEBUG,
11689 "nl80211: Failed to invoke driver ACS function: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070011690 strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011691 }
11692 return ret;
11693}
11694
11695
Hai Shalom60840252021-02-19 19:02:11 -080011696static int nl80211_set_band(void *priv, u32 band_mask)
Ravi Joshie6ccb162015-07-16 17:45:41 -070011697{
11698 struct i802_bss *bss = priv;
11699 struct wpa_driver_nl80211_data *drv = bss->drv;
11700 struct nl_msg *msg;
11701 struct nlattr *data;
11702 int ret;
Hai Shalom60840252021-02-19 19:02:11 -080011703 enum qca_set_band qca_band_value;
11704 u32 qca_band_mask = QCA_SETBAND_AUTO;
Ravi Joshie6ccb162015-07-16 17:45:41 -070011705
Hai Shalom60840252021-02-19 19:02:11 -080011706 if (!drv->setband_vendor_cmd_avail ||
11707 (band_mask > (WPA_SETBAND_2G | WPA_SETBAND_5G | WPA_SETBAND_6G)))
Ravi Joshie6ccb162015-07-16 17:45:41 -070011708 return -1;
11709
Hai Shalom60840252021-02-19 19:02:11 -080011710 if (band_mask & WPA_SETBAND_5G)
11711 qca_band_mask |= QCA_SETBAND_5G;
11712 if (band_mask & WPA_SETBAND_2G)
11713 qca_band_mask |= QCA_SETBAND_2G;
11714 if (band_mask & WPA_SETBAND_6G)
11715 qca_band_mask |= QCA_SETBAND_6G;
11716
11717 /*
11718 * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE is a legacy interface hence make
11719 * it suite to its values (AUTO/5G/2G) for backwards compatibility.
11720 */
11721 qca_band_value = ((qca_band_mask & QCA_SETBAND_5G) &&
11722 (qca_band_mask & QCA_SETBAND_2G)) ?
11723 QCA_SETBAND_AUTO :
11724 qca_band_mask & ~QCA_SETBAND_6G;
11725
11726 wpa_printf(MSG_DEBUG,
11727 "nl80211: QCA_BAND_MASK = 0x%x, QCA_BAND_VALUE = %d",
11728 qca_band_mask, qca_band_value);
Ravi Joshie6ccb162015-07-16 17:45:41 -070011729
11730 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11731 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11732 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11733 QCA_NL80211_VENDOR_SUBCMD_SETBAND) ||
11734 !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
Hai Shalom60840252021-02-19 19:02:11 -080011735 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE,
11736 qca_band_value) ||
11737 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_MASK,
11738 qca_band_mask)) {
Ravi Joshie6ccb162015-07-16 17:45:41 -070011739 nlmsg_free(msg);
11740 return -ENOBUFS;
11741 }
11742 nla_nest_end(msg, data);
11743
Hai Shalom899fcc72020-10-19 14:38:18 -070011744 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Ravi Joshie6ccb162015-07-16 17:45:41 -070011745 if (ret) {
11746 wpa_printf(MSG_DEBUG,
11747 "nl80211: Driver setband function failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070011748 strerror(-ret));
Ravi Joshie6ccb162015-07-16 17:45:41 -070011749 }
11750 return ret;
11751}
11752
11753
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011754struct nl80211_pcl {
11755 unsigned int num;
Sunil8cd6f4d2022-06-28 18:40:46 +000011756 struct weighted_pcl *freq_list;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011757};
11758
Sunil8cd6f4d2022-06-28 18:40:46 +000011759static void get_pcl_attr_values(struct weighted_pcl *wpcl, struct nlattr *nl[])
11760{
11761 if (nl[QCA_WLAN_VENDOR_ATTR_PCL_FREQ])
11762 wpcl->freq = nla_get_u32(nl[QCA_WLAN_VENDOR_ATTR_PCL_FREQ]);
11763 if (nl[QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT])
11764 wpcl->weight = nla_get_u8(nl[QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT]);
11765 if (nl[QCA_WLAN_VENDOR_ATTR_PCL_FLAG]) {
11766 u32 flags = nla_get_u32(nl[QCA_WLAN_VENDOR_ATTR_PCL_FLAG]);
11767
11768 wpcl->flag = 0;
11769 if (flags & BIT(0))
11770 wpcl->flag |= WEIGHTED_PCL_GO;
11771 if (flags & BIT(1))
11772 wpcl->flag |= WEIGHTED_PCL_CLI;
11773 if (flags & BIT(2))
11774 wpcl->flag |= WEIGHTED_PCL_MUST_CONSIDER;
11775 if (flags & BIT(3))
11776 wpcl->flag |= WEIGHTED_PCL_EXCLUDE;
11777 } else {
11778 wpcl->flag = WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI;
11779 }
11780}
11781
11782
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011783static int preferred_freq_info_handler(struct nl_msg *msg, void *arg)
11784{
11785 struct nlattr *tb[NL80211_ATTR_MAX + 1];
11786 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
11787 struct nl80211_pcl *param = arg;
11788 struct nlattr *nl_vend, *attr;
11789 enum qca_iface_type iface_type;
11790 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
Sunil8cd6f4d2022-06-28 18:40:46 +000011791 struct nlattr *nl_pcl[QCA_WLAN_VENDOR_ATTR_PCL_MAX + 1];
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011792 unsigned int num, max_num;
11793 u32 *freqs;
11794
11795 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
11796 genlmsg_attrlen(gnlh, 0), NULL);
11797
11798 nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
11799 if (!nl_vend)
11800 return NL_SKIP;
11801
11802 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
11803 nla_data(nl_vend), nla_len(nl_vend), NULL);
11804
11805 attr = tb_vendor[
11806 QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE];
11807 if (!attr) {
11808 wpa_printf(MSG_ERROR, "nl80211: iface_type couldn't be found");
11809 param->num = 0;
11810 return NL_SKIP;
11811 }
11812
11813 iface_type = (enum qca_iface_type) nla_get_u32(attr);
11814 wpa_printf(MSG_DEBUG, "nl80211: Driver returned iface_type=%d",
11815 iface_type);
11816
Sunil8cd6f4d2022-06-28 18:40:46 +000011817 attr = tb_vendor[
11818 QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_WEIGHED_PCL];
11819 if (attr) {
11820 int rem;
11821 struct nlattr *wpcl = attr;
11822 unsigned int i;
11823
11824 num = 0;
11825 nla_for_each_nested(attr, wpcl, rem) {
11826 if (num == param->num)
11827 break; /* not enough room for all entries */
11828 if (nla_parse(nl_pcl, QCA_WLAN_VENDOR_ATTR_PCL_MAX,
11829 nla_data(attr), nla_len(attr), NULL)) {
11830 wpa_printf(MSG_ERROR,
11831 "nl80211: Failed to parse PCL info");
11832 param->num = 0;
11833 return NL_SKIP;
11834 }
11835 get_pcl_attr_values(&param->freq_list[num], nl_pcl);
11836 num++;
11837 }
11838 param->num = num;
11839
11840 /* Sort frequencies based on their weight */
11841 for (i = 0; i < num; i++) {
11842 unsigned int j;
11843
11844 for (j = i + 1; j < num; j++) {
11845 if (param->freq_list[i].weight <
11846 param->freq_list[j].weight) {
11847 struct weighted_pcl tmp;
11848
11849 tmp = param->freq_list[i];
11850 param->freq_list[i] =
11851 param->freq_list[j];
11852 param->freq_list[j] = tmp;
11853 }
11854 }
11855 }
11856 } else if (tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST]) {
11857 wpa_printf(MSG_DEBUG,
11858 "nl80211: Driver does not provide weighted PCL; use the non-weighted variant");
11859 attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST];
11860 /*
11861 * param->num has the maximum number of entries for which there
11862 * is room in the freq_list provided by the caller.
11863 */
11864 freqs = nla_data(attr);
11865 max_num = nla_len(attr) / sizeof(u32);
11866 if (max_num > param->num)
11867 max_num = param->num;
11868 for (num = 0; num < max_num; num++) {
11869 param->freq_list[num].freq = freqs[num];
11870 param->freq_list[num].flag =
11871 WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI;
11872 }
11873 param->num = num;
11874 } else {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011875 wpa_printf(MSG_ERROR,
11876 "nl80211: preferred_freq_list couldn't be found");
11877 param->num = 0;
11878 return NL_SKIP;
11879 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011880 return NL_SKIP;
11881}
11882
11883
11884static int nl80211_get_pref_freq_list(void *priv,
11885 enum wpa_driver_if_type if_type,
11886 unsigned int *num,
Sunil8cd6f4d2022-06-28 18:40:46 +000011887 struct weighted_pcl *freq_list)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011888{
11889 struct i802_bss *bss = priv;
11890 struct wpa_driver_nl80211_data *drv = bss->drv;
11891 struct nl_msg *msg;
11892 int ret;
11893 unsigned int i;
11894 struct nlattr *params;
11895 struct nl80211_pcl param;
11896 enum qca_iface_type iface_type;
11897
11898 if (!drv->get_pref_freq_list)
11899 return -1;
11900
11901 switch (if_type) {
11902 case WPA_IF_STATION:
11903 iface_type = QCA_IFACE_TYPE_STA;
11904 break;
11905 case WPA_IF_AP_BSS:
11906 iface_type = QCA_IFACE_TYPE_AP;
11907 break;
11908 case WPA_IF_P2P_GO:
11909 iface_type = QCA_IFACE_TYPE_P2P_GO;
11910 break;
11911 case WPA_IF_P2P_CLIENT:
11912 iface_type = QCA_IFACE_TYPE_P2P_CLIENT;
11913 break;
11914 case WPA_IF_IBSS:
11915 iface_type = QCA_IFACE_TYPE_IBSS;
11916 break;
11917 case WPA_IF_TDLS:
11918 iface_type = QCA_IFACE_TYPE_TDLS;
11919 break;
11920 default:
11921 return -1;
11922 }
11923
11924 param.num = *num;
11925 param.freq_list = freq_list;
11926
11927 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11928 nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) ||
11929 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11930 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11931 QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST) ||
11932 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
11933 nla_put_u32(msg,
11934 QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE,
11935 iface_type)) {
11936 wpa_printf(MSG_ERROR,
11937 "%s: err in adding vendor_cmd and vendor_data",
11938 __func__);
11939 nlmsg_free(msg);
11940 return -1;
11941 }
11942 nla_nest_end(msg, params);
11943
Sunil8cd6f4d2022-06-28 18:40:46 +000011944 if (freq_list)
11945 os_memset(freq_list, 0, *num * sizeof(struct weighted_pcl));
Hai Shalom899fcc72020-10-19 14:38:18 -070011946 ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, &param,
11947 NULL, NULL);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011948 if (ret) {
11949 wpa_printf(MSG_ERROR,
11950 "%s: err in send_and_recv_msgs", __func__);
11951 return ret;
11952 }
11953
11954 *num = param.num;
11955
11956 for (i = 0; i < *num; i++) {
Sunil8cd6f4d2022-06-28 18:40:46 +000011957 wpa_printf(MSG_DEBUG,
11958 "nl80211: preferred_channel_list[%d]=%d[%d]:0x%x",
11959 i, freq_list[i].freq, freq_list[i].weight,
11960 freq_list[i].flag);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011961 }
11962
11963 return 0;
11964}
11965
11966
11967static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq)
11968{
11969 struct i802_bss *bss = priv;
11970 struct wpa_driver_nl80211_data *drv = bss->drv;
11971 struct nl_msg *msg;
11972 int ret;
11973 struct nlattr *params;
11974
11975 if (!drv->set_prob_oper_freq)
11976 return -1;
11977
11978 wpa_printf(MSG_DEBUG,
11979 "nl80211: Set P2P probable operating freq %u for ifindex %d",
11980 freq, bss->ifindex);
11981
11982 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11983 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11984 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11985 QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL) ||
11986 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
11987 nla_put_u32(msg,
11988 QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE,
11989 QCA_IFACE_TYPE_P2P_CLIENT) ||
11990 nla_put_u32(msg,
11991 QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ,
11992 freq)) {
11993 wpa_printf(MSG_ERROR,
11994 "%s: err in adding vendor_cmd and vendor_data",
11995 __func__);
11996 nlmsg_free(msg);
11997 return -1;
11998 }
11999 nla_nest_end(msg, params);
12000
Hai Shalom899fcc72020-10-19 14:38:18 -070012001 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012002 msg = NULL;
12003 if (ret) {
12004 wpa_printf(MSG_ERROR, "%s: err in send_and_recv_msgs",
12005 __func__);
12006 return ret;
12007 }
12008 nlmsg_free(msg);
12009 return 0;
12010}
12011
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070012012
12013static int nl80211_p2p_lo_start(void *priv, unsigned int freq,
12014 unsigned int period, unsigned int interval,
12015 unsigned int count, const u8 *device_types,
12016 size_t dev_types_len,
12017 const u8 *ies, size_t ies_len)
12018{
12019 struct i802_bss *bss = priv;
12020 struct wpa_driver_nl80211_data *drv = bss->drv;
12021 struct nl_msg *msg;
12022 struct nlattr *container;
12023 int ret;
12024
12025 wpa_printf(MSG_DEBUG,
12026 "nl80211: Start P2P Listen offload: freq=%u, period=%u, interval=%u, count=%u",
12027 freq, period, interval, count);
12028
12029 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
12030 return -1;
12031
12032 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
12033 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
12034 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
12035 QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START))
12036 goto fail;
12037
12038 container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
12039 if (!container)
12040 goto fail;
12041
12042 if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL,
12043 freq) ||
12044 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD,
12045 period) ||
12046 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL,
12047 interval) ||
12048 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT,
12049 count) ||
12050 nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES,
12051 dev_types_len, device_types) ||
12052 nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE,
12053 ies_len, ies))
12054 goto fail;
12055
12056 nla_nest_end(msg, container);
Hai Shalom899fcc72020-10-19 14:38:18 -070012057 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070012058 msg = NULL;
12059 if (ret) {
12060 wpa_printf(MSG_DEBUG,
12061 "nl80211: Failed to send P2P Listen offload vendor command");
12062 goto fail;
12063 }
12064
12065 return 0;
12066
12067fail:
12068 nlmsg_free(msg);
12069 return -1;
12070}
12071
12072
12073static int nl80211_p2p_lo_stop(void *priv)
12074{
12075 struct i802_bss *bss = priv;
12076 struct wpa_driver_nl80211_data *drv = bss->drv;
12077 struct nl_msg *msg;
12078
12079 wpa_printf(MSG_DEBUG, "nl80211: Stop P2P Listen offload");
12080
12081 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
12082 return -1;
12083
12084 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
12085 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
12086 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
12087 QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP)) {
12088 nlmsg_free(msg);
12089 return -1;
12090 }
12091
Hai Shalom899fcc72020-10-19 14:38:18 -070012092 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070012093}
12094
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080012095
12096static int nl80211_set_tdls_mode(void *priv, int tdls_external_control)
12097{
12098 struct i802_bss *bss = priv;
12099 struct wpa_driver_nl80211_data *drv = bss->drv;
12100 struct nl_msg *msg;
12101 struct nlattr *params;
12102 int ret;
12103 u32 tdls_mode;
12104
12105 wpa_printf(MSG_DEBUG,
12106 "nl80211: Set TDKS mode: tdls_external_control=%d",
12107 tdls_external_control);
12108
12109 if (tdls_external_control == 1)
12110 tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT |
12111 QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL;
12112 else
12113 tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT;
12114
12115 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
12116 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
12117 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
12118 QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS))
12119 goto fail;
12120
12121 params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
12122 if (!params)
12123 goto fail;
12124
12125 if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE,
12126 tdls_mode))
12127 goto fail;
12128
12129 nla_nest_end(msg, params);
12130
Hai Shalom899fcc72020-10-19 14:38:18 -070012131 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080012132 msg = NULL;
12133 if (ret) {
12134 wpa_printf(MSG_ERROR,
12135 "nl80211: Set TDLS mode failed: ret=%d (%s)",
12136 ret, strerror(-ret));
12137 goto fail;
12138 }
12139 return 0;
12140fail:
12141 nlmsg_free(msg);
12142 return -1;
12143}
12144
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012145
12146#ifdef CONFIG_MBO
12147
12148static enum mbo_transition_reject_reason
12149nl80211_mbo_reject_reason_mapping(enum qca_wlan_btm_candidate_status status)
12150{
12151 switch (status) {
12152 case QCA_STATUS_REJECT_EXCESSIVE_FRAME_LOSS_EXPECTED:
12153 return MBO_TRANSITION_REJECT_REASON_FRAME_LOSS;
12154 case QCA_STATUS_REJECT_EXCESSIVE_DELAY_EXPECTED:
12155 return MBO_TRANSITION_REJECT_REASON_DELAY;
12156 case QCA_STATUS_REJECT_INSUFFICIENT_QOS_CAPACITY:
12157 return MBO_TRANSITION_REJECT_REASON_QOS_CAPACITY;
12158 case QCA_STATUS_REJECT_LOW_RSSI:
12159 return MBO_TRANSITION_REJECT_REASON_RSSI;
12160 case QCA_STATUS_REJECT_HIGH_INTERFERENCE:
12161 return MBO_TRANSITION_REJECT_REASON_INTERFERENCE;
12162 case QCA_STATUS_REJECT_UNKNOWN:
12163 default:
12164 return MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
12165 }
12166}
12167
12168
12169static void nl80211_parse_btm_candidate_info(struct candidate_list *candidate,
12170 struct nlattr *tb[], int num)
12171{
12172 enum qca_wlan_btm_candidate_status status;
12173 char buf[50];
12174
12175 os_memcpy(candidate->bssid,
12176 nla_data(tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]),
12177 ETH_ALEN);
12178
12179 status = nla_get_u32(
12180 tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS]);
12181 candidate->is_accept = status == QCA_STATUS_ACCEPT;
12182 candidate->reject_reason = nl80211_mbo_reject_reason_mapping(status);
12183
12184 if (candidate->is_accept)
12185 os_snprintf(buf, sizeof(buf), "Accepted");
12186 else
12187 os_snprintf(buf, sizeof(buf),
12188 "Rejected, Reject_reason: %d",
12189 candidate->reject_reason);
12190 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%d]: " MACSTR " %s",
12191 num, MAC2STR(candidate->bssid), buf);
12192}
12193
12194
12195static int
12196nl80211_get_bss_transition_status_handler(struct nl_msg *msg, void *arg)
12197{
12198 struct wpa_bss_candidate_info *info = arg;
12199 struct candidate_list *candidate = info->candidates;
12200 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
12201 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
12202 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1];
12203 static struct nla_policy policy[
12204 QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1] = {
12205 [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] = {
12206 .minlen = ETH_ALEN
12207 },
12208 [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS] = {
12209 .type = NLA_U32,
12210 },
12211 };
12212 struct nlattr *attr;
12213 int rem;
12214 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
12215 u8 num;
12216
12217 num = info->num; /* number of candidates sent to driver */
12218 info->num = 0;
12219 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
12220 genlmsg_attrlen(gnlh, 0), NULL);
12221
12222 if (!tb_msg[NL80211_ATTR_VENDOR_DATA] ||
12223 nla_parse_nested(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
12224 tb_msg[NL80211_ATTR_VENDOR_DATA], NULL) ||
12225 !tb_vendor[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO])
12226 return NL_SKIP;
12227
12228 wpa_printf(MSG_DEBUG,
12229 "nl80211: WNM Candidate list received from driver");
12230 nla_for_each_nested(attr,
12231 tb_vendor[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO],
12232 rem) {
12233 if (info->num >= num ||
12234 nla_parse_nested(
12235 tb, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX,
12236 attr, policy) ||
12237 !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] ||
12238 !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS])
12239 break;
12240
12241 nl80211_parse_btm_candidate_info(candidate, tb, info->num);
12242
12243 candidate++;
12244 info->num++;
12245 }
12246
12247 return NL_SKIP;
12248}
12249
12250
12251static struct wpa_bss_candidate_info *
12252nl80211_get_bss_transition_status(void *priv, struct wpa_bss_trans_info *params)
12253{
12254 struct i802_bss *bss = priv;
12255 struct wpa_driver_nl80211_data *drv = bss->drv;
12256 struct nl_msg *msg;
12257 struct nlattr *attr, *attr1, *attr2;
12258 struct wpa_bss_candidate_info *info;
12259 u8 i;
12260 int ret;
12261 u8 *pos;
12262
12263 if (!drv->fetch_bss_trans_status)
12264 return NULL;
12265
12266 info = os_zalloc(sizeof(*info));
12267 if (!info)
12268 return NULL;
12269 /* Allocate memory for number of candidates sent to driver */
12270 info->candidates = os_calloc(params->n_candidates,
12271 sizeof(*info->candidates));
12272 if (!info->candidates) {
12273 os_free(info);
12274 return NULL;
12275 }
12276
12277 /* Copy the number of candidates being sent to driver. This is used in
12278 * nl80211_get_bss_transition_status_handler() to limit the number of
12279 * candidates that can be populated in info->candidates and will be
12280 * later overwritten with the actual number of candidates received from
12281 * the driver.
12282 */
12283 info->num = params->n_candidates;
12284
12285 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
12286 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
12287 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
12288 QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS))
12289 goto fail;
12290
12291 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
12292 if (!attr)
12293 goto fail;
12294
12295 if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON,
12296 params->mbo_transition_reason))
12297 goto fail;
12298
12299 attr1 = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO);
12300 if (!attr1)
12301 goto fail;
12302
12303 wpa_printf(MSG_DEBUG,
12304 "nl80211: WNM Candidate list info sending to driver: mbo_transition_reason: %d n_candidates: %d",
12305 params->mbo_transition_reason, params->n_candidates);
12306 pos = params->bssid;
12307 for (i = 0; i < params->n_candidates; i++) {
12308 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%d]: " MACSTR, i,
12309 MAC2STR(pos));
12310 attr2 = nla_nest_start(msg, i);
12311 if (!attr2 ||
12312 nla_put(msg, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID,
12313 ETH_ALEN, pos))
12314 goto fail;
12315 pos += ETH_ALEN;
12316 nla_nest_end(msg, attr2);
12317 }
12318
12319 nla_nest_end(msg, attr1);
12320 nla_nest_end(msg, attr);
12321
12322 ret = send_and_recv_msgs(drv, msg,
12323 nl80211_get_bss_transition_status_handler,
Hai Shalom899fcc72020-10-19 14:38:18 -070012324 info, NULL, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012325 msg = NULL;
12326 if (ret) {
12327 wpa_printf(MSG_ERROR,
12328 "nl80211: WNM Get BSS transition status failed: ret=%d (%s)",
12329 ret, strerror(-ret));
12330 goto fail;
12331 }
12332 return info;
12333
12334fail:
12335 nlmsg_free(msg);
12336 os_free(info->candidates);
12337 os_free(info);
12338 return NULL;
12339}
12340
12341
12342/**
12343 * nl80211_ignore_assoc_disallow - Configure driver to ignore assoc_disallow
12344 * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
12345 * @ignore_assoc_disallow: 0 to not ignore, 1 to ignore
12346 * Returns: 0 on success, -1 on failure
12347 */
12348static int nl80211_ignore_assoc_disallow(void *priv, int ignore_disallow)
12349{
12350 struct i802_bss *bss = priv;
12351 struct wpa_driver_nl80211_data *drv = bss->drv;
12352 struct nl_msg *msg;
12353 struct nlattr *attr;
12354 int ret = -1;
12355
12356 if (!drv->set_wifi_conf_vendor_cmd_avail)
12357 return -1;
12358
12359 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
12360 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
12361 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
12362 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION))
12363 goto fail;
12364
12365 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
12366 if (!attr)
12367 goto fail;
12368
12369 wpa_printf(MSG_DEBUG, "nl80211: Set ignore_assoc_disallow %d",
12370 ignore_disallow);
12371 if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED,
12372 ignore_disallow))
12373 goto fail;
12374
12375 nla_nest_end(msg, attr);
12376
Hai Shalom899fcc72020-10-19 14:38:18 -070012377 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012378 msg = NULL;
12379 if (ret) {
12380 wpa_printf(MSG_ERROR,
12381 "nl80211: Set ignore_assoc_disallow failed: ret=%d (%s)",
12382 ret, strerror(-ret));
12383 goto fail;
12384 }
12385
12386fail:
12387 nlmsg_free(msg);
12388 return ret;
12389}
12390
12391#endif /* CONFIG_MBO */
12392
Sunil Ravi89eba102022-09-13 21:04:37 -070012393
12394#ifdef CONFIG_PASN
12395
12396static int nl80211_send_pasn_resp(void *priv, struct pasn_auth *params)
12397{
12398 unsigned int i;
12399 struct i802_bss *bss = priv;
12400 struct nl_msg *msg = NULL;
12401 struct nlattr *nlpeers, *attr, *attr1;
12402 struct wpa_driver_nl80211_data *drv = bss->drv;
12403
12404 wpa_dbg(drv->ctx, MSG_DEBUG,
12405 "nl80211: PASN authentication response for %d entries",
12406 params->num_peers);
12407 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
12408 if (!msg ||
12409 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
12410 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
12411 QCA_NL80211_VENDOR_SUBCMD_PASN))
12412 goto fail;
12413
12414 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
12415 if (!attr)
12416 goto fail;
12417
12418 nlpeers = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEERS);
12419 if (!nlpeers)
12420 goto fail;
12421
12422 for (i = 0; i < params->num_peers; i++) {
12423 attr1 = nla_nest_start(msg, i);
12424 if (!attr1 ||
12425 nla_put(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR,
12426 ETH_ALEN, params->peer[i].own_addr) ||
12427 nla_put(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR,
12428 ETH_ALEN, params->peer[i].peer_addr))
12429 goto fail;
12430
12431 if (params->peer[i].status == 0)
12432 nla_put_flag(msg,
12433 QCA_WLAN_VENDOR_ATTR_PASN_PEER_STATUS_SUCCESS);
12434
12435 wpa_printf(MSG_DEBUG,
12436 "nl80211: Own address[%u]: " MACSTR
12437 " Peer address[%u]: " MACSTR " Status: %s",
12438 i, MAC2STR(params->peer[i].own_addr), i,
12439 MAC2STR(params->peer[i].peer_addr),
12440 params->peer[i].status ? "Fail" : "Success");
12441 nla_nest_end(msg, attr1);
12442 }
12443
12444 nla_nest_end(msg, nlpeers);
12445 nla_nest_end(msg, attr);
12446
12447 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
12448
12449fail:
12450 nlmsg_free(msg);
12451 return -1;
12452}
12453
12454
12455static u32 wpa_ltf_keyseed_len_to_sha_type(size_t len)
12456{
12457 if (len == SHA384_MAC_LEN)
12458 return QCA_WLAN_VENDOR_SHA_384;
12459 if (len == SHA256_MAC_LEN)
12460 return QCA_WLAN_VENDOR_SHA_256;
12461
12462 wpa_printf(MSG_ERROR, "nl80211: Unexpected LTF keyseed len %zu", len);
12463 return (u32) -1;
12464}
12465
12466
12467static int nl80211_set_secure_ranging_ctx(void *priv,
12468 struct secure_ranging_params *params)
12469{
12470 int ret;
12471 u32 suite;
12472 struct nlattr *attr;
12473 struct nl_msg *msg = NULL;
12474 struct i802_bss *bss = priv;
12475 struct wpa_driver_nl80211_data *drv = bss->drv;
12476
12477 /* Configure secure ranging context only to the drivers that support it.
12478 */
12479 if (!drv->secure_ranging_ctx_vendor_cmd_avail)
12480 return 0;
12481
12482 if (!params->peer_addr || !params->own_addr)
12483 return -1;
12484
12485 wpa_dbg(drv->ctx, MSG_DEBUG,
12486 "nl80211: Secure ranging context for " MACSTR,
12487 MAC2STR(params->peer_addr));
12488
12489 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
12490 if (!msg ||
12491 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
12492 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
12493 QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT))
12494 goto fail;
12495
12496 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
12497 if (!attr)
12498 goto fail;
12499
12500 if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR,
12501 ETH_ALEN, params->peer_addr) ||
12502 nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR,
12503 ETH_ALEN, params->own_addr) ||
12504 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION,
12505 params->action))
12506 goto fail;
12507
12508 if (params->cipher) {
12509 suite = wpa_cipher_to_cipher_suite(params->cipher);
12510 if (!suite ||
12511 nla_put_u32(msg,
12512 QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER,
12513 suite))
12514 goto fail;
12515 }
12516
12517 if (params->tk_len && params->tk) {
12518 if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK,
12519 params->tk_len, params->tk))
12520 goto fail;
12521 wpa_hexdump_key(MSG_DEBUG, "nl80211: TK",
12522 params->tk, params->tk_len);
12523 }
12524
12525 if (params->ltf_keyseed_len && params->ltf_keyseed) {
12526 u32 sha_type = wpa_ltf_keyseed_len_to_sha_type(
12527 params->ltf_keyseed_len);
12528
12529 if (sha_type == (u32) -1 ||
12530 nla_put_u32(
12531 msg,
12532 QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE,
12533 sha_type) ||
12534 nla_put(msg,
12535 QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED,
12536 params->ltf_keyseed_len, params->ltf_keyseed))
12537 goto fail;
12538 wpa_hexdump_key(MSG_DEBUG, "nl80211: LTF keyseed",
12539 params->ltf_keyseed, params->ltf_keyseed_len);
12540 }
12541 nla_nest_end(msg, attr);
12542
12543 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
12544 if (ret)
12545 wpa_printf(MSG_DEBUG,
12546 "nl80211: Set secure ranging context failed: ret=%d (%s)",
12547 ret, strerror(-ret));
12548 return ret;
12549fail:
12550 nlmsg_free(msg);
12551 return -1;
12552}
12553
12554#endif /* CONFIG_PASN */
12555
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012556#endif /* CONFIG_DRIVER_NL80211_QCA */
12557
Hai Shalomc1a21442022-02-04 13:43:00 -080012558static int nl80211_do_acs(void *priv, struct drv_acs_params *params)
12559{
Andy Kuoaba17c12022-04-14 16:05:31 +080012560#if defined(CONFIG_DRIVER_NL80211_QCA) || defined(CONFIG_DRIVER_NL80211_BRCM) \
12561 || defined(CONFIG_DRIVER_NL80211_SYNA)
Hai Shalomc1a21442022-02-04 13:43:00 -080012562 struct i802_bss *bss = priv;
12563 struct wpa_driver_nl80211_data *drv = bss->drv;
Andy Kuoaba17c12022-04-14 16:05:31 +080012564#endif /* CONFIG_DRIVER_NL80211_QCA || CONFIG_DRIVER_NL80211_BRCM \
12565 || defined(CONFIG_DRIVER_NL80211_SYNA) */
Hai Shalomc1a21442022-02-04 13:43:00 -080012566
12567#ifdef CONFIG_DRIVER_NL80211_QCA
12568 if (drv->qca_do_acs)
12569 return nl80211_qca_do_acs(drv, params);
12570#endif /* CONFIG_DRIVER_NL80211_QCA */
12571
Andy Kuoaba17c12022-04-14 16:05:31 +080012572#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Hai Shalomc1a21442022-02-04 13:43:00 -080012573 if (drv->brcm_do_acs)
12574 return wpa_driver_do_broadcom_acs(drv, params);
Andy Kuoaba17c12022-04-14 16:05:31 +080012575#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
Hai Shalomc1a21442022-02-04 13:43:00 -080012576
12577 return -1;
12578}
12579
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012580
Dmitry Shmidt849734c2016-05-27 09:59:01 -070012581static int nl80211_write_to_file(const char *name, unsigned int val)
12582{
12583 int fd, len;
12584 char tmp[128];
Hai Shalomc3565922019-10-28 11:58:20 -070012585 int ret = 0;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070012586
12587 fd = open(name, O_RDWR);
12588 if (fd < 0) {
Hai Shalomc3565922019-10-28 11:58:20 -070012589 int level;
12590 /*
12591 * Flags may not exist on older kernels, or while we're tearing
12592 * down a disappearing device.
12593 */
12594 if (errno == ENOENT) {
12595 ret = 0;
12596 level = MSG_DEBUG;
12597 } else {
12598 ret = -1;
12599 level = MSG_ERROR;
12600 }
12601 wpa_printf(level, "nl80211: Failed to open %s: %s",
Dmitry Shmidt849734c2016-05-27 09:59:01 -070012602 name, strerror(errno));
Hai Shalomc3565922019-10-28 11:58:20 -070012603 return ret;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070012604 }
12605
12606 len = os_snprintf(tmp, sizeof(tmp), "%u\n", val);
12607 len = write(fd, tmp, len);
Hai Shalomc3565922019-10-28 11:58:20 -070012608 if (len < 0) {
12609 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070012610 wpa_printf(MSG_ERROR, "nl80211: Failed to write to %s: %s",
12611 name, strerror(errno));
Hai Shalomc3565922019-10-28 11:58:20 -070012612 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -070012613 close(fd);
12614
Hai Shalomc3565922019-10-28 11:58:20 -070012615 return ret;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070012616}
12617
12618
12619static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags)
12620{
12621 struct i802_bss *bss = priv;
12622 char path[128];
12623 int ret;
12624
Hai Shalom60840252021-02-19 19:02:11 -080012625 /* P2P-Device has no netdev that can (or should) be configured here */
12626 if (nl80211_get_ifmode(bss) == NL80211_IFTYPE_P2P_DEVICE)
12627 return 0;
12628
Dmitry Shmidt849734c2016-05-27 09:59:01 -070012629 wpa_printf(MSG_DEBUG, "nl80211: Data frame filter flags=0x%x",
12630 filter_flags);
12631
12632 /* Configure filtering of unicast frame encrypted using GTK */
12633 ret = os_snprintf(path, sizeof(path),
12634 "/proc/sys/net/ipv4/conf/%s/drop_unicast_in_l2_multicast",
12635 bss->ifname);
12636 if (os_snprintf_error(sizeof(path), ret))
12637 return -1;
12638
12639 ret = nl80211_write_to_file(path,
12640 !!(filter_flags &
12641 WPA_DATA_FRAME_FILTER_FLAG_GTK));
12642 if (ret) {
12643 wpa_printf(MSG_ERROR,
12644 "nl80211: Failed to set IPv4 unicast in multicast filter");
12645 return ret;
12646 }
12647
12648 os_snprintf(path, sizeof(path),
12649 "/proc/sys/net/ipv6/conf/%s/drop_unicast_in_l2_multicast",
12650 bss->ifname);
12651 ret = nl80211_write_to_file(path,
12652 !!(filter_flags &
12653 WPA_DATA_FRAME_FILTER_FLAG_GTK));
12654
12655 if (ret) {
12656 wpa_printf(MSG_ERROR,
12657 "nl80211: Failed to set IPv6 unicast in multicast filter");
12658 return ret;
12659 }
12660
12661 /* Configure filtering of unicast frame encrypted using GTK */
12662 os_snprintf(path, sizeof(path),
12663 "/proc/sys/net/ipv4/conf/%s/drop_gratuitous_arp",
12664 bss->ifname);
12665 ret = nl80211_write_to_file(path,
12666 !!(filter_flags &
12667 WPA_DATA_FRAME_FILTER_FLAG_ARP));
12668 if (ret) {
12669 wpa_printf(MSG_ERROR,
12670 "nl80211: Failed set gratuitous ARP filter");
12671 return ret;
12672 }
12673
12674 /* Configure filtering of IPv6 NA frames */
12675 os_snprintf(path, sizeof(path),
12676 "/proc/sys/net/ipv6/conf/%s/drop_unsolicited_na",
12677 bss->ifname);
12678 ret = nl80211_write_to_file(path,
12679 !!(filter_flags &
12680 WPA_DATA_FRAME_FILTER_FLAG_NA));
12681 if (ret) {
12682 wpa_printf(MSG_ERROR,
12683 "nl80211: Failed to set unsolicited NA filter");
12684 return ret;
12685 }
12686
12687 return 0;
12688}
12689
12690
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070012691static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type,
12692 const u8 **ext_capa, const u8 **ext_capa_mask,
12693 unsigned int *ext_capa_len)
12694{
12695 struct i802_bss *bss = priv;
12696 struct wpa_driver_nl80211_data *drv = bss->drv;
12697 enum nl80211_iftype nlmode;
12698 unsigned int i;
12699
12700 if (!ext_capa || !ext_capa_mask || !ext_capa_len)
12701 return -1;
12702
12703 nlmode = wpa_driver_nl80211_if_type(type);
12704
12705 /* By default, use the per-radio values */
12706 *ext_capa = drv->extended_capa;
12707 *ext_capa_mask = drv->extended_capa_mask;
12708 *ext_capa_len = drv->extended_capa_len;
12709
12710 /* Replace the default value if a per-interface type value exists */
12711 for (i = 0; i < drv->num_iface_ext_capa; i++) {
12712 if (nlmode == drv->iface_ext_capa[i].iftype) {
12713 *ext_capa = drv->iface_ext_capa[i].ext_capa;
12714 *ext_capa_mask = drv->iface_ext_capa[i].ext_capa_mask;
12715 *ext_capa_len = drv->iface_ext_capa[i].ext_capa_len;
12716 break;
12717 }
12718 }
12719
12720 return 0;
12721}
12722
12723
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012724static int nl80211_update_connection_params(
12725 void *priv, struct wpa_driver_associate_params *params,
12726 enum wpa_drv_update_connect_params_mask mask)
12727{
12728 struct i802_bss *bss = priv;
12729 struct wpa_driver_nl80211_data *drv = bss->drv;
12730 struct nl_msg *msg;
12731 int ret = -1;
12732 enum nl80211_auth_type type;
12733
Hai Shalomc3565922019-10-28 11:58:20 -070012734 /* Update Connection Params is intended for drivers that implement
12735 * internal SME and expect these updated connection params from
12736 * wpa_supplicant. Do not send this request for the drivers using
12737 * SME from wpa_supplicant.
12738 */
12739 if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
12740 return 0;
12741
Vinayak Yadawade62409f2022-01-20 12:32:07 +053012742 /* Handle any connection param update here which might receive kernel handling in future */
12743#ifdef CONFIG_DRIVER_NL80211_BRCM
12744 if (mask & WPA_DRV_UPDATE_TD_POLICY) {
12745 ret = nl80211_set_td_policy(priv, params->td_policy);
12746 if (ret) {
12747 wpa_dbg(drv->ctx, MSG_DEBUG,
12748 "nl80211: Update connect params command failed: ret=%d (%s)",
12749 ret, strerror(-ret));
12750 }
12751 return ret;
12752 }
12753#endif /* CONFIG_DRIVER_NL80211_BRCM */
12754
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012755 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_CONNECT_PARAMS);
12756 if (!msg)
12757 goto fail;
12758
12759 wpa_printf(MSG_DEBUG, "nl80211: Update connection params (ifindex=%d)",
12760 drv->ifindex);
12761
12762 if ((mask & WPA_DRV_UPDATE_ASSOC_IES) && params->wpa_ie) {
12763 if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
12764 params->wpa_ie))
12765 goto fail;
12766 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie,
12767 params->wpa_ie_len);
12768 }
12769
12770 if (mask & WPA_DRV_UPDATE_AUTH_TYPE) {
12771 type = get_nl_auth_type(params->auth_alg);
12772 if (type == NL80211_AUTHTYPE_MAX ||
12773 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
12774 goto fail;
12775 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
12776 }
12777
12778 if ((mask & WPA_DRV_UPDATE_FILS_ERP_INFO) &&
12779 nl80211_put_fils_connect_params(drv, params, msg))
12780 goto fail;
12781
Hai Shalom899fcc72020-10-19 14:38:18 -070012782 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012783 msg = NULL;
12784 if (ret)
12785 wpa_dbg(drv->ctx, MSG_DEBUG,
12786 "nl80211: Update connect params command failed: ret=%d (%s)",
12787 ret, strerror(-ret));
12788
12789fail:
12790 nlmsg_free(msg);
12791 return ret;
12792}
12793
12794
Roshan Pius3a1667e2018-07-03 15:17:14 -070012795static int nl80211_send_external_auth_status(void *priv,
12796 struct external_auth *params)
12797{
12798 struct i802_bss *bss = priv;
12799 struct wpa_driver_nl80211_data *drv = bss->drv;
12800 struct nl_msg *msg = NULL;
12801 int ret = -1;
12802
Hai Shalom5f92bc92019-04-18 11:54:11 -070012803 /* External auth command/status is intended for drivers that implement
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080012804 * internal SME but want to offload authentication processing (e.g.,
12805 * SAE) to hostapd/wpa_supplicant. Do not send the status to drivers
Hai Shalom5f92bc92019-04-18 11:54:11 -070012806 * which do not support AP SME or use wpa_supplicant/hostapd SME.
12807 */
Hai Shalom81f62d82019-07-22 12:10:00 -070012808 if ((is_ap_interface(drv->nlmode) && !bss->drv->device_ap_sme) ||
Hai Shalom5f92bc92019-04-18 11:54:11 -070012809 (drv->capa.flags & WPA_DRIVER_FLAGS_SME))
12810 return -1;
12811
Roshan Pius3a1667e2018-07-03 15:17:14 -070012812 wpa_dbg(drv->ctx, MSG_DEBUG,
12813 "nl80211: External auth status: %u", params->status);
12814
12815 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_EXTERNAL_AUTH);
12816 if (!msg ||
12817 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, params->status) ||
Hai Shalom5f92bc92019-04-18 11:54:11 -070012818 (params->ssid && params->ssid_len &&
12819 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
12820 (params->pmkid &&
12821 nla_put(msg, NL80211_ATTR_PMKID, PMKID_LEN, params->pmkid)) ||
12822 (params->bssid &&
12823 nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid)))
Roshan Pius3a1667e2018-07-03 15:17:14 -070012824 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -070012825 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -070012826 msg = NULL;
12827 if (ret) {
12828 wpa_printf(MSG_DEBUG,
12829 "nl80211: External Auth status update failed: ret=%d (%s)",
12830 ret, strerror(-ret));
12831 goto fail;
12832 }
12833fail:
12834 nlmsg_free(msg);
12835 return ret;
12836}
12837
12838
Hai Shalom74f70d42019-02-11 14:42:39 -080012839static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname,
12840 int val)
12841{
12842 struct i802_bss *bss = priv;
12843 struct wpa_driver_nl80211_data *drv = bss->drv;
12844 struct nl_msg *msg;
12845 int ret = -ENOBUFS;
12846
12847 wpa_printf(MSG_DEBUG, "nl80211: %s 4addr mode (bridge_ifname: %s)",
12848 val ? "Enable" : "Disable", bridge_ifname);
12849
12850 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
12851 if (!msg || nla_put_u8(msg, NL80211_ATTR_4ADDR, val))
12852 goto fail;
12853
12854 if (bridge_ifname[0] && bss->added_if_into_bridge && !val) {
12855 if (linux_br_del_if(drv->global->ioctl_sock,
12856 bridge_ifname, bss->ifname)) {
12857 wpa_printf(MSG_ERROR,
12858 "nl80211: Failed to remove interface %s from bridge %s",
12859 bss->ifname, bridge_ifname);
12860 return -1;
12861 }
12862 bss->added_if_into_bridge = 0;
12863 }
12864
Hai Shalom899fcc72020-10-19 14:38:18 -070012865 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalom74f70d42019-02-11 14:42:39 -080012866 msg = NULL;
Hai Shalom60840252021-02-19 19:02:11 -080012867 if (ret && val && nl80211_get_4addr(bss) == 1) {
12868 wpa_printf(MSG_DEBUG,
12869 "nl80211: 4addr mode was already enabled");
12870 ret = 0;
12871 }
Hai Shalom74f70d42019-02-11 14:42:39 -080012872 if (!ret) {
12873 if (bridge_ifname[0] && val &&
12874 i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0)
12875 return -1;
12876 return 0;
12877 }
12878
12879fail:
12880 nlmsg_free(msg);
12881 wpa_printf(MSG_ERROR, "nl80211: Failed to enable/disable 4addr");
12882
12883 return ret;
12884}
12885
12886
Hai Shalome21d4e82020-04-29 16:34:06 -070012887#ifdef CONFIG_DPP
12888static int nl80211_dpp_listen(void *priv, bool enable)
12889{
12890 struct i802_bss *bss = priv;
12891 struct wpa_driver_nl80211_data *drv = bss->drv;
12892 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
12893 struct nl_sock *handle;
12894
12895 if (!drv->multicast_registrations || !bss->nl_mgmt)
12896 return 0; /* cannot do more than hope broadcast RX works */
12897
12898 wpa_printf(MSG_DEBUG,
12899 "nl80211: Update DPP Public Action frame registration (%s multicast RX)",
12900 enable ? "enable" : "disable");
12901 handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID);
12902 return nl80211_register_frame(bss, handle, type,
12903 (u8 *) "\x04\x09\x50\x6f\x9a\x1a", 6,
12904 enable);
12905}
12906#endif /* CONFIG_DPP */
12907
Vinayak Yadawade62409f2022-01-20 12:32:07 +053012908#ifdef CONFIG_DRIVER_NL80211_BRCM
12909static int nl80211_set_td_policy(void *priv, u32 td_policy)
12910{
12911 struct i802_bss *bss = priv;
12912 struct wpa_driver_nl80211_data *drv = bss->drv;
12913 struct nl_msg *msg;
12914 int ret;
12915 struct nlattr *params;
12916
12917 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
12918 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
12919 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, BRCM_VENDOR_SCMD_SET_TD_POLICY) ||
12920 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
12921 (nla_put_u32(msg, BRCM_ATTR_DRIVER_TD_POLICY, td_policy))) {
12922 nl80211_nlmsg_clear(msg);
12923 nlmsg_free(msg);
12924 return -ENOBUFS;
12925 }
12926 nla_nest_end(msg, params);
12927 wpa_printf(MSG_DEBUG, "nl80211: Transition Disable Policy %d\n", td_policy);
12928
12929 ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
12930 if (ret) {
12931 wpa_printf(MSG_DEBUG, "nl80211: Transition Disable setting failed: ret=%d (%s)",
12932 ret, strerror(-ret));
12933 }
12934
12935 return ret;
12936}
12937#endif /* CONFIG_DRIVER_NL80211_BRCM */
Hai Shalome21d4e82020-04-29 16:34:06 -070012938
Hai Shalomc1a21442022-02-04 13:43:00 -080012939#ifdef CONFIG_TESTING_OPTIONS
12940
12941static int testing_nl80211_register_frame(void *priv, u16 type,
12942 const u8 *match, size_t match_len,
12943 bool multicast)
12944{
12945 struct i802_bss *bss = priv;
12946 struct nl_sock *handle;
12947
12948 if (!bss->nl_mgmt)
12949 return -1;
12950 handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID);
12951 return nl80211_register_frame(bss, handle, type, match, match_len,
12952 multicast);
12953}
12954
12955
12956static int testing_nl80211_radio_disable(void *priv, int disabled)
12957{
12958 struct i802_bss *bss = priv;
12959 struct wpa_driver_nl80211_data *drv = bss->drv;
12960
12961 /* For now, this is supported only partially in station mode with
12962 * SME-in-wpa_supplicant case where the NL80211_ATTR_LOCAL_STATE_CHANGE
12963 * attribute can be used to avoid sending out the Deauthentication frame
12964 * to the currently associated AP. */
12965
12966 if (!disabled)
12967 return 0;
12968
12969 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
12970 return -1;
12971
12972 if (!drv->associated)
12973 return 0;
12974
12975 return wpa_driver_nl80211_mlme(drv, drv->bssid,
12976 NL80211_CMD_DEAUTHENTICATE,
12977 WLAN_REASON_PREV_AUTH_NOT_VALID, 1,
12978 drv->first_bss);
12979}
12980
12981#endif /* CONFIG_TESTING_OPTIONS */
12982
12983
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012984const struct wpa_driver_ops wpa_driver_nl80211_ops = {
12985 .name = "nl80211",
12986 .desc = "Linux nl80211/cfg80211",
12987 .get_bssid = wpa_driver_nl80211_get_bssid,
12988 .get_ssid = wpa_driver_nl80211_get_ssid,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012989 .set_key = driver_nl80211_set_key,
12990 .scan2 = driver_nl80211_scan2,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012991 .sched_scan = wpa_driver_nl80211_sched_scan,
12992 .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012993 .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080012994 .abort_scan = wpa_driver_nl80211_abort_scan,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012995 .deauthenticate = driver_nl80211_deauthenticate,
12996 .authenticate = driver_nl80211_authenticate,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012997 .associate = wpa_driver_nl80211_associate,
12998 .global_init = nl80211_global_init,
12999 .global_deinit = nl80211_global_deinit,
13000 .init2 = wpa_driver_nl80211_init,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080013001 .deinit = driver_nl80211_deinit,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013002 .get_capa = wpa_driver_nl80211_get_capa,
13003 .set_operstate = wpa_driver_nl80211_set_operstate,
13004 .set_supp_port = wpa_driver_nl80211_set_supp_port,
13005 .set_country = wpa_driver_nl80211_set_country,
Dmitry Shmidtcce06662013-11-04 18:44:24 -080013006 .get_country = wpa_driver_nl80211_get_country,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080013007 .set_ap = wpa_driver_nl80211_set_ap,
Dmitry Shmidt8bae4132013-06-06 11:25:10 -070013008 .set_acl = wpa_driver_nl80211_set_acl,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013009 .if_add = wpa_driver_nl80211_if_add,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080013010 .if_remove = driver_nl80211_if_remove,
13011 .send_mlme = driver_nl80211_send_mlme,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080013012 .get_hw_feature_data = nl80211_get_hw_feature_data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013013 .sta_add = wpa_driver_nl80211_sta_add,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080013014 .sta_remove = driver_nl80211_sta_remove,
Hai Shalomfdcde762020-04-02 11:19:20 -070013015 .tx_control_port = nl80211_tx_control_port,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013016 .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
13017 .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
Hai Shalom81f62d82019-07-22 12:10:00 -070013018 .sta_set_airtime_weight = driver_nl80211_sta_set_airtime_weight,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013019 .hapd_init = i802_init,
13020 .hapd_deinit = i802_deinit,
Jouni Malinen75ecf522011-06-27 15:19:46 -070013021 .set_wds_sta = i802_set_wds_sta,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013022 .get_seqnum = i802_get_seqnum,
13023 .flush = i802_flush,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013024 .get_inact_sec = i802_get_inact_sec,
13025 .sta_clear_stats = i802_sta_clear_stats,
13026 .set_rts = i802_set_rts,
13027 .set_frag = i802_set_frag,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013028 .set_tx_queue_params = i802_set_tx_queue_params,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080013029 .set_sta_vlan = driver_nl80211_set_sta_vlan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013030 .sta_deauth = i802_sta_deauth,
13031 .sta_disassoc = i802_sta_disassoc,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080013032 .read_sta_data = driver_nl80211_read_sta_data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013033 .set_freq = i802_set_freq,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080013034 .send_action = driver_nl80211_send_action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013035 .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
13036 .remain_on_channel = wpa_driver_nl80211_remain_on_channel,
13037 .cancel_remain_on_channel =
13038 wpa_driver_nl80211_cancel_remain_on_channel,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080013039 .probe_req_report = driver_nl80211_probe_req_report,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013040 .deinit_ap = wpa_driver_nl80211_deinit_ap,
Dmitry Shmidt04949592012-07-19 12:16:46 -070013041 .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013042 .resume = wpa_driver_nl80211_resume,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013043 .signal_monitor = nl80211_signal_monitor,
13044 .signal_poll = nl80211_signal_poll,
Sunil Ravi89eba102022-09-13 21:04:37 -070013045 .mlo_signal_poll = nl80211_mlo_signal_poll,
Hai Shalom74f70d42019-02-11 14:42:39 -080013046 .channel_info = nl80211_channel_info,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013047 .set_param = nl80211_set_param,
13048 .get_radio_name = nl80211_get_radio_name,
Jouni Malinen75ecf522011-06-27 15:19:46 -070013049 .add_pmkid = nl80211_add_pmkid,
13050 .remove_pmkid = nl80211_remove_pmkid,
13051 .flush_pmkid = nl80211_flush_pmkid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080013052 .set_rekey_info = nl80211_set_rekey_info,
13053 .poll_client = nl80211_poll_client,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080013054 .set_p2p_powersave = nl80211_set_p2p_powersave,
Dmitry Shmidtea69e842013-05-13 14:52:28 -070013055 .start_dfs_cac = nl80211_start_radar_detection,
13056 .stop_ap = wpa_driver_nl80211_stop_ap,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080013057#ifdef CONFIG_TDLS
13058 .send_tdls_mgmt = nl80211_send_tdls_mgmt,
13059 .tdls_oper = nl80211_tdls_oper,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080013060 .tdls_enable_channel_switch = nl80211_tdls_enable_channel_switch,
13061 .tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080013062#endif /* CONFIG_TDLS */
Dmitry Shmidt700a1372013-03-15 14:14:44 -070013063 .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
Hai Shalom81f62d82019-07-22 12:10:00 -070013064 .update_dh_ie = nl80211_update_dh_ie,
Dmitry Shmidt34af3062013-07-11 10:46:32 -070013065 .get_mac_addr = wpa_driver_nl80211_get_macaddr,
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070013066 .get_survey = wpa_driver_nl80211_get_survey,
Dmitry Shmidt56052862013-10-04 10:23:25 -070013067 .status = wpa_driver_nl80211_status,
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080013068 .switch_channel = nl80211_switch_channel,
Sunil Ravia04bd252022-05-02 22:54:18 -070013069#ifdef CONFIG_IEEE80211AX
13070 .switch_color = nl80211_switch_color,
13071#endif /* CONFIG_IEEE80211AX */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080013072#ifdef ANDROID_P2P
Dmitry Shmidt6e933c12011-09-27 12:29:26 -070013073 .set_noa = wpa_driver_set_p2p_noa,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080013074 .get_noa = wpa_driver_get_p2p_noa,
Dmitry Shmidt6e933c12011-09-27 12:29:26 -070013075 .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
Dmitry Shmidt292b0c32013-11-22 12:54:42 -080013076#endif /* ANDROID_P2P */
Dmitry Shmidt738a26e2011-07-07 14:22:14 -070013077#ifdef ANDROID
Dmitry Shmidt41712582015-06-29 11:02:15 -070013078#ifndef ANDROID_LIB_STUB
Dmitry Shmidt738a26e2011-07-07 14:22:14 -070013079 .driver_cmd = wpa_driver_nl80211_driver_cmd,
Dmitry Shmidt41712582015-06-29 11:02:15 -070013080#endif /* !ANDROID_LIB_STUB */
Dmitry Shmidt292b0c32013-11-22 12:54:42 -080013081#endif /* ANDROID */
Dmitry Shmidta38abf92014-03-06 13:38:44 -080013082 .vendor_cmd = nl80211_vendor_cmd,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080013083 .set_qos_map = nl80211_set_qos_map,
Hai Shalomfdcde762020-04-02 11:19:20 -070013084 .get_wowlan = nl80211_get_wowlan,
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070013085 .set_wowlan = nl80211_set_wowlan,
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070013086 .set_mac_addr = nl80211_set_mac_addr,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080013087#ifdef CONFIG_MESH
13088 .init_mesh = wpa_driver_nl80211_init_mesh,
13089 .join_mesh = wpa_driver_nl80211_join_mesh,
13090 .leave_mesh = wpa_driver_nl80211_leave_mesh,
Hai Shalom81f62d82019-07-22 12:10:00 -070013091 .probe_mesh_link = nl80211_probe_mesh_link,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080013092#endif /* CONFIG_MESH */
13093 .br_add_ip_neigh = wpa_driver_br_add_ip_neigh,
13094 .br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh,
13095 .br_port_set_attr = wpa_driver_br_port_set_attr,
13096 .br_set_net_param = wpa_driver_br_set_net_param,
13097 .add_tx_ts = nl80211_add_ts,
13098 .del_tx_ts = nl80211_del_ts,
Dmitry Shmidte4663042016-04-04 10:07:49 -070013099 .get_ifindex = nl80211_get_ifindex,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080013100#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070013101 .roaming = nl80211_roaming,
Roshan Pius3a1667e2018-07-03 15:17:14 -070013102 .disable_fils = nl80211_disable_fils,
Ravi Joshie6ccb162015-07-16 17:45:41 -070013103 .set_band = nl80211_set_band,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080013104 .get_pref_freq_list = nl80211_get_pref_freq_list,
13105 .set_prob_oper_freq = nl80211_set_prob_oper_freq,
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070013106 .p2p_lo_start = nl80211_p2p_lo_start,
13107 .p2p_lo_stop = nl80211_p2p_lo_stop,
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -070013108 .set_default_scan_ies = nl80211_set_default_scan_ies,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080013109 .set_tdls_mode = nl80211_set_tdls_mode,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070013110#ifdef CONFIG_MBO
13111 .get_bss_transition_status = nl80211_get_bss_transition_status,
13112 .ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
13113#endif /* CONFIG_MBO */
Hai Shalom899fcc72020-10-19 14:38:18 -070013114 .set_bssid_tmp_disallow = nl80211_set_bssid_tmp_disallow,
Hai Shalomc3565922019-10-28 11:58:20 -070013115 .add_sta_node = nl80211_add_sta_node,
Sunil Ravi89eba102022-09-13 21:04:37 -070013116#ifdef CONFIG_PASN
13117 .send_pasn_resp = nl80211_send_pasn_resp,
13118 .set_secure_ranging_ctx = nl80211_set_secure_ranging_ctx,
13119#endif /* CONFIG_PASN */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080013120#endif /* CONFIG_DRIVER_NL80211_QCA */
Hai Shalomc1a21442022-02-04 13:43:00 -080013121 .do_acs = nl80211_do_acs,
Dmitry Shmidt849734c2016-05-27 09:59:01 -070013122 .configure_data_frame_filters = nl80211_configure_data_frame_filters,
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070013123 .get_ext_capab = nl80211_get_ext_capab,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070013124 .update_connect_params = nl80211_update_connection_params,
Roshan Pius3a1667e2018-07-03 15:17:14 -070013125 .send_external_auth_status = nl80211_send_external_auth_status,
Hai Shalom74f70d42019-02-11 14:42:39 -080013126 .set_4addr_mode = nl80211_set_4addr_mode,
Hai Shalome21d4e82020-04-29 16:34:06 -070013127#ifdef CONFIG_DPP
13128 .dpp_listen = nl80211_dpp_listen,
13129#endif /* CONFIG_DPP */
Sunil Ravi89eba102022-09-13 21:04:37 -070013130 .get_sta_mlo_info = nl80211_get_sta_mlo_info,
Hai Shalomc1a21442022-02-04 13:43:00 -080013131#ifdef CONFIG_TESTING_OPTIONS
13132 .register_frame = testing_nl80211_register_frame,
13133 .radio_disable = testing_nl80211_radio_disable,
13134#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070013135};