blob: acd122d52fc71346b4fdbf8ccd0dd71842f07069 [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"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070034#include "netlink.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080035#include "linux_defines.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070036#include "linux_ioctl.h"
37#include "radiotap.h"
38#include "radiotap_iter.h"
39#include "rfkill.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080040#include "driver_nl80211.h"
Ajay Davanagerib921bb82020-09-16 12:49:08 +053041#ifdef CONFIG_DRIVER_NL80211_BRCM
42#include "common/brcm_vendor.h"
43#endif /* CONFIG_DRIVER_NL80211_BRCM */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080044
Hai Shalom74f70d42019-02-11 14:42:39 -080045#ifndef NETLINK_CAP_ACK
46#define NETLINK_CAP_ACK 10
47#endif /* NETLINK_CAP_ACK */
Hai Shalom39ba6fc2019-01-22 12:40:38 -080048/* support for extack if compilation headers are too old */
49#ifndef NETLINK_EXT_ACK
50#define NETLINK_EXT_ACK 11
51enum nlmsgerr_attrs {
52 NLMSGERR_ATTR_UNUSED,
53 NLMSGERR_ATTR_MSG,
54 NLMSGERR_ATTR_OFFS,
55 NLMSGERR_ATTR_COOKIE,
56
57 __NLMSGERR_ATTR_MAX,
58 NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
59};
60#endif
61#ifndef NLM_F_CAPPED
62#define NLM_F_CAPPED 0x100
63#endif
64#ifndef NLM_F_ACK_TLVS
65#define NLM_F_ACK_TLVS 0x200
66#endif
67#ifndef SOL_NETLINK
68#define SOL_NETLINK 270
69#endif
70
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070071
Dmitry Shmidt54605472013-11-08 11:10:19 -080072#ifdef ANDROID
73/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
Dmitry Shmidt54605472013-11-08 11:10:19 -080074#undef nl_socket_set_nonblocking
75#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080076
Dmitry Shmidt54605472013-11-08 11:10:19 -080077#endif /* ANDROID */
78
79
Hai Shalomfdcde762020-04-02 11:19:20 -070080static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080081{
Hai Shalomfdcde762020-04-02 11:19:20 -070082 struct nl_sock *handle;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080083
Hai Shalomfdcde762020-04-02 11:19:20 -070084 handle = nl_socket_alloc_cb(cb);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080085 if (handle == NULL) {
86 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
87 "callbacks (%s)", dbg);
88 return NULL;
89 }
90
91 if (genl_connect(handle)) {
92 wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
93 "netlink (%s)", dbg);
Hai Shalomfdcde762020-04-02 11:19:20 -070094 nl_socket_free(handle);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080095 return NULL;
96 }
97
98 return handle;
99}
100
101
Hai Shalomfdcde762020-04-02 11:19:20 -0700102static void nl_destroy_handles(struct nl_sock **handle)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800103{
104 if (*handle == NULL)
105 return;
Hai Shalomfdcde762020-04-02 11:19:20 -0700106 nl_socket_free(*handle);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800107 *handle = NULL;
108}
109
110
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700111#if __WORDSIZE == 64
112#define ELOOP_SOCKET_INVALID (intptr_t) 0x8888888888888889ULL
113#else
114#define ELOOP_SOCKET_INVALID (intptr_t) 0x88888889ULL
115#endif
116
Hai Shalomfdcde762020-04-02 11:19:20 -0700117static void nl80211_register_eloop_read(struct nl_sock **handle,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700118 eloop_sock_handler handler,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700119 void *eloop_data, int persist)
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700120{
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800121 /*
122 * libnl uses a pretty small buffer (32 kB that gets converted to 64 kB)
123 * by default. It is possible to hit that limit in some cases where
124 * operations are blocked, e.g., with a burst of Deauthentication frames
125 * to hostapd and STA entry deletion. Try to increase the buffer to make
126 * this less likely to occur.
127 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700128 int err;
129
130 err = nl_socket_set_buffer_size(*handle, 262144, 0);
131 if (err < 0) {
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800132 wpa_printf(MSG_DEBUG,
133 "nl80211: Could not set nl_socket RX buffer size: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -0700134 nl_geterror(err));
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800135 /* continue anyway with the default (smaller) buffer */
136 }
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800137
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700138 nl_socket_set_nonblocking(*handle);
139 eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
140 eloop_data, *handle);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700141 if (!persist)
142 *handle = (void *) (((intptr_t) *handle) ^
143 ELOOP_SOCKET_INVALID);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700144}
145
146
Hai Shalomfdcde762020-04-02 11:19:20 -0700147static void nl80211_destroy_eloop_handle(struct nl_sock **handle, int persist)
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700148{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700149 if (!persist)
150 *handle = (void *) (((intptr_t) *handle) ^
151 ELOOP_SOCKET_INVALID);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700152 eloop_unregister_read_sock(nl_socket_get_fd(*handle));
153 nl_destroy_handles(handle);
154}
155
156
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800157static void nl80211_global_deinit(void *priv);
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800158static void nl80211_check_global(struct nl80211_global *global);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800159
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800160static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -0700161static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
162 struct hostapd_freq_params *freq);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -0700163
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700164static int
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800165wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800166 const u8 *set_addr, int first,
167 const char *driver_params);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800168static int nl80211_send_frame_cmd(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700169 unsigned int freq, unsigned int wait,
Hai Shalomfdcde762020-04-02 11:19:20 -0700170 const u8 *buf, size_t buf_len,
171 int save_cookie,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800172 int no_cck, int no_ack, int offchanok,
173 const u16 *csa_offs, size_t csa_offs_len);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800174static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
175 int report);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700176
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800177#define IFIDX_ANY -1
178
179static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
180 int ifidx_reason);
181static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
182 int ifidx_reason);
183static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
184 int ifidx_reason);
Dmitry Shmidt738a26e2011-07-07 14:22:14 -0700185
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700186static int nl80211_set_channel(struct i802_bss *bss,
187 struct hostapd_freq_params *freq, int set_chan);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700188static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
189 int ifindex, int disabled);
190
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800191static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
192 int reset_mode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800193
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700194static int i802_set_iface_flags(struct i802_bss *bss, int up);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800195static int nl80211_set_param(void *priv, const char *param);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -0700196#ifdef CONFIG_MESH
197static int nl80211_put_mesh_config(struct nl_msg *msg,
198 struct wpa_driver_mesh_bss_params *params);
199#endif /* CONFIG_MESH */
Dmitry Shmidt29333592017-01-09 12:27:11 -0800200static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -0700201 u16 reason);
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700202
203
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800204/* Converts nl80211_chan_width to a common format */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800205enum chan_width convert2width(int width)
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800206{
207 switch (width) {
208 case NL80211_CHAN_WIDTH_20_NOHT:
209 return CHAN_WIDTH_20_NOHT;
210 case NL80211_CHAN_WIDTH_20:
211 return CHAN_WIDTH_20;
212 case NL80211_CHAN_WIDTH_40:
213 return CHAN_WIDTH_40;
214 case NL80211_CHAN_WIDTH_80:
215 return CHAN_WIDTH_80;
216 case NL80211_CHAN_WIDTH_80P80:
217 return CHAN_WIDTH_80P80;
218 case NL80211_CHAN_WIDTH_160:
219 return CHAN_WIDTH_160;
220 }
221 return CHAN_WIDTH_UNKNOWN;
222}
223
224
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800225int is_ap_interface(enum nl80211_iftype nlmode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800226{
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700227 return nlmode == NL80211_IFTYPE_AP ||
228 nlmode == NL80211_IFTYPE_P2P_GO;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800229}
230
231
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800232int is_sta_interface(enum nl80211_iftype nlmode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800233{
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700234 return nlmode == NL80211_IFTYPE_STATION ||
235 nlmode == NL80211_IFTYPE_P2P_CLIENT;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800236}
237
238
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700239static int is_p2p_net_interface(enum nl80211_iftype nlmode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800240{
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700241 return nlmode == NL80211_IFTYPE_P2P_CLIENT ||
242 nlmode == NL80211_IFTYPE_P2P_GO;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800243}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700244
245
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800246struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
247 int ifindex)
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -0700248{
249 struct i802_bss *bss;
250
251 for (bss = drv->first_bss; bss; bss = bss->next) {
252 if (bss->ifindex == ifindex)
253 return bss;
254 }
255
256 return NULL;
257}
258
259
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800260static int is_mesh_interface(enum nl80211_iftype nlmode)
261{
262 return nlmode == NL80211_IFTYPE_MESH_POINT;
263}
264
265
266void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
Dmitry Shmidt8bae4132013-06-06 11:25:10 -0700267{
268 if (drv->associated)
269 os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
270 drv->associated = 0;
271 os_memset(drv->bssid, 0, ETH_ALEN);
Hai Shalom5f92bc92019-04-18 11:54:11 -0700272 drv->first_bss->freq = 0;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -0700273}
274
275
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700276/* nl80211 code */
277static int ack_handler(struct nl_msg *msg, void *arg)
278{
279 int *err = arg;
280 *err = 0;
281 return NL_STOP;
282}
283
Hai Shalom899fcc72020-10-19 14:38:18 -0700284
285struct nl80211_ack_ext_arg {
286 int *err;
287 void *ext_data;
288};
289
290
291static int ack_handler_cookie(struct nl_msg *msg, void *arg)
292{
293 struct nl80211_ack_ext_arg *ext_arg = arg;
294 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
295 u64 *cookie = ext_arg->ext_data;
296 struct nlattr *attrs;
297 size_t ack_len, attr_len;
298
299 *ext_arg->err = 0;
300 ack_len = sizeof(struct nlmsghdr) + sizeof(int) +
301 sizeof(struct nlmsghdr);
302 attrs = (struct nlattr *)
303 ((u8 *) nlmsg_data(nlmsg_hdr(msg)) + sizeof(struct nlmsghdr) +
304 sizeof(int));
305 if (nlmsg_hdr(msg)->nlmsg_len <= ack_len)
306 return NL_STOP;
307
308 attr_len = nlmsg_hdr(msg)->nlmsg_len - ack_len;
309
310 if(!(nlmsg_hdr(msg)->nlmsg_flags & NLM_F_ACK_TLVS))
311 return NL_STOP;
312
313 nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, attr_len, NULL);
314 if (tb[NLMSGERR_ATTR_COOKIE])
315 *cookie = nla_get_u64(tb[NLMSGERR_ATTR_COOKIE]);
316
317 return NL_STOP;
318}
319
320
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700321static int finish_handler(struct nl_msg *msg, void *arg)
322{
323 int *ret = arg;
324 *ret = 0;
325 return NL_SKIP;
326}
327
328static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
329 void *arg)
330{
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800331 struct nlmsghdr *nlh = (struct nlmsghdr *) err - 1;
332 int len = nlh->nlmsg_len;
333 struct nlattr *attrs;
334 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700335 int *ret = arg;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800336 int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh);
337
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700338 *ret = err->error;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800339
340 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
341 return NL_SKIP;
342
343 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
344 ack_len += err->msg.nlmsg_len - sizeof(*nlh);
345
346 if (len <= ack_len)
347 return NL_STOP;
348
349 attrs = (void *) ((unsigned char *) nlh + ack_len);
350 len -= ack_len;
351
352 nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, len, NULL);
353 if (tb[NLMSGERR_ATTR_MSG]) {
354 len = strnlen((char *) nla_data(tb[NLMSGERR_ATTR_MSG]),
355 nla_len(tb[NLMSGERR_ATTR_MSG]));
356 wpa_printf(MSG_ERROR, "nl80211: kernel reports: %*s",
357 len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG]));
358 }
359
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700360 return NL_SKIP;
361}
362
363
364static int no_seq_check(struct nl_msg *msg, void *arg)
365{
366 return NL_OK;
367}
368
369
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800370static void nl80211_nlmsg_clear(struct nl_msg *msg)
371{
372 /*
373 * Clear nlmsg data, e.g., to make sure key material is not left in
374 * heap memory for unnecessarily long time.
375 */
376 if (msg) {
377 struct nlmsghdr *hdr = nlmsg_hdr(msg);
378 void *data = nlmsg_data(hdr);
379 /*
380 * This would use nlmsg_datalen() or the older nlmsg_len() if
381 * only libnl were to maintain a stable API.. Neither will work
382 * with all released versions, so just calculate the length
383 * here.
384 */
385 int len = hdr->nlmsg_len - NLMSG_HDRLEN;
386
387 os_memset(data, 0, len);
388 }
389}
390
391
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800392static int send_and_recv(struct nl80211_global *global,
Hai Shalomfdcde762020-04-02 11:19:20 -0700393 struct nl_sock *nl_handle, struct nl_msg *msg,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700394 int (*valid_handler)(struct nl_msg *, void *),
Hai Shalom899fcc72020-10-19 14:38:18 -0700395 void *valid_data,
396 int (*ack_handler_custom)(struct nl_msg *, void *),
397 void *ack_data)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700398{
399 struct nl_cb *cb;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800400 int err = -ENOMEM, opt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700401
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800402 if (!msg)
403 return -ENOMEM;
404
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800405 cb = nl_cb_clone(global->nl_cb);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700406 if (!cb)
407 goto out;
408
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800409 /* try to set NETLINK_EXT_ACK to 1, ignoring errors */
410 opt = 1;
411 setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
412 NETLINK_EXT_ACK, &opt, sizeof(opt));
413
Hai Shalom74f70d42019-02-11 14:42:39 -0800414 /* try to set NETLINK_CAP_ACK to 1, ignoring errors */
415 opt = 1;
416 setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
417 NETLINK_CAP_ACK, &opt, sizeof(opt));
418
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700419 err = nl_send_auto_complete(nl_handle, msg);
Hai Shalomfdcde762020-04-02 11:19:20 -0700420 if (err < 0) {
421 wpa_printf(MSG_INFO,
422 "nl80211: nl_send_auto_complete() failed: %s",
423 nl_geterror(err));
424 /* Need to convert libnl error code to an errno value. For now,
425 * just hardcode this to EBADF; the real error reason is shown
426 * in that error print above. */
427 err = -EBADF;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700428 goto out;
Hai Shalomfdcde762020-04-02 11:19:20 -0700429 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700430
431 err = 1;
432
433 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
434 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
Hai Shalom899fcc72020-10-19 14:38:18 -0700435 if (ack_handler_custom) {
436 struct nl80211_ack_ext_arg *ext_arg = ack_data;
437
438 ext_arg->err = &err;
439 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM,
440 ack_handler_custom, ack_data);
441 } else {
442 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
443 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700444
445 if (valid_handler)
446 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
447 valid_handler, valid_data);
448
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700449 while (err > 0) {
450 int res = nl_recvmsgs(nl_handle, cb);
Hai Shalomfdcde762020-04-02 11:19:20 -0700451
452 if (res == -NLE_DUMP_INTR) {
453 /* Most likely one of the nl80211 dump routines hit a
454 * case where internal results changed while the dump
455 * was being sent. The most common known case for this
456 * is scan results fetching while associated were every
457 * received Beacon frame from the AP may end up
458 * incrementing bss_generation. This
459 * NL80211_CMD_GET_SCAN case tries again in the caller;
460 * other cases (of which there are no known common ones)
461 * will stop and return an error. */
462 wpa_printf(MSG_DEBUG, "nl80211: %s; convert to -EAGAIN",
463 nl_geterror(res));
464 err = -EAGAIN;
465 } else if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700466 wpa_printf(MSG_INFO,
Hai Shalomfdcde762020-04-02 11:19:20 -0700467 "nl80211: %s->nl_recvmsgs failed: %d (%s)",
468 __func__, res, nl_geterror(res));
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700469 }
470 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700471 out:
472 nl_cb_put(cb);
Hai Shalom60840252021-02-19 19:02:11 -0800473 /* Always clear the message as it can potentially contain keys */
474 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700475 nlmsg_free(msg);
476 return err;
477}
478
479
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800480int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
481 struct nl_msg *msg,
482 int (*valid_handler)(struct nl_msg *, void *),
Hai Shalom899fcc72020-10-19 14:38:18 -0700483 void *valid_data,
484 int (*ack_handler_custom)(struct nl_msg *, void *),
485 void *ack_data)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700486{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800487 return send_and_recv(drv->global, drv->global->nl, msg,
Hai Shalom899fcc72020-10-19 14:38:18 -0700488 valid_handler, valid_data,
489 ack_handler_custom, ack_data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700490}
491
492
Hai Shalomb755a2a2020-04-23 21:49:02 -0700493/* Use this method to mark that it is necessary to own the connection/interface
494 * for this operation.
495 * handle may be set to NULL, to get the same behavior as send_and_recv_msgs().
496 * set_owner can be used to mark this socket for receiving control port frames.
497 */
498static int send_and_recv_msgs_owner(struct wpa_driver_nl80211_data *drv,
499 struct nl_msg *msg,
500 struct nl_sock *handle, int set_owner,
501 int (*valid_handler)(struct nl_msg *,
502 void *),
Hai Shalom899fcc72020-10-19 14:38:18 -0700503 void *valid_data,
504 int (*ack_handler_custom)(struct nl_msg *,
505 void *),
506 void *ack_data)
Hai Shalomb755a2a2020-04-23 21:49:02 -0700507{
Hai Shalom60840252021-02-19 19:02:11 -0800508 if (!msg)
509 return -ENOMEM;
510
Hai Shalomb755a2a2020-04-23 21:49:02 -0700511 /* Control port over nl80211 needs the flags and attributes below.
512 *
513 * The Linux kernel has initial checks for them (in nl80211.c) like:
514 * validate_pae_over_nl80211(...)
515 * or final checks like:
516 * dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid
517 *
518 * Final operations (e.g., disassociate) don't need to set these
519 * attributes, but they have to be performed on the socket, which has
520 * the connection owner property set in the kernel.
521 */
522 if ((drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) &&
523 handle && set_owner &&
524 (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) ||
525 nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER) ||
526 nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
527 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_PREAUTH)))
528 return -1;
529
530 return send_and_recv(drv->global, handle ? handle : drv->global->nl,
Hai Shalom899fcc72020-10-19 14:38:18 -0700531 msg, valid_handler, valid_data,
532 ack_handler_custom, ack_data);
Hai Shalomb755a2a2020-04-23 21:49:02 -0700533}
534
535
Hai Shalomc1a21442022-02-04 13:43:00 -0800536static int
537send_and_recv_msgs_connect_handle(struct wpa_driver_nl80211_data *drv,
538 struct nl_msg *msg, struct i802_bss *bss,
539 int set_owner)
540{
541 struct nl_sock *nl_connect = get_connect_handle(bss);
542
543 if (nl_connect)
544 return send_and_recv_msgs_owner(drv, msg, nl_connect, set_owner,
545 process_bss_event, bss, NULL,
546 NULL);
547 else
548 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
549}
550
551
Hai Shalomb755a2a2020-04-23 21:49:02 -0700552struct nl_sock * get_connect_handle(struct i802_bss *bss)
553{
554 if ((bss->drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) ||
555 bss->use_nl_connect)
556 return bss->nl_connect;
557
558 return NULL;
559}
560
561
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700562struct family_data {
563 const char *group;
564 int id;
565};
566
567
568static int family_handler(struct nl_msg *msg, void *arg)
569{
570 struct family_data *res = arg;
571 struct nlattr *tb[CTRL_ATTR_MAX + 1];
572 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
573 struct nlattr *mcgrp;
574 int i;
575
576 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
577 genlmsg_attrlen(gnlh, 0), NULL);
578 if (!tb[CTRL_ATTR_MCAST_GROUPS])
579 return NL_SKIP;
580
581 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
582 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
583 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
584 nla_len(mcgrp), NULL);
585 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
586 !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
587 os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
588 res->group,
589 nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
590 continue;
591 res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
592 break;
593 };
594
595 return NL_SKIP;
596}
597
598
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800599static int nl_get_multicast_id(struct nl80211_global *global,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700600 const char *family, const char *group)
601{
602 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800603 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700604 struct family_data res = { group, -ENOENT };
605
606 msg = nlmsg_alloc();
607 if (!msg)
608 return -ENOMEM;
Hai Shalomc1a21442022-02-04 13:43:00 -0800609 if (!genlmsg_put(msg, 0, 0, global->nlctrl_id,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800610 0, 0, CTRL_CMD_GETFAMILY, 0) ||
611 nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family)) {
612 nlmsg_free(msg);
613 return -1;
614 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700615
Hai Shalom899fcc72020-10-19 14:38:18 -0700616 ret = send_and_recv(global, global->nl, msg, family_handler, &res,
617 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700618 if (ret == 0)
619 ret = res.id;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700620 return ret;
621}
622
623
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800624void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
625 struct nl_msg *msg, int flags, uint8_t cmd)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800626{
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700627 if (TEST_FAIL())
628 return NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800629 return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
630 0, flags, cmd, 0);
631}
632
633
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800634static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
635{
636 if (bss->wdev_id_set)
637 return nla_put_u64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
638 return nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
639}
640
641
642struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd)
643{
644 struct nl_msg *msg;
645
646 msg = nlmsg_alloc();
647 if (!msg)
648 return NULL;
649
650 if (!nl80211_cmd(bss->drv, msg, flags, cmd) ||
651 nl80211_set_iface_id(msg, bss) < 0) {
652 nlmsg_free(msg);
653 return NULL;
654 }
655
656 return msg;
657}
658
659
660static struct nl_msg *
Hai Shalomc1a21442022-02-04 13:43:00 -0800661nl80211_ifindex_msg_build(struct wpa_driver_nl80211_data *drv,
662 struct nl_msg *msg, int ifindex, int flags,
663 uint8_t cmd)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800664{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800665 if (!msg)
666 return NULL;
667
668 if (!nl80211_cmd(drv, msg, flags, cmd) ||
669 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
670 nlmsg_free(msg);
671 return NULL;
672 }
673
674 return msg;
675}
676
677
Hai Shalomc1a21442022-02-04 13:43:00 -0800678static struct nl_msg *
679nl80211_ifindex_msg(struct wpa_driver_nl80211_data *drv, int ifindex,
680 int flags, uint8_t cmd)
681{
682 return nl80211_ifindex_msg_build(drv, nlmsg_alloc(), ifindex, flags,
683 cmd);
684}
685
686
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800687struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
688 uint8_t cmd)
689{
690 return nl80211_ifindex_msg(drv, drv->ifindex, flags, cmd);
691}
692
693
694struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd)
695{
696 return nl80211_ifindex_msg(bss->drv, bss->ifindex, flags, cmd);
697}
698
699
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800700struct wiphy_idx_data {
701 int wiphy_idx;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700702 enum nl80211_iftype nlmode;
703 u8 *macaddr;
Hai Shalom60840252021-02-19 19:02:11 -0800704 u8 use_4addr;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800705};
706
707
708static int netdev_info_handler(struct nl_msg *msg, void *arg)
709{
710 struct nlattr *tb[NL80211_ATTR_MAX + 1];
711 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
712 struct wiphy_idx_data *info = arg;
713
714 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
715 genlmsg_attrlen(gnlh, 0), NULL);
716
717 if (tb[NL80211_ATTR_WIPHY])
718 info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
719
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700720 if (tb[NL80211_ATTR_IFTYPE])
721 info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]);
722
723 if (tb[NL80211_ATTR_MAC] && info->macaddr)
724 os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
725 ETH_ALEN);
726
Hai Shalom60840252021-02-19 19:02:11 -0800727 if (tb[NL80211_ATTR_4ADDR])
728 info->use_4addr = nla_get_u8(tb[NL80211_ATTR_4ADDR]);
729
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800730 return NL_SKIP;
731}
732
733
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800734int nl80211_get_wiphy_index(struct i802_bss *bss)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800735{
736 struct nl_msg *msg;
737 struct wiphy_idx_data data = {
738 .wiphy_idx = -1,
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700739 .macaddr = NULL,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800740 };
741
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800742 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
743 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800744
Hai Shalom899fcc72020-10-19 14:38:18 -0700745 if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
746 NULL, NULL) == 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800747 return data.wiphy_idx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800748 return -1;
749}
750
751
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700752static enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
753{
754 struct nl_msg *msg;
755 struct wiphy_idx_data data = {
756 .nlmode = NL80211_IFTYPE_UNSPECIFIED,
757 .macaddr = NULL,
758 };
759
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800760 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
761 return NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700762
Hai Shalom899fcc72020-10-19 14:38:18 -0700763 if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
764 NULL, NULL) == 0)
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700765 return data.nlmode;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700766 return NL80211_IFTYPE_UNSPECIFIED;
767}
768
769
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700770static int nl80211_get_macaddr(struct i802_bss *bss)
771{
772 struct nl_msg *msg;
773 struct wiphy_idx_data data = {
774 .macaddr = bss->addr,
775 };
776
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800777 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
778 return -1;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700779
Hai Shalom899fcc72020-10-19 14:38:18 -0700780 return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
781 NULL, NULL);
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700782}
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700783
784
Hai Shalom60840252021-02-19 19:02:11 -0800785static int nl80211_get_4addr(struct i802_bss *bss)
786{
787 struct nl_msg *msg;
788 struct wiphy_idx_data data = {
789 .use_4addr = 0,
790 };
791
792 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)) ||
793 send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
794 NULL, NULL))
795 return -1;
796 return data.use_4addr;
797}
798
799
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800800static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
801 struct nl80211_wiphy_data *w)
802{
803 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800804 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800805
806 msg = nlmsg_alloc();
807 if (!msg)
808 return -1;
809
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800810 if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS) ||
811 nla_put_u32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx)) {
812 nlmsg_free(msg);
813 return -1;
814 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800815
Hai Shalom899fcc72020-10-19 14:38:18 -0700816 ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL,
817 NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800818 if (ret) {
819 wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
820 "failed: ret=%d (%s)",
821 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800822 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800823 return ret;
824}
825
826
827static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
828{
829 struct nl80211_wiphy_data *w = eloop_ctx;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700830 int res;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800831
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800832 wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800833
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700834 res = nl_recvmsgs(handle, w->nl_cb);
Dmitry Shmidt71757432014-06-02 13:50:35 -0700835 if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700836 wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
837 __func__, res);
838 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800839}
840
841
842static int process_beacon_event(struct nl_msg *msg, void *arg)
843{
844 struct nl80211_wiphy_data *w = arg;
845 struct wpa_driver_nl80211_data *drv;
846 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
847 struct nlattr *tb[NL80211_ATTR_MAX + 1];
848 union wpa_event_data event;
849
850 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
851 genlmsg_attrlen(gnlh, 0), NULL);
852
853 if (gnlh->cmd != NL80211_CMD_FRAME) {
854 wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
855 gnlh->cmd);
856 return NL_SKIP;
857 }
858
859 if (!tb[NL80211_ATTR_FRAME])
860 return NL_SKIP;
861
862 dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
863 wiphy_list) {
864 os_memset(&event, 0, sizeof(event));
865 event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
866 event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
867 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
868 }
869
870 return NL_SKIP;
871}
872
873
874static struct nl80211_wiphy_data *
875nl80211_get_wiphy_data_ap(struct i802_bss *bss)
876{
877 static DEFINE_DL_LIST(nl80211_wiphys);
878 struct nl80211_wiphy_data *w;
879 int wiphy_idx, found = 0;
880 struct i802_bss *tmp_bss;
Paul Stewart092955c2017-02-06 09:13:09 -0800881 u8 channel;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800882
883 if (bss->wiphy_data != NULL)
884 return bss->wiphy_data;
885
886 wiphy_idx = nl80211_get_wiphy_index(bss);
887
888 dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
889 if (w->wiphy_idx == wiphy_idx)
890 goto add;
891 }
892
893 /* alloc new one */
894 w = os_zalloc(sizeof(*w));
895 if (w == NULL)
896 return NULL;
897 w->wiphy_idx = wiphy_idx;
898 dl_list_init(&w->bsss);
899 dl_list_init(&w->drvs);
900
Paul Stewart092955c2017-02-06 09:13:09 -0800901 /* Beacon frames not supported in IEEE 802.11ad */
902 if (ieee80211_freq_to_chan(bss->freq, &channel) !=
903 HOSTAPD_MODE_IEEE80211AD) {
904 w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
905 if (!w->nl_cb) {
906 os_free(w);
907 return NULL;
908 }
909 nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
910 no_seq_check, NULL);
911 nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
912 process_beacon_event, w);
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000913
Paul Stewart092955c2017-02-06 09:13:09 -0800914 w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
915 "wiphy beacons");
916 if (w->nl_beacons == NULL) {
917 os_free(w);
918 return NULL;
919 }
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000920
Paul Stewart092955c2017-02-06 09:13:09 -0800921 if (nl80211_register_beacons(bss->drv, w)) {
922 nl_destroy_handles(&w->nl_beacons);
923 os_free(w);
924 return NULL;
925 }
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000926
Paul Stewart092955c2017-02-06 09:13:09 -0800927 nl80211_register_eloop_read(&w->nl_beacons,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700928 nl80211_recv_beacons, w, 0);
Paul Stewart092955c2017-02-06 09:13:09 -0800929 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800930
931 dl_list_add(&nl80211_wiphys, &w->list);
932
933add:
934 /* drv entry for this bss already there? */
935 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
936 if (tmp_bss->drv == bss->drv) {
937 found = 1;
938 break;
939 }
940 }
941 /* if not add it */
942 if (!found)
943 dl_list_add(&w->drvs, &bss->drv->wiphy_list);
944
945 dl_list_add(&w->bsss, &bss->wiphy_list);
946 bss->wiphy_data = w;
947 return w;
948}
949
950
951static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
952{
953 struct nl80211_wiphy_data *w = bss->wiphy_data;
954 struct i802_bss *tmp_bss;
955 int found = 0;
956
957 if (w == NULL)
958 return;
959 bss->wiphy_data = NULL;
960 dl_list_del(&bss->wiphy_list);
961
962 /* still any for this drv present? */
963 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
964 if (tmp_bss->drv == bss->drv) {
965 found = 1;
966 break;
967 }
968 }
969 /* if not remove it */
970 if (!found)
971 dl_list_del(&bss->drv->wiphy_list);
972
973 if (!dl_list_empty(&w->bsss))
974 return;
975
Paul Stewart092955c2017-02-06 09:13:09 -0800976 if (w->nl_beacons)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700977 nl80211_destroy_eloop_handle(&w->nl_beacons, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800978
979 nl_cb_put(w->nl_cb);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800980 dl_list_del(&w->list);
981 os_free(w);
982}
983
984
Dmitry Shmidte4663042016-04-04 10:07:49 -0700985static unsigned int nl80211_get_ifindex(void *priv)
986{
987 struct i802_bss *bss = priv;
988 struct wpa_driver_nl80211_data *drv = bss->drv;
989
990 return drv->ifindex;
991}
992
993
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700994static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
995{
996 struct i802_bss *bss = priv;
997 struct wpa_driver_nl80211_data *drv = bss->drv;
998 if (!drv->associated)
999 return -1;
1000 os_memcpy(bssid, drv->bssid, ETH_ALEN);
1001 return 0;
1002}
1003
1004
1005static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
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(ssid, drv->ssid, drv->ssid_len);
1012 return drv->ssid_len;
1013}
1014
1015
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001016static void wpa_driver_nl80211_event_newlink(
Dmitry Shmidte4663042016-04-04 10:07:49 -07001017 struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
1018 int ifindex, const char *ifname)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001019{
1020 union wpa_event_data event;
1021
Dmitry Shmidte4663042016-04-04 10:07:49 -07001022 if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001023 if (if_nametoindex(drv->first_bss->ifname) == 0) {
1024 wpa_printf(MSG_DEBUG, "nl80211: Interface %s does not exist - ignore RTM_NEWLINK",
1025 drv->first_bss->ifname);
1026 return;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001027 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001028 if (!drv->if_removed)
1029 return;
1030 wpa_printf(MSG_DEBUG, "nl80211: Mark if_removed=0 for %s based on RTM_NEWLINK event",
1031 drv->first_bss->ifname);
1032 drv->if_removed = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001033 }
1034
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001035 os_memset(&event, 0, sizeof(event));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001036 event.interface_status.ifindex = ifindex;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001037 os_strlcpy(event.interface_status.ifname, ifname,
1038 sizeof(event.interface_status.ifname));
1039 event.interface_status.ievent = EVENT_INTERFACE_ADDED;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001040 if (drv)
1041 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
1042 else
1043 wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
1044 &event);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001045}
1046
1047
1048static void wpa_driver_nl80211_event_dellink(
Dmitry Shmidte4663042016-04-04 10:07:49 -07001049 struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
1050 int ifindex, const char *ifname)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001051{
1052 union wpa_event_data event;
1053
Dmitry Shmidte4663042016-04-04 10:07:49 -07001054 if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001055 if (drv->if_removed) {
1056 wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s",
1057 ifname);
1058 return;
1059 }
1060 wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed - mark if_removed=1",
1061 ifname);
1062 drv->if_removed = 1;
1063 } else {
1064 wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed",
1065 ifname);
1066 }
1067
1068 os_memset(&event, 0, sizeof(event));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001069 event.interface_status.ifindex = ifindex;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001070 os_strlcpy(event.interface_status.ifname, ifname,
1071 sizeof(event.interface_status.ifname));
1072 event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001073 if (drv)
1074 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
1075 else
1076 wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
1077 &event);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001078}
1079
1080
1081static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
1082 u8 *buf, size_t len)
1083{
1084 int attrlen, rta_len;
1085 struct rtattr *attr;
1086
1087 attrlen = len;
1088 attr = (struct rtattr *) buf;
1089
1090 rta_len = RTA_ALIGN(sizeof(struct rtattr));
1091 while (RTA_OK(attr, attrlen)) {
1092 if (attr->rta_type == IFLA_IFNAME) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001093 if (os_strcmp(((char *) attr) + rta_len,
1094 drv->first_bss->ifname) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001095 return 1;
1096 else
1097 break;
1098 }
1099 attr = RTA_NEXT(attr, attrlen);
1100 }
1101
1102 return 0;
1103}
1104
1105
1106static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
1107 int ifindex, u8 *buf, size_t len)
1108{
1109 if (drv->ifindex == ifindex)
1110 return 1;
1111
1112 if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001113 nl80211_check_global(drv->global);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001114 wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
1115 "interface");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001116 if (wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL) < 0)
1117 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001118 return 1;
1119 }
1120
1121 return 0;
1122}
1123
1124
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001125static struct wpa_driver_nl80211_data *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001126nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len,
1127 int *init_failed)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001128{
1129 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001130 int res;
1131
1132 if (init_failed)
1133 *init_failed = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001134 dl_list_for_each(drv, &global->interfaces,
1135 struct wpa_driver_nl80211_data, list) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001136 res = wpa_driver_nl80211_own_ifindex(drv, idx, buf, len);
1137 if (res < 0) {
1138 wpa_printf(MSG_DEBUG,
1139 "nl80211: Found matching own interface, but failed to complete reinitialization");
1140 if (init_failed)
1141 *init_failed = 1;
1142 return drv;
1143 }
1144 if (res > 0 || have_ifidx(drv, idx, IFIDX_ANY))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001145 return drv;
1146 }
1147 return NULL;
1148}
1149
1150
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001151static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001152 int ifindex, int notify)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001153{
1154 struct i802_bss *bss;
1155 u8 addr[ETH_ALEN];
1156
1157 bss = get_bss_ifindex(drv, ifindex);
1158 if (bss &&
1159 linux_get_ifhwaddr(drv->global->ioctl_sock,
1160 bss->ifname, addr) < 0) {
1161 wpa_printf(MSG_DEBUG,
1162 "nl80211: %s: failed to re-read MAC address",
1163 bss->ifname);
1164 } else if (bss && os_memcmp(addr, bss->addr, ETH_ALEN) != 0) {
1165 wpa_printf(MSG_DEBUG,
1166 "nl80211: Own MAC address on ifindex %d (%s) changed from "
1167 MACSTR " to " MACSTR,
1168 ifindex, bss->ifname,
1169 MAC2STR(bss->addr), MAC2STR(addr));
1170 os_memcpy(bss->addr, addr, ETH_ALEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001171 if (notify)
1172 wpa_supplicant_event(drv->ctx,
1173 EVENT_INTERFACE_MAC_CHANGED, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001174 }
1175}
1176
1177
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001178static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
1179 struct ifinfomsg *ifi,
1180 u8 *buf, size_t len)
1181{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001182 struct nl80211_global *global = ctx;
1183 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001184 int attrlen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001185 struct rtattr *attr;
1186 u32 brid = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001187 char namebuf[IFNAMSIZ];
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001188 char ifname[IFNAMSIZ + 1];
1189 char extra[100], *pos, *end;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001190 int init_failed;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001191
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001192 extra[0] = '\0';
1193 pos = extra;
1194 end = pos + sizeof(extra);
1195 ifname[0] = '\0';
1196
1197 attrlen = len;
1198 attr = (struct rtattr *) buf;
1199 while (RTA_OK(attr, attrlen)) {
1200 switch (attr->rta_type) {
1201 case IFLA_IFNAME:
Hai Shalomfdcde762020-04-02 11:19:20 -07001202 if (RTA_PAYLOAD(attr) > IFNAMSIZ)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001203 break;
1204 os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
1205 ifname[RTA_PAYLOAD(attr)] = '\0';
1206 break;
1207 case IFLA_MASTER:
1208 brid = nla_get_u32((struct nlattr *) attr);
1209 pos += os_snprintf(pos, end - pos, " master=%u", brid);
1210 break;
1211 case IFLA_WIRELESS:
1212 pos += os_snprintf(pos, end - pos, " wext");
1213 break;
1214 case IFLA_OPERSTATE:
1215 pos += os_snprintf(pos, end - pos, " operstate=%u",
1216 nla_get_u32((struct nlattr *) attr));
1217 break;
1218 case IFLA_LINKMODE:
1219 pos += os_snprintf(pos, end - pos, " linkmode=%u",
1220 nla_get_u32((struct nlattr *) attr));
1221 break;
1222 }
1223 attr = RTA_NEXT(attr, attrlen);
1224 }
1225 extra[sizeof(extra) - 1] = '\0';
1226
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001227 wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
1228 ifi->ifi_index, ifname, extra, ifi->ifi_family,
1229 ifi->ifi_flags,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001230 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
1231 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
1232 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
1233 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
1234
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001235 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, &init_failed);
Dmitry Shmidte4663042016-04-04 10:07:49 -07001236 if (!drv)
1237 goto event_newlink;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001238 if (init_failed)
1239 return; /* do not update interface state */
Dmitry Shmidte4663042016-04-04 10:07:49 -07001240
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001241 if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001242 namebuf[0] = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001243 if (if_indextoname(ifi->ifi_index, namebuf) &&
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001244 linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001245 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
1246 "event since interface %s is up", namebuf);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001247 drv->ignore_if_down_event = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001248 /* Re-read MAC address as it may have changed */
1249 nl80211_refresh_mac(drv, ifi->ifi_index, 1);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001250 return;
1251 }
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001252 wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
1253 namebuf, ifname);
1254 if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
1255 wpa_printf(MSG_DEBUG,
1256 "nl80211: Not the main interface (%s) - do not indicate interface down",
1257 drv->first_bss->ifname);
1258 } else if (drv->ignore_if_down_event) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001259 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
1260 "event generated by mode change");
1261 drv->ignore_if_down_event = 0;
1262 } else {
1263 drv->if_disabled = 1;
1264 wpa_supplicant_event(drv->ctx,
1265 EVENT_INTERFACE_DISABLED, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08001266
1267 /*
1268 * Try to get drv again, since it may be removed as
1269 * part of the EVENT_INTERFACE_DISABLED handling for
1270 * dynamic interfaces
1271 */
1272 drv = nl80211_find_drv(global, ifi->ifi_index,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001273 buf, len, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08001274 if (!drv)
1275 return;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001276 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001277 }
1278
1279 if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
Hai Shalomc9e41a12018-07-31 14:41:42 -07001280 namebuf[0] = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001281 if (if_indextoname(ifi->ifi_index, namebuf) &&
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001282 linux_iface_up(drv->global->ioctl_sock, namebuf) == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001283 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1284 "event since interface %s is down",
1285 namebuf);
Hai Shalomc9e41a12018-07-31 14:41:42 -07001286 return;
1287 }
1288 wpa_printf(MSG_DEBUG, "nl80211: Interface up (%s/%s)",
1289 namebuf, ifname);
1290 if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
1291 wpa_printf(MSG_DEBUG,
1292 "nl80211: Not the main interface (%s) - do not indicate interface up",
1293 drv->first_bss->ifname);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001294 } else if (if_nametoindex(drv->first_bss->ifname) == 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001295 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1296 "event since interface %s does not exist",
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001297 drv->first_bss->ifname);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001298 } else if (drv->if_removed) {
1299 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1300 "event since interface %s is marked "
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001301 "removed", drv->first_bss->ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001302 } else {
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07001303 /* Re-read MAC address as it may have changed */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001304 nl80211_refresh_mac(drv, ifi->ifi_index, 0);
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07001305
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001306 drv->if_disabled = 0;
1307 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
1308 NULL);
1309 }
Sunil Ravi90775442020-09-24 11:53:19 -07001310 } else if (ifi->ifi_flags & IFF_UP) {
1311 /* Re-read MAC address as it may have changed */
1312 nl80211_refresh_mac(drv, ifi->ifi_index, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001313 }
1314
1315 /*
1316 * Some drivers send the association event before the operup event--in
1317 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
1318 * fails. This will hit us when wpa_supplicant does not need to do
1319 * IEEE 802.1X authentication
1320 */
1321 if (drv->operstate == 1 &&
1322 (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001323 !(ifi->ifi_flags & IFF_RUNNING)) {
1324 wpa_printf(MSG_DEBUG, "nl80211: Set IF_OPER_UP again based on ifi_flags and expected operstate");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001325 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001326 -1, IF_OPER_UP);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001327 }
1328
Dmitry Shmidte4663042016-04-04 10:07:49 -07001329event_newlink:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001330 if (ifname[0])
Dmitry Shmidte4663042016-04-04 10:07:49 -07001331 wpa_driver_nl80211_event_newlink(global, drv, ifi->ifi_index,
1332 ifname);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001333
Dmitry Shmidte4663042016-04-04 10:07:49 -07001334 if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001335 struct i802_bss *bss;
1336
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001337 /* device has been added to bridge */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001338 if (!if_indextoname(brid, namebuf)) {
1339 wpa_printf(MSG_DEBUG,
1340 "nl80211: Could not find bridge ifname for ifindex %u",
1341 brid);
1342 return;
1343 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001344 wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
1345 brid, namebuf);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001346 add_ifidx(drv, brid, ifi->ifi_index);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001347
1348 for (bss = drv->first_bss; bss; bss = bss->next) {
1349 if (os_strcmp(ifname, bss->ifname) == 0) {
1350 os_strlcpy(bss->brname, namebuf, IFNAMSIZ);
1351 break;
1352 }
1353 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001354 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001355}
1356
1357
1358static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
1359 struct ifinfomsg *ifi,
1360 u8 *buf, size_t len)
1361{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001362 struct nl80211_global *global = ctx;
1363 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001364 int attrlen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001365 struct rtattr *attr;
1366 u32 brid = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001367 char ifname[IFNAMSIZ + 1];
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001368 char extra[100], *pos, *end;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001369
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001370 extra[0] = '\0';
1371 pos = extra;
1372 end = pos + sizeof(extra);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001373 ifname[0] = '\0';
1374
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001375 attrlen = len;
1376 attr = (struct rtattr *) buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001377 while (RTA_OK(attr, attrlen)) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001378 switch (attr->rta_type) {
1379 case IFLA_IFNAME:
Hai Shalomfdcde762020-04-02 11:19:20 -07001380 if (RTA_PAYLOAD(attr) > IFNAMSIZ)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001381 break;
1382 os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
1383 ifname[RTA_PAYLOAD(attr)] = '\0';
1384 break;
1385 case IFLA_MASTER:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001386 brid = nla_get_u32((struct nlattr *) attr);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001387 pos += os_snprintf(pos, end - pos, " master=%u", brid);
1388 break;
1389 case IFLA_OPERSTATE:
1390 pos += os_snprintf(pos, end - pos, " operstate=%u",
1391 nla_get_u32((struct nlattr *) attr));
1392 break;
1393 case IFLA_LINKMODE:
1394 pos += os_snprintf(pos, end - pos, " linkmode=%u",
1395 nla_get_u32((struct nlattr *) attr));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001396 break;
1397 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001398 attr = RTA_NEXT(attr, attrlen);
1399 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001400 extra[sizeof(extra) - 1] = '\0';
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001401
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001402 wpa_printf(MSG_DEBUG, "RTM_DELLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
1403 ifi->ifi_index, ifname, extra, ifi->ifi_family,
1404 ifi->ifi_flags,
1405 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
1406 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
1407 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
1408 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
1409
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001410 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001411
Dmitry Shmidte4663042016-04-04 10:07:49 -07001412 if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001413 /* device has been removed from bridge */
1414 char namebuf[IFNAMSIZ];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001415
1416 if (!if_indextoname(brid, namebuf)) {
1417 wpa_printf(MSG_DEBUG,
1418 "nl80211: Could not find bridge ifname for ifindex %u",
1419 brid);
1420 } else {
1421 wpa_printf(MSG_DEBUG,
1422 "nl80211: Remove ifindex %u for bridge %s",
1423 brid, namebuf);
1424 }
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001425 del_ifidx(drv, brid, ifi->ifi_index);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001426 }
Dmitry Shmidte4663042016-04-04 10:07:49 -07001427
1428 if (ifi->ifi_family != AF_BRIDGE || !brid)
1429 wpa_driver_nl80211_event_dellink(global, drv, ifi->ifi_index,
1430 ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001431}
1432
1433
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001434struct nl80211_get_assoc_freq_arg {
1435 struct wpa_driver_nl80211_data *drv;
1436 unsigned int assoc_freq;
1437 unsigned int ibss_freq;
1438 u8 assoc_bssid[ETH_ALEN];
1439 u8 assoc_ssid[SSID_MAX_LEN];
1440 u8 assoc_ssid_len;
1441};
1442
1443static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg)
1444{
1445 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1446 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1447 struct nlattr *bss[NL80211_BSS_MAX + 1];
1448 static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
1449 [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
1450 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
1451 [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
1452 [NL80211_BSS_STATUS] = { .type = NLA_U32 },
1453 };
1454 struct nl80211_get_assoc_freq_arg *ctx = arg;
1455 enum nl80211_bss_status status;
1456
1457 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1458 genlmsg_attrlen(gnlh, 0), NULL);
1459 if (!tb[NL80211_ATTR_BSS] ||
1460 nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
1461 bss_policy) ||
1462 !bss[NL80211_BSS_STATUS])
1463 return NL_SKIP;
1464
1465 status = nla_get_u32(bss[NL80211_BSS_STATUS]);
1466 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1467 bss[NL80211_BSS_FREQUENCY]) {
1468 ctx->assoc_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
1469 wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
1470 ctx->assoc_freq);
1471 }
1472 if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
1473 bss[NL80211_BSS_FREQUENCY]) {
1474 ctx->ibss_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
1475 wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
1476 ctx->ibss_freq);
1477 }
1478 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1479 bss[NL80211_BSS_BSSID]) {
1480 os_memcpy(ctx->assoc_bssid,
1481 nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
1482 wpa_printf(MSG_DEBUG, "nl80211: Associated with "
1483 MACSTR, MAC2STR(ctx->assoc_bssid));
1484 }
1485
1486 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1487 bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
1488 const u8 *ie, *ssid;
1489 size_t ie_len;
1490
1491 ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1492 ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1493 ssid = get_ie(ie, ie_len, WLAN_EID_SSID);
1494 if (ssid && ssid[1] > 0 && ssid[1] <= SSID_MAX_LEN) {
1495 ctx->assoc_ssid_len = ssid[1];
1496 os_memcpy(ctx->assoc_ssid, ssid + 2, ssid[1]);
1497 }
1498 }
1499
1500 return NL_SKIP;
1501}
1502
1503
1504int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid)
Jouni Malinen87fd2792011-05-16 18:35:42 +03001505{
1506 struct nl_msg *msg;
1507 int ret;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001508 struct nl80211_get_assoc_freq_arg arg;
Hai Shalomfdcde762020-04-02 11:19:20 -07001509 int count = 0;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001510
Hai Shalomfdcde762020-04-02 11:19:20 -07001511try_again:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001512 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
Jouni Malinen87fd2792011-05-16 18:35:42 +03001513 os_memset(&arg, 0, sizeof(arg));
Jouni Malinen87fd2792011-05-16 18:35:42 +03001514 arg.drv = drv;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001515 ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
Hai Shalom899fcc72020-10-19 14:38:18 -07001516 &arg, NULL, NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -07001517 if (ret == -EAGAIN) {
1518 count++;
1519 if (count >= 10) {
1520 wpa_printf(MSG_INFO,
1521 "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid");
1522 } else {
1523 wpa_printf(MSG_DEBUG,
1524 "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid - try again");
1525 goto try_again;
1526 }
1527 }
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001528 if (ret == 0) {
1529 os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len);
1530 return arg.assoc_ssid_len;
1531 }
1532 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d (%s)",
1533 ret, strerror(-ret));
1534 return ret;
1535}
1536
1537
1538unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
1539{
1540 struct nl_msg *msg;
1541 int ret;
1542 struct nl80211_get_assoc_freq_arg arg;
Hai Shalomfdcde762020-04-02 11:19:20 -07001543 int count = 0;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001544
Hai Shalomfdcde762020-04-02 11:19:20 -07001545try_again:
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001546 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
1547 os_memset(&arg, 0, sizeof(arg));
1548 arg.drv = drv;
1549 ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
Hai Shalom899fcc72020-10-19 14:38:18 -07001550 &arg, NULL, NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -07001551 if (ret == -EAGAIN) {
1552 count++;
1553 if (count >= 10) {
1554 wpa_printf(MSG_INFO,
1555 "nl80211: Failed to receive consistent scan result dump for get_assoc_freq");
1556 } else {
1557 wpa_printf(MSG_DEBUG,
1558 "nl80211: Failed to receive consistent scan result dump for get_assoc_freq - try again");
1559 goto try_again;
1560 }
1561 }
Jouni Malinen87fd2792011-05-16 18:35:42 +03001562 if (ret == 0) {
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07001563 unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
1564 arg.ibss_freq : arg.assoc_freq;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001565 wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07001566 "associated BSS from scan results: %u MHz", freq);
1567 if (freq)
1568 drv->assoc_freq = freq;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001569 return drv->assoc_freq;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001570 }
1571 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
1572 "(%s)", ret, strerror(-ret));
Jouni Malinen87fd2792011-05-16 18:35:42 +03001573 return drv->assoc_freq;
1574}
1575
1576
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001577static int get_link_signal(struct nl_msg *msg, void *arg)
1578{
1579 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1580 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1581 struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
1582 static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
1583 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
Dmitry Shmidt34af3062013-07-11 10:46:32 -07001584 [NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07001585 [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001586 };
1587 struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
1588 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
1589 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
1590 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
1591 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
1592 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
1593 };
1594 struct wpa_signal_info *sig_change = arg;
1595
1596 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1597 genlmsg_attrlen(gnlh, 0), NULL);
1598 if (!tb[NL80211_ATTR_STA_INFO] ||
1599 nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
1600 tb[NL80211_ATTR_STA_INFO], policy))
1601 return NL_SKIP;
1602 if (!sinfo[NL80211_STA_INFO_SIGNAL])
1603 return NL_SKIP;
1604
1605 sig_change->current_signal =
1606 (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
1607
Dmitry Shmidt34af3062013-07-11 10:46:32 -07001608 if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
1609 sig_change->avg_signal =
1610 (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
1611 else
1612 sig_change->avg_signal = 0;
1613
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07001614 if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG])
1615 sig_change->avg_beacon_signal =
1616 (s8)
1617 nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
1618 else
1619 sig_change->avg_beacon_signal = 0;
1620
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001621 if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
1622 if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
1623 sinfo[NL80211_STA_INFO_TX_BITRATE],
1624 rate_policy)) {
1625 sig_change->current_txrate = 0;
1626 } else {
1627 if (rinfo[NL80211_RATE_INFO_BITRATE]) {
1628 sig_change->current_txrate =
1629 nla_get_u16(rinfo[
1630 NL80211_RATE_INFO_BITRATE]) * 100;
1631 }
1632 }
1633 }
1634
1635 return NL_SKIP;
1636}
1637
1638
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001639int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
1640 struct wpa_signal_info *sig)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001641{
1642 struct nl_msg *msg;
1643
Hai Shalom74f70d42019-02-11 14:42:39 -08001644 sig->current_signal = -WPA_INVALID_NOISE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001645 sig->current_txrate = 0;
1646
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001647 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
1648 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid)) {
1649 nlmsg_free(msg);
1650 return -ENOBUFS;
1651 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001652
Hai Shalom899fcc72020-10-19 14:38:18 -07001653 return send_and_recv_msgs(drv, msg, get_link_signal, sig, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001654}
1655
1656
1657static int get_link_noise(struct nl_msg *msg, void *arg)
1658{
1659 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1660 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1661 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
1662 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
1663 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
1664 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
1665 };
1666 struct wpa_signal_info *sig_change = arg;
1667
1668 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1669 genlmsg_attrlen(gnlh, 0), NULL);
1670
1671 if (!tb[NL80211_ATTR_SURVEY_INFO]) {
1672 wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
1673 return NL_SKIP;
1674 }
1675
1676 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
1677 tb[NL80211_ATTR_SURVEY_INFO],
1678 survey_policy)) {
1679 wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested "
1680 "attributes!");
1681 return NL_SKIP;
1682 }
1683
1684 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
1685 return NL_SKIP;
1686
1687 if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
1688 sig_change->frequency)
1689 return NL_SKIP;
1690
1691 if (!sinfo[NL80211_SURVEY_INFO_NOISE])
1692 return NL_SKIP;
1693
1694 sig_change->current_noise =
1695 (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
1696
1697 return NL_SKIP;
1698}
1699
1700
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001701int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
1702 struct wpa_signal_info *sig_change)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001703{
1704 struct nl_msg *msg;
1705
Hai Shalom74f70d42019-02-11 14:42:39 -08001706 sig_change->current_noise = WPA_INVALID_NOISE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001707 sig_change->frequency = drv->assoc_freq;
1708
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001709 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
Hai Shalom899fcc72020-10-19 14:38:18 -07001710 return send_and_recv_msgs(drv, msg, get_link_noise, sig_change,
1711 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001712}
1713
1714
Hai Shalom74f70d42019-02-11 14:42:39 -08001715static int get_channel_info(struct nl_msg *msg, void *arg)
1716{
1717 struct nlattr *tb[NL80211_ATTR_MAX + 1] = { 0 };
1718 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1719 struct wpa_channel_info *chan_info = arg;
1720
1721 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1722 genlmsg_attrlen(gnlh, 0), NULL);
1723
1724 os_memset(chan_info, 0, sizeof(struct wpa_channel_info));
1725 chan_info->chanwidth = CHAN_WIDTH_UNKNOWN;
1726
1727 if (tb[NL80211_ATTR_WIPHY_FREQ])
1728 chan_info->frequency =
1729 nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
1730 if (tb[NL80211_ATTR_CHANNEL_WIDTH])
1731 chan_info->chanwidth = convert2width(
1732 nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
1733 if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
1734 enum nl80211_channel_type ct =
1735 nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
1736
1737 switch (ct) {
1738 case NL80211_CHAN_HT40MINUS:
1739 chan_info->sec_channel = -1;
1740 break;
1741 case NL80211_CHAN_HT40PLUS:
1742 chan_info->sec_channel = 1;
1743 break;
1744 default:
1745 chan_info->sec_channel = 0;
1746 break;
1747 }
1748 }
1749 if (tb[NL80211_ATTR_CENTER_FREQ1])
1750 chan_info->center_frq1 =
1751 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
1752 if (tb[NL80211_ATTR_CENTER_FREQ2])
1753 chan_info->center_frq2 =
1754 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
1755
1756 if (chan_info->center_frq2) {
1757 u8 seg1_idx = 0;
1758
1759 if (ieee80211_freq_to_chan(chan_info->center_frq2, &seg1_idx) !=
1760 NUM_HOSTAPD_MODES)
1761 chan_info->seg1_idx = seg1_idx;
1762 }
1763
1764 return NL_SKIP;
1765}
1766
1767
1768static int nl80211_channel_info(void *priv, struct wpa_channel_info *ci)
1769{
1770 struct i802_bss *bss = priv;
1771 struct wpa_driver_nl80211_data *drv = bss->drv;
1772 struct nl_msg *msg;
1773
1774 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
Hai Shalom899fcc72020-10-19 14:38:18 -07001775 return send_and_recv_msgs(drv, msg, get_channel_info, ci, NULL, NULL);
Hai Shalom74f70d42019-02-11 14:42:39 -08001776}
1777
1778
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001779static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
1780 void *handle)
1781{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001782 struct nl_cb *cb = eloop_ctx;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001783 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001784
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07001785 wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001786
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001787 res = nl_recvmsgs(handle, cb);
Dmitry Shmidt71757432014-06-02 13:50:35 -07001788 if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001789 wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
1790 __func__, res);
1791 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001792}
1793
1794
1795/**
1796 * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
1797 * @priv: driver_nl80211 private data
1798 * @alpha2_arg: country to which to switch to
1799 * Returns: 0 on success, -1 on failure
1800 *
1801 * This asks nl80211 to set the regulatory domain for given
1802 * country ISO / IEC alpha2.
1803 */
1804static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
1805{
1806 struct i802_bss *bss = priv;
1807 struct wpa_driver_nl80211_data *drv = bss->drv;
1808 char alpha2[3];
1809 struct nl_msg *msg;
1810
1811 msg = nlmsg_alloc();
1812 if (!msg)
1813 return -ENOMEM;
1814
1815 alpha2[0] = alpha2_arg[0];
1816 alpha2[1] = alpha2_arg[1];
1817 alpha2[2] = '\0';
1818
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001819 if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG) ||
1820 nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, alpha2)) {
1821 nlmsg_free(msg);
1822 return -EINVAL;
1823 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001824 if (send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001825 return -EINVAL;
1826 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001827}
1828
1829
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001830static int nl80211_get_country(struct nl_msg *msg, void *arg)
1831{
1832 char *alpha2 = arg;
1833 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
1834 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1835
1836 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1837 genlmsg_attrlen(gnlh, 0), NULL);
1838 if (!tb_msg[NL80211_ATTR_REG_ALPHA2]) {
1839 wpa_printf(MSG_DEBUG, "nl80211: No country information available");
1840 return NL_SKIP;
1841 }
1842 os_strlcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3);
1843 return NL_SKIP;
1844}
1845
1846
1847static int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
1848{
1849 struct i802_bss *bss = priv;
1850 struct wpa_driver_nl80211_data *drv = bss->drv;
1851 struct nl_msg *msg;
1852 int ret;
1853
1854 msg = nlmsg_alloc();
1855 if (!msg)
1856 return -ENOMEM;
1857
1858 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
1859 alpha2[0] = '\0';
Hai Shalom899fcc72020-10-19 14:38:18 -07001860 ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2,
1861 NULL, NULL);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001862 if (!alpha2[0])
1863 ret = -1;
1864
1865 return ret;
1866}
1867
1868
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001869static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001870{
1871 int ret;
1872
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001873 global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
1874 if (global->nl_cb == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001875 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
1876 "callbacks");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001877 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001878 }
1879
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001880 global->nl = nl_create_handle(global->nl_cb, "nl");
1881 if (global->nl == NULL)
1882 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001883
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001884 global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
1885 if (global->nl80211_id < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001886 wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
1887 "found");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001888 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001889 }
1890
Hai Shalomc1a21442022-02-04 13:43:00 -08001891 global->nlctrl_id = genl_ctrl_resolve(global->nl, "nlctrl");
1892 if (global->nlctrl_id < 0) {
1893 wpa_printf(MSG_ERROR,
1894 "nl80211: 'nlctrl' generic netlink not found");
1895 goto err;
1896 }
1897
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001898 global->nl_event = nl_create_handle(global->nl_cb, "event");
1899 if (global->nl_event == NULL)
1900 goto err;
1901
1902 ret = nl_get_multicast_id(global, "nl80211", "scan");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001903 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001904 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001905 if (ret < 0) {
1906 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
1907 "membership for scan events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001908 ret, nl_geterror(ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001909 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001910 }
1911
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001912 ret = nl_get_multicast_id(global, "nl80211", "mlme");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001913 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001914 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001915 if (ret < 0) {
1916 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
1917 "membership for mlme events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001918 ret, nl_geterror(ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001919 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001920 }
1921
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001922 ret = nl_get_multicast_id(global, "nl80211", "regulatory");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001923 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001924 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001925 if (ret < 0) {
1926 wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
1927 "membership for regulatory events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001928 ret, nl_geterror(ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001929 /* Continue without regulatory events */
1930 }
1931
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001932 ret = nl_get_multicast_id(global, "nl80211", "vendor");
1933 if (ret >= 0)
1934 ret = nl_socket_add_membership(global->nl_event, ret);
1935 if (ret < 0) {
1936 wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
1937 "membership for vendor events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001938 ret, nl_geterror(ret));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001939 /* Continue without vendor events */
1940 }
1941
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001942 nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
1943 no_seq_check, NULL);
1944 nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
1945 process_global_event, global);
1946
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001947 nl80211_register_eloop_read(&global->nl_event,
1948 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001949 global->nl_cb, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001950
1951 return 0;
1952
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001953err:
1954 nl_destroy_handles(&global->nl_event);
1955 nl_destroy_handles(&global->nl);
1956 nl_cb_put(global->nl_cb);
1957 global->nl_cb = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001958 return -1;
1959}
1960
1961
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001962static void nl80211_check_global(struct nl80211_global *global)
1963{
Hai Shalomfdcde762020-04-02 11:19:20 -07001964 struct nl_sock *handle;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001965 const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL };
1966 int ret;
1967 unsigned int i;
1968
1969 /*
1970 * Try to re-add memberships to handle case of cfg80211 getting reloaded
1971 * and all registration having been cleared.
1972 */
1973 handle = (void *) (((intptr_t) global->nl_event) ^
1974 ELOOP_SOCKET_INVALID);
1975
1976 for (i = 0; groups[i]; i++) {
1977 ret = nl_get_multicast_id(global, "nl80211", groups[i]);
1978 if (ret >= 0)
1979 ret = nl_socket_add_membership(handle, ret);
1980 if (ret < 0) {
1981 wpa_printf(MSG_INFO,
1982 "nl80211: Could not re-add multicast membership for %s events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001983 groups[i], ret, nl_geterror(ret));
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001984 }
1985 }
1986}
1987
1988
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001989static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
1990{
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08001991 struct wpa_driver_nl80211_data *drv = ctx;
1992
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001993 wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08001994
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001995 /*
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08001996 * rtnetlink ifdown handler will report interfaces other than the P2P
1997 * Device interface as disabled.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001998 */
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08001999 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
2000 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002001}
2002
2003
2004static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
2005{
2006 struct wpa_driver_nl80211_data *drv = ctx;
2007 wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002008 if (i802_set_iface_flags(drv->first_bss, 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002009 wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
2010 "after rfkill unblock");
2011 return;
2012 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002013
2014 if (is_p2p_net_interface(drv->nlmode))
2015 nl80211_disable_11b_rates(drv, drv->ifindex, 1);
2016
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002017 /*
2018 * rtnetlink ifup handler will report interfaces other than the P2P
2019 * Device interface as enabled.
2020 */
2021 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
2022 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002023}
2024
2025
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002026static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
2027 void *eloop_ctx,
2028 void *handle)
2029{
2030 struct wpa_driver_nl80211_data *drv = eloop_ctx;
2031 u8 data[2048];
2032 struct msghdr msg;
2033 struct iovec entry;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002034 u8 control[512];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002035 struct cmsghdr *cmsg;
2036 int res, found_ee = 0, found_wifi = 0, acked = 0;
2037 union wpa_event_data event;
2038
2039 memset(&msg, 0, sizeof(msg));
2040 msg.msg_iov = &entry;
2041 msg.msg_iovlen = 1;
2042 entry.iov_base = data;
2043 entry.iov_len = sizeof(data);
2044 msg.msg_control = &control;
2045 msg.msg_controllen = sizeof(control);
2046
2047 res = recvmsg(sock, &msg, MSG_ERRQUEUE);
2048 /* if error or not fitting 802.3 header, return */
2049 if (res < 14)
2050 return;
2051
2052 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
2053 {
2054 if (cmsg->cmsg_level == SOL_SOCKET &&
2055 cmsg->cmsg_type == SCM_WIFI_STATUS) {
2056 int *ack;
2057
2058 found_wifi = 1;
2059 ack = (void *)CMSG_DATA(cmsg);
2060 acked = *ack;
2061 }
2062
2063 if (cmsg->cmsg_level == SOL_PACKET &&
2064 cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
2065 struct sock_extended_err *err =
2066 (struct sock_extended_err *)CMSG_DATA(cmsg);
2067
2068 if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
2069 found_ee = 1;
2070 }
2071 }
2072
2073 if (!found_ee || !found_wifi)
2074 return;
2075
2076 memset(&event, 0, sizeof(event));
2077 event.eapol_tx_status.dst = data;
2078 event.eapol_tx_status.data = data + 14;
2079 event.eapol_tx_status.data_len = res - 14;
2080 event.eapol_tx_status.ack = acked;
2081 wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
2082}
2083
2084
Hai Shalomb755a2a2020-04-23 21:49:02 -07002085static int nl80211_init_connect_handle(struct i802_bss *bss)
2086{
2087 if (bss->nl_connect) {
2088 wpa_printf(MSG_DEBUG,
2089 "nl80211: Connect handle already created (nl_connect=%p)",
2090 bss->nl_connect);
2091 return -1;
2092 }
2093
2094 bss->nl_connect = nl_create_handle(bss->nl_cb, "connect");
2095 if (!bss->nl_connect)
2096 return -1;
2097 nl80211_register_eloop_read(&bss->nl_connect,
2098 wpa_driver_nl80211_event_receive,
2099 bss->nl_cb, 1);
2100 return 0;
2101}
2102
2103
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002104static int nl80211_init_bss(struct i802_bss *bss)
2105{
2106 bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
2107 if (!bss->nl_cb)
2108 return -1;
2109
2110 nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
2111 no_seq_check, NULL);
2112 nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
2113 process_bss_event, bss);
2114
Hai Shalomb755a2a2020-04-23 21:49:02 -07002115 nl80211_init_connect_handle(bss);
2116
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002117 return 0;
2118}
2119
2120
2121static void nl80211_destroy_bss(struct i802_bss *bss)
2122{
2123 nl_cb_put(bss->nl_cb);
2124 bss->nl_cb = NULL;
Hai Shalomb755a2a2020-04-23 21:49:02 -07002125
2126 if (bss->nl_connect)
2127 nl80211_destroy_eloop_handle(&bss->nl_connect, 1);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002128}
2129
2130
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002131static void
2132wpa_driver_nl80211_drv_init_rfkill(struct wpa_driver_nl80211_data *drv)
2133{
2134 struct rfkill_config *rcfg;
2135
2136 if (drv->rfkill)
2137 return;
2138
2139 rcfg = os_zalloc(sizeof(*rcfg));
2140 if (!rcfg)
2141 return;
2142
2143 rcfg->ctx = drv;
2144
2145 /* rfkill uses netdev sysfs for initialization. However, P2P Device is
2146 * not associated with a netdev, so use the name of some other interface
2147 * sharing the same wiphy as the P2P Device interface.
2148 *
2149 * Note: This is valid, as a P2P Device interface is always dynamically
2150 * created and is created only once another wpa_s interface was added.
2151 */
2152 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
2153 struct nl80211_global *global = drv->global;
2154 struct wpa_driver_nl80211_data *tmp1;
2155
2156 dl_list_for_each(tmp1, &global->interfaces,
2157 struct wpa_driver_nl80211_data, list) {
2158 if (drv == tmp1 || drv->wiphy_idx != tmp1->wiphy_idx ||
2159 !tmp1->rfkill)
2160 continue;
2161
2162 wpa_printf(MSG_DEBUG,
2163 "nl80211: Use (%s) to initialize P2P Device rfkill",
2164 tmp1->first_bss->ifname);
2165 os_strlcpy(rcfg->ifname, tmp1->first_bss->ifname,
2166 sizeof(rcfg->ifname));
2167 break;
2168 }
2169 } else {
2170 os_strlcpy(rcfg->ifname, drv->first_bss->ifname,
2171 sizeof(rcfg->ifname));
2172 }
2173
2174 rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
2175 rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
2176 drv->rfkill = rfkill_init(rcfg);
2177 if (!drv->rfkill) {
2178 wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
2179 os_free(rcfg);
2180 }
2181}
2182
2183
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002184static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
2185 void *global_priv, int hostapd,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002186 const u8 *set_addr,
2187 const char *driver_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002188{
2189 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002190 struct i802_bss *bss;
2191
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002192 if (global_priv == NULL)
2193 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002194 drv = os_zalloc(sizeof(*drv));
2195 if (drv == NULL)
2196 return NULL;
2197 drv->global = global_priv;
2198 drv->ctx = ctx;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002199 drv->hostapd = !!hostapd;
2200 drv->eapol_sock = -1;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002201
2202 /*
2203 * There is no driver capability flag for this, so assume it is
2204 * supported and disable this on first attempt to use if the driver
2205 * rejects the command due to missing support.
2206 */
2207 drv->set_rekey_offload = 1;
2208
Hai Shalom81f62d82019-07-22 12:10:00 -07002209 drv->num_if_indices = ARRAY_SIZE(drv->default_if_indices);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002210 drv->if_indices = drv->default_if_indices;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002211
2212 drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
2213 if (!drv->first_bss) {
2214 os_free(drv);
2215 return NULL;
2216 }
2217 bss = drv->first_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002218 bss->drv = drv;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002219 bss->ctx = ctx;
2220
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002221 os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
2222 drv->monitor_ifidx = -1;
2223 drv->monitor_sock = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002224 drv->eapol_tx_sock = -1;
2225 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002226
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002227 if (nl80211_init_bss(bss))
2228 goto failed;
2229
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002230 if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002231 goto failed;
2232
Hai Shalom899fcc72020-10-19 14:38:18 -07002233 if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS) {
2234 drv->control_port_ap = 1;
2235 goto skip_wifi_status;
2236 }
2237
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002238 drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
2239 if (drv->eapol_tx_sock < 0)
2240 goto failed;
2241
2242 if (drv->data_tx_status) {
2243 int enabled = 1;
2244
2245 if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
2246 &enabled, sizeof(enabled)) < 0) {
2247 wpa_printf(MSG_DEBUG,
Hai Shalom899fcc72020-10-19 14:38:18 -07002248 "nl80211: wifi status sockopt failed: %s",
2249 strerror(errno));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002250 drv->data_tx_status = 0;
2251 if (!drv->use_monitor)
2252 drv->capa.flags &=
2253 ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
2254 } else {
Hai Shalom899fcc72020-10-19 14:38:18 -07002255 eloop_register_read_sock(
2256 drv->eapol_tx_sock,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002257 wpa_driver_nl80211_handle_eapol_tx_status,
2258 drv, NULL);
2259 }
2260 }
Hai Shalom899fcc72020-10-19 14:38:18 -07002261skip_wifi_status:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002262
2263 if (drv->global) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002264 nl80211_check_global(drv->global);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002265 dl_list_add(&drv->global->interfaces, &drv->list);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002266 drv->in_interface_list = 1;
2267 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002268
2269 return bss;
2270
2271failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002272 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002273 return NULL;
2274}
2275
2276
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002277/**
2278 * wpa_driver_nl80211_init - Initialize nl80211 driver interface
2279 * @ctx: context to be used when calling wpa_supplicant functions,
2280 * e.g., wpa_supplicant_event()
2281 * @ifname: interface name, e.g., wlan0
2282 * @global_priv: private driver global data from global_init()
2283 * Returns: Pointer to private data, %NULL on failure
2284 */
2285static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
2286 void *global_priv)
2287{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002288 return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL,
2289 NULL);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002290}
2291
2292
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002293static int nl80211_register_frame(struct i802_bss *bss,
Hai Shalomfdcde762020-04-02 11:19:20 -07002294 struct nl_sock *nl_handle,
Hai Shalome21d4e82020-04-29 16:34:06 -07002295 u16 type, const u8 *match, size_t match_len,
2296 bool multicast)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002297{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002298 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002299 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002300 int ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002301 char buf[30];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002302
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002303 buf[0] = '\0';
2304 wpa_snprintf_hex(buf, sizeof(buf), match, match_len);
Hai Shalome21d4e82020-04-29 16:34:06 -07002305 wpa_printf(MSG_DEBUG,
2306 "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s multicast=%d",
2307 type, fc2str(type), nl_handle, buf, multicast);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002308
Hai Shalomfdcde762020-04-02 11:19:20 -07002309 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_FRAME)) ||
Hai Shalome21d4e82020-04-29 16:34:06 -07002310 (multicast && nla_put_flag(msg, NL80211_ATTR_RECEIVE_MULTICAST)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002311 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type) ||
2312 nla_put(msg, NL80211_ATTR_FRAME_MATCH, match_len, match)) {
2313 nlmsg_free(msg);
2314 return -1;
2315 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002316
Hai Shalom899fcc72020-10-19 14:38:18 -07002317 ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL,
2318 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002319 if (ret) {
2320 wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
2321 "failed (type=%u): ret=%d (%s)",
2322 type, ret, strerror(-ret));
2323 wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
2324 match, match_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002325 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002326 return ret;
2327}
2328
2329
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002330static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
2331{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002332 if (bss->nl_mgmt) {
2333 wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
2334 "already on! (nl_mgmt=%p)", bss->nl_mgmt);
2335 return -1;
2336 }
2337
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002338 bss->nl_mgmt = nl_create_handle(bss->nl_cb, "mgmt");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002339 if (bss->nl_mgmt == NULL)
2340 return -1;
2341
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002342 return 0;
2343}
2344
2345
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002346static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss)
2347{
2348 nl80211_register_eloop_read(&bss->nl_mgmt,
2349 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002350 bss->nl_cb, 0);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002351}
2352
2353
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002354static int nl80211_register_action_frame(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002355 const u8 *match, size_t match_len)
2356{
2357 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002358 return nl80211_register_frame(bss, bss->nl_mgmt,
Hai Shalome21d4e82020-04-29 16:34:06 -07002359 type, match, match_len, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002360}
2361
2362
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002363static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002364{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002365 struct wpa_driver_nl80211_data *drv = bss->drv;
Hai Shalomfdcde762020-04-02 11:19:20 -07002366 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002367 int ret = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002368
2369 if (nl80211_alloc_mgmt_handle(bss))
2370 return -1;
2371 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
2372 "handle %p", bss->nl_mgmt);
2373
Hai Shalomfdcde762020-04-02 11:19:20 -07002374 if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002375 /* register for any AUTH message */
Hai Shalome21d4e82020-04-29 16:34:06 -07002376 nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0, false);
Hai Shalomfdcde762020-04-02 11:19:20 -07002377 } else if ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
2378 !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
2379 /* register for SAE Authentication frames */
2380 nl80211_register_frame(bss, bss->nl_mgmt, type,
Hai Shalome21d4e82020-04-29 16:34:06 -07002381 (u8 *) "\x03\x00", 2, false);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002382 }
2383
Hai Shalom60840252021-02-19 19:02:11 -08002384#ifdef CONFIG_PASN
2385 /* register for PASN Authentication frames */
2386 if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
2387 nl80211_register_frame(bss, bss->nl_mgmt, type,
2388 (u8 *) "\x07\x00", 2, false))
2389 ret = -1;
2390#endif /* CONFIG_PASN */
2391
Dmitry Shmidt051af732013-10-22 13:52:46 -07002392#ifdef CONFIG_INTERWORKING
2393 /* QoS Map Configure */
2394 if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002395 ret = -1;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002396#endif /* CONFIG_INTERWORKING */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002397#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002398 /* GAS Initial Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002399 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002400 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002401 /* GAS Initial Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002402 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002403 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002404 /* GAS Comeback Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002405 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002406 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002407 /* GAS Comeback Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002408 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002409 ret = -1;
Dmitry Shmidt18463232014-01-24 12:29:41 -08002410 /* Protected GAS Initial Request */
2411 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0a", 2) < 0)
2412 ret = -1;
2413 /* Protected GAS Initial Response */
2414 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0b", 2) < 0)
2415 ret = -1;
2416 /* Protected GAS Comeback Request */
2417 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0c", 2) < 0)
2418 ret = -1;
2419 /* Protected GAS Comeback Response */
2420 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0d", 2) < 0)
2421 ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002422#endif /* CONFIG_P2P || CONFIG_INTERWORKING || CONFIG_DPP */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002423#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002424 /* P2P Public Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002425 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002426 (u8 *) "\x04\x09\x50\x6f\x9a\x09",
2427 6) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002428 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002429 /* P2P Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002430 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002431 (u8 *) "\x7f\x50\x6f\x9a\x09",
2432 5) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002433 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002434#endif /* CONFIG_P2P */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002435#ifdef CONFIG_DPP
2436 /* DPP Public Action */
2437 if (nl80211_register_action_frame(bss,
2438 (u8 *) "\x04\x09\x50\x6f\x9a\x1a",
2439 6) < 0)
2440 ret = -1;
2441#endif /* CONFIG_DPP */
Hai Shalom74f70d42019-02-11 14:42:39 -08002442#ifdef CONFIG_OCV
2443 /* SA Query Request */
2444 if (nl80211_register_action_frame(bss, (u8 *) "\x08\x00", 2) < 0)
2445 ret = -1;
2446#endif /* CONFIG_OCV */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002447 /* SA Query Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002448 if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002449 ret = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002450#ifdef CONFIG_TDLS
2451 if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
2452 /* TDLS Discovery Response */
2453 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
2454 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002455 ret = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002456 }
2457#endif /* CONFIG_TDLS */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002458#ifdef CONFIG_FST
2459 /* FST Action frames */
2460 if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
2461 ret = -1;
2462#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002463
2464 /* FT Action frames */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002465 if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002466 ret = -1;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002467 else if (!drv->has_driver_key_mgmt) {
2468 int i;
2469
2470 /* Update supported AKMs only if the driver doesn't advertize
2471 * any AKM capabilities. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002472 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
2473 WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
2474
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002475 /* Update per interface supported AKMs */
2476 for (i = 0; i < WPA_IF_MAX; i++)
2477 drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt;
2478 }
2479
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002480 /* WNM - BSS Transition Management Request */
2481 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002482 ret = -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002483 /* WNM-Sleep Mode Response */
2484 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002485 ret = -1;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08002486#ifdef CONFIG_WNM
2487 /* WNM - Collocated Interference Request */
2488 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x0b", 2) < 0)
2489 ret = -1;
2490#endif /* CONFIG_WNM */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002491
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002492#ifdef CONFIG_HS20
2493 /* WNM-Notification */
2494 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x1a", 2) < 0)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002495 ret = -1;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002496#endif /* CONFIG_HS20 */
2497
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002498 /* WMM-AC ADDTS Response */
2499 if (nl80211_register_action_frame(bss, (u8 *) "\x11\x01", 2) < 0)
2500 ret = -1;
2501
2502 /* WMM-AC DELTS */
2503 if (nl80211_register_action_frame(bss, (u8 *) "\x11\x02", 2) < 0)
2504 ret = -1;
2505
2506 /* Radio Measurement - Neighbor Report Response */
2507 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
2508 ret = -1;
2509
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002510 /* Radio Measurement - Radio Measurement Request */
Hai Shalom899fcc72020-10-19 14:38:18 -07002511 if (!drv->no_rrm &&
2512 nl80211_register_action_frame(bss, (u8 *) "\x05\x00", 2) < 0)
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002513 ret = -1;
2514
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002515 /* Radio Measurement - Link Measurement Request */
2516 if ((drv->capa.rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) &&
2517 (nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
2518 ret = -1;
2519
Hai Shalomc1a21442022-02-04 13:43:00 -08002520 /* Robust AV SCS Response */
2521 if (nl80211_register_action_frame(bss, (u8 *) "\x13\x01", 2) < 0)
2522 ret = -1;
2523
Hai Shalom899fcc72020-10-19 14:38:18 -07002524 /* Robust AV MSCS Response */
2525 if (nl80211_register_action_frame(bss, (u8 *) "\x13\x05", 2) < 0)
2526 ret = -1;
2527
Hai Shalomc1a21442022-02-04 13:43:00 -08002528 /* Protected QoS Management Action frame */
2529 if (nl80211_register_action_frame(bss, (u8 *) "\x7e\x50\x6f\x9a\x1a",
2530 5) < 0)
2531 ret = -1;
2532
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002533 nl80211_mgmt_handle_register_eloop(bss);
2534
2535 return ret;
2536}
2537
2538
2539static int nl80211_mgmt_subscribe_mesh(struct i802_bss *bss)
2540{
2541 int ret = 0;
2542
2543 if (nl80211_alloc_mgmt_handle(bss))
2544 return -1;
2545
2546 wpa_printf(MSG_DEBUG,
2547 "nl80211: Subscribe to mgmt frames with mesh handle %p",
2548 bss->nl_mgmt);
2549
2550 /* Auth frames for mesh SAE */
2551 if (nl80211_register_frame(bss, bss->nl_mgmt,
2552 (WLAN_FC_TYPE_MGMT << 2) |
2553 (WLAN_FC_STYPE_AUTH << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07002554 NULL, 0, false) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002555 ret = -1;
2556
2557 /* Mesh peering open */
2558 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x01", 2) < 0)
2559 ret = -1;
2560 /* Mesh peering confirm */
2561 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x02", 2) < 0)
2562 ret = -1;
2563 /* Mesh peering close */
2564 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x03", 2) < 0)
2565 ret = -1;
2566
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002567 nl80211_mgmt_handle_register_eloop(bss);
2568
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002569 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002570}
2571
2572
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002573static int nl80211_register_spurious_class3(struct i802_bss *bss)
2574{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002575 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002576 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002577
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002578 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
Hai Shalom899fcc72020-10-19 14:38:18 -07002579 ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL,
2580 NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002581 if (ret) {
2582 wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
2583 "failed: ret=%d (%s)",
2584 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002585 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002586 return ret;
2587}
2588
2589
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002590static int nl80211_action_subscribe_ap(struct i802_bss *bss)
2591{
2592 int ret = 0;
2593
2594 /* Public Action frames */
2595 if (nl80211_register_action_frame(bss, (u8 *) "\x04", 1) < 0)
2596 ret = -1;
2597 /* RRM Measurement Report */
2598 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x01", 2) < 0)
2599 ret = -1;
Paul Stewart092955c2017-02-06 09:13:09 -08002600 /* RRM Link Measurement Report */
2601 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x03", 2) < 0)
2602 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002603 /* RRM Neighbor Report Request */
2604 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x04", 2) < 0)
2605 ret = -1;
2606 /* FT Action frames */
2607 if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
2608 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002609 /* SA Query */
2610 if (nl80211_register_action_frame(bss, (u8 *) "\x08", 1) < 0)
2611 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002612 /* Protected Dual of Public Action */
2613 if (nl80211_register_action_frame(bss, (u8 *) "\x09", 1) < 0)
2614 ret = -1;
2615 /* WNM */
2616 if (nl80211_register_action_frame(bss, (u8 *) "\x0a", 1) < 0)
2617 ret = -1;
2618 /* WMM */
2619 if (nl80211_register_action_frame(bss, (u8 *) "\x11", 1) < 0)
2620 ret = -1;
2621#ifdef CONFIG_FST
2622 /* FST Action frames */
2623 if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
2624 ret = -1;
2625#endif /* CONFIG_FST */
2626 /* Vendor-specific */
2627 if (nl80211_register_action_frame(bss, (u8 *) "\x7f", 1) < 0)
2628 ret = -1;
2629
2630 return ret;
2631}
2632
2633
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002634static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
2635{
2636 static const int stypes[] = {
2637 WLAN_FC_STYPE_AUTH,
2638 WLAN_FC_STYPE_ASSOC_REQ,
2639 WLAN_FC_STYPE_REASSOC_REQ,
2640 WLAN_FC_STYPE_DISASSOC,
2641 WLAN_FC_STYPE_DEAUTH,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002642 WLAN_FC_STYPE_PROBE_REQ,
2643/* Beacon doesn't work as mac80211 doesn't currently allow
2644 * it, but it wouldn't really be the right thing anyway as
2645 * it isn't per interface ... maybe just dump the scan
2646 * results periodically for OLBC?
2647 */
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002648 /* WLAN_FC_STYPE_BEACON, */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002649 };
2650 unsigned int i;
2651
2652 if (nl80211_alloc_mgmt_handle(bss))
2653 return -1;
2654 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
2655 "handle %p", bss->nl_mgmt);
2656
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002657 for (i = 0; i < ARRAY_SIZE(stypes); i++) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002658 if (nl80211_register_frame(bss, bss->nl_mgmt,
2659 (WLAN_FC_TYPE_MGMT << 2) |
2660 (stypes[i] << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07002661 NULL, 0, false) < 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002662 goto out_err;
2663 }
2664 }
2665
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002666 if (nl80211_action_subscribe_ap(bss))
2667 goto out_err;
2668
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002669 if (nl80211_register_spurious_class3(bss))
2670 goto out_err;
2671
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002672 nl80211_mgmt_handle_register_eloop(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002673 return 0;
2674
2675out_err:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002676 nl_destroy_handles(&bss->nl_mgmt);
2677 return -1;
2678}
2679
2680
2681static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
2682{
2683 if (nl80211_alloc_mgmt_handle(bss))
2684 return -1;
2685 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
2686 "handle %p (device SME)", bss->nl_mgmt);
2687
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002688 if (nl80211_action_subscribe_ap(bss))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002689 goto out_err;
2690
Hai Shalom5f92bc92019-04-18 11:54:11 -07002691 if (bss->drv->device_ap_sme) {
2692 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
2693
2694 /* Register for all Authentication frames */
Hai Shalome21d4e82020-04-29 16:34:06 -07002695 if (nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0,
2696 false) < 0)
Hai Shalom5f92bc92019-04-18 11:54:11 -07002697 wpa_printf(MSG_DEBUG,
2698 "nl80211: Failed to subscribe to handle Authentication frames - SAE offload may not work");
2699 }
2700
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002701 nl80211_mgmt_handle_register_eloop(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002702 return 0;
2703
2704out_err:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002705 nl_destroy_handles(&bss->nl_mgmt);
2706 return -1;
2707}
2708
2709
2710static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
2711{
2712 if (bss->nl_mgmt == NULL)
2713 return;
2714 wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
2715 "(%s)", bss->nl_mgmt, reason);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002716 nl80211_destroy_eloop_handle(&bss->nl_mgmt, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002717
2718 nl80211_put_wiphy_data_ap(bss);
2719}
2720
2721
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002722static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
2723{
2724 wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
2725}
2726
2727
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002728static void nl80211_del_p2pdev(struct i802_bss *bss)
2729{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002730 struct nl_msg *msg;
2731 int ret;
2732
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002733 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
Hai Shalom899fcc72020-10-19 14:38:18 -07002734 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002735
2736 wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
2737 bss->ifname, (long long unsigned int) bss->wdev_id,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002738 strerror(-ret));
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002739}
2740
2741
2742static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
2743{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002744 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002745 int ret;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002746
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002747 msg = nl80211_cmd_msg(bss, 0, start ? NL80211_CMD_START_P2P_DEVICE :
2748 NL80211_CMD_STOP_P2P_DEVICE);
Hai Shalom899fcc72020-10-19 14:38:18 -07002749 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002750
2751 wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
2752 start ? "Start" : "Stop",
2753 bss->ifname, (long long unsigned int) bss->wdev_id,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002754 strerror(-ret));
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002755 return ret;
2756}
2757
2758
2759static int i802_set_iface_flags(struct i802_bss *bss, int up)
2760{
2761 enum nl80211_iftype nlmode;
2762
2763 nlmode = nl80211_get_ifmode(bss);
2764 if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
2765 return linux_set_iface_flags(bss->drv->global->ioctl_sock,
2766 bss->ifname, up);
2767 }
2768
2769 /* P2P Device has start/stop which is equivalent */
2770 return nl80211_set_p2pdev(bss, up);
2771}
2772
2773
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002774#ifdef CONFIG_TESTING_OPTIONS
2775static int qca_vendor_test_cmd_handler(struct nl_msg *msg, void *arg)
2776{
2777 /* struct wpa_driver_nl80211_data *drv = arg; */
2778 struct nlattr *tb[NL80211_ATTR_MAX + 1];
2779 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2780
2781
2782 wpa_printf(MSG_DEBUG,
2783 "nl80211: QCA vendor test command response received");
2784
2785 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2786 genlmsg_attrlen(gnlh, 0), NULL);
2787 if (!tb[NL80211_ATTR_VENDOR_DATA]) {
2788 wpa_printf(MSG_DEBUG, "nl80211: No vendor data attribute");
2789 return NL_SKIP;
2790 }
2791
2792 wpa_hexdump(MSG_DEBUG,
2793 "nl80211: Received QCA vendor test command response",
2794 nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
2795 nla_len(tb[NL80211_ATTR_VENDOR_DATA]));
2796
2797 return NL_SKIP;
2798}
2799#endif /* CONFIG_TESTING_OPTIONS */
2800
2801
2802static void qca_vendor_test(struct wpa_driver_nl80211_data *drv)
2803{
2804#ifdef CONFIG_TESTING_OPTIONS
2805 struct nl_msg *msg;
2806 struct nlattr *params;
2807 int ret;
2808
2809 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
2810 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
2811 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
2812 QCA_NL80211_VENDOR_SUBCMD_TEST) ||
2813 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
2814 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TEST, 123)) {
2815 nlmsg_free(msg);
2816 return;
2817 }
2818 nla_nest_end(msg, params);
2819
Hai Shalom899fcc72020-10-19 14:38:18 -07002820 ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv,
2821 NULL, NULL);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002822 wpa_printf(MSG_DEBUG,
2823 "nl80211: QCA vendor test command returned %d (%s)",
2824 ret, strerror(-ret));
2825#endif /* CONFIG_TESTING_OPTIONS */
2826}
2827
2828
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002829static int
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002830wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002831 const u8 *set_addr, int first,
2832 const char *driver_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002833{
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002834 struct i802_bss *bss = drv->first_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002835 int send_rfkill_event = 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002836 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002837
2838 drv->ifindex = if_nametoindex(bss->ifname);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002839 bss->ifindex = drv->ifindex;
2840 bss->wdev_id = drv->global->if_add_wdevid;
2841 bss->wdev_id_set = drv->global->if_add_wdevid_set;
2842
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002843 bss->if_dynamic = drv->ifindex == drv->global->if_add_ifindex;
2844 bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002845 drv->global->if_add_wdevid_set = 0;
2846
Dmitry Shmidt03658832014-08-13 11:03:49 -07002847 if (!bss->if_dynamic && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
2848 bss->static_ap = 1;
2849
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08002850 if (first &&
2851 nl80211_get_ifmode(bss) != NL80211_IFTYPE_P2P_DEVICE &&
2852 linux_iface_up(drv->global->ioctl_sock, bss->ifname) > 0)
2853 drv->start_iface_up = 1;
2854
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002855 if (wpa_driver_nl80211_capa(drv))
2856 return -1;
2857
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002858 if (driver_params && nl80211_set_param(bss, driver_params) < 0)
2859 return -1;
2860
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002861 wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
2862 bss->ifname, drv->phyname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002863
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002864 if (set_addr &&
2865 (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) ||
2866 linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
2867 set_addr)))
2868 return -1;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002869
Hai Shalomc1a21442022-02-04 13:43:00 -08002870 if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_STATION)
2871 drv->start_mode_sta = 1;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002872
Dmitry Shmidt03658832014-08-13 11:03:49 -07002873 if (drv->hostapd || bss->static_ap)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002874 nlmode = NL80211_IFTYPE_AP;
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07002875 else if (bss->if_dynamic ||
2876 nl80211_get_ifmode(bss) == NL80211_IFTYPE_MESH_POINT)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002877 nlmode = nl80211_get_ifmode(bss);
2878 else
2879 nlmode = NL80211_IFTYPE_STATION;
2880
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002881 if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002882 wpa_printf(MSG_ERROR, "nl80211: Could not configure driver mode");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002883 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002884 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002885
Dmitry Shmidt98660862014-03-11 17:26:21 -07002886 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002887 nl80211_get_macaddr(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002888
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002889 wpa_driver_nl80211_drv_init_rfkill(drv);
2890
Dmitry Shmidt98660862014-03-11 17:26:21 -07002891 if (!rfkill_is_blocked(drv->rfkill)) {
2892 int ret = i802_set_iface_flags(bss, 1);
2893 if (ret) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002894 wpa_printf(MSG_ERROR, "nl80211: Could not set "
2895 "interface '%s' UP", bss->ifname);
Dmitry Shmidt98660862014-03-11 17:26:21 -07002896 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002897 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002898
2899 if (is_p2p_net_interface(nlmode))
2900 nl80211_disable_11b_rates(bss->drv,
2901 bss->drv->ifindex, 1);
2902
Dmitry Shmidt98660862014-03-11 17:26:21 -07002903 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
2904 return ret;
2905 } else {
2906 wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
2907 "interface '%s' due to rfkill", bss->ifname);
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002908 if (nlmode != NL80211_IFTYPE_P2P_DEVICE)
2909 drv->if_disabled = 1;
2910
Dmitry Shmidt98660862014-03-11 17:26:21 -07002911 send_rfkill_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002912 }
2913
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002914 if (!drv->hostapd && nlmode != NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002915 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
2916 1, IF_OPER_DORMANT);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002917
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002918 if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
2919 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
2920 bss->addr))
2921 return -1;
2922 os_memcpy(drv->perm_addr, bss->addr, ETH_ALEN);
2923 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002924
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002925 if (send_rfkill_event) {
2926 eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
2927 drv, drv->ctx);
2928 }
2929
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002930 if (drv->vendor_cmd_test_avail)
2931 qca_vendor_test(drv);
2932
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002933 return 0;
2934}
2935
2936
Paul Stewart092955c2017-02-06 09:13:09 -08002937static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002938{
2939 struct nl_msg *msg;
Paul Stewart092955c2017-02-06 09:13:09 -08002940 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002941
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002942 wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
2943 drv->ifindex);
Paul Stewart092955c2017-02-06 09:13:09 -08002944 nl80211_put_wiphy_data_ap(bss);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002945 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
Hai Shalom899fcc72020-10-19 14:38:18 -07002946 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002947}
2948
2949
2950/**
2951 * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08002952 * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002953 *
2954 * Shut down driver interface and processing of driver events. Free
2955 * private data buffer if one was allocated in wpa_driver_nl80211_init().
2956 */
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08002957static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002958{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002959 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07002960 unsigned int i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002961
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002962 wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
2963 bss->ifname, drv->disabled_11b_rates);
2964
Dmitry Shmidt04949592012-07-19 12:16:46 -07002965 bss->in_deinit = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002966 if (drv->data_tx_status)
2967 eloop_unregister_read_sock(drv->eapol_tx_sock);
2968 if (drv->eapol_tx_sock >= 0)
2969 close(drv->eapol_tx_sock);
2970
2971 if (bss->nl_preq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002972 wpa_driver_nl80211_probe_req_report(bss, 0);
2973 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002974 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
2975 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002976 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
2977 "interface %s from bridge %s: %s",
2978 bss->ifname, bss->brname, strerror(errno));
2979 }
Hai Shalomc9e41a12018-07-31 14:41:42 -07002980
2981 if (drv->rtnl_sk)
Hai Shalomfdcde762020-04-02 11:19:20 -07002982 nl_socket_free(drv->rtnl_sk);
Hai Shalomc9e41a12018-07-31 14:41:42 -07002983
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002984 if (bss->added_bridge) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002985 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
2986 0) < 0)
2987 wpa_printf(MSG_INFO,
2988 "nl80211: Could not set bridge %s down",
2989 bss->brname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002990 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002991 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
2992 "bridge %s: %s",
2993 bss->brname, strerror(errno));
2994 }
2995
2996 nl80211_remove_monitor_interface(drv);
2997
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002998 if (is_ap_interface(drv->nlmode))
Paul Stewart092955c2017-02-06 09:13:09 -08002999 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003000
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003001 if (drv->eapol_sock >= 0) {
3002 eloop_unregister_read_sock(drv->eapol_sock);
3003 close(drv->eapol_sock);
3004 }
3005
3006 if (drv->if_indices != drv->default_if_indices)
3007 os_free(drv->if_indices);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003008
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003009 if (drv->disabled_11b_rates)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003010 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
3011
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003012 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
3013 IF_OPER_UP);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07003014 eloop_cancel_timeout(wpa_driver_nl80211_send_rfkill, drv, drv->ctx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003015 rfkill_deinit(drv->rfkill);
3016
3017 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
3018
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003019 if (!drv->start_iface_up)
3020 (void) i802_set_iface_flags(bss, 0);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003021
3022 if (drv->addr_changed) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003023 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
3024 0) < 0) {
3025 wpa_printf(MSG_DEBUG,
3026 "nl80211: Could not set interface down to restore permanent MAC address");
3027 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003028 if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
3029 drv->perm_addr) < 0) {
3030 wpa_printf(MSG_DEBUG,
3031 "nl80211: Could not restore permanent MAC address");
3032 }
3033 }
3034
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003035 if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
Hai Shalomc1a21442022-02-04 13:43:00 -08003036 if (drv->start_mode_sta)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003037 wpa_driver_nl80211_set_mode(bss,
3038 NL80211_IFTYPE_STATION);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07003039 nl80211_mgmt_unsubscribe(bss, "deinit");
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003040 } else {
3041 nl80211_mgmt_unsubscribe(bss, "deinit");
3042 nl80211_del_p2pdev(bss);
3043 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003044
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003045 nl80211_destroy_bss(drv->first_bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003046
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003047 os_free(drv->filter_ssids);
3048
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003049 os_free(drv->auth_ie);
Hai Shalom60840252021-02-19 19:02:11 -08003050 os_free(drv->auth_data);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003051
3052 if (drv->in_interface_list)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003053 dl_list_del(&drv->list);
3054
Dmitry Shmidt444d5672013-04-01 13:08:44 -07003055 os_free(drv->extended_capa);
3056 os_free(drv->extended_capa_mask);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07003057 for (i = 0; i < drv->num_iface_ext_capa; i++) {
3058 os_free(drv->iface_ext_capa[i].ext_capa);
3059 os_free(drv->iface_ext_capa[i].ext_capa_mask);
3060 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003061 os_free(drv->first_bss);
Hai Shalom60840252021-02-19 19:02:11 -08003062#ifdef CONFIG_DRIVER_NL80211_QCA
3063 os_free(drv->pending_roam_data);
3064#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003065 os_free(drv);
3066}
3067
3068
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003069static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len)
3070{
3071 switch (alg) {
3072 case WPA_ALG_WEP:
3073 if (key_len == 5)
Paul Stewart092955c2017-02-06 09:13:09 -08003074 return RSN_CIPHER_SUITE_WEP40;
3075 return RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003076 case WPA_ALG_TKIP:
Paul Stewart092955c2017-02-06 09:13:09 -08003077 return RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003078 case WPA_ALG_CCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003079 return RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003080 case WPA_ALG_GCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003081 return RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003082 case WPA_ALG_CCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003083 return RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003084 case WPA_ALG_GCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003085 return RSN_CIPHER_SUITE_GCMP_256;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003086 case WPA_ALG_BIP_CMAC_128:
Paul Stewart092955c2017-02-06 09:13:09 -08003087 return RSN_CIPHER_SUITE_AES_128_CMAC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003088 case WPA_ALG_BIP_GMAC_128:
Paul Stewart092955c2017-02-06 09:13:09 -08003089 return RSN_CIPHER_SUITE_BIP_GMAC_128;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003090 case WPA_ALG_BIP_GMAC_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003091 return RSN_CIPHER_SUITE_BIP_GMAC_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003092 case WPA_ALG_BIP_CMAC_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003093 return RSN_CIPHER_SUITE_BIP_CMAC_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003094 case WPA_ALG_SMS4:
Paul Stewart092955c2017-02-06 09:13:09 -08003095 return RSN_CIPHER_SUITE_SMS4;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003096 case WPA_ALG_KRK:
Paul Stewart092955c2017-02-06 09:13:09 -08003097 return RSN_CIPHER_SUITE_KRK;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003098 case WPA_ALG_NONE:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003099 wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d",
3100 alg);
3101 return 0;
3102 }
3103
3104 wpa_printf(MSG_ERROR, "nl80211: Unsupported encryption algorithm %d",
3105 alg);
3106 return 0;
3107}
3108
3109
3110static u32 wpa_cipher_to_cipher_suite(unsigned int cipher)
3111{
3112 switch (cipher) {
3113 case WPA_CIPHER_CCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003114 return RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003115 case WPA_CIPHER_GCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003116 return RSN_CIPHER_SUITE_GCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003117 case WPA_CIPHER_CCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003118 return RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003119 case WPA_CIPHER_GCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003120 return RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003121 case WPA_CIPHER_TKIP:
Paul Stewart092955c2017-02-06 09:13:09 -08003122 return RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003123 case WPA_CIPHER_WEP104:
Paul Stewart092955c2017-02-06 09:13:09 -08003124 return RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003125 case WPA_CIPHER_WEP40:
Paul Stewart092955c2017-02-06 09:13:09 -08003126 return RSN_CIPHER_SUITE_WEP40;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003127 case WPA_CIPHER_GTK_NOT_USED:
Paul Stewart092955c2017-02-06 09:13:09 -08003128 return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003129 }
3130
3131 return 0;
3132}
3133
3134
3135static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[],
3136 int max_suites)
3137{
3138 int num_suites = 0;
3139
3140 if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP_256)
Paul Stewart092955c2017-02-06 09:13:09 -08003141 suites[num_suites++] = RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003142 if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP_256)
Paul Stewart092955c2017-02-06 09:13:09 -08003143 suites[num_suites++] = RSN_CIPHER_SUITE_GCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003144 if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP)
Paul Stewart092955c2017-02-06 09:13:09 -08003145 suites[num_suites++] = RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003146 if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP)
Paul Stewart092955c2017-02-06 09:13:09 -08003147 suites[num_suites++] = RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003148 if (num_suites < max_suites && ciphers & WPA_CIPHER_TKIP)
Paul Stewart092955c2017-02-06 09:13:09 -08003149 suites[num_suites++] = RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003150 if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP104)
Paul Stewart092955c2017-02-06 09:13:09 -08003151 suites[num_suites++] = RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003152 if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP40)
Paul Stewart092955c2017-02-06 09:13:09 -08003153 suites[num_suites++] = RSN_CIPHER_SUITE_WEP40;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003154
3155 return num_suites;
3156}
3157
3158
Hai Shalomfdcde762020-04-02 11:19:20 -07003159static int wpa_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
3160 int max_suites)
3161{
3162 int num_suites = 0;
3163
3164#define __AKM(a, b) \
3165 if (num_suites < max_suites && \
3166 (key_mgmt_suites & (WPA_KEY_MGMT_ ## a))) \
3167 suites[num_suites++] = (RSN_AUTH_KEY_MGMT_ ## b)
3168 __AKM(IEEE8021X, UNSPEC_802_1X);
3169 __AKM(PSK, PSK_OVER_802_1X);
3170 __AKM(FT_IEEE8021X, FT_802_1X);
3171 __AKM(FT_PSK, FT_PSK);
3172 __AKM(IEEE8021X_SHA256, 802_1X_SHA256);
3173 __AKM(PSK_SHA256, PSK_SHA256);
3174 __AKM(SAE, SAE);
3175 __AKM(FT_SAE, FT_SAE);
3176 __AKM(CCKM, CCKM);
3177 __AKM(OSEN, OSEN);
3178 __AKM(IEEE8021X_SUITE_B, 802_1X_SUITE_B);
3179 __AKM(IEEE8021X_SUITE_B_192, 802_1X_SUITE_B_192);
3180 __AKM(FILS_SHA256, FILS_SHA256);
3181 __AKM(FILS_SHA384, FILS_SHA384);
3182 __AKM(FT_FILS_SHA256, FT_FILS_SHA256);
3183 __AKM(FT_FILS_SHA384, FT_FILS_SHA384);
3184 __AKM(OWE, OWE);
3185 __AKM(DPP, DPP);
3186 __AKM(FT_IEEE8021X_SHA384, FT_802_1X_SHA384);
3187#undef __AKM
3188
3189 return num_suites;
3190}
3191
Ajay Davanagerib921bb82020-09-16 12:49:08 +05303192#ifdef CONFIG_DRIVER_NL80211_BRCM
Hai Shalomc1a21442022-02-04 13:43:00 -08003193static int wpa_driver_do_broadcom_acs(struct wpa_driver_nl80211_data *drv,
3194 struct drv_acs_params *params)
Ajay Davanagerib921bb82020-09-16 12:49:08 +05303195{
Ajay Davanagerib921bb82020-09-16 12:49:08 +05303196 struct nl_msg *msg;
3197 struct nlattr *data;
Hai Shalomc1a21442022-02-04 13:43:00 -08003198 int freq_list_len;
3199 int ret = -1;
Ajay Davanagerib921bb82020-09-16 12:49:08 +05303200
Hai Shalomc1a21442022-02-04 13:43:00 -08003201 freq_list_len = int_array_len(params->freq_list);
3202 wpa_printf(MSG_DEBUG, "%s: freq_list_len=%d",
3203 __func__, freq_list_len);
3204
3205 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
3206 if (!msg ||
3207 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
3208 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
3209 BRCM_VENDOR_SCMD_ACS) ||
3210 !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
3211 nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HW_MODE, params->hw_mode) ||
3212 nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT_ENABLED,
3213 params->ht_enabled) ||
3214 nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED,
3215 params->ht40_enabled) ||
3216 nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED,
3217 params->vht_enabled) ||
3218 nla_put_u16(msg, BRCM_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width) ||
3219 (freq_list_len > 0 &&
3220 nla_put(msg, BRCM_VENDOR_ATTR_ACS_FREQ_LIST,
3221 sizeof(int) * freq_list_len, params->freq_list)))
3222 goto fail;
3223 nla_nest_end(msg, data);
3224
3225 wpa_printf(MSG_DEBUG,
3226 "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d",
3227 params->hw_mode, params->ht_enabled, params->ht40_enabled,
3228 params->vht_enabled, params->ch_width);
3229
3230 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
3231 if (ret) {
3232 wpa_printf(MSG_ERROR,
3233 "nl80211: BRCM Failed to invoke driver ACS function: %s",
3234 strerror(errno));
3235 }
3236
3237 msg = NULL;
3238fail:
3239 nlmsg_free(msg);
Ajay Davanagerib921bb82020-09-16 12:49:08 +05303240 return ret;
3241}
3242#endif /* CONFIG_DRIVER_NL80211_BRCM */
Hai Shalomfdcde762020-04-02 11:19:20 -07003243
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003244#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003245static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
3246 const u8 *key, size_t key_len)
3247{
3248 struct nl_msg *msg;
3249 int ret;
3250
3251 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
3252 return 0;
3253
3254 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
3255 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
3256 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
3257 QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY) ||
3258 nla_put(msg, NL80211_ATTR_VENDOR_DATA, key_len, key)) {
3259 nl80211_nlmsg_clear(msg);
3260 nlmsg_free(msg);
3261 return -1;
3262 }
Hai Shalom60840252021-02-19 19:02:11 -08003263 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003264 if (ret) {
3265 wpa_printf(MSG_DEBUG,
3266 "nl80211: Key management set key failed: ret=%d (%s)",
3267 ret, strerror(-ret));
3268 }
3269
3270 return ret;
3271}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003272#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003273
3274
Mir Ali677e7482020-11-12 19:49:02 +05303275#ifdef CONFIG_DRIVER_NL80211_BRCM
3276static int key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
3277 const u8 *key, size_t key_len)
3278{
3279 struct nl_msg *msg;
3280 int ret;
3281 struct nlattr *params;
3282
3283 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
3284 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
3285 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
Hai Shalomc1a21442022-02-04 13:43:00 -08003286 BRCM_VENDOR_SCMD_SET_PMK) ||
Mir Ali677e7482020-11-12 19:49:02 +05303287 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
3288 nla_put(msg, BRCM_ATTR_DRIVER_KEY_PMK, key_len, key)) {
3289 nl80211_nlmsg_clear(msg);
3290 nlmsg_free(msg);
3291 return -ENOBUFS;
3292 }
3293 nla_nest_end(msg, params);
3294
3295 ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
3296 if (ret) {
3297 wpa_printf(MSG_DEBUG, "nl80211: Key mgmt set key failed: ret=%d (%s)",
3298 ret, strerror(-ret));
3299 }
3300
3301 return ret;
3302}
3303#endif /* CONFIG_DRIVER_NL80211_BRCM */
3304
Roshan Pius3a1667e2018-07-03 15:17:14 -07003305static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
3306 const u8 *key, size_t key_len,
3307 const u8 *addr)
3308{
3309 struct nl_msg *msg = NULL;
3310 int ret;
3311
3312 /*
3313 * If the authenticator address is not set, assume it is
3314 * the current BSSID.
3315 */
3316 if (!addr && drv->associated)
3317 addr = drv->bssid;
3318 else if (!addr)
3319 return -1;
3320
3321 wpa_printf(MSG_DEBUG, "nl80211: Set PMK to the driver for " MACSTR,
3322 MAC2STR(addr));
3323 wpa_hexdump_key(MSG_DEBUG, "nl80211: PMK", key, key_len);
3324 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_PMK);
3325 if (!msg ||
3326 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
3327 nla_put(msg, NL80211_ATTR_PMK, key_len, key)) {
3328 nl80211_nlmsg_clear(msg);
3329 nlmsg_free(msg);
3330 return -ENOBUFS;
3331 }
3332
Hai Shalom60840252021-02-19 19:02:11 -08003333 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003334 if (ret) {
3335 wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)",
3336 ret, strerror(-ret));
3337 }
3338
3339 return ret;
3340}
3341
3342
Hai Shalomfdcde762020-04-02 11:19:20 -07003343static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
3344 struct wpa_driver_set_key_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003345{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003346 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003347 int ifindex;
Hai Shalomc3565922019-10-28 11:58:20 -07003348 struct nl_msg *msg;
3349 struct nl_msg *key_msg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003350 int ret;
Hai Shalomfdcde762020-04-02 11:19:20 -07003351 int skip_set_key = 1;
3352 const char *ifname = params->ifname;
3353 enum wpa_alg alg = params->alg;
3354 const u8 *addr = params->addr;
3355 int key_idx = params->key_idx;
3356 int set_tx = params->set_tx;
3357 const u8 *seq = params->seq;
3358 size_t seq_len = params->seq_len;
3359 const u8 *key = params->key;
3360 size_t key_len = params->key_len;
3361 int vlan_id = params->vlan_id;
3362 enum key_flag key_flag = params->key_flag;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003363
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003364 /* Ignore for P2P Device */
3365 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
3366 return 0;
3367
3368 ifindex = if_nametoindex(ifname);
3369 wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
Hai Shalomfdcde762020-04-02 11:19:20 -07003370 "set_tx=%d seq_len=%lu key_len=%lu key_flag=0x%x",
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003371 __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
Hai Shalomfdcde762020-04-02 11:19:20 -07003372 (unsigned long) seq_len, (unsigned long) key_len, key_flag);
3373
3374 if (check_key_flag(key_flag)) {
3375 wpa_printf(MSG_DEBUG, "%s: invalid key_flag", __func__);
3376 return -EINVAL;
Dmitry Shmidtd5c075b2013-08-05 14:36:10 -07003377 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003378
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003379#ifdef CONFIG_DRIVER_NL80211_QCA
Hai Shalomfdcde762020-04-02 11:19:20 -07003380 if ((key_flag & KEY_FLAG_PMK) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003381 (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
3382 wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
3383 __func__);
3384 ret = issue_key_mgmt_set_key(drv, key, key_len);
3385 return ret;
3386 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003387#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003388
Hai Shalomfdcde762020-04-02 11:19:20 -07003389 if (key_flag & KEY_FLAG_PMK) {
3390 if (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)
3391 return nl80211_set_pmk(drv, key, key_len, addr);
Mir Ali677e7482020-11-12 19:49:02 +05303392#ifdef CONFIG_DRIVER_NL80211_BRCM
3393 if (drv->vendor_set_pmk) {
Jay Patel731adae2021-02-17 14:55:58 -08003394 wpa_printf(MSG_INFO, "nl80211: key_mgmt_set_key with key_len %lu", (unsigned long) key_len);
Mir Ali677e7482020-11-12 19:49:02 +05303395 return key_mgmt_set_key(drv, key, key_len);
3396 }
3397#endif /* CONFIG_DRIVER_NL80211_BRCM */
Hai Shalomfdcde762020-04-02 11:19:20 -07003398 /* The driver does not have any offload mechanism for PMK, so
3399 * there is no need to configure this key. */
3400 return 0;
3401 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003402
Hai Shalomfdcde762020-04-02 11:19:20 -07003403 ret = -ENOBUFS;
Hai Shalomc3565922019-10-28 11:58:20 -07003404 key_msg = nlmsg_alloc();
3405 if (!key_msg)
Hai Shalomfdcde762020-04-02 11:19:20 -07003406 return ret;
Hai Shalomc3565922019-10-28 11:58:20 -07003407
Hai Shalomfdcde762020-04-02 11:19:20 -07003408 if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3409 KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
3410 wpa_printf(MSG_DEBUG,
3411 "nl80211: SET_KEY (pairwise RX/TX modify)");
3412 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
3413 if (!msg)
3414 goto fail2;
3415 } else if (alg == WPA_ALG_NONE && (key_flag & KEY_FLAG_RX_TX)) {
3416 wpa_printf(MSG_DEBUG, "%s: invalid key_flag to delete key",
3417 __func__);
3418 ret = -EINVAL;
3419 goto fail2;
3420 } else if (alg == WPA_ALG_NONE) {
3421 wpa_printf(MSG_DEBUG, "nl80211: DEL_KEY");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003422 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
3423 if (!msg)
Hai Shalomc3565922019-10-28 11:58:20 -07003424 goto fail2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003425 } else {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003426 u32 suite;
3427
3428 suite = wpa_alg_to_cipher_suite(alg, key_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07003429 if (!suite) {
3430 ret = -EINVAL;
Hai Shalomc3565922019-10-28 11:58:20 -07003431 goto fail2;
Hai Shalomfdcde762020-04-02 11:19:20 -07003432 }
3433 wpa_printf(MSG_DEBUG, "nl80211: NEW_KEY");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003434 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
Hai Shalomc3565922019-10-28 11:58:20 -07003435 if (!msg)
3436 goto fail2;
3437 if (nla_put(key_msg, NL80211_KEY_DATA, key_len, key) ||
3438 nla_put_u32(key_msg, NL80211_KEY_CIPHER, suite))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003439 goto fail;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003440 wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003441
Hai Shalomfdcde762020-04-02 11:19:20 -07003442 if (seq && seq_len) {
3443 if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq))
3444 goto fail;
3445 wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ",
3446 seq, seq_len);
3447 }
Dmitry Shmidt98660862014-03-11 17:26:21 -07003448 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003449
3450 if (addr && !is_broadcast_ether_addr(addr)) {
3451 wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003452 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
3453 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003454
Hai Shalomfdcde762020-04-02 11:19:20 -07003455 if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3456 KEY_FLAG_PAIRWISE_RX ||
3457 (key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3458 KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
3459 if (nla_put_u8(key_msg, NL80211_KEY_MODE,
3460 key_flag == KEY_FLAG_PAIRWISE_RX ?
3461 NL80211_KEY_NO_TX : NL80211_KEY_SET_TX))
3462 goto fail;
3463 } else if ((key_flag & KEY_FLAG_GROUP_MASK) ==
3464 KEY_FLAG_GROUP_RX) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003465 wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
Hai Shalomc3565922019-10-28 11:58:20 -07003466 if (nla_put_u32(key_msg, NL80211_KEY_TYPE,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003467 NL80211_KEYTYPE_GROUP))
3468 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003469 } else if (!(key_flag & KEY_FLAG_PAIRWISE)) {
3470 wpa_printf(MSG_DEBUG,
3471 " key_flag missing PAIRWISE when setting a pairwise key");
3472 ret = -EINVAL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003473 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003474 } else if (alg == WPA_ALG_WEP &&
3475 (key_flag & KEY_FLAG_RX_TX) == KEY_FLAG_RX_TX) {
3476 wpa_printf(MSG_DEBUG, " unicast WEP key");
3477 skip_set_key = 0;
3478 } else {
3479 wpa_printf(MSG_DEBUG, " pairwise key");
3480 }
3481 } else if ((key_flag & KEY_FLAG_PAIRWISE) ||
3482 !(key_flag & KEY_FLAG_GROUP)) {
3483 wpa_printf(MSG_DEBUG,
3484 " invalid key_flag for a broadcast key");
3485 ret = -EINVAL;
3486 goto fail;
3487 } else {
3488 wpa_printf(MSG_DEBUG, " broadcast key");
3489 if (key_flag & KEY_FLAG_DEFAULT)
3490 skip_set_key = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003491 }
Hai Shalomc3565922019-10-28 11:58:20 -07003492 if (nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
3493 nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003494 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003495 nl80211_nlmsg_clear(key_msg);
3496 nlmsg_free(key_msg);
3497 key_msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003498
Hai Shalomfdcde762020-04-02 11:19:20 -07003499 if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
3500 wpa_printf(MSG_DEBUG, "nl80211: VLAN ID %d", vlan_id);
3501 if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
3502 goto fail;
3503 }
3504
Hai Shalom60840252021-02-19 19:02:11 -08003505 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003506 if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
3507 ret = 0;
3508 if (ret)
Hai Shalomfdcde762020-04-02 11:19:20 -07003509 wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003510 ret, strerror(-ret));
3511
3512 /*
Hai Shalomfdcde762020-04-02 11:19:20 -07003513 * If we failed or don't need to set the key as default (below),
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003514 * we're done here.
3515 */
Hai Shalomfdcde762020-04-02 11:19:20 -07003516 if (ret || skip_set_key)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003517 return ret;
Hai Shalomfdcde762020-04-02 11:19:20 -07003518 wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_SET_KEY - default key");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003519
Hai Shalomfdcde762020-04-02 11:19:20 -07003520 ret = -ENOBUFS;
Hai Shalomc3565922019-10-28 11:58:20 -07003521 key_msg = nlmsg_alloc();
3522 if (!key_msg)
Hai Shalomfdcde762020-04-02 11:19:20 -07003523 return ret;
Hai Shalomc3565922019-10-28 11:58:20 -07003524
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003525 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
Hai Shalomc3565922019-10-28 11:58:20 -07003526 if (!msg)
3527 goto fail2;
3528 if (!key_msg ||
3529 nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003530 nla_put_flag(key_msg, wpa_alg_bip(alg) ?
Hai Shalomfdcde762020-04-02 11:19:20 -07003531 (key_idx == 6 || key_idx == 7 ?
3532 NL80211_KEY_DEFAULT_BEACON :
3533 NL80211_KEY_DEFAULT_MGMT) :
3534 NL80211_KEY_DEFAULT))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003535 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003536 if (addr && is_broadcast_ether_addr(addr)) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003537 struct nlattr *types;
3538
Hai Shalomc3565922019-10-28 11:58:20 -07003539 types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003540 if (!types ||
Hai Shalomc3565922019-10-28 11:58:20 -07003541 nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003542 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003543 nla_nest_end(key_msg, types);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003544 } else if (addr) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003545 struct nlattr *types;
3546
Hai Shalomc3565922019-10-28 11:58:20 -07003547 types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003548 if (!types ||
Hai Shalomc3565922019-10-28 11:58:20 -07003549 nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003550 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003551 nla_nest_end(key_msg, types);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003552 }
3553
Hai Shalomc3565922019-10-28 11:58:20 -07003554 if (nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
3555 goto fail;
3556 nl80211_nlmsg_clear(key_msg);
3557 nlmsg_free(key_msg);
3558 key_msg = NULL;
3559
Hai Shalomfdcde762020-04-02 11:19:20 -07003560 if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
3561 wpa_printf(MSG_DEBUG, "nl80211: set_key default - VLAN ID %d",
3562 vlan_id);
3563 if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
3564 goto fail;
3565 }
3566
Hai Shalom899fcc72020-10-19 14:38:18 -07003567 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003568 if (ret)
Hai Shalomfdcde762020-04-02 11:19:20 -07003569 wpa_printf(MSG_DEBUG,
3570 "nl80211: set_key default failed; err=%d %s",
3571 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003572 return ret;
3573
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003574fail:
3575 nl80211_nlmsg_clear(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003576 nlmsg_free(msg);
Hai Shalomc3565922019-10-28 11:58:20 -07003577fail2:
3578 nl80211_nlmsg_clear(key_msg);
3579 nlmsg_free(key_msg);
Hai Shalomfdcde762020-04-02 11:19:20 -07003580 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003581}
3582
3583
3584static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
3585 int key_idx, int defkey,
3586 const u8 *seq, size_t seq_len,
3587 const u8 *key, size_t key_len)
3588{
3589 struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003590 u32 suite;
3591
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003592 if (!key_attr)
3593 return -1;
3594
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003595 suite = wpa_alg_to_cipher_suite(alg, key_len);
3596 if (!suite)
3597 return -1;
3598
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003599 if (defkey && wpa_alg_bip(alg)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003600 if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT))
3601 return -1;
3602 } else if (defkey) {
3603 if (nla_put_flag(msg, NL80211_KEY_DEFAULT))
3604 return -1;
3605 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003606
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003607 if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) ||
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003608 nla_put_u32(msg, NL80211_KEY_CIPHER, suite) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003609 (seq && seq_len &&
3610 nla_put(msg, NL80211_KEY_SEQ, seq_len, seq)) ||
3611 nla_put(msg, NL80211_KEY_DATA, key_len, key))
3612 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003613
3614 nla_nest_end(msg, key_attr);
3615
3616 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003617}
3618
3619
3620static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
3621 struct nl_msg *msg)
3622{
3623 int i, privacy = 0;
3624 struct nlattr *nl_keys, *nl_key;
3625
3626 for (i = 0; i < 4; i++) {
3627 if (!params->wep_key[i])
3628 continue;
3629 privacy = 1;
3630 break;
3631 }
3632 if (params->wps == WPS_MODE_PRIVACY)
3633 privacy = 1;
3634 if (params->pairwise_suite &&
3635 params->pairwise_suite != WPA_CIPHER_NONE)
3636 privacy = 1;
3637
3638 if (!privacy)
3639 return 0;
3640
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003641 if (nla_put_flag(msg, NL80211_ATTR_PRIVACY))
3642 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003643
3644 nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
3645 if (!nl_keys)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003646 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003647
3648 for (i = 0; i < 4; i++) {
3649 if (!params->wep_key[i])
3650 continue;
3651
3652 nl_key = nla_nest_start(msg, i);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003653 if (!nl_key ||
3654 nla_put(msg, NL80211_KEY_DATA, params->wep_key_len[i],
3655 params->wep_key[i]) ||
3656 nla_put_u32(msg, NL80211_KEY_CIPHER,
3657 params->wep_key_len[i] == 5 ?
Paul Stewart092955c2017-02-06 09:13:09 -08003658 RSN_CIPHER_SUITE_WEP40 :
3659 RSN_CIPHER_SUITE_WEP104) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003660 nla_put_u8(msg, NL80211_KEY_IDX, i) ||
3661 (i == params->wep_tx_keyidx &&
3662 nla_put_flag(msg, NL80211_KEY_DEFAULT)))
3663 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003664
3665 nla_nest_end(msg, nl_key);
3666 }
3667 nla_nest_end(msg, nl_keys);
3668
3669 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003670}
3671
3672
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003673int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
3674 const u8 *addr, int cmd, u16 reason_code,
Hai Shalom74f70d42019-02-11 14:42:39 -08003675 int local_state_change,
Hai Shalomc1a21442022-02-04 13:43:00 -08003676 struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003677{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003678 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003679 struct nl_msg *msg;
Hai Shalomc1a21442022-02-04 13:43:00 -08003680 struct nl_sock *nl_connect = get_connect_handle(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003681
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003682 if (!(msg = nl80211_drv_msg(drv, 0, cmd)) ||
3683 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code) ||
3684 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
3685 (local_state_change &&
3686 nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))) {
3687 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003688 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003689 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003690
Hai Shalom74f70d42019-02-11 14:42:39 -08003691 if (nl_connect)
Hai Shalomc1a21442022-02-04 13:43:00 -08003692 ret = send_and_recv(drv->global, nl_connect, msg,
3693 process_bss_event, bss, NULL, NULL);
Hai Shalom74f70d42019-02-11 14:42:39 -08003694 else
Hai Shalom899fcc72020-10-19 14:38:18 -07003695 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003696 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003697 wpa_dbg(drv->ctx, MSG_DEBUG,
3698 "nl80211: MLME command failed: reason=%u ret=%d (%s)",
3699 reason_code, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003700 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003701 return ret;
3702}
3703
3704
3705static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
Hai Shalom81f62d82019-07-22 12:10:00 -07003706 u16 reason_code,
Hai Shalomc1a21442022-02-04 13:43:00 -08003707 struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003708{
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003709 int ret;
Hai Shalomce48b4a2018-09-05 11:41:35 -07003710 int drv_associated = drv->associated;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003711
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003712 wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003713 nl80211_mark_disconnected(drv);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003714 /* Disconnect command doesn't need BSSID - it uses cached value */
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003715 ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
Hai Shalomc1a21442022-02-04 13:43:00 -08003716 reason_code, 0, bss);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003717 /*
3718 * For locally generated disconnect, supplicant already generates a
3719 * DEAUTH event, so ignore the event from NL80211.
3720 */
Hai Shalomce48b4a2018-09-05 11:41:35 -07003721 drv->ignore_next_local_disconnect = drv_associated && (ret == 0);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003722
3723 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003724}
3725
3726
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003727static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
Hai Shalom81f62d82019-07-22 12:10:00 -07003728 const u8 *addr, u16 reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003729{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003730 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003731 int ret;
Hai Shalomce48b4a2018-09-05 11:41:35 -07003732 int drv_associated = drv->associated;
Dmitry Shmidt413dde72014-04-11 10:23:22 -07003733
3734 if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
3735 nl80211_mark_disconnected(drv);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003736 return nl80211_leave_ibss(drv, 1);
Dmitry Shmidt413dde72014-04-11 10:23:22 -07003737 }
Hai Shalom74f70d42019-02-11 14:42:39 -08003738 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
Hai Shalomc1a21442022-02-04 13:43:00 -08003739 return wpa_driver_nl80211_disconnect(drv, reason_code, bss);
Hai Shalom74f70d42019-02-11 14:42:39 -08003740 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003741 wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
3742 __func__, MAC2STR(addr), reason_code);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003743 nl80211_mark_disconnected(drv);
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003744 ret = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
Hai Shalomc1a21442022-02-04 13:43:00 -08003745 reason_code, 0, bss);
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003746 /*
3747 * For locally generated deauthenticate, supplicant already generates a
3748 * DEAUTH event, so ignore the event from NL80211.
3749 */
Hai Shalomce48b4a2018-09-05 11:41:35 -07003750 drv->ignore_next_local_deauth = drv_associated && (ret == 0);
3751
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003752 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003753}
3754
3755
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003756static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
3757 struct wpa_driver_auth_params *params)
3758{
3759 int i;
3760
3761 drv->auth_freq = params->freq;
3762 drv->auth_alg = params->auth_alg;
3763 drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
3764 drv->auth_local_state_change = params->local_state_change;
3765 drv->auth_p2p = params->p2p;
3766
3767 if (params->bssid)
3768 os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
3769 else
3770 os_memset(drv->auth_bssid_, 0, ETH_ALEN);
3771
3772 if (params->ssid) {
3773 os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
3774 drv->auth_ssid_len = params->ssid_len;
3775 } else
3776 drv->auth_ssid_len = 0;
3777
3778
3779 os_free(drv->auth_ie);
3780 drv->auth_ie = NULL;
3781 drv->auth_ie_len = 0;
3782 if (params->ie) {
3783 drv->auth_ie = os_malloc(params->ie_len);
3784 if (drv->auth_ie) {
3785 os_memcpy(drv->auth_ie, params->ie, params->ie_len);
3786 drv->auth_ie_len = params->ie_len;
3787 }
3788 }
3789
Hai Shalom60840252021-02-19 19:02:11 -08003790 os_free(drv->auth_data);
3791 drv->auth_data = NULL;
3792 drv->auth_data_len = 0;
3793 if (params->auth_data) {
3794 drv->auth_data = os_memdup(params->auth_data,
3795 params->auth_data_len);
3796 if (drv->auth_data)
3797 drv->auth_data_len = params->auth_data_len;
3798 }
3799
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003800 for (i = 0; i < 4; i++) {
3801 if (params->wep_key[i] && params->wep_key_len[i] &&
3802 params->wep_key_len[i] <= 16) {
3803 os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
3804 params->wep_key_len[i]);
3805 drv->auth_wep_key_len[i] = params->wep_key_len[i];
3806 } else
3807 drv->auth_wep_key_len[i] = 0;
3808 }
3809}
3810
3811
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003812static void nl80211_unmask_11b_rates(struct i802_bss *bss)
3813{
3814 struct wpa_driver_nl80211_data *drv = bss->drv;
3815
3816 if (is_p2p_net_interface(drv->nlmode) || !drv->disabled_11b_rates)
3817 return;
3818
3819 /*
3820 * Looks like we failed to unmask 11b rates previously. This could
3821 * happen, e.g., if the interface was down at the point in time when a
3822 * P2P group was terminated.
3823 */
3824 wpa_printf(MSG_DEBUG,
3825 "nl80211: Interface %s mode is for non-P2P, but 11b rates were disabled - re-enable them",
3826 bss->ifname);
3827 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
3828}
3829
3830
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003831static enum nl80211_auth_type get_nl_auth_type(int wpa_auth_alg)
3832{
3833 if (wpa_auth_alg & WPA_AUTH_ALG_OPEN)
3834 return NL80211_AUTHTYPE_OPEN_SYSTEM;
3835 if (wpa_auth_alg & WPA_AUTH_ALG_SHARED)
3836 return NL80211_AUTHTYPE_SHARED_KEY;
3837 if (wpa_auth_alg & WPA_AUTH_ALG_LEAP)
3838 return NL80211_AUTHTYPE_NETWORK_EAP;
3839 if (wpa_auth_alg & WPA_AUTH_ALG_FT)
3840 return NL80211_AUTHTYPE_FT;
3841 if (wpa_auth_alg & WPA_AUTH_ALG_SAE)
3842 return NL80211_AUTHTYPE_SAE;
3843 if (wpa_auth_alg & WPA_AUTH_ALG_FILS)
3844 return NL80211_AUTHTYPE_FILS_SK;
3845 if (wpa_auth_alg & WPA_AUTH_ALG_FILS_SK_PFS)
3846 return NL80211_AUTHTYPE_FILS_SK_PFS;
3847
3848 return NL80211_AUTHTYPE_MAX;
3849}
3850
3851
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003852static int wpa_driver_nl80211_authenticate(
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003853 struct i802_bss *bss, struct wpa_driver_auth_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003854{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003855 struct wpa_driver_nl80211_data *drv = bss->drv;
3856 int ret = -1, i;
3857 struct nl_msg *msg;
3858 enum nl80211_auth_type type;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003859 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003860 int count = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003861 int is_retry;
Hai Shalomfdcde762020-04-02 11:19:20 -07003862 struct wpa_driver_set_key_params p;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003863
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003864 nl80211_unmask_11b_rates(bss);
3865
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003866 is_retry = drv->retry_auth;
3867 drv->retry_auth = 0;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003868 drv->ignore_deauth_event = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003869
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003870 nl80211_mark_disconnected(drv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003871 os_memset(drv->auth_bssid, 0, ETH_ALEN);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003872 if (params->bssid)
3873 os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
3874 else
3875 os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003876 /* FIX: IBSS mode */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003877 nlmode = params->p2p ?
3878 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
3879 if (drv->nlmode != nlmode &&
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003880 wpa_driver_nl80211_set_mode(bss, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003881 return -1;
3882
3883retry:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003884 wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
3885 drv->ifindex);
3886
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003887 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_AUTHENTICATE);
3888 if (!msg)
3889 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003890
Hai Shalomfdcde762020-04-02 11:19:20 -07003891 os_memset(&p, 0, sizeof(p));
3892 p.ifname = bss->ifname;
3893 p.alg = WPA_ALG_WEP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003894 for (i = 0; i < 4; i++) {
3895 if (!params->wep_key[i])
3896 continue;
Hai Shalomfdcde762020-04-02 11:19:20 -07003897 p.key_idx = i;
3898 p.set_tx = i == params->wep_tx_keyidx;
3899 p.key = params->wep_key[i];
3900 p.key_len = params->wep_key_len[i];
3901 p.key_flag = i == params->wep_tx_keyidx ?
3902 KEY_FLAG_GROUP_RX_TX_DEFAULT :
3903 KEY_FLAG_GROUP_RX_TX;
3904 wpa_driver_nl80211_set_key(bss, &p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003905 if (params->wep_tx_keyidx != i)
3906 continue;
3907 if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003908 params->wep_key[i], params->wep_key_len[i]))
3909 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003910 }
3911
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003912 if (params->bssid) {
3913 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
3914 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003915 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
3916 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003917 }
3918 if (params->freq) {
3919 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003920 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
3921 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003922 }
3923 if (params->ssid) {
Hai Shalom74f70d42019-02-11 14:42:39 -08003924 wpa_printf(MSG_DEBUG, " * SSID=%s",
3925 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003926 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
3927 params->ssid))
3928 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003929 }
3930 wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003931 if (params->ie &&
3932 nla_put(msg, NL80211_ATTR_IE, params->ie_len, params->ie))
3933 goto fail;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003934 if (params->auth_data) {
3935 wpa_hexdump(MSG_DEBUG, " * auth_data", params->auth_data,
3936 params->auth_data_len);
3937 if (nla_put(msg, NL80211_ATTR_SAE_DATA, params->auth_data_len,
3938 params->auth_data))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003939 goto fail;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003940 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003941 type = get_nl_auth_type(params->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003942 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003943 if (type == NL80211_AUTHTYPE_MAX ||
3944 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003945 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003946 if (params->local_state_change) {
3947 wpa_printf(MSG_DEBUG, " * Local state change only");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003948 if (nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))
3949 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003950 }
3951
Hai Shalom899fcc72020-10-19 14:38:18 -07003952 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003953 msg = NULL;
3954 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003955 wpa_dbg(drv->ctx, MSG_DEBUG,
Roshan Pius3a1667e2018-07-03 15:17:14 -07003956 "nl80211: MLME command failed (auth): count=%d ret=%d (%s)",
3957 count, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003958 count++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003959 if ((ret == -EALREADY || ret == -EEXIST) && count == 1 &&
3960 params->bssid && !params->local_state_change) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003961 /*
3962 * mac80211 does not currently accept new
3963 * authentication if we are already authenticated. As a
3964 * workaround, force deauthentication and try again.
3965 */
3966 wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
3967 "after forced deauthentication");
Dmitry Shmidt98660862014-03-11 17:26:21 -07003968 drv->ignore_deauth_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003969 wpa_driver_nl80211_deauthenticate(
3970 bss, params->bssid,
3971 WLAN_REASON_PREV_AUTH_NOT_VALID);
3972 nlmsg_free(msg);
3973 goto retry;
3974 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003975
3976 if (ret == -ENOENT && params->freq && !is_retry) {
3977 /*
3978 * cfg80211 has likely expired the BSS entry even
3979 * though it was previously available in our internal
3980 * BSS table. To recover quickly, start a single
3981 * channel scan on the specified channel.
3982 */
3983 struct wpa_driver_scan_params scan;
3984 int freqs[2];
3985
3986 os_memset(&scan, 0, sizeof(scan));
3987 scan.num_ssids = 1;
3988 if (params->ssid) {
3989 scan.ssids[0].ssid = params->ssid;
3990 scan.ssids[0].ssid_len = params->ssid_len;
3991 }
3992 freqs[0] = params->freq;
3993 freqs[1] = 0;
3994 scan.freqs = freqs;
3995 wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
3996 "channel scan to refresh cfg80211 BSS "
3997 "entry");
3998 ret = wpa_driver_nl80211_scan(bss, &scan);
3999 if (ret == 0) {
4000 nl80211_copy_auth_params(drv, params);
4001 drv->scan_for_auth = 1;
4002 }
4003 } else if (is_retry) {
4004 /*
4005 * Need to indicate this with an event since the return
4006 * value from the retry is not delivered to core code.
4007 */
4008 union wpa_event_data event;
4009 wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
4010 "failed");
4011 os_memset(&event, 0, sizeof(event));
4012 os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
4013 ETH_ALEN);
4014 wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
4015 &event);
4016 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004017 } else {
4018 wpa_printf(MSG_DEBUG,
4019 "nl80211: Authentication request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004020 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004021
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004022fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004023 nlmsg_free(msg);
4024 return ret;
4025}
4026
4027
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004028int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004029{
4030 struct wpa_driver_auth_params params;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08004031 struct i802_bss *bss = drv->first_bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004032 int i;
4033
4034 wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
4035
4036 os_memset(&params, 0, sizeof(params));
4037 params.freq = drv->auth_freq;
4038 params.auth_alg = drv->auth_alg;
4039 params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
4040 params.local_state_change = drv->auth_local_state_change;
4041 params.p2p = drv->auth_p2p;
4042
4043 if (!is_zero_ether_addr(drv->auth_bssid_))
4044 params.bssid = drv->auth_bssid_;
4045
4046 if (drv->auth_ssid_len) {
4047 params.ssid = drv->auth_ssid;
4048 params.ssid_len = drv->auth_ssid_len;
4049 }
4050
4051 params.ie = drv->auth_ie;
4052 params.ie_len = drv->auth_ie_len;
Hai Shalom60840252021-02-19 19:02:11 -08004053 params.auth_data = drv->auth_data;
4054 params.auth_data_len = drv->auth_data_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004055
4056 for (i = 0; i < 4; i++) {
4057 if (drv->auth_wep_key_len[i]) {
4058 params.wep_key[i] = drv->auth_wep_key[i];
4059 params.wep_key_len[i] = drv->auth_wep_key_len[i];
4060 }
4061 }
4062
4063 drv->retry_auth = 1;
4064 return wpa_driver_nl80211_authenticate(bss, &params);
4065}
4066
4067
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004068static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
4069 size_t data_len, int noack,
4070 unsigned int freq, int no_cck,
4071 int offchanok,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004072 unsigned int wait_time,
4073 const u16 *csa_offs,
Hai Shalomfdcde762020-04-02 11:19:20 -07004074 size_t csa_offs_len, int no_encrypt)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004075{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004076 struct wpa_driver_nl80211_data *drv = bss->drv;
4077 struct ieee80211_mgmt *mgmt;
Hai Shalomfdcde762020-04-02 11:19:20 -07004078 int encrypt = !no_encrypt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004079 u16 fc;
Hai Shalomfdcde762020-04-02 11:19:20 -07004080 int use_cookie = 1;
4081 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004082
4083 mgmt = (struct ieee80211_mgmt *) data;
4084 fc = le_to_host16(mgmt->frame_control);
Hai Shalomfdcde762020-04-02 11:19:20 -07004085 wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR
4086 " 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 -07004087 MAC2STR(mgmt->da), noack, freq, no_cck, offchanok, wait_time,
Hai Shalomfdcde762020-04-02 11:19:20 -07004088 no_encrypt, fc, fc2str(fc), drv->nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004089
Dmitry Shmidt34af3062013-07-11 10:46:32 -07004090 if ((is_sta_interface(drv->nlmode) ||
4091 drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004092 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4093 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
4094 /*
4095 * The use of last_mgmt_freq is a bit of a hack,
4096 * but it works due to the single-threaded nature
4097 * of wpa_supplicant.
4098 */
Dmitry Shmidt56052862013-10-04 10:23:25 -07004099 if (freq == 0) {
4100 wpa_printf(MSG_DEBUG, "nl80211: Use last_mgmt_freq=%d",
4101 drv->last_mgmt_freq);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004102 freq = drv->last_mgmt_freq;
Dmitry Shmidt56052862013-10-04 10:23:25 -07004103 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004104 wait_time = 0;
4105 use_cookie = 0;
4106 no_cck = 1;
4107 offchanok = 1;
4108 goto send_frame_cmd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004109 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004110
4111 if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
Dmitry Shmidt56052862013-10-04 10:23:25 -07004112 if (freq == 0) {
4113 wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d",
4114 bss->freq);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004115 freq = bss->freq;
Dmitry Shmidt56052862013-10-04 10:23:25 -07004116 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004117 if ((int) freq == bss->freq)
4118 wait_time = 0;
4119 goto send_frame_cmd;
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07004120 }
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07004121
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004122 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4123 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
4124 /*
4125 * Only one of the authentication frame types is encrypted.
4126 * In order for static WEP encryption to work properly (i.e.,
4127 * to not encrypt the frame), we need to tell mac80211 about
4128 * the frames that must not be encrypted.
4129 */
4130 u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
4131 u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
4132 if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
4133 encrypt = 0;
4134 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004135
Hai Shalom60840252021-02-19 19:02:11 -08004136 if (is_sta_interface(drv->nlmode) &&
Hai Shalomfdcde762020-04-02 11:19:20 -07004137 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4138 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
Hai Shalom60840252021-02-19 19:02:11 -08004139 if (freq == 0 &&
4140 (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
4141 !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
4142 freq = nl80211_get_assoc_freq(drv);
4143 wpa_printf(MSG_DEBUG,
4144 "nl80211: send_mlme - Use assoc_freq=%u for external auth",
4145 freq);
4146 }
4147
4148 /* Allow off channel for PASN authentication */
4149 if (data_len >= IEEE80211_HDRLEN + 2 &&
4150 WPA_GET_LE16(data + IEEE80211_HDRLEN) == WLAN_AUTH_PASN &&
4151 !offchanok) {
4152 wpa_printf(MSG_DEBUG,
4153 "nl80211: send_mlme: allow off channel for PASN");
4154 offchanok = 1;
4155 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004156 }
4157
Hai Shalomc1a21442022-02-04 13:43:00 -08004158#ifdef CONFIG_PASN
4159 if (is_sta_interface(drv->nlmode) &&
4160 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4161 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_DEAUTH) {
4162 wpa_printf(MSG_DEBUG,
4163 "nl80211: send_mlme: allow Deauthentication frame for PASN");
4164
4165 use_cookie = 0;
4166 offchanok = 1;
4167 goto send_frame_cmd;
4168 }
4169#endif /* CONFIG_PASN */
4170
Hai Shalomfdcde762020-04-02 11:19:20 -07004171 if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
4172 freq = nl80211_get_assoc_freq(drv);
4173 wpa_printf(MSG_DEBUG,
4174 "nl80211: send_mlme - Use assoc_freq=%u for IBSS",
4175 freq);
4176 }
4177 if (freq == 0) {
4178 wpa_printf(MSG_DEBUG, "nl80211: send_mlme - Use bss->freq=%u",
4179 bss->freq);
4180 freq = bss->freq;
4181 }
4182
Hai Shalomc1a21442022-02-04 13:43:00 -08004183 if (drv->use_monitor && is_ap_interface(drv->nlmode)) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004184 wpa_printf(MSG_DEBUG,
4185 "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
4186 freq, bss->freq);
4187 return nl80211_send_monitor(drv, data, data_len, encrypt,
4188 noack);
4189 }
4190
4191 if (noack || WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
4192 WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
4193 use_cookie = 0;
4194send_frame_cmd:
4195#ifdef CONFIG_TESTING_OPTIONS
4196 if (no_encrypt && !encrypt && !drv->use_monitor) {
4197 wpa_printf(MSG_DEBUG,
4198 "nl80211: Request to send an unencrypted frame - use a monitor interface for this");
4199 if (nl80211_create_monitor_interface(drv) < 0)
4200 return -1;
4201 res = nl80211_send_monitor(drv, data, data_len, encrypt,
4202 noack);
4203 nl80211_remove_monitor_interface(drv);
4204 return res;
4205 }
4206#endif /* CONFIG_TESTING_OPTIONS */
4207
4208 wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame_cmd");
4209 res = nl80211_send_frame_cmd(bss, freq, wait_time, data, data_len,
4210 use_cookie, no_cck, noack, offchanok,
4211 csa_offs, csa_offs_len);
4212
4213 return res;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004214}
4215
4216
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004217static int nl80211_put_basic_rates(struct nl_msg *msg, const int *basic_rates)
4218{
4219 u8 rates[NL80211_MAX_SUPP_RATES];
4220 u8 rates_len = 0;
4221 int i;
4222
4223 if (!basic_rates)
4224 return 0;
4225
4226 for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
4227 rates[rates_len++] = basic_rates[i] / 5;
4228
4229 return nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
4230}
4231
4232
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004233static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
4234 int slot, int ht_opmode, int ap_isolate,
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004235 const int *basic_rates)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004236{
4237 struct wpa_driver_nl80211_data *drv = bss->drv;
4238 struct nl_msg *msg;
4239
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004240 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_BSS)) ||
4241 (cts >= 0 &&
4242 nla_put_u8(msg, NL80211_ATTR_BSS_CTS_PROT, cts)) ||
4243 (preamble >= 0 &&
4244 nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble)) ||
4245 (slot >= 0 &&
4246 nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot)) ||
4247 (ht_opmode >= 0 &&
4248 nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) ||
4249 (ap_isolate >= 0 &&
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004250 nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)) ||
4251 nl80211_put_basic_rates(msg, basic_rates)) {
4252 nlmsg_free(msg);
4253 return -ENOBUFS;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004254 }
4255
Hai Shalom899fcc72020-10-19 14:38:18 -07004256 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004257}
4258
4259
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004260static int wpa_driver_nl80211_set_acl(void *priv,
4261 struct hostapd_acl_params *params)
4262{
4263 struct i802_bss *bss = priv;
4264 struct wpa_driver_nl80211_data *drv = bss->drv;
4265 struct nl_msg *msg;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004266 struct nl_msg *acl;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004267 unsigned int i;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004268 int ret;
Hai Shalomc1a21442022-02-04 13:43:00 -08004269 size_t acl_nla_sz, acl_nlmsg_sz, nla_sz, nlmsg_sz;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004270
4271 if (!(drv->capa.max_acl_mac_addrs))
4272 return -ENOTSUP;
4273
4274 if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
4275 return -ENOTSUP;
4276
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004277 wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
4278 params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
4279
Hai Shalomc1a21442022-02-04 13:43:00 -08004280 acl_nla_sz = nla_total_size(ETH_ALEN) * params->num_mac_acl;
4281 acl_nlmsg_sz = nlmsg_total_size(acl_nla_sz);
4282 acl = nlmsg_alloc_size(acl_nlmsg_sz);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004283 if (!acl)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004284 return -ENOMEM;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004285 for (i = 0; i < params->num_mac_acl; i++) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004286 if (nla_put(acl, i + 1, ETH_ALEN, params->mac_acl[i].addr)) {
4287 nlmsg_free(acl);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004288 return -ENOMEM;
4289 }
4290 }
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004291
Hai Shalomc1a21442022-02-04 13:43:00 -08004292 /*
4293 * genetlink message header (Length of user header is 0) +
4294 * u32 attr: NL80211_ATTR_IFINDEX +
4295 * u32 attr: NL80211_ATTR_ACL_POLICY +
4296 * nested acl attr
4297 */
4298 nla_sz = GENL_HDRLEN +
4299 nla_total_size(4) * 2 +
4300 nla_total_size(acl_nla_sz);
4301 nlmsg_sz = nlmsg_total_size(nla_sz);
4302 if (!(msg = nl80211_ifindex_msg_build(drv, nlmsg_alloc_size(nlmsg_sz),
4303 drv->ifindex, 0,
4304 NL80211_CMD_SET_MAC_ACL)) ||
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004305 nla_put_u32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
4306 NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
4307 NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED) ||
4308 nla_put_nested(msg, NL80211_ATTR_MAC_ADDRS, acl)) {
4309 nlmsg_free(msg);
4310 nlmsg_free(acl);
4311 return -ENOMEM;
4312 }
4313 nlmsg_free(acl);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004314
Hai Shalom899fcc72020-10-19 14:38:18 -07004315 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004316 if (ret) {
4317 wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
4318 ret, strerror(-ret));
4319 }
4320
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004321 return ret;
4322}
4323
4324
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004325static int nl80211_put_beacon_int(struct nl_msg *msg, int beacon_int)
4326{
4327 if (beacon_int > 0) {
4328 wpa_printf(MSG_DEBUG, " * beacon_int=%d", beacon_int);
4329 return nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
4330 beacon_int);
4331 }
4332
4333 return 0;
4334}
4335
4336
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004337static int nl80211_put_dtim_period(struct nl_msg *msg, int dtim_period)
4338{
4339 if (dtim_period > 0) {
4340 wpa_printf(MSG_DEBUG, " * dtim_period=%d", dtim_period);
4341 return nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
4342 }
4343
4344 return 0;
4345}
4346
4347
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004348#ifdef CONFIG_MESH
4349static int nl80211_set_mesh_config(void *priv,
4350 struct wpa_driver_mesh_bss_params *params)
4351{
4352 struct i802_bss *bss = priv;
4353 struct wpa_driver_nl80211_data *drv = bss->drv;
4354 struct nl_msg *msg;
4355 int ret;
4356
4357 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MESH_CONFIG);
4358 if (!msg)
4359 return -1;
4360
4361 ret = nl80211_put_mesh_config(msg, params);
4362 if (ret < 0) {
4363 nlmsg_free(msg);
4364 return ret;
4365 }
4366
Hai Shalom899fcc72020-10-19 14:38:18 -07004367 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004368 if (ret) {
4369 wpa_printf(MSG_ERROR,
4370 "nl80211: Mesh config set failed: %d (%s)",
4371 ret, strerror(-ret));
4372 return ret;
4373 }
4374 return 0;
4375}
4376#endif /* CONFIG_MESH */
4377
4378
Hai Shalom60840252021-02-19 19:02:11 -08004379static int nl80211_put_beacon_rate(struct nl_msg *msg, u64 flags, u64 flags2,
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004380 struct wpa_driver_ap_params *params)
4381{
4382 struct nlattr *bands, *band;
4383 struct nl80211_txrate_vht vht_rate;
Hai Shalom60840252021-02-19 19:02:11 -08004384 struct nl80211_txrate_he he_rate;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004385
4386 if (!params->freq ||
4387 (params->beacon_rate == 0 &&
4388 params->rate_type == BEACON_RATE_LEGACY))
4389 return 0;
4390
4391 bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
4392 if (!bands)
4393 return -1;
4394
4395 switch (params->freq->mode) {
4396 case HOSTAPD_MODE_IEEE80211B:
4397 case HOSTAPD_MODE_IEEE80211G:
4398 band = nla_nest_start(msg, NL80211_BAND_2GHZ);
4399 break;
4400 case HOSTAPD_MODE_IEEE80211A:
Hai Shalom60840252021-02-19 19:02:11 -08004401 if (is_6ghz_freq(params->freq->freq))
4402 band = nla_nest_start(msg, NL80211_BAND_6GHZ);
4403 else
4404 band = nla_nest_start(msg, NL80211_BAND_5GHZ);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004405 break;
4406 case HOSTAPD_MODE_IEEE80211AD:
4407 band = nla_nest_start(msg, NL80211_BAND_60GHZ);
4408 break;
4409 default:
4410 return 0;
4411 }
4412
4413 if (!band)
4414 return -1;
4415
4416 os_memset(&vht_rate, 0, sizeof(vht_rate));
Hai Shalom60840252021-02-19 19:02:11 -08004417 os_memset(&he_rate, 0, sizeof(he_rate));
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004418
4419 switch (params->rate_type) {
4420 case BEACON_RATE_LEGACY:
4421 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY)) {
4422 wpa_printf(MSG_INFO,
4423 "nl80211: Driver does not support setting Beacon frame rate (legacy)");
4424 return -1;
4425 }
4426
4427 if (nla_put_u8(msg, NL80211_TXRATE_LEGACY,
4428 (u8) params->beacon_rate / 5) ||
4429 nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
4430 (params->freq->vht_enabled &&
4431 nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4432 &vht_rate)))
4433 return -1;
4434
4435 wpa_printf(MSG_DEBUG, " * beacon_rate = legacy:%u (* 100 kbps)",
4436 params->beacon_rate);
4437 break;
4438 case BEACON_RATE_HT:
4439 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_HT)) {
4440 wpa_printf(MSG_INFO,
4441 "nl80211: Driver does not support setting Beacon frame rate (HT)");
4442 return -1;
4443 }
4444 if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
4445 nla_put_u8(msg, NL80211_TXRATE_HT, params->beacon_rate) ||
4446 (params->freq->vht_enabled &&
4447 nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4448 &vht_rate)))
4449 return -1;
4450 wpa_printf(MSG_DEBUG, " * beacon_rate = HT-MCS %u",
4451 params->beacon_rate);
4452 break;
4453 case BEACON_RATE_VHT:
4454 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_VHT)) {
4455 wpa_printf(MSG_INFO,
4456 "nl80211: Driver does not support setting Beacon frame rate (VHT)");
4457 return -1;
4458 }
4459 vht_rate.mcs[0] = BIT(params->beacon_rate);
4460 if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL))
4461 return -1;
4462 if (nla_put(msg, NL80211_TXRATE_HT, 0, NULL))
4463 return -1;
4464 if (nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4465 &vht_rate))
4466 return -1;
4467 wpa_printf(MSG_DEBUG, " * beacon_rate = VHT-MCS %u",
4468 params->beacon_rate);
4469 break;
Hai Shalom60840252021-02-19 19:02:11 -08004470 case BEACON_RATE_HE:
4471 if (!(flags2 & WPA_DRIVER_FLAGS2_BEACON_RATE_HE)) {
4472 wpa_printf(MSG_INFO,
4473 "nl80211: Driver does not support setting Beacon frame rate (HE)");
4474 return -1;
4475 }
4476 he_rate.mcs[0] = BIT(params->beacon_rate);
4477 if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
4478 nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
4479 nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4480 &vht_rate) ||
4481 nla_put(msg, NL80211_TXRATE_HE, sizeof(he_rate), &he_rate))
4482 return -1;
4483 wpa_printf(MSG_DEBUG, " * beacon_rate = HE-MCS %u",
4484 params->beacon_rate);
4485 break;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004486 }
4487
4488 nla_nest_end(msg, band);
4489 nla_nest_end(msg, bands);
4490
4491 return 0;
4492}
4493
4494
4495static int nl80211_set_multicast_to_unicast(struct i802_bss *bss,
4496 int multicast_to_unicast)
4497{
4498 struct wpa_driver_nl80211_data *drv = bss->drv;
4499 struct nl_msg *msg;
4500 int ret;
4501
4502 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_MULTICAST_TO_UNICAST);
4503 if (!msg ||
4504 (multicast_to_unicast &&
4505 nla_put_flag(msg, NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED))) {
4506 wpa_printf(MSG_ERROR,
4507 "nl80211: Failed to build NL80211_CMD_SET_MULTICAST_TO_UNICAST msg for %s",
4508 bss->ifname);
4509 nlmsg_free(msg);
4510 return -ENOBUFS;
4511 }
4512
Hai Shalom899fcc72020-10-19 14:38:18 -07004513 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004514
4515 switch (ret) {
4516 case 0:
4517 wpa_printf(MSG_DEBUG,
4518 "nl80211: multicast to unicast %s on interface %s",
4519 multicast_to_unicast ? "enabled" : "disabled",
4520 bss->ifname);
4521 break;
4522 case -EOPNOTSUPP:
4523 if (!multicast_to_unicast)
4524 break;
4525 wpa_printf(MSG_INFO,
4526 "nl80211: multicast to unicast not supported on interface %s",
4527 bss->ifname);
4528 break;
4529 default:
4530 wpa_printf(MSG_ERROR,
4531 "nl80211: %s multicast to unicast failed with %d (%s) on interface %s",
4532 multicast_to_unicast ? "enabling" : "disabling",
4533 ret, strerror(-ret), bss->ifname);
4534 break;
4535 }
4536
4537 return ret;
4538}
4539
4540
Hai Shalom60840252021-02-19 19:02:11 -08004541#ifdef CONFIG_SAE
4542static int nl80211_put_sae_pwe(struct nl_msg *msg, int pwe)
4543{
4544 u8 sae_pwe;
4545
4546 wpa_printf(MSG_DEBUG, "nl802111: sae_pwe=%d", pwe);
4547 if (pwe == 0)
4548 sae_pwe = NL80211_SAE_PWE_HUNT_AND_PECK;
4549 else if (pwe == 1)
4550 sae_pwe = NL80211_SAE_PWE_HASH_TO_ELEMENT;
4551 else if (pwe == 2)
4552 sae_pwe = NL80211_SAE_PWE_BOTH;
4553 else if (pwe == 3)
4554 return 0; /* special test mode */
4555 else
4556 return -1;
4557 if (nla_put_u8(msg, NL80211_ATTR_SAE_PWE, sae_pwe))
4558 return -1;
4559
4560 return 0;
4561}
4562#endif /* CONFIG_SAE */
4563
4564
4565#ifdef CONFIG_FILS
4566static int nl80211_fils_discovery(struct i802_bss *bss, struct nl_msg *msg,
4567 struct wpa_driver_ap_params *params)
4568{
4569 struct nlattr *attr;
4570
4571 if (!bss->drv->fils_discovery) {
4572 wpa_printf(MSG_ERROR,
4573 "nl80211: Driver does not support FILS Discovery frame transmission for %s",
4574 bss->ifname);
4575 return -1;
4576 }
4577
4578 attr = nla_nest_start(msg, NL80211_ATTR_FILS_DISCOVERY);
4579 if (!attr ||
4580 nla_put_u32(msg, NL80211_FILS_DISCOVERY_ATTR_INT_MIN,
4581 params->fd_min_int) ||
4582 nla_put_u32(msg, NL80211_FILS_DISCOVERY_ATTR_INT_MAX,
4583 params->fd_max_int) ||
4584 (params->fd_frame_tmpl &&
4585 nla_put(msg, NL80211_FILS_DISCOVERY_ATTR_TMPL,
4586 params->fd_frame_tmpl_len, params->fd_frame_tmpl)))
4587 return -1;
4588
4589 nla_nest_end(msg, attr);
4590 return 0;
4591}
4592#endif /* CONFIG_FILS */
4593
4594
4595#ifdef CONFIG_IEEE80211AX
4596static int nl80211_unsol_bcast_probe_resp(struct i802_bss *bss,
4597 struct nl_msg *msg,
4598 struct wpa_driver_ap_params *params)
4599{
4600 struct nlattr *attr;
4601
4602 if (!bss->drv->unsol_bcast_probe_resp) {
4603 wpa_printf(MSG_ERROR,
4604 "nl80211: Driver does not support unsolicited broadcast Probe Response frame transmission for %s",
4605 bss->ifname);
4606 return -1;
4607 }
4608
4609 wpa_printf(MSG_DEBUG,
4610 "nl80211: Unsolicited broadcast Probe Response frame interval: %u",
4611 params->unsol_bcast_probe_resp_interval);
4612 attr = nla_nest_start(msg, NL80211_ATTR_UNSOL_BCAST_PROBE_RESP);
4613 if (!attr ||
4614 nla_put_u32(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT,
4615 params->unsol_bcast_probe_resp_interval) ||
4616 (params->unsol_bcast_probe_resp_tmpl &&
4617 nla_put(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL,
4618 params->unsol_bcast_probe_resp_tmpl_len,
4619 params->unsol_bcast_probe_resp_tmpl)))
4620 return -1;
4621
4622 nla_nest_end(msg, attr);
4623 return 0;
4624}
4625#endif /* CONFIG_IEEE80211AX */
4626
4627
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004628static int wpa_driver_nl80211_set_ap(void *priv,
4629 struct wpa_driver_ap_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004630{
4631 struct i802_bss *bss = priv;
4632 struct wpa_driver_nl80211_data *drv = bss->drv;
4633 struct nl_msg *msg;
4634 u8 cmd = NL80211_CMD_NEW_BEACON;
Hai Shalom74f70d42019-02-11 14:42:39 -08004635 int ret = -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004636 int beacon_set;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004637 int num_suites;
Hai Shalomfdcde762020-04-02 11:19:20 -07004638 u32 suites[20], suite;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004639 u32 ver;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004640#ifdef CONFIG_MESH
4641 struct wpa_driver_mesh_bss_params mesh_params;
4642#endif /* CONFIG_MESH */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004643
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004644 beacon_set = params->reenable ? 0 : bss->beacon_set;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004645
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004646 wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
4647 beacon_set);
4648 if (beacon_set)
4649 cmd = NL80211_CMD_SET_BEACON;
Paul Stewart092955c2017-02-06 09:13:09 -08004650 else if (!drv->device_ap_sme && !drv->use_monitor &&
4651 !nl80211_get_wiphy_data_ap(bss))
4652 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004653
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004654 wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
4655 params->head, params->head_len);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004656 wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
4657 params->tail, params->tail_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004658 wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004659 wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004660 wpa_printf(MSG_DEBUG, "nl80211: beacon_rate=%u", params->beacon_rate);
4661 wpa_printf(MSG_DEBUG, "nl80211: rate_type=%d", params->rate_type);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004662 wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
Hai Shalom74f70d42019-02-11 14:42:39 -08004663 wpa_printf(MSG_DEBUG, "nl80211: ssid=%s",
4664 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004665 if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
4666 nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
4667 params->head) ||
4668 nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
4669 params->tail) ||
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004670 nl80211_put_beacon_int(msg, params->beacon_int) ||
Hai Shalom60840252021-02-19 19:02:11 -08004671 nl80211_put_beacon_rate(msg, drv->capa.flags, drv->capa.flags2,
4672 params) ||
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004673 nl80211_put_dtim_period(msg, params->dtim_period) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004674 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
4675 goto fail;
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004676 if (params->proberesp && params->proberesp_len) {
4677 wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
4678 params->proberesp, params->proberesp_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004679 if (nla_put(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
4680 params->proberesp))
4681 goto fail;
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004682 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004683 switch (params->hide_ssid) {
4684 case NO_SSID_HIDING:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004685 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004686 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
4687 NL80211_HIDDEN_SSID_NOT_IN_USE))
4688 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004689 break;
4690 case HIDDEN_SSID_ZERO_LEN:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004691 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004692 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
4693 NL80211_HIDDEN_SSID_ZERO_LEN))
4694 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004695 break;
4696 case HIDDEN_SSID_ZERO_CONTENTS:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004697 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004698 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
4699 NL80211_HIDDEN_SSID_ZERO_CONTENTS))
4700 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004701 break;
4702 }
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004703 wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004704 if (params->privacy &&
4705 nla_put_flag(msg, NL80211_ATTR_PRIVACY))
4706 goto fail;
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004707 wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004708 if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
4709 (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
4710 /* Leave out the attribute */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004711 } else if (params->auth_algs & WPA_AUTH_ALG_SHARED) {
4712 if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
4713 NL80211_AUTHTYPE_SHARED_KEY))
4714 goto fail;
4715 } else {
4716 if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
4717 NL80211_AUTHTYPE_OPEN_SYSTEM))
4718 goto fail;
4719 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004720
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004721 wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004722 ver = 0;
4723 if (params->wpa_version & WPA_PROTO_WPA)
4724 ver |= NL80211_WPA_VERSION_1;
4725 if (params->wpa_version & WPA_PROTO_RSN)
4726 ver |= NL80211_WPA_VERSION_2;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004727 if (ver &&
4728 nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
4729 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004730
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004731 wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
4732 params->key_mgmt_suites);
Hai Shalomfdcde762020-04-02 11:19:20 -07004733 num_suites = wpa_key_mgmt_to_suites(params->key_mgmt_suites,
4734 suites, ARRAY_SIZE(suites));
4735 if (num_suites > NL80211_MAX_NR_AKM_SUITES)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004736 wpa_printf(MSG_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07004737 "nl80211: Not enough room for all AKM suites (num_suites=%d > NL80211_MAX_NR_AKM_SUITES)",
4738 num_suites);
4739 else if (num_suites &&
4740 nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
4741 suites))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004742 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004743
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004744 if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004745 (!params->pairwise_ciphers ||
4746 params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
4747 (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
4748 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004749 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004750
Hai Shalom81f62d82019-07-22 12:10:00 -07004751 if (drv->device_ap_sme &&
4752 (params->key_mgmt_suites & WPA_KEY_MGMT_SAE) &&
4753 nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
4754 goto fail;
Hai Shalom5f92bc92019-04-18 11:54:11 -07004755
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004756 wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
4757 params->pairwise_ciphers);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004758 num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers,
4759 suites, ARRAY_SIZE(suites));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004760 if (num_suites &&
4761 nla_put(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
4762 num_suites * sizeof(u32), suites))
4763 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004764
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004765 wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
4766 params->group_cipher);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004767 suite = wpa_cipher_to_cipher_suite(params->group_cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004768 if (suite &&
4769 nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
4770 goto fail;
4771
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004772 if (params->beacon_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004773 wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
4774 params->beacon_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004775 if (nla_put(msg, NL80211_ATTR_IE,
4776 wpabuf_len(params->beacon_ies),
4777 wpabuf_head(params->beacon_ies)))
4778 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004779 }
4780 if (params->proberesp_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004781 wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
4782 params->proberesp_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004783 if (nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
4784 wpabuf_len(params->proberesp_ies),
4785 wpabuf_head(params->proberesp_ies)))
4786 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004787 }
4788 if (params->assocresp_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004789 wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
4790 params->assocresp_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004791 if (nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
4792 wpabuf_len(params->assocresp_ies),
4793 wpabuf_head(params->assocresp_ies)))
4794 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004795 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004796
Dmitry Shmidt04949592012-07-19 12:16:46 -07004797 if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004798 wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
4799 params->ap_max_inactivity);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004800 if (nla_put_u16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
4801 params->ap_max_inactivity))
4802 goto fail;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004803 }
4804
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004805#ifdef CONFIG_P2P
4806 if (params->p2p_go_ctwindow > 0) {
4807 if (drv->p2p_go_ctwindow_supported) {
4808 wpa_printf(MSG_DEBUG, "nl80211: P2P GO ctwindow=%d",
4809 params->p2p_go_ctwindow);
4810 if (nla_put_u8(msg, NL80211_ATTR_P2P_CTWINDOW,
4811 params->p2p_go_ctwindow))
4812 goto fail;
4813 } else {
4814 wpa_printf(MSG_INFO,
4815 "nl80211: Driver does not support CTWindow configuration - ignore this parameter");
4816 }
4817 }
4818#endif /* CONFIG_P2P */
4819
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004820 if (params->pbss) {
4821 wpa_printf(MSG_DEBUG, "nl80211: PBSS");
4822 if (nla_put_flag(msg, NL80211_ATTR_PBSS))
4823 goto fail;
4824 }
4825
Hai Shalom74f70d42019-02-11 14:42:39 -08004826 if (params->ftm_responder) {
4827 struct nlattr *ftm;
4828
4829 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_FTM_RESPONDER)) {
4830 ret = -ENOTSUP;
4831 goto fail;
4832 }
4833
4834 ftm = nla_nest_start(msg, NL80211_ATTR_FTM_RESPONDER);
4835 if (!ftm ||
4836 nla_put_flag(msg, NL80211_FTM_RESP_ATTR_ENABLED) ||
4837 (params->lci &&
4838 nla_put(msg, NL80211_FTM_RESP_ATTR_LCI,
4839 wpabuf_len(params->lci),
4840 wpabuf_head(params->lci))) ||
4841 (params->civic &&
4842 nla_put(msg, NL80211_FTM_RESP_ATTR_CIVICLOC,
4843 wpabuf_len(params->civic),
4844 wpabuf_head(params->civic))))
4845 goto fail;
4846 nla_nest_end(msg, ftm);
4847 }
4848
Hai Shalomc3565922019-10-28 11:58:20 -07004849#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08004850 if (params->he_spr_ctrl) {
Hai Shalomc3565922019-10-28 11:58:20 -07004851 struct nlattr *spr;
4852
4853 spr = nla_nest_start(msg, NL80211_ATTR_HE_OBSS_PD);
Hai Shalom60840252021-02-19 19:02:11 -08004854 wpa_printf(MSG_DEBUG, "nl80211: he_spr_ctrl=0x%x",
4855 params->he_spr_ctrl);
Hai Shalomc3565922019-10-28 11:58:20 -07004856
Hai Shalomfdcde762020-04-02 11:19:20 -07004857 if (!spr ||
Hai Shalom60840252021-02-19 19:02:11 -08004858 nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_SR_CTRL,
4859 params->he_spr_ctrl) ||
4860 ((params->he_spr_ctrl &
4861 SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) &&
4862 nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET,
4863 params->he_spr_non_srg_obss_pd_max_offset)))
4864 goto fail;
4865
4866 if ((params->he_spr_ctrl &
4867 SPATIAL_REUSE_SRG_INFORMATION_PRESENT) &&
4868 (nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
4869 params->he_spr_srg_obss_pd_min_offset) ||
4870 nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
4871 params->he_spr_srg_obss_pd_max_offset) ||
4872 nla_put(msg, NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP,
4873 sizeof(params->he_spr_bss_color_bitmap),
4874 params->he_spr_bss_color_bitmap) ||
4875 nla_put(msg, NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP,
4876 sizeof(params->he_spr_partial_bssid_bitmap),
4877 params->he_spr_partial_bssid_bitmap)))
Hai Shalomc3565922019-10-28 11:58:20 -07004878 goto fail;
4879
4880 nla_nest_end(msg, spr);
4881 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004882
4883 if (params->freq && params->freq->he_enabled) {
4884 struct nlattr *bss_color;
4885
4886 bss_color = nla_nest_start(msg, NL80211_ATTR_HE_BSS_COLOR);
4887 if (!bss_color ||
4888 (params->he_bss_color_disabled &&
4889 nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_DISABLED)) ||
4890 (params->he_bss_color_partial &&
4891 nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_PARTIAL)) ||
4892 nla_put_u8(msg, NL80211_HE_BSS_COLOR_ATTR_COLOR,
4893 params->he_bss_color))
4894 goto fail;
4895 nla_nest_end(msg, bss_color);
4896 }
4897
4898 if (params->twt_responder) {
4899 wpa_printf(MSG_DEBUG, "nl80211: twt_responder=%d",
4900 params->twt_responder);
4901 if (nla_put_flag(msg, NL80211_ATTR_TWT_RESPONDER))
4902 goto fail;
4903 }
Hai Shalom60840252021-02-19 19:02:11 -08004904
4905 if (params->unsol_bcast_probe_resp_interval &&
4906 nl80211_unsol_bcast_probe_resp(bss, msg, params) < 0)
4907 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07004908#endif /* CONFIG_IEEE80211AX */
4909
Hai Shalom60840252021-02-19 19:02:11 -08004910#ifdef CONFIG_SAE
4911 if (((params->key_mgmt_suites & WPA_KEY_MGMT_SAE) ||
4912 (params->key_mgmt_suites & WPA_KEY_MGMT_FT_SAE)) &&
4913 nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
4914 goto fail;
4915#endif /* CONFIG_SAE */
4916
4917#ifdef CONFIG_FILS
4918 if (params->fd_max_int && nl80211_fils_discovery(bss, msg, params) < 0)
4919 goto fail;
4920#endif /* CONFIG_FILS */
4921
Hai Shalomc1a21442022-02-04 13:43:00 -08004922 ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004923 if (ret) {
4924 wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
4925 ret, strerror(-ret));
4926 } else {
4927 bss->beacon_set = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004928 nl80211_set_bss(bss, params->cts_protect, params->preamble,
4929 params->short_slot_time, params->ht_opmode,
4930 params->isolate, params->basic_rates);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004931 nl80211_set_multicast_to_unicast(bss,
4932 params->multicast_to_unicast);
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004933 if (beacon_set && params->freq &&
4934 params->freq->bandwidth != bss->bandwidth) {
4935 wpa_printf(MSG_DEBUG,
4936 "nl80211: Update BSS %s bandwidth: %d -> %d",
4937 bss->ifname, bss->bandwidth,
4938 params->freq->bandwidth);
4939 ret = nl80211_set_channel(bss, params->freq, 1);
4940 if (ret) {
4941 wpa_printf(MSG_DEBUG,
4942 "nl80211: Frequency set failed: %d (%s)",
4943 ret, strerror(-ret));
4944 } else {
4945 wpa_printf(MSG_DEBUG,
4946 "nl80211: Frequency set succeeded for ht2040 coex");
4947 bss->bandwidth = params->freq->bandwidth;
4948 }
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004949 } else if (!beacon_set && params->freq) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004950 /*
4951 * cfg80211 updates the driver on frequence change in AP
4952 * mode only at the point when beaconing is started, so
4953 * set the initial value here.
4954 */
4955 bss->bandwidth = params->freq->bandwidth;
4956 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004957 }
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004958
4959#ifdef CONFIG_MESH
4960 if (is_mesh_interface(drv->nlmode) && params->ht_opmode != -1) {
4961 os_memset(&mesh_params, 0, sizeof(mesh_params));
4962 mesh_params.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
4963 mesh_params.ht_opmode = params->ht_opmode;
4964 ret = nl80211_set_mesh_config(priv, &mesh_params);
4965 if (ret < 0)
4966 return ret;
4967 }
4968#endif /* CONFIG_MESH */
4969
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004970 return ret;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004971fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004972 nlmsg_free(msg);
Hai Shalom74f70d42019-02-11 14:42:39 -08004973 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004974}
4975
4976
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08004977static int nl80211_put_freq_params(struct nl_msg *msg,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004978 const struct hostapd_freq_params *freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004979{
Hai Shalomc3565922019-10-28 11:58:20 -07004980 enum hostapd_hw_mode hw_mode;
4981 int is_24ghz;
4982 u8 channel;
4983
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004984 wpa_printf(MSG_DEBUG, " * freq=%d", freq->freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004985 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
4986 return -ENOBUFS;
4987
Hai Shalom81f62d82019-07-22 12:10:00 -07004988 wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004989 wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
4990 wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
4991
Hai Shalomc3565922019-10-28 11:58:20 -07004992 hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
4993 is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
4994 hw_mode == HOSTAPD_MODE_IEEE80211B;
4995
4996 if (freq->vht_enabled || (freq->he_enabled && !is_24ghz)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004997 enum nl80211_chan_width cw;
4998
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004999 wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005000 switch (freq->bandwidth) {
5001 case 20:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005002 cw = NL80211_CHAN_WIDTH_20;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005003 break;
5004 case 40:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005005 cw = NL80211_CHAN_WIDTH_40;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005006 break;
5007 case 80:
5008 if (freq->center_freq2)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005009 cw = NL80211_CHAN_WIDTH_80P80;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005010 else
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005011 cw = NL80211_CHAN_WIDTH_80;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005012 break;
5013 case 160:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005014 cw = NL80211_CHAN_WIDTH_160;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005015 break;
5016 default:
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005017 return -EINVAL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005018 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005019
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005020 wpa_printf(MSG_DEBUG, " * channel_width=%d", cw);
5021 wpa_printf(MSG_DEBUG, " * center_freq1=%d",
5022 freq->center_freq1);
5023 wpa_printf(MSG_DEBUG, " * center_freq2=%d",
5024 freq->center_freq2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005025 if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) ||
5026 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1,
5027 freq->center_freq1) ||
5028 (freq->center_freq2 &&
5029 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2,
5030 freq->center_freq2)))
5031 return -ENOBUFS;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005032 } else if (freq->ht_enabled) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005033 enum nl80211_channel_type ct;
5034
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005035 wpa_printf(MSG_DEBUG, " * sec_channel_offset=%d",
5036 freq->sec_channel_offset);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005037 switch (freq->sec_channel_offset) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005038 case -1:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005039 ct = NL80211_CHAN_HT40MINUS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005040 break;
5041 case 1:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005042 ct = NL80211_CHAN_HT40PLUS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005043 break;
5044 default:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005045 ct = NL80211_CHAN_HT20;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005046 break;
5047 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005048
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005049 wpa_printf(MSG_DEBUG, " * channel_type=%d", ct);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005050 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
5051 return -ENOBUFS;
Hai Shalomc3565922019-10-28 11:58:20 -07005052 } else if (freq->edmg.channels && freq->edmg.bw_config) {
5053 wpa_printf(MSG_DEBUG,
5054 " * EDMG configuration: channels=0x%x bw_config=%d",
5055 freq->edmg.channels, freq->edmg.bw_config);
5056 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
5057 freq->edmg.channels) ||
5058 nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
5059 freq->edmg.bw_config))
5060 return -1;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005061 } else {
5062 wpa_printf(MSG_DEBUG, " * channel_type=%d",
5063 NL80211_CHAN_NO_HT);
5064 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
5065 NL80211_CHAN_NO_HT))
5066 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005067 }
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005068 return 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005069}
5070
5071
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005072static int nl80211_set_channel(struct i802_bss *bss,
5073 struct hostapd_freq_params *freq, int set_chan)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005074{
5075 struct wpa_driver_nl80211_data *drv = bss->drv;
5076 struct nl_msg *msg;
5077 int ret;
5078
5079 wpa_printf(MSG_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07005080 "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
5081 freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005082 freq->bandwidth, freq->center_freq1, freq->center_freq2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005083
5084 msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
5085 NL80211_CMD_SET_WIPHY);
5086 if (!msg || nl80211_put_freq_params(msg, freq) < 0) {
5087 nlmsg_free(msg);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005088 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005089 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005090
Hai Shalom899fcc72020-10-19 14:38:18 -07005091 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005092 if (ret == 0) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005093 bss->freq = freq->freq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005094 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005095 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005096 wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005097 "%d (%s)", freq->freq, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005098 return -1;
5099}
5100
5101
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005102static u32 sta_flags_nl80211(int flags)
5103{
5104 u32 f = 0;
5105
5106 if (flags & WPA_STA_AUTHORIZED)
5107 f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
5108 if (flags & WPA_STA_WMM)
5109 f |= BIT(NL80211_STA_FLAG_WME);
5110 if (flags & WPA_STA_SHORT_PREAMBLE)
5111 f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
5112 if (flags & WPA_STA_MFP)
5113 f |= BIT(NL80211_STA_FLAG_MFP);
5114 if (flags & WPA_STA_TDLS_PEER)
5115 f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005116 if (flags & WPA_STA_AUTHENTICATED)
5117 f |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005118 if (flags & WPA_STA_ASSOCIATED)
5119 f |= BIT(NL80211_STA_FLAG_ASSOCIATED);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005120
5121 return f;
5122}
5123
5124
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005125#ifdef CONFIG_MESH
5126static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
5127{
5128 switch (state) {
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005129 case PLINK_IDLE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005130 return NL80211_PLINK_LISTEN;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005131 case PLINK_OPN_SNT:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005132 return NL80211_PLINK_OPN_SNT;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005133 case PLINK_OPN_RCVD:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005134 return NL80211_PLINK_OPN_RCVD;
5135 case PLINK_CNF_RCVD:
5136 return NL80211_PLINK_CNF_RCVD;
5137 case PLINK_ESTAB:
5138 return NL80211_PLINK_ESTAB;
5139 case PLINK_HOLDING:
5140 return NL80211_PLINK_HOLDING;
5141 case PLINK_BLOCKED:
5142 return NL80211_PLINK_BLOCKED;
5143 default:
5144 wpa_printf(MSG_ERROR, "nl80211: Invalid mesh plink state %d",
5145 state);
5146 }
5147 return -1;
5148}
5149#endif /* CONFIG_MESH */
5150
5151
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005152static int wpa_driver_nl80211_sta_add(void *priv,
5153 struct hostapd_sta_add_params *params)
5154{
5155 struct i802_bss *bss = priv;
5156 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005157 struct nl_msg *msg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005158 struct nl80211_sta_flag_update upd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005159 int ret = -ENOBUFS;
5160
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005161 if ((params->flags & WPA_STA_TDLS_PEER) &&
5162 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
5163 return -EOPNOTSUPP;
5164
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005165 wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
5166 params->set ? "Set" : "Add", MAC2STR(params->addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005167 msg = nl80211_bss_msg(bss, 0, params->set ? NL80211_CMD_SET_STATION :
5168 NL80211_CMD_NEW_STATION);
5169 if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
5170 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005171
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005172 /*
5173 * Set the below properties only in one of the following cases:
5174 * 1. New station is added, already associated.
5175 * 2. Set WPA_STA_TDLS_PEER station.
5176 * 3. Set an already added unassociated station, if driver supports
5177 * full AP client state. (Set these properties after station became
5178 * associated will be rejected by the driver).
5179 */
5180 if (!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
5181 (params->set && FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags) &&
5182 (params->flags & WPA_STA_ASSOCIATED))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005183 wpa_hexdump(MSG_DEBUG, " * supported rates",
5184 params->supp_rates, params->supp_rates_len);
5185 wpa_printf(MSG_DEBUG, " * capability=0x%x",
5186 params->capability);
5187 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_RATES,
5188 params->supp_rates_len, params->supp_rates) ||
5189 nla_put_u16(msg, NL80211_ATTR_STA_CAPABILITY,
5190 params->capability))
5191 goto fail;
5192
5193 if (params->ht_capabilities) {
5194 wpa_hexdump(MSG_DEBUG, " * ht_capabilities",
5195 (u8 *) params->ht_capabilities,
5196 sizeof(*params->ht_capabilities));
5197 if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY,
5198 sizeof(*params->ht_capabilities),
5199 params->ht_capabilities))
5200 goto fail;
5201 }
5202
5203 if (params->vht_capabilities) {
5204 wpa_hexdump(MSG_DEBUG, " * vht_capabilities",
5205 (u8 *) params->vht_capabilities,
5206 sizeof(*params->vht_capabilities));
5207 if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY,
5208 sizeof(*params->vht_capabilities),
5209 params->vht_capabilities))
5210 goto fail;
5211 }
5212
Hai Shalom81f62d82019-07-22 12:10:00 -07005213 if (params->he_capab) {
5214 wpa_hexdump(MSG_DEBUG, " * he_capab",
5215 params->he_capab, params->he_capab_len);
5216 if (nla_put(msg, NL80211_ATTR_HE_CAPABILITY,
5217 params->he_capab_len, params->he_capab))
5218 goto fail;
5219 }
5220
Hai Shalom60840252021-02-19 19:02:11 -08005221 if (params->he_6ghz_capab) {
5222 wpa_hexdump(MSG_DEBUG, " * he_6ghz_capab",
5223 params->he_6ghz_capab,
5224 sizeof(*params->he_6ghz_capab));
5225 if (nla_put(msg, NL80211_ATTR_HE_6GHZ_CAPABILITY,
5226 sizeof(*params->he_6ghz_capab),
5227 params->he_6ghz_capab))
5228 goto fail;
5229 }
5230
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005231 if (params->ext_capab) {
5232 wpa_hexdump(MSG_DEBUG, " * ext_capab",
5233 params->ext_capab, params->ext_capab_len);
5234 if (nla_put(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
5235 params->ext_capab_len, params->ext_capab))
5236 goto fail;
5237 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005238
5239 if (is_ap_interface(drv->nlmode) &&
5240 nla_put_u8(msg, NL80211_ATTR_STA_SUPPORT_P2P_PS,
5241 params->support_p2p_ps ?
5242 NL80211_P2P_PS_SUPPORTED :
5243 NL80211_P2P_PS_UNSUPPORTED))
5244 goto fail;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005245 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005246 if (!params->set) {
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005247 if (params->aid) {
5248 wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005249 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid))
5250 goto fail;
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005251 } else {
5252 /*
5253 * cfg80211 validates that AID is non-zero, so we have
5254 * to make this a non-zero value for the TDLS case where
Hai Shalomc1a21442022-02-04 13:43:00 -08005255 * a stub STA entry is used for now and for a station
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005256 * that is still not associated.
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005257 */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005258 wpa_printf(MSG_DEBUG, " * aid=1 (%s workaround)",
5259 (params->flags & WPA_STA_TDLS_PEER) ?
5260 "TDLS" : "UNASSOC_STA");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005261 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, 1))
5262 goto fail;
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005263 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005264 wpa_printf(MSG_DEBUG, " * listen_interval=%u",
5265 params->listen_interval);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005266 if (nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
5267 params->listen_interval))
5268 goto fail;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07005269 } else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
5270 wpa_printf(MSG_DEBUG, " * peer_aid=%u", params->aid);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005271 if (nla_put_u16(msg, NL80211_ATTR_PEER_AID, params->aid))
5272 goto fail;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005273 } else if (FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags) &&
5274 (params->flags & WPA_STA_ASSOCIATED)) {
5275 wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
5276 wpa_printf(MSG_DEBUG, " * listen_interval=%u",
5277 params->listen_interval);
5278 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid) ||
5279 nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
5280 params->listen_interval))
5281 goto fail;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005282 }
5283
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08005284 if (params->vht_opmode_enabled) {
5285 wpa_printf(MSG_DEBUG, " * opmode=%u", params->vht_opmode);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005286 if (nla_put_u8(msg, NL80211_ATTR_OPMODE_NOTIF,
5287 params->vht_opmode))
5288 goto fail;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005289 }
5290
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005291 if (params->supp_channels) {
5292 wpa_hexdump(MSG_DEBUG, " * supported channels",
5293 params->supp_channels, params->supp_channels_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005294 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
5295 params->supp_channels_len, params->supp_channels))
5296 goto fail;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005297 }
5298
5299 if (params->supp_oper_classes) {
5300 wpa_hexdump(MSG_DEBUG, " * supported operating classes",
5301 params->supp_oper_classes,
5302 params->supp_oper_classes_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005303 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
5304 params->supp_oper_classes_len,
5305 params->supp_oper_classes))
5306 goto fail;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005307 }
5308
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005309 os_memset(&upd, 0, sizeof(upd));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005310 upd.set = sta_flags_nl80211(params->flags);
5311 upd.mask = upd.set | sta_flags_nl80211(params->flags_mask);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005312
5313 /*
5314 * If the driver doesn't support full AP client state, ignore ASSOC/AUTH
5315 * flags, as nl80211 driver moves a new station, by default, into
5316 * associated state.
5317 *
5318 * On the other hand, if the driver supports that feature and the
5319 * station is added in unauthenticated state, set the
5320 * authenticated/associated bits in the mask to prevent moving this
5321 * station to associated state before it is actually associated.
5322 *
5323 * This is irrelevant for mesh mode where the station is added to the
5324 * driver as authenticated already, and ASSOCIATED isn't part of the
5325 * nl80211 API.
5326 */
5327 if (!is_mesh_interface(drv->nlmode)) {
5328 if (!FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) {
5329 wpa_printf(MSG_DEBUG,
5330 "nl80211: Ignore ASSOC/AUTH flags since driver doesn't support full AP client state");
5331 upd.mask &= ~(BIT(NL80211_STA_FLAG_ASSOCIATED) |
5332 BIT(NL80211_STA_FLAG_AUTHENTICATED));
5333 } else if (!params->set &&
5334 !(params->flags & WPA_STA_TDLS_PEER)) {
5335 if (!(params->flags & WPA_STA_AUTHENTICATED))
5336 upd.mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
5337 if (!(params->flags & WPA_STA_ASSOCIATED))
5338 upd.mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
5339 }
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005340#ifdef CONFIG_MESH
5341 } else {
5342 if (params->plink_state == PLINK_ESTAB && params->peer_aid) {
5343 ret = nla_put_u16(msg, NL80211_ATTR_MESH_PEER_AID,
5344 params->peer_aid);
5345 if (ret)
5346 goto fail;
5347 }
5348#endif /* CONFIG_MESH */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005349 }
5350
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005351 wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x",
5352 upd.set, upd.mask);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005353 if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
5354 goto fail;
5355
5356#ifdef CONFIG_MESH
5357 if (params->plink_state &&
5358 nla_put_u8(msg, NL80211_ATTR_STA_PLINK_STATE,
5359 sta_plink_state_nl80211(params->plink_state)))
5360 goto fail;
5361#endif /* CONFIG_MESH */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005362
Hai Shalomc3565922019-10-28 11:58:20 -07005363 if ((!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
5364 FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) &&
5365 (params->flags & WPA_STA_WMM)) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005366 struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
5367
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005368 wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005369 if (!wme ||
5370 nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
5371 params->qosinfo & WMM_QOSINFO_STA_AC_MASK) ||
5372 nla_put_u8(msg, NL80211_STA_WME_MAX_SP,
5373 (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
5374 WMM_QOSINFO_STA_SP_MASK))
5375 goto fail;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005376 nla_nest_end(msg, wme);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005377 }
5378
Hai Shalom899fcc72020-10-19 14:38:18 -07005379 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005380 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005381 if (ret)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005382 wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
5383 "result: %d (%s)", params->set ? "SET" : "NEW", ret,
5384 strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005385 if (ret == -EEXIST)
5386 ret = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005387fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005388 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005389 return ret;
5390}
5391
5392
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005393static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr)
5394{
5395#ifdef CONFIG_LIBNL3_ROUTE
5396 struct wpa_driver_nl80211_data *drv = bss->drv;
5397 struct rtnl_neigh *rn;
5398 struct nl_addr *nl_addr;
5399 int err;
5400
5401 rn = rtnl_neigh_alloc();
5402 if (!rn)
5403 return;
5404
5405 rtnl_neigh_set_family(rn, AF_BRIDGE);
5406 rtnl_neigh_set_ifindex(rn, bss->ifindex);
5407 nl_addr = nl_addr_build(AF_BRIDGE, (void *) addr, ETH_ALEN);
5408 if (!nl_addr) {
5409 rtnl_neigh_put(rn);
5410 return;
5411 }
5412 rtnl_neigh_set_lladdr(rn, nl_addr);
5413
5414 err = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
5415 if (err < 0) {
5416 wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for "
5417 MACSTR " ifindex=%d failed: %s", MAC2STR(addr),
5418 bss->ifindex, nl_geterror(err));
5419 } else {
5420 wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry for "
5421 MACSTR, MAC2STR(addr));
5422 }
5423
5424 nl_addr_put(nl_addr);
5425 rtnl_neigh_put(rn);
5426#endif /* CONFIG_LIBNL3_ROUTE */
5427}
5428
5429
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005430static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
5431 int deauth, u16 reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005432{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005433 struct wpa_driver_nl80211_data *drv = bss->drv;
5434 struct nl_msg *msg;
5435 int ret;
5436
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005437 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION)) ||
5438 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
5439 (deauth == 0 &&
5440 nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
5441 WLAN_FC_STYPE_DISASSOC)) ||
5442 (deauth == 1 &&
5443 nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
5444 WLAN_FC_STYPE_DEAUTH)) ||
5445 (reason_code &&
5446 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code))) {
5447 nlmsg_free(msg);
5448 return -ENOBUFS;
5449 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005450
Hai Shalom899fcc72020-10-19 14:38:18 -07005451 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07005452 wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
5453 " --> %d (%s)",
5454 bss->ifname, MAC2STR(addr), ret, strerror(-ret));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005455
5456 if (drv->rtnl_sk)
5457 rtnl_neigh_delete_fdb_entry(bss, addr);
5458
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005459 if (ret == -ENOENT)
5460 return 0;
5461 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005462}
5463
5464
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005465void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005466{
5467 struct nl_msg *msg;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005468 struct wpa_driver_nl80211_data *drv2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005469
5470 wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
5471
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005472 /* stop listening for EAPOL on this interface */
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005473 dl_list_for_each(drv2, &drv->global->interfaces,
5474 struct wpa_driver_nl80211_data, list)
Dmitry Shmidt9c175262016-03-03 10:20:07 -08005475 {
5476 del_ifidx(drv2, ifidx, IFIDX_ANY);
5477 /* Remove all bridges learned for this iface */
5478 del_ifidx(drv2, IFIDX_ANY, ifidx);
5479 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005480
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005481 msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
Hai Shalom899fcc72020-10-19 14:38:18 -07005482 if (send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005483 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005484 wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
5485}
5486
5487
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07005488const char * nl80211_iftype_str(enum nl80211_iftype mode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005489{
5490 switch (mode) {
5491 case NL80211_IFTYPE_ADHOC:
5492 return "ADHOC";
5493 case NL80211_IFTYPE_STATION:
5494 return "STATION";
5495 case NL80211_IFTYPE_AP:
5496 return "AP";
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07005497 case NL80211_IFTYPE_AP_VLAN:
5498 return "AP_VLAN";
5499 case NL80211_IFTYPE_WDS:
5500 return "WDS";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005501 case NL80211_IFTYPE_MONITOR:
5502 return "MONITOR";
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07005503 case NL80211_IFTYPE_MESH_POINT:
5504 return "MESH_POINT";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005505 case NL80211_IFTYPE_P2P_CLIENT:
5506 return "P2P_CLIENT";
5507 case NL80211_IFTYPE_P2P_GO:
5508 return "P2P_GO";
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005509 case NL80211_IFTYPE_P2P_DEVICE:
5510 return "P2P_DEVICE";
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005511 case NL80211_IFTYPE_OCB:
5512 return "OCB";
5513 case NL80211_IFTYPE_NAN:
5514 return "NAN";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005515 default:
5516 return "unknown";
5517 }
5518}
5519
5520
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005521static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
5522 const char *ifname,
5523 enum nl80211_iftype iftype,
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005524 const u8 *addr, int wds,
5525 int (*handler)(struct nl_msg *, void *),
5526 void *arg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005527{
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005528 struct nl_msg *msg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005529 int ifidx;
5530 int ret = -ENOBUFS;
5531
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005532 wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
5533 iftype, nl80211_iftype_str(iftype));
5534
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005535 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_NEW_INTERFACE);
5536 if (!msg ||
5537 nla_put_string(msg, NL80211_ATTR_IFNAME, ifname) ||
5538 nla_put_u32(msg, NL80211_ATTR_IFTYPE, iftype))
5539 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005540
5541 if (iftype == NL80211_IFTYPE_MONITOR) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005542 struct nlattr *flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005543
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005544 flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005545 if (!flags ||
5546 nla_put_flag(msg, NL80211_MNTR_FLAG_COOK_FRAMES))
5547 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005548
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005549 nla_nest_end(msg, flags);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005550 } else if (wds) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005551 if (nla_put_u8(msg, NL80211_ATTR_4ADDR, wds))
5552 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005553 }
5554
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07005555 /*
5556 * Tell cfg80211 that the interface belongs to the socket that created
5557 * it, and the interface should be deleted when the socket is closed.
5558 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005559 if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
5560 goto fail;
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07005561
Hai Shalom60840252021-02-19 19:02:11 -08005562 if ((addr && iftype == NL80211_IFTYPE_P2P_DEVICE) &&
5563 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
5564 goto fail;
5565
Hai Shalom899fcc72020-10-19 14:38:18 -07005566 ret = send_and_recv_msgs(drv, msg, handler, arg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005567 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005568 if (ret) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005569 fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005570 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005571 wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
5572 ifname, ret, strerror(-ret));
5573 return ret;
5574 }
5575
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005576 if (iftype == NL80211_IFTYPE_P2P_DEVICE)
5577 return 0;
5578
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005579 ifidx = if_nametoindex(ifname);
5580 wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
5581 ifname, ifidx);
5582
5583 if (ifidx <= 0)
5584 return -1;
5585
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005586 /*
5587 * Some virtual interfaces need to process EAPOL packets and events on
5588 * the parent interface. This is used mainly with hostapd.
5589 */
5590 if (drv->hostapd ||
5591 iftype == NL80211_IFTYPE_AP_VLAN ||
5592 iftype == NL80211_IFTYPE_WDS ||
5593 iftype == NL80211_IFTYPE_MONITOR) {
5594 /* start listening for EAPOL on this interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08005595 add_ifidx(drv, ifidx, IFIDX_ANY);
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005596 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005597
5598 if (addr && iftype != NL80211_IFTYPE_MONITOR &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005599 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005600 nl80211_remove_iface(drv, ifidx);
5601 return -1;
5602 }
5603
5604 return ifidx;
5605}
5606
5607
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005608int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
5609 const char *ifname, enum nl80211_iftype iftype,
5610 const u8 *addr, int wds,
5611 int (*handler)(struct nl_msg *, void *),
5612 void *arg, int use_existing)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005613{
5614 int ret;
5615
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005616 ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
5617 arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005618
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005619 /* if error occurred and interface exists already */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005620 if (ret == -ENFILE && if_nametoindex(ifname)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005621 if (use_existing) {
5622 wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s",
5623 ifname);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07005624 if (addr && iftype != NL80211_IFTYPE_MONITOR &&
5625 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
5626 addr) < 0 &&
5627 (linux_set_iface_flags(drv->global->ioctl_sock,
5628 ifname, 0) < 0 ||
5629 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
5630 addr) < 0 ||
5631 linux_set_iface_flags(drv->global->ioctl_sock,
5632 ifname, 1) < 0))
5633 return -1;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005634 return -ENFILE;
5635 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005636 wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
5637
5638 /* Try to remove the interface that was already there. */
5639 nl80211_remove_iface(drv, if_nametoindex(ifname));
5640
5641 /* Try to create the interface again */
5642 ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005643 wds, handler, arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005644 }
5645
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005646 if (ret >= 0 && is_p2p_net_interface(iftype)) {
5647 wpa_printf(MSG_DEBUG,
5648 "nl80211: Interface %s created for P2P - disable 11b rates",
5649 ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005650 nl80211_disable_11b_rates(drv, ret, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005651 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005652
5653 return ret;
5654}
5655
5656
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005657static int nl80211_setup_ap(struct i802_bss *bss)
5658{
5659 struct wpa_driver_nl80211_data *drv = bss->drv;
5660
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005661 wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d use_monitor=%d",
5662 bss->ifname, drv->device_ap_sme, drv->use_monitor);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005663
5664 /*
5665 * Disable Probe Request reporting unless we need it in this way for
5666 * devices that include the AP SME, in the other case (unless using
5667 * monitor iface) we'll get it through the nl_mgmt socket instead.
5668 */
5669 if (!drv->device_ap_sme)
5670 wpa_driver_nl80211_probe_req_report(bss, 0);
5671
5672 if (!drv->device_ap_sme && !drv->use_monitor)
5673 if (nl80211_mgmt_subscribe_ap(bss))
5674 return -1;
5675
5676 if (drv->device_ap_sme && !drv->use_monitor)
5677 if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005678 wpa_printf(MSG_DEBUG,
5679 "nl80211: Failed to subscribe for mgmt frames from SME driver - trying to run without it");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005680
5681 if (!drv->device_ap_sme && drv->use_monitor &&
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005682 nl80211_create_monitor_interface(drv) &&
5683 !drv->device_ap_sme)
Dmitry Shmidt04949592012-07-19 12:16:46 -07005684 return -1;
5685
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005686 if (drv->device_ap_sme &&
5687 wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
5688 wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
5689 "Probe Request frame reporting in AP mode");
5690 /* Try to survive without this */
5691 }
5692
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005693 return 0;
5694}
5695
5696
5697static void nl80211_teardown_ap(struct i802_bss *bss)
5698{
5699 struct wpa_driver_nl80211_data *drv = bss->drv;
5700
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005701 wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d use_monitor=%d",
5702 bss->ifname, drv->device_ap_sme, drv->use_monitor);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005703 if (drv->device_ap_sme) {
5704 wpa_driver_nl80211_probe_req_report(bss, 0);
5705 if (!drv->use_monitor)
5706 nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
5707 } else if (drv->use_monitor)
5708 nl80211_remove_monitor_interface(drv);
5709 else
5710 nl80211_mgmt_unsubscribe(bss, "AP teardown");
5711
Paul Stewart092955c2017-02-06 09:13:09 -08005712 nl80211_put_wiphy_data_ap(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005713 bss->beacon_set = 0;
5714}
5715
5716
Hai Shalomfdcde762020-04-02 11:19:20 -07005717static int nl80211_tx_control_port(void *priv, const u8 *dest,
5718 u16 proto, const u8 *buf, size_t len,
5719 int no_encrypt)
5720{
Hai Shalom899fcc72020-10-19 14:38:18 -07005721 struct nl80211_ack_ext_arg ext_arg;
Hai Shalomfdcde762020-04-02 11:19:20 -07005722 struct i802_bss *bss = priv;
5723 struct nl_msg *msg;
Hai Shalom899fcc72020-10-19 14:38:18 -07005724 u64 cookie = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07005725 int ret;
5726
5727 wpa_printf(MSG_DEBUG,
5728 "nl80211: Send over control port dest=" MACSTR
5729 " proto=0x%04x len=%u no_encrypt=%d",
5730 MAC2STR(dest), proto, (unsigned int) len, no_encrypt);
5731
5732 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CONTROL_PORT_FRAME);
5733 if (!msg ||
5734 nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
5735 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dest) ||
5736 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
5737 (no_encrypt &&
5738 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) {
5739 nlmsg_free(msg);
5740 return -ENOBUFS;
5741 }
5742
Hai Shalom899fcc72020-10-19 14:38:18 -07005743 os_memset(&ext_arg, 0, sizeof(struct nl80211_ack_ext_arg));
5744 ext_arg.ext_data = &cookie;
5745 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL,
5746 ack_handler_cookie, &ext_arg);
5747 if (ret) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005748 wpa_printf(MSG_DEBUG,
5749 "nl80211: tx_control_port failed: ret=%d (%s)",
5750 ret, strerror(-ret));
Hai Shalom899fcc72020-10-19 14:38:18 -07005751 } else {
5752 struct wpa_driver_nl80211_data *drv = bss->drv;
5753
5754 wpa_printf(MSG_DEBUG,
5755 "nl80211: tx_control_port cookie=0x%llx",
5756 (long long unsigned int) cookie);
5757 drv->eapol_tx_cookie = cookie;
5758 }
Hai Shalomfdcde762020-04-02 11:19:20 -07005759
5760 return ret;
5761}
5762
5763
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005764static int nl80211_send_eapol_data(struct i802_bss *bss,
5765 const u8 *addr, const u8 *data,
5766 size_t data_len)
5767{
5768 struct sockaddr_ll ll;
5769 int ret;
5770
5771 if (bss->drv->eapol_tx_sock < 0) {
5772 wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
5773 return -1;
5774 }
5775
5776 os_memset(&ll, 0, sizeof(ll));
5777 ll.sll_family = AF_PACKET;
5778 ll.sll_ifindex = bss->ifindex;
5779 ll.sll_protocol = htons(ETH_P_PAE);
5780 ll.sll_halen = ETH_ALEN;
5781 os_memcpy(ll.sll_addr, addr, ETH_ALEN);
5782 ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
5783 (struct sockaddr *) &ll, sizeof(ll));
5784 if (ret < 0)
5785 wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
5786 strerror(errno));
5787
5788 return ret;
5789}
5790
5791
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005792static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
5793
5794static int wpa_driver_nl80211_hapd_send_eapol(
5795 void *priv, const u8 *addr, const u8 *data,
5796 size_t data_len, int encrypt, const u8 *own_addr, u32 flags)
5797{
5798 struct i802_bss *bss = priv;
5799 struct wpa_driver_nl80211_data *drv = bss->drv;
5800 struct ieee80211_hdr *hdr;
5801 size_t len;
5802 u8 *pos;
5803 int res;
5804 int qos = flags & WPA_STA_WMM;
Dmitry Shmidt641185e2013-11-06 15:17:13 -08005805
Hai Shalomb755a2a2020-04-23 21:49:02 -07005806 /* For now, disable EAPOL TX over control port in AP mode by default
5807 * since it does not provide TX status notifications. */
5808 if (drv->control_port_ap &&
5809 (drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT))
Hai Shalomfdcde762020-04-02 11:19:20 -07005810 return nl80211_tx_control_port(bss, addr, ETH_P_EAPOL,
5811 data, data_len, !encrypt);
5812
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005813 if (drv->device_ap_sme || !drv->use_monitor)
5814 return nl80211_send_eapol_data(bss, addr, data, data_len);
5815
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005816 len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
5817 data_len;
5818 hdr = os_zalloc(len);
5819 if (hdr == NULL) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005820 wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)",
5821 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005822 return -1;
5823 }
5824
5825 hdr->frame_control =
5826 IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
5827 hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
5828 if (encrypt)
5829 hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
5830 if (qos) {
5831 hdr->frame_control |=
5832 host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
5833 }
5834
5835 memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
5836 memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
5837 memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
5838 pos = (u8 *) (hdr + 1);
5839
5840 if (qos) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07005841 /* Set highest priority in QoS header */
5842 pos[0] = 7;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005843 pos[1] = 0;
5844 pos += 2;
5845 }
5846
5847 memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
5848 pos += sizeof(rfc1042_header);
5849 WPA_PUT_BE16(pos, ETH_P_PAE);
5850 pos += 2;
5851 memcpy(pos, data, data_len);
5852
Hai Shalomfdcde762020-04-02 11:19:20 -07005853 res = nl80211_send_monitor(drv, hdr, len, encrypt, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005854 if (res < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005855 wpa_printf(MSG_ERROR,
5856 "hapd_send_eapol - packet len: %lu - failed",
5857 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005858 }
5859 os_free(hdr);
5860
5861 return res;
5862}
5863
5864
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005865static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005866 unsigned int total_flags,
5867 unsigned int flags_or,
5868 unsigned int flags_and)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005869{
5870 struct i802_bss *bss = priv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005871 struct nl_msg *msg;
5872 struct nlattr *flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005873 struct nl80211_sta_flag_update upd;
5874
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005875 wpa_printf(MSG_DEBUG, "nl80211: Set STA flags - ifname=%s addr=" MACSTR
5876 " total_flags=0x%x flags_or=0x%x flags_and=0x%x authorized=%d",
5877 bss->ifname, MAC2STR(addr), total_flags, flags_or, flags_and,
5878 !!(total_flags & WPA_STA_AUTHORIZED));
5879
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005880 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
5881 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
5882 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005883
5884 /*
5885 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
5886 * can be removed eventually.
5887 */
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005888 flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005889 if (!flags ||
5890 ((total_flags & WPA_STA_AUTHORIZED) &&
5891 nla_put_flag(msg, NL80211_STA_FLAG_AUTHORIZED)) ||
5892 ((total_flags & WPA_STA_WMM) &&
5893 nla_put_flag(msg, NL80211_STA_FLAG_WME)) ||
5894 ((total_flags & WPA_STA_SHORT_PREAMBLE) &&
5895 nla_put_flag(msg, NL80211_STA_FLAG_SHORT_PREAMBLE)) ||
5896 ((total_flags & WPA_STA_MFP) &&
5897 nla_put_flag(msg, NL80211_STA_FLAG_MFP)) ||
5898 ((total_flags & WPA_STA_TDLS_PEER) &&
5899 nla_put_flag(msg, NL80211_STA_FLAG_TDLS_PEER)))
5900 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005901
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005902 nla_nest_end(msg, flags);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005903
5904 os_memset(&upd, 0, sizeof(upd));
5905 upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
5906 upd.set = sta_flags_nl80211(flags_or);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005907 if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
5908 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005909
Hai Shalom899fcc72020-10-19 14:38:18 -07005910 return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005911fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005912 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005913 return -ENOBUFS;
5914}
5915
5916
Hai Shalom81f62d82019-07-22 12:10:00 -07005917static int driver_nl80211_sta_set_airtime_weight(void *priv, const u8 *addr,
5918 unsigned int weight)
5919{
5920 struct i802_bss *bss = priv;
5921 struct nl_msg *msg;
Hai Shalomc1a21442022-02-04 13:43:00 -08005922 int ret;
Hai Shalom81f62d82019-07-22 12:10:00 -07005923
5924 wpa_printf(MSG_DEBUG,
5925 "nl80211: Set STA airtime weight - ifname=%s addr=" MACSTR
5926 " weight=%u", bss->ifname, MAC2STR(addr), weight);
5927
5928 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
5929 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
5930 nla_put_u16(msg, NL80211_ATTR_AIRTIME_WEIGHT, weight))
5931 goto fail;
5932
Hai Shalomc1a21442022-02-04 13:43:00 -08005933 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
5934 if (ret) {
5935 wpa_printf(MSG_DEBUG,
5936 "nl80211: SET_STATION[AIRTIME_WEIGHT] failed: ret=%d (%s)",
5937 ret, strerror(-ret));
5938 }
5939 return ret;
Hai Shalom81f62d82019-07-22 12:10:00 -07005940fail:
5941 nlmsg_free(msg);
5942 return -ENOBUFS;
5943}
5944
5945
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005946static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
5947 struct wpa_driver_associate_params *params)
5948{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005949 enum nl80211_iftype nlmode, old_mode;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005950
5951 if (params->p2p) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005952 wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
5953 "group (GO)");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005954 nlmode = NL80211_IFTYPE_P2P_GO;
5955 } else
5956 nlmode = NL80211_IFTYPE_AP;
5957
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005958 old_mode = drv->nlmode;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005959 if (wpa_driver_nl80211_set_mode(drv->first_bss, nlmode)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005960 nl80211_remove_monitor_interface(drv);
5961 return -1;
5962 }
5963
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08005964 if (params->freq.freq &&
5965 nl80211_set_channel(drv->first_bss, &params->freq, 0)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005966 if (old_mode != nlmode)
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005967 wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005968 nl80211_remove_monitor_interface(drv);
5969 return -1;
5970 }
5971
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005972 return 0;
5973}
5974
5975
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005976static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
5977 int reset_mode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005978{
5979 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005980 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005981
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005982 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
Hai Shalomc1a21442022-02-04 13:43:00 -08005983 ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005984 if (ret) {
5985 wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
5986 "(%s)", ret, strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005987 } else {
5988 wpa_printf(MSG_DEBUG,
5989 "nl80211: Leave IBSS request sent successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005990 }
5991
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005992 if (reset_mode &&
5993 wpa_driver_nl80211_set_mode(drv->first_bss,
Dmitry Shmidt56052862013-10-04 10:23:25 -07005994 NL80211_IFTYPE_STATION)) {
5995 wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
5996 "station mode");
5997 }
5998
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005999 return ret;
6000}
6001
6002
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006003static int nl80211_ht_vht_overrides(struct nl_msg *msg,
6004 struct wpa_driver_associate_params *params)
6005{
6006 if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
6007 return -1;
6008
6009 if (params->htcaps && params->htcaps_mask) {
6010 int sz = sizeof(struct ieee80211_ht_capabilities);
6011 wpa_hexdump(MSG_DEBUG, " * htcaps", params->htcaps, sz);
6012 wpa_hexdump(MSG_DEBUG, " * htcaps_mask",
6013 params->htcaps_mask, sz);
6014 if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
6015 params->htcaps) ||
6016 nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
6017 params->htcaps_mask))
6018 return -1;
6019 }
6020
6021#ifdef CONFIG_VHT_OVERRIDES
6022 if (params->disable_vht) {
6023 wpa_printf(MSG_DEBUG, " * VHT disabled");
6024 if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
6025 return -1;
6026 }
6027
6028 if (params->vhtcaps && params->vhtcaps_mask) {
6029 int sz = sizeof(struct ieee80211_vht_capabilities);
6030 wpa_hexdump(MSG_DEBUG, " * vhtcaps", params->vhtcaps, sz);
6031 wpa_hexdump(MSG_DEBUG, " * vhtcaps_mask",
6032 params->vhtcaps_mask, sz);
6033 if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
6034 params->vhtcaps) ||
6035 nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
6036 params->vhtcaps_mask))
6037 return -1;
6038 }
6039#endif /* CONFIG_VHT_OVERRIDES */
6040
Hai Shalomc1a21442022-02-04 13:43:00 -08006041#ifdef CONFIG_HE_OVERRIDES
6042 if (params->disable_he) {
6043 wpa_printf(MSG_DEBUG, " * HE disabled");
6044 if (nla_put_flag(msg, NL80211_ATTR_DISABLE_HE))
6045 return -1;
6046 }
6047#endif /* CONFIG_HE_OVERRIDES */
6048
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006049 return 0;
6050}
6051
6052
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006053static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
6054 struct wpa_driver_associate_params *params)
6055{
6056 struct nl_msg *msg;
6057 int ret = -1;
6058 int count = 0;
6059
6060 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
6061
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006062 if (wpa_driver_nl80211_set_mode_ibss(drv->first_bss, &params->freq)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006063 wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
6064 "IBSS mode");
6065 return -1;
6066 }
6067
6068retry:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006069 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_IBSS)) ||
6070 params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
6071 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006072
Hai Shalom74f70d42019-02-11 14:42:39 -08006073 wpa_printf(MSG_DEBUG, " * SSID=%s",
6074 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006075 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
6076 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006077 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6078 drv->ssid_len = params->ssid_len;
6079
Dmitry Shmidtff787d52015-01-12 13:01:47 -08006080 if (nl80211_put_freq_params(msg, &params->freq) < 0 ||
6081 nl80211_put_beacon_int(msg, params->beacon_int))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006082 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006083
6084 ret = nl80211_set_conn_keys(params, msg);
6085 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006086 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006087
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006088 if (params->bssid && params->fixed_bssid) {
6089 wpa_printf(MSG_DEBUG, " * BSSID=" MACSTR,
6090 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006091 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
6092 goto fail;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006093 }
6094
Dmitry Shmidt7f656022015-02-25 14:36:37 -08006095 if (params->fixed_freq) {
6096 wpa_printf(MSG_DEBUG, " * fixed_freq");
6097 if (nla_put_flag(msg, NL80211_ATTR_FREQ_FIXED))
6098 goto fail;
6099 }
6100
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006101 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
6102 params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
6103 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
6104 params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006105 wpa_printf(MSG_DEBUG, " * control port");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006106 if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
6107 goto fail;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006108 }
6109
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006110 if (params->wpa_ie) {
6111 wpa_hexdump(MSG_DEBUG,
6112 " * Extra IEs for Beacon/Probe Response frames",
6113 params->wpa_ie, params->wpa_ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006114 if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
6115 params->wpa_ie))
6116 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006117 }
6118
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08006119 ret = nl80211_ht_vht_overrides(msg, params);
6120 if (ret < 0)
6121 goto fail;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006122
Hai Shalomc1a21442022-02-04 13:43:00 -08006123 ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006124 msg = NULL;
6125 if (ret) {
6126 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
6127 ret, strerror(-ret));
6128 count++;
6129 if (ret == -EALREADY && count == 1) {
6130 wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
6131 "forced leave");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006132 nl80211_leave_ibss(drv, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006133 nlmsg_free(msg);
6134 goto retry;
6135 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006136 } else {
6137 wpa_printf(MSG_DEBUG,
6138 "nl80211: Join IBSS request sent successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006139 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006140
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006141fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006142 nlmsg_free(msg);
6143 return ret;
6144}
6145
6146
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006147static int nl80211_put_fils_connect_params(struct wpa_driver_nl80211_data *drv,
6148 struct wpa_driver_associate_params *params,
6149 struct nl_msg *msg)
6150{
6151 if (params->fils_erp_username_len) {
6152 wpa_hexdump_ascii(MSG_DEBUG, " * FILS ERP EMSKname/username",
6153 params->fils_erp_username,
6154 params->fils_erp_username_len);
6155 if (nla_put(msg, NL80211_ATTR_FILS_ERP_USERNAME,
6156 params->fils_erp_username_len,
6157 params->fils_erp_username))
6158 return -1;
6159 }
6160
6161 if (params->fils_erp_realm_len) {
6162 wpa_hexdump_ascii(MSG_DEBUG, " * FILS ERP Realm",
6163 params->fils_erp_realm,
6164 params->fils_erp_realm_len);
6165 if (nla_put(msg, NL80211_ATTR_FILS_ERP_REALM,
6166 params->fils_erp_realm_len, params->fils_erp_realm))
6167 return -1;
6168 }
6169
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006170 if (params->fils_erp_rrk_len) {
Vinita S. Maloo3a5b4412020-05-19 17:43:22 +05306171 wpa_printf(MSG_DEBUG, " * FILS ERP next seq %u",
6172 params->fils_erp_next_seq_num);
6173 if (nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
6174 params->fils_erp_next_seq_num))
6175 return -1;
6176
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006177 wpa_printf(MSG_DEBUG, " * FILS ERP rRK (len=%lu)",
6178 (unsigned long) params->fils_erp_rrk_len);
6179 if (nla_put(msg, NL80211_ATTR_FILS_ERP_RRK,
6180 params->fils_erp_rrk_len, params->fils_erp_rrk))
6181 return -1;
6182 }
6183
6184 return 0;
6185}
6186
6187
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006188static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
6189 struct wpa_driver_associate_params *params,
6190 struct nl_msg *msg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006191{
Paul Stewart092955c2017-02-06 09:13:09 -08006192 if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
6193 return -1;
6194
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006195 if (params->bssid) {
6196 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
6197 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006198 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
6199 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006200 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006201
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006202 if (params->bssid_hint) {
6203 wpa_printf(MSG_DEBUG, " * bssid_hint=" MACSTR,
6204 MAC2STR(params->bssid_hint));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006205 if (nla_put(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
6206 params->bssid_hint))
6207 return -1;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006208 }
6209
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006210 if (params->freq.freq) {
6211 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq.freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006212 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
6213 params->freq.freq))
6214 return -1;
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006215 drv->assoc_freq = params->freq.freq;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07006216 } else
6217 drv->assoc_freq = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006218
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006219 if (params->freq_hint) {
6220 wpa_printf(MSG_DEBUG, " * freq_hint=%d", params->freq_hint);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006221 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_HINT,
6222 params->freq_hint))
6223 return -1;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006224 }
6225
Hai Shalomc3565922019-10-28 11:58:20 -07006226 if (params->freq.edmg.channels && params->freq.edmg.bw_config) {
6227 wpa_printf(MSG_DEBUG,
6228 " * EDMG configuration: channels=0x%x bw_config=%d",
6229 params->freq.edmg.channels,
6230 params->freq.edmg.bw_config);
6231 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
6232 params->freq.edmg.channels) ||
6233 nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
6234 params->freq.edmg.bw_config))
6235 return -1;
6236 }
6237
Dmitry Shmidt04949592012-07-19 12:16:46 -07006238 if (params->bg_scan_period >= 0) {
6239 wpa_printf(MSG_DEBUG, " * bg scan period=%d",
6240 params->bg_scan_period);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006241 if (nla_put_u16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
6242 params->bg_scan_period))
6243 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07006244 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006245
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006246 if (params->ssid) {
Hai Shalom74f70d42019-02-11 14:42:39 -08006247 wpa_printf(MSG_DEBUG, " * SSID=%s",
6248 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006249 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
6250 params->ssid))
6251 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006252 if (params->ssid_len > sizeof(drv->ssid))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006253 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006254 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6255 drv->ssid_len = params->ssid_len;
6256 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006257
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006258 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006259 if (params->wpa_ie &&
6260 nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie))
6261 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006262
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006263 if (params->wpa_proto) {
6264 enum nl80211_wpa_versions ver = 0;
6265
6266 if (params->wpa_proto & WPA_PROTO_WPA)
6267 ver |= NL80211_WPA_VERSION_1;
6268 if (params->wpa_proto & WPA_PROTO_RSN)
6269 ver |= NL80211_WPA_VERSION_2;
6270
6271 wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006272 if (nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
6273 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006274 }
6275
6276 if (params->pairwise_suite != WPA_CIPHER_NONE) {
6277 u32 cipher = wpa_cipher_to_cipher_suite(params->pairwise_suite);
6278 wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006279 if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
6280 cipher))
6281 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006282 }
6283
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08006284 if (params->group_suite == WPA_CIPHER_GTK_NOT_USED &&
6285 !(drv->capa.enc & WPA_DRIVER_CAPA_ENC_GTK_NOT_USED)) {
6286 /*
6287 * This is likely to work even though many drivers do not
6288 * advertise support for operations without GTK.
6289 */
6290 wpa_printf(MSG_DEBUG, " * skip group cipher configuration for GTK_NOT_USED due to missing driver support advertisement");
6291 } else if (params->group_suite != WPA_CIPHER_NONE) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006292 u32 cipher = wpa_cipher_to_cipher_suite(params->group_suite);
6293 wpa_printf(MSG_DEBUG, " * group=0x%x", cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006294 if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher))
6295 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006296 }
6297
6298 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
6299 params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
6300 params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X ||
6301 params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
Dmitry Shmidt15907092014-03-25 10:42:57 -07006302 params->key_mgmt_suite == WPA_KEY_MGMT_CCKM ||
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07006303 params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
6304 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006305 params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
Hai Shalom021b0b52019-04-10 11:17:58 -07006306 params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
6307 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE ||
Dmitry Shmidt807291d2015-01-27 13:40:23 -08006308 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006309 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ||
Hai Shalom021b0b52019-04-10 11:17:58 -07006310 params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006311 params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA256 ||
6312 params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA384 ||
6313 params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA256 ||
Roshan Pius3a1667e2018-07-03 15:17:14 -07006314 params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384 ||
6315 params->key_mgmt_suite == WPA_KEY_MGMT_OWE ||
6316 params->key_mgmt_suite == WPA_KEY_MGMT_DPP) {
Paul Stewart092955c2017-02-06 09:13:09 -08006317 int mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006318
6319 switch (params->key_mgmt_suite) {
6320 case WPA_KEY_MGMT_CCKM:
Paul Stewart092955c2017-02-06 09:13:09 -08006321 mgmt = RSN_AUTH_KEY_MGMT_CCKM;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006322 break;
6323 case WPA_KEY_MGMT_IEEE8021X:
Paul Stewart092955c2017-02-06 09:13:09 -08006324 mgmt = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006325 break;
6326 case WPA_KEY_MGMT_FT_IEEE8021X:
Paul Stewart092955c2017-02-06 09:13:09 -08006327 mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006328 break;
6329 case WPA_KEY_MGMT_FT_PSK:
Paul Stewart092955c2017-02-06 09:13:09 -08006330 mgmt = RSN_AUTH_KEY_MGMT_FT_PSK;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006331 break;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07006332 case WPA_KEY_MGMT_IEEE8021X_SHA256:
Paul Stewart092955c2017-02-06 09:13:09 -08006333 mgmt = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07006334 break;
6335 case WPA_KEY_MGMT_PSK_SHA256:
Paul Stewart092955c2017-02-06 09:13:09 -08006336 mgmt = RSN_AUTH_KEY_MGMT_PSK_SHA256;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07006337 break;
Dmitry Shmidt15907092014-03-25 10:42:57 -07006338 case WPA_KEY_MGMT_OSEN:
Paul Stewart092955c2017-02-06 09:13:09 -08006339 mgmt = RSN_AUTH_KEY_MGMT_OSEN;
Dmitry Shmidt15907092014-03-25 10:42:57 -07006340 break;
Hai Shalom021b0b52019-04-10 11:17:58 -07006341 case WPA_KEY_MGMT_SAE:
6342 mgmt = RSN_AUTH_KEY_MGMT_SAE;
6343 break;
6344 case WPA_KEY_MGMT_FT_SAE:
6345 mgmt = RSN_AUTH_KEY_MGMT_FT_SAE;
6346 break;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006347 case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
Paul Stewart092955c2017-02-06 09:13:09 -08006348 mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006349 break;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08006350 case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
Paul Stewart092955c2017-02-06 09:13:09 -08006351 mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08006352 break;
Hai Shalom021b0b52019-04-10 11:17:58 -07006353 case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
6354 mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
6355 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006356 case WPA_KEY_MGMT_FILS_SHA256:
6357 mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA256;
6358 break;
6359 case WPA_KEY_MGMT_FILS_SHA384:
6360 mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA384;
6361 break;
6362 case WPA_KEY_MGMT_FT_FILS_SHA256:
6363 mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
6364 break;
6365 case WPA_KEY_MGMT_FT_FILS_SHA384:
6366 mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
6367 break;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006368 case WPA_KEY_MGMT_OWE:
6369 mgmt = RSN_AUTH_KEY_MGMT_OWE;
6370 break;
6371 case WPA_KEY_MGMT_DPP:
6372 mgmt = RSN_AUTH_KEY_MGMT_DPP;
6373 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006374 case WPA_KEY_MGMT_PSK:
6375 default:
Paul Stewart092955c2017-02-06 09:13:09 -08006376 mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006377 break;
6378 }
Dmitry Shmidt15907092014-03-25 10:42:57 -07006379 wpa_printf(MSG_DEBUG, " * akm=0x%x", mgmt);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006380 if (nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, mgmt))
6381 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006382 }
6383
Hai Shalomc3565922019-10-28 11:58:20 -07006384 if (params->req_handshake_offload &&
Hai Shalom74f70d42019-02-11 14:42:39 -08006385 (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) {
6386 wpa_printf(MSG_DEBUG, " * WANT_1X_4WAY_HS");
6387 if (nla_put_flag(msg, NL80211_ATTR_WANT_1X_4WAY_HS))
6388 return -1;
6389 }
6390
Roshan Pius3a1667e2018-07-03 15:17:14 -07006391 /* Add PSK in case of 4-way handshake offload */
6392 if (params->psk &&
Hai Shalom74f70d42019-02-11 14:42:39 -08006393 (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006394 wpa_hexdump_key(MSG_DEBUG, " * PSK", params->psk, 32);
6395 if (nla_put(msg, NL80211_ATTR_PMK, 32, params->psk))
6396 return -1;
6397 }
6398
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006399 if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
6400 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006401
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006402 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
6403 (params->pairwise_suite == WPA_CIPHER_NONE ||
6404 params->pairwise_suite == WPA_CIPHER_WEP104 ||
6405 params->pairwise_suite == WPA_CIPHER_WEP40) &&
6406 (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
6407 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
6408 return -1;
6409
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006410 if (params->rrm_used) {
6411 u32 drv_rrm_flags = drv->capa.rrm_flags;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006412 if ((!((drv_rrm_flags &
6413 WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) &&
6414 (drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) &&
6415 !(drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006416 nla_put_flag(msg, NL80211_ATTR_USE_RRM))
6417 return -1;
6418 }
6419
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006420 if (nl80211_ht_vht_overrides(msg, params) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006421 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006422
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006423 if (params->p2p)
6424 wpa_printf(MSG_DEBUG, " * P2P group");
6425
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006426 if (params->pbss) {
6427 wpa_printf(MSG_DEBUG, " * PBSS");
6428 if (nla_put_flag(msg, NL80211_ATTR_PBSS))
6429 return -1;
6430 }
6431
Dmitry Shmidte4663042016-04-04 10:07:49 -07006432 drv->connect_reassoc = 0;
6433 if (params->prev_bssid) {
6434 wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR,
6435 MAC2STR(params->prev_bssid));
6436 if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
6437 params->prev_bssid))
6438 return -1;
6439 drv->connect_reassoc = 1;
6440 }
6441
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006442 if ((params->auth_alg & WPA_AUTH_ALG_FILS) &&
6443 nl80211_put_fils_connect_params(drv, params, msg) != 0)
6444 return -1;
6445
Hai Shalomc3565922019-10-28 11:58:20 -07006446 if ((params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
6447 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) &&
Roshan Pius3a1667e2018-07-03 15:17:14 -07006448 (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
6449 nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
6450 return -1;
6451
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006452 return 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006453}
6454
6455
6456static int wpa_driver_nl80211_try_connect(
6457 struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006458 struct wpa_driver_associate_params *params,
Hai Shalomc1a21442022-02-04 13:43:00 -08006459 struct i802_bss *bss)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006460{
6461 struct nl_msg *msg;
6462 enum nl80211_auth_type type;
6463 int ret;
6464 int algs;
6465
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006466#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006467 if (params->req_key_mgmt_offload && params->psk &&
6468 (params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
6469 params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
6470 params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
6471 wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK");
6472 ret = issue_key_mgmt_set_key(drv, params->psk, 32);
6473 if (ret)
6474 return ret;
6475 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006476#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006477
6478 wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
6479 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_CONNECT);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006480 if (!msg)
6481 return -1;
6482
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006483 ret = nl80211_connect_common(drv, params, msg);
6484 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006485 goto fail;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006486
Roshan Pius3a1667e2018-07-03 15:17:14 -07006487 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
6488 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
6489 goto fail;
6490
6491 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_OPTIONAL &&
6492 (drv->capa.flags & WPA_DRIVER_FLAGS_MFP_OPTIONAL) &&
6493 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_OPTIONAL))
6494 goto fail;
6495
Hai Shalom60840252021-02-19 19:02:11 -08006496#ifdef CONFIG_SAE
6497 if ((params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
6498 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) &&
6499 nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
6500 goto fail;
6501#endif /* CONFIG_SAE */
6502
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006503 algs = 0;
6504 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
6505 algs++;
6506 if (params->auth_alg & WPA_AUTH_ALG_SHARED)
6507 algs++;
6508 if (params->auth_alg & WPA_AUTH_ALG_LEAP)
6509 algs++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006510 if (params->auth_alg & WPA_AUTH_ALG_FILS)
6511 algs++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006512 if (params->auth_alg & WPA_AUTH_ALG_FT)
6513 algs++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006514 if (algs > 1) {
6515 wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic "
6516 "selection");
6517 goto skip_auth_type;
6518 }
6519
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006520 type = get_nl_auth_type(params->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006521 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006522 if (type == NL80211_AUTHTYPE_MAX ||
6523 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006524 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006525
6526skip_auth_type:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006527 ret = nl80211_set_conn_keys(params, msg);
6528 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006529 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006530
Hai Shalomc1a21442022-02-04 13:43:00 -08006531 ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006532 msg = NULL;
6533 if (ret) {
6534 wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
6535 "(%s)", ret, strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006536 } else {
Hai Shalom60840252021-02-19 19:02:11 -08006537#ifdef CONFIG_DRIVER_NL80211_QCA
6538 drv->roam_indication_done = false;
6539#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006540 wpa_printf(MSG_DEBUG,
6541 "nl80211: Connect request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006542 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006543
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006544fail:
Hai Shalom74f70d42019-02-11 14:42:39 -08006545 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006546 nlmsg_free(msg);
6547 return ret;
6548
6549}
6550
6551
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006552static int wpa_driver_nl80211_connect(
6553 struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006554 struct wpa_driver_associate_params *params,
Hai Shalomc1a21442022-02-04 13:43:00 -08006555 struct i802_bss *bss)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006556{
Jithu Jancea7c60b42014-12-03 18:54:40 +05306557 int ret;
6558
6559 /* Store the connection attempted bssid for future use */
6560 if (params->bssid)
6561 os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
6562 else
6563 os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
6564
Hai Shalomc1a21442022-02-04 13:43:00 -08006565 ret = wpa_driver_nl80211_try_connect(drv, params, bss);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006566 if (ret == -EALREADY) {
6567 /*
6568 * cfg80211 does not currently accept new connections if
6569 * we are already connected. As a workaround, force
6570 * disconnection and try again.
6571 */
6572 wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
6573 "disconnecting before reassociation "
6574 "attempt");
6575 if (wpa_driver_nl80211_disconnect(
Hai Shalomc1a21442022-02-04 13:43:00 -08006576 drv, WLAN_REASON_PREV_AUTH_NOT_VALID, bss))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006577 return -1;
Hai Shalomc1a21442022-02-04 13:43:00 -08006578 ret = wpa_driver_nl80211_try_connect(drv, params, bss);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006579 }
6580 return ret;
6581}
6582
6583
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006584static int wpa_driver_nl80211_associate(
6585 void *priv, struct wpa_driver_associate_params *params)
6586{
6587 struct i802_bss *bss = priv;
6588 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006589 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006590 struct nl_msg *msg;
6591
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006592 nl80211_unmask_11b_rates(bss);
6593
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006594 if (params->mode == IEEE80211_MODE_AP)
6595 return wpa_driver_nl80211_ap(drv, params);
6596
6597 if (params->mode == IEEE80211_MODE_IBSS)
6598 return wpa_driver_nl80211_ibss(drv, params);
6599
6600 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006601 enum nl80211_iftype nlmode = params->p2p ?
6602 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
6603
6604 if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006605 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07006606 if (params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
Hai Shalomb755a2a2020-04-23 21:49:02 -07006607 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE)
Hai Shalom74f70d42019-02-11 14:42:39 -08006608 bss->use_nl_connect = 1;
Hai Shalomb755a2a2020-04-23 21:49:02 -07006609 else
Hai Shalom74f70d42019-02-11 14:42:39 -08006610 bss->use_nl_connect = 0;
Hai Shalom74f70d42019-02-11 14:42:39 -08006611
Hai Shalomc1a21442022-02-04 13:43:00 -08006612 return wpa_driver_nl80211_connect(drv, params, bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006613 }
6614
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07006615 nl80211_mark_disconnected(drv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006616
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006617 wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
6618 drv->ifindex);
6619 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ASSOCIATE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006620 if (!msg)
6621 return -1;
6622
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006623 ret = nl80211_connect_common(drv, params, msg);
6624 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006625 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006626
Roshan Pius3a1667e2018-07-03 15:17:14 -07006627 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
6628 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
6629 goto fail;
6630
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006631 if (params->fils_kek) {
6632 wpa_printf(MSG_DEBUG, " * FILS KEK (len=%u)",
6633 (unsigned int) params->fils_kek_len);
6634 if (nla_put(msg, NL80211_ATTR_FILS_KEK, params->fils_kek_len,
6635 params->fils_kek))
6636 goto fail;
6637 }
6638 if (params->fils_nonces) {
6639 wpa_hexdump(MSG_DEBUG, " * FILS nonces (for AAD)",
6640 params->fils_nonces,
6641 params->fils_nonces_len);
6642 if (nla_put(msg, NL80211_ATTR_FILS_NONCES,
6643 params->fils_nonces_len, params->fils_nonces))
6644 goto fail;
6645 }
6646
Hai Shalomc1a21442022-02-04 13:43:00 -08006647 ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006648 msg = NULL;
6649 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006650 wpa_dbg(drv->ctx, MSG_DEBUG,
6651 "nl80211: MLME command failed (assoc): ret=%d (%s)",
6652 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006653 nl80211_dump_scan(drv);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006654 } else {
6655 wpa_printf(MSG_DEBUG,
6656 "nl80211: Association request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006657 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006658
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006659fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006660 nlmsg_free(msg);
6661 return ret;
6662}
6663
6664
6665static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006666 int ifindex, enum nl80211_iftype mode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006667{
6668 struct nl_msg *msg;
6669 int ret = -ENOBUFS;
6670
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006671 wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
6672 ifindex, mode, nl80211_iftype_str(mode));
6673
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006674 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
6675 if (!msg || nla_put_u32(msg, NL80211_ATTR_IFTYPE, mode))
6676 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006677
Hai Shalom899fcc72020-10-19 14:38:18 -07006678 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006679 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006680 if (!ret)
6681 return 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006682fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006683 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006684 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
6685 " %d (%s)", ifindex, mode, ret, strerror(-ret));
6686 return ret;
6687}
6688
6689
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006690static int wpa_driver_nl80211_set_mode_impl(
6691 struct i802_bss *bss,
6692 enum nl80211_iftype nlmode,
6693 struct hostapd_freq_params *desired_freq_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006694{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006695 struct wpa_driver_nl80211_data *drv = bss->drv;
6696 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006697 int i;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006698 int was_ap = is_ap_interface(drv->nlmode);
6699 int res;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006700 int mode_switch_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006701
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07006702 if (TEST_FAIL())
6703 return -1;
6704
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006705 mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
6706 if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))
6707 mode_switch_res = 0;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006708
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006709 if (mode_switch_res == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006710 drv->nlmode = nlmode;
6711 ret = 0;
6712 goto done;
6713 }
6714
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006715 if (mode_switch_res == -ENODEV)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006716 return -1;
6717
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006718 if (nlmode == drv->nlmode) {
6719 wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
6720 "requested mode - ignore error");
6721 ret = 0;
6722 goto done; /* Already in the requested mode */
6723 }
6724
6725 /* mac80211 doesn't allow mode changes while the device is up, so
6726 * take the device down, try to set the mode again, and bring the
6727 * device back up.
6728 */
6729 wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
6730 "interface down");
6731 for (i = 0; i < 10; i++) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006732 res = i802_set_iface_flags(bss, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006733 if (res == -EACCES || res == -ENODEV)
6734 break;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006735 if (res != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006736 wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
6737 "interface down");
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006738 os_sleep(0, 100000);
6739 continue;
6740 }
6741
6742 /*
6743 * Setting the mode will fail for some drivers if the phy is
6744 * on a frequency that the mode is disallowed in.
6745 */
6746 if (desired_freq_params) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006747 res = nl80211_set_channel(bss, desired_freq_params, 0);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006748 if (res) {
6749 wpa_printf(MSG_DEBUG,
6750 "nl80211: Failed to set frequency on interface");
6751 }
6752 }
6753
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006754 if (i == 0 && was_ap && !is_ap_interface(nlmode) &&
6755 bss->brname[0] &&
6756 (bss->added_if_into_bridge || bss->already_in_bridge)) {
6757 wpa_printf(MSG_DEBUG,
6758 "nl80211: Remove AP interface %s temporarily from the bridge %s to allow its mode to be set to STATION",
6759 bss->ifname, bss->brname);
6760 if (linux_br_del_if(drv->global->ioctl_sock,
6761 bss->brname, bss->ifname) < 0)
6762 wpa_printf(MSG_INFO,
6763 "nl80211: Failed to remove interface %s from bridge %s: %s",
6764 bss->ifname, bss->brname,
6765 strerror(errno));
6766 }
6767
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006768 /* Try to set the mode again while the interface is down */
6769 mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
6770 if (mode_switch_res == -EBUSY) {
6771 wpa_printf(MSG_DEBUG,
6772 "nl80211: Delaying mode set while interface going down");
6773 os_sleep(0, 100000);
6774 continue;
6775 }
6776 ret = mode_switch_res;
6777 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006778 }
6779
6780 if (!ret) {
6781 wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
6782 "interface is down");
6783 drv->nlmode = nlmode;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006784 drv->ignore_if_down_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006785 }
6786
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006787 /* Bring the interface back up */
6788 res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
6789 if (res != 0) {
6790 wpa_printf(MSG_DEBUG,
6791 "nl80211: Failed to set interface up after switching mode");
6792 ret = -1;
6793 }
6794
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006795done:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006796 if (ret) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006797 wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
6798 "from %d failed", nlmode, drv->nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006799 return ret;
6800 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006801
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006802 if (is_p2p_net_interface(nlmode)) {
6803 wpa_printf(MSG_DEBUG,
6804 "nl80211: Interface %s mode change to P2P - disable 11b rates",
6805 bss->ifname);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006806 nl80211_disable_11b_rates(drv, drv->ifindex, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006807 } else if (drv->disabled_11b_rates) {
6808 wpa_printf(MSG_DEBUG,
6809 "nl80211: Interface %s mode changed to non-P2P - re-enable 11b rates",
6810 bss->ifname);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006811 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006812 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006813
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006814 if (is_ap_interface(nlmode)) {
6815 nl80211_mgmt_unsubscribe(bss, "start AP");
6816 /* Setup additional AP mode functionality if needed */
6817 if (nl80211_setup_ap(bss))
6818 return -1;
6819 } else if (was_ap) {
6820 /* Remove additional AP mode functionality */
6821 nl80211_teardown_ap(bss);
6822 } else {
6823 nl80211_mgmt_unsubscribe(bss, "mode change");
6824 }
6825
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006826 if (is_mesh_interface(nlmode) &&
6827 nl80211_mgmt_subscribe_mesh(bss))
6828 return -1;
6829
Dmitry Shmidt04949592012-07-19 12:16:46 -07006830 if (!bss->in_deinit && !is_ap_interface(nlmode) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006831 !is_mesh_interface(nlmode) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006832 nl80211_mgmt_subscribe_non_ap(bss) < 0)
6833 wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
6834 "frame processing - ignore for now");
6835
6836 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006837}
6838
6839
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006840void nl80211_restore_ap_mode(struct i802_bss *bss)
6841{
6842 struct wpa_driver_nl80211_data *drv = bss->drv;
6843 int was_ap = is_ap_interface(drv->nlmode);
leslc3979c32021-03-29 22:34:02 +08006844 int br_ifindex;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006845
6846 wpa_driver_nl80211_set_mode(bss, drv->ap_scan_as_station);
6847 if (!was_ap && is_ap_interface(drv->ap_scan_as_station) &&
6848 bss->brname[0] &&
6849 (bss->added_if_into_bridge || bss->already_in_bridge)) {
6850 wpa_printf(MSG_DEBUG,
6851 "nl80211: Add AP interface %s back into the bridge %s",
6852 bss->ifname, bss->brname);
6853 if (linux_br_add_if(drv->global->ioctl_sock, bss->brname,
6854 bss->ifname) < 0) {
6855 wpa_printf(MSG_WARNING,
6856 "nl80211: Failed to add interface %s into bridge %s: %s",
6857 bss->ifname, bss->brname, strerror(errno));
6858 }
leslc3979c32021-03-29 22:34:02 +08006859 br_ifindex = if_nametoindex(bss->brname);
6860 add_ifidx(drv, br_ifindex, drv->ifindex);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006861 }
6862 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
6863}
6864
6865
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006866int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
6867 enum nl80211_iftype nlmode)
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006868{
6869 return wpa_driver_nl80211_set_mode_impl(bss, nlmode, NULL);
6870}
6871
6872
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006873static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
6874 struct hostapd_freq_params *freq)
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006875{
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006876 return wpa_driver_nl80211_set_mode_impl(bss, NL80211_IFTYPE_ADHOC,
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006877 freq);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006878}
6879
6880
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006881static int wpa_driver_nl80211_get_capa(void *priv,
6882 struct wpa_driver_capa *capa)
6883{
6884 struct i802_bss *bss = priv;
6885 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07006886
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006887 if (!drv->has_capability)
6888 return -1;
6889 os_memcpy(capa, &drv->capa, sizeof(*capa));
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006890 if (drv->extended_capa && drv->extended_capa_mask) {
6891 capa->extended_capa = drv->extended_capa;
6892 capa->extended_capa_mask = drv->extended_capa_mask;
6893 capa->extended_capa_len = drv->extended_capa_len;
6894 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006895
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006896 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006897}
6898
6899
6900static int wpa_driver_nl80211_set_operstate(void *priv, int state)
6901{
6902 struct i802_bss *bss = priv;
6903 struct wpa_driver_nl80211_data *drv = bss->drv;
6904
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006905 wpa_printf(MSG_DEBUG, "nl80211: Set %s operstate %d->%d (%s)",
6906 bss->ifname, drv->operstate, state,
6907 state ? "UP" : "DORMANT");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006908 drv->operstate = state;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006909 return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006910 state ? IF_OPER_UP : IF_OPER_DORMANT);
6911}
6912
6913
6914static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
6915{
6916 struct i802_bss *bss = priv;
6917 struct wpa_driver_nl80211_data *drv = bss->drv;
6918 struct nl_msg *msg;
6919 struct nl80211_sta_flag_update upd;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006920 int ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006921
6922 if (!drv->associated && is_zero_ether_addr(drv->bssid) && !authorized) {
6923 wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated");
6924 return 0;
6925 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006926
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07006927 wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
6928 MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
6929
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006930 os_memset(&upd, 0, sizeof(upd));
6931 upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
6932 if (authorized)
6933 upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006934
6935 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
6936 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid) ||
6937 nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd)) {
6938 nlmsg_free(msg);
6939 return -ENOBUFS;
6940 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006941
Hai Shalom899fcc72020-10-19 14:38:18 -07006942 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006943 if (!ret)
6944 return 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006945 wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)",
6946 ret, strerror(-ret));
6947 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006948}
6949
6950
Jouni Malinen75ecf522011-06-27 15:19:46 -07006951/* Set kernel driver on given frequency (MHz) */
6952static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006953{
Jouni Malinen75ecf522011-06-27 15:19:46 -07006954 struct i802_bss *bss = priv;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006955 return nl80211_set_channel(bss, freq, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006956}
6957
6958
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006959static inline int min_int(int a, int b)
6960{
6961 if (a < b)
6962 return a;
6963 return b;
6964}
6965
6966
6967static int get_key_handler(struct nl_msg *msg, void *arg)
6968{
6969 struct nlattr *tb[NL80211_ATTR_MAX + 1];
6970 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
6971
6972 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
6973 genlmsg_attrlen(gnlh, 0), NULL);
6974
6975 /*
6976 * TODO: validate the key index and mac address!
6977 * Otherwise, there's a race condition as soon as
6978 * the kernel starts sending key notifications.
6979 */
6980
6981 if (tb[NL80211_ATTR_KEY_SEQ])
6982 memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
6983 min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
Hai Shalom021b0b52019-04-10 11:17:58 -07006984 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006985 return NL_SKIP;
6986}
6987
6988
6989static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
6990 int idx, u8 *seq)
6991{
6992 struct i802_bss *bss = priv;
6993 struct wpa_driver_nl80211_data *drv = bss->drv;
6994 struct nl_msg *msg;
6995
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006996 msg = nl80211_ifindex_msg(drv, if_nametoindex(iface), 0,
6997 NL80211_CMD_GET_KEY);
6998 if (!msg ||
6999 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
7000 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, idx)) {
7001 nlmsg_free(msg);
7002 return -ENOBUFS;
7003 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007004
7005 memset(seq, 0, 6);
7006
Hai Shalom899fcc72020-10-19 14:38:18 -07007007 return send_and_recv_msgs(drv, msg, get_key_handler, seq, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007008}
7009
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007010
7011static int i802_set_rts(void *priv, int rts)
7012{
7013 struct i802_bss *bss = priv;
7014 struct wpa_driver_nl80211_data *drv = bss->drv;
7015 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007016 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007017 u32 val;
7018
Hai Shalom021b0b52019-04-10 11:17:58 -07007019 if (rts >= 2347 || rts == -1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007020 val = (u32) -1;
7021 else
7022 val = rts;
7023
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007024 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
7025 nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val)) {
7026 nlmsg_free(msg);
7027 return -ENOBUFS;
7028 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007029
Hai Shalom899fcc72020-10-19 14:38:18 -07007030 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007031 if (!ret)
7032 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007033 wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
7034 "%d (%s)", rts, ret, strerror(-ret));
7035 return ret;
7036}
7037
7038
7039static int i802_set_frag(void *priv, int frag)
7040{
7041 struct i802_bss *bss = priv;
7042 struct wpa_driver_nl80211_data *drv = bss->drv;
7043 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007044 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007045 u32 val;
7046
Hai Shalom021b0b52019-04-10 11:17:58 -07007047 if (frag >= 2346 || frag == -1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007048 val = (u32) -1;
7049 else
7050 val = frag;
7051
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007052 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
7053 nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val)) {
7054 nlmsg_free(msg);
7055 return -ENOBUFS;
7056 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007057
Hai Shalom899fcc72020-10-19 14:38:18 -07007058 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007059 if (!ret)
7060 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007061 wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
7062 "%d: %d (%s)", frag, ret, strerror(-ret));
7063 return ret;
7064}
7065
7066
7067static int i802_flush(void *priv)
7068{
7069 struct i802_bss *bss = priv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007070 struct nl_msg *msg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007071 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007072
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07007073 wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
7074 bss->ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007075
7076 /*
7077 * XXX: FIX! this needs to flush all VLANs too
7078 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007079 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
Hai Shalom899fcc72020-10-19 14:38:18 -07007080 res = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007081 if (res) {
7082 wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
7083 "(%s)", res, strerror(-res));
7084 }
7085 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007086}
7087
7088
Hai Shalom81f62d82019-07-22 12:10:00 -07007089static void get_sta_tid_stats(struct hostap_sta_driver_data *data,
7090 struct nlattr *attr)
7091{
7092 struct nlattr *tid_stats[NL80211_TID_STATS_MAX + 1], *tidattr;
7093 struct nlattr *txq_stats[NL80211_TXQ_STATS_MAX + 1];
7094 static struct nla_policy txq_stats_policy[NL80211_TXQ_STATS_MAX + 1] = {
7095 [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 },
7096 [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 },
7097 };
7098 int rem;
7099
7100 nla_for_each_nested(tidattr, attr, rem) {
7101 if (nla_parse_nested(tid_stats, NL80211_TID_STATS_MAX,
7102 tidattr, NULL) != 0 ||
7103 !tid_stats[NL80211_TID_STATS_TXQ_STATS] ||
7104 nla_parse_nested(txq_stats, NL80211_TXQ_STATS_MAX,
7105 tid_stats[NL80211_TID_STATS_TXQ_STATS],
7106 txq_stats_policy) != 0)
7107 continue;
7108 /* sum the backlogs over all TIDs for station */
7109 if (txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES])
7110 data->backlog_bytes += nla_get_u32(
7111 txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES]);
7112 if (txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS])
7113 data->backlog_bytes += nla_get_u32(
7114 txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS]);
7115 }
7116}
7117
7118
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007119static int get_sta_handler(struct nl_msg *msg, void *arg)
7120{
7121 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7122 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7123 struct hostap_sta_driver_data *data = arg;
7124 struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
7125 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
7126 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
7127 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
7128 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
7129 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
7130 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007131 [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007132 [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
7133 [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007134 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
Roshan Pius3a1667e2018-07-03 15:17:14 -07007135 [NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 },
Hai Shalom81f62d82019-07-22 12:10:00 -07007136 [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 },
7137 [NL80211_STA_INFO_TX_DURATION] = { .type = NLA_U64 },
Hai Shalomc1a21442022-02-04 13:43:00 -08007138 [NL80211_STA_INFO_CONNECTED_TIME] = { .type = NLA_U32 },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007139 };
7140 struct nlattr *rate[NL80211_RATE_INFO_MAX + 1];
7141 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
7142 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
7143 [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 },
7144 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
7145 [NL80211_RATE_INFO_VHT_MCS] = { .type = NLA_U8 },
7146 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
7147 [NL80211_RATE_INFO_VHT_NSS] = { .type = NLA_U8 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007148 };
7149
7150 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7151 genlmsg_attrlen(gnlh, 0), NULL);
7152
7153 /*
7154 * TODO: validate the interface and mac address!
7155 * Otherwise, there's a race condition as soon as
7156 * the kernel starts sending station notifications.
7157 */
7158
7159 if (!tb[NL80211_ATTR_STA_INFO]) {
7160 wpa_printf(MSG_DEBUG, "sta stats missing!");
7161 return NL_SKIP;
7162 }
7163 if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
7164 tb[NL80211_ATTR_STA_INFO],
7165 stats_policy)) {
7166 wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
7167 return NL_SKIP;
7168 }
7169
7170 if (stats[NL80211_STA_INFO_INACTIVE_TIME])
7171 data->inactive_msec =
7172 nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007173 /* For backwards compatibility, fetch the 32-bit counters first. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007174 if (stats[NL80211_STA_INFO_RX_BYTES])
7175 data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
7176 if (stats[NL80211_STA_INFO_TX_BYTES])
7177 data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007178 if (stats[NL80211_STA_INFO_RX_BYTES64] &&
7179 stats[NL80211_STA_INFO_TX_BYTES64]) {
7180 /*
7181 * The driver supports 64-bit counters, so use them to override
7182 * the 32-bit values.
7183 */
7184 data->rx_bytes =
7185 nla_get_u64(stats[NL80211_STA_INFO_RX_BYTES64]);
7186 data->tx_bytes =
7187 nla_get_u64(stats[NL80211_STA_INFO_TX_BYTES64]);
7188 data->bytes_64bit = 1;
7189 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007190 if (stats[NL80211_STA_INFO_RX_PACKETS])
7191 data->rx_packets =
7192 nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
7193 if (stats[NL80211_STA_INFO_TX_PACKETS])
7194 data->tx_packets =
7195 nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
Hai Shalom81f62d82019-07-22 12:10:00 -07007196 if (stats[NL80211_STA_INFO_RX_DURATION])
7197 data->rx_airtime =
7198 nla_get_u64(stats[NL80211_STA_INFO_RX_DURATION]);
7199 if (stats[NL80211_STA_INFO_TX_DURATION])
7200 data->tx_airtime =
7201 nla_get_u64(stats[NL80211_STA_INFO_TX_DURATION]);
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007202 if (stats[NL80211_STA_INFO_TX_FAILED])
7203 data->tx_retry_failed =
7204 nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007205 if (stats[NL80211_STA_INFO_SIGNAL])
7206 data->signal = nla_get_u8(stats[NL80211_STA_INFO_SIGNAL]);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007207 if (stats[NL80211_STA_INFO_ACK_SIGNAL]) {
7208 data->last_ack_rssi =
7209 nla_get_u8(stats[NL80211_STA_INFO_ACK_SIGNAL]);
7210 data->flags |= STA_DRV_DATA_LAST_ACK_RSSI;
7211 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007212
Hai Shalomc1a21442022-02-04 13:43:00 -08007213 if (stats[NL80211_STA_INFO_CONNECTED_TIME]) {
7214 data->connected_sec =
7215 nla_get_u32(stats[NL80211_STA_INFO_CONNECTED_TIME]);
7216 data->flags |= STA_DRV_DATA_CONN_TIME;
7217 }
7218
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007219 if (stats[NL80211_STA_INFO_TX_BITRATE] &&
7220 nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
7221 stats[NL80211_STA_INFO_TX_BITRATE],
7222 rate_policy) == 0) {
7223 if (rate[NL80211_RATE_INFO_BITRATE32])
7224 data->current_tx_rate =
7225 nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
7226 else if (rate[NL80211_RATE_INFO_BITRATE])
7227 data->current_tx_rate =
7228 nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
7229
7230 if (rate[NL80211_RATE_INFO_MCS]) {
7231 data->tx_mcs = nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
7232 data->flags |= STA_DRV_DATA_TX_MCS;
7233 }
7234 if (rate[NL80211_RATE_INFO_VHT_MCS]) {
7235 data->tx_vhtmcs =
7236 nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
7237 data->flags |= STA_DRV_DATA_TX_VHT_MCS;
7238 }
7239 if (rate[NL80211_RATE_INFO_SHORT_GI])
7240 data->flags |= STA_DRV_DATA_TX_SHORT_GI;
7241 if (rate[NL80211_RATE_INFO_VHT_NSS]) {
7242 data->tx_vht_nss =
7243 nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
7244 data->flags |= STA_DRV_DATA_TX_VHT_NSS;
7245 }
7246 }
7247
7248 if (stats[NL80211_STA_INFO_RX_BITRATE] &&
7249 nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
7250 stats[NL80211_STA_INFO_RX_BITRATE],
7251 rate_policy) == 0) {
7252 if (rate[NL80211_RATE_INFO_BITRATE32])
7253 data->current_rx_rate =
7254 nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
7255 else if (rate[NL80211_RATE_INFO_BITRATE])
7256 data->current_rx_rate =
7257 nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
7258
7259 if (rate[NL80211_RATE_INFO_MCS]) {
7260 data->rx_mcs =
7261 nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
7262 data->flags |= STA_DRV_DATA_RX_MCS;
7263 }
7264 if (rate[NL80211_RATE_INFO_VHT_MCS]) {
7265 data->rx_vhtmcs =
7266 nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
7267 data->flags |= STA_DRV_DATA_RX_VHT_MCS;
7268 }
7269 if (rate[NL80211_RATE_INFO_SHORT_GI])
7270 data->flags |= STA_DRV_DATA_RX_SHORT_GI;
7271 if (rate[NL80211_RATE_INFO_VHT_NSS]) {
7272 data->rx_vht_nss =
7273 nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
7274 data->flags |= STA_DRV_DATA_RX_VHT_NSS;
7275 }
7276 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007277
Hai Shalom81f62d82019-07-22 12:10:00 -07007278 if (stats[NL80211_STA_INFO_TID_STATS])
7279 get_sta_tid_stats(data, stats[NL80211_STA_INFO_TID_STATS]);
7280
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007281 return NL_SKIP;
7282}
7283
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007284static int i802_read_sta_data(struct i802_bss *bss,
7285 struct hostap_sta_driver_data *data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007286 const u8 *addr)
7287{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007288 struct nl_msg *msg;
7289
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007290 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_STATION)) ||
7291 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
7292 nlmsg_free(msg);
7293 return -ENOBUFS;
7294 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007295
Hai Shalom899fcc72020-10-19 14:38:18 -07007296 return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data,
7297 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007298}
7299
7300
7301static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
7302 int cw_min, int cw_max, int burst_time)
7303{
7304 struct i802_bss *bss = priv;
7305 struct wpa_driver_nl80211_data *drv = bss->drv;
7306 struct nl_msg *msg;
7307 struct nlattr *txq, *params;
Hai Shalom74f70d42019-02-11 14:42:39 -08007308 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007309
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007310 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007311 if (!msg)
7312 return -1;
7313
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007314 txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
7315 if (!txq)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007316 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007317
7318 /* We are only sending parameters for a single TXQ at a time */
7319 params = nla_nest_start(msg, 1);
7320 if (!params)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007321 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007322
7323 switch (queue) {
7324 case 0:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007325 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO))
7326 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007327 break;
7328 case 1:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007329 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI))
7330 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007331 break;
7332 case 2:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007333 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE))
7334 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007335 break;
7336 case 3:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007337 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK))
7338 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007339 break;
7340 }
7341 /* Burst time is configured in units of 0.1 msec and TXOP parameter in
7342 * 32 usec, so need to convert the value here. */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007343 if (nla_put_u16(msg, NL80211_TXQ_ATTR_TXOP,
7344 (burst_time * 100 + 16) / 32) ||
7345 nla_put_u16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min) ||
7346 nla_put_u16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max) ||
7347 nla_put_u8(msg, NL80211_TXQ_ATTR_AIFS, aifs))
7348 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007349
7350 nla_nest_end(msg, params);
7351
7352 nla_nest_end(msg, txq);
7353
Hai Shalom899fcc72020-10-19 14:38:18 -07007354 res = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalom74f70d42019-02-11 14:42:39 -08007355 wpa_printf(MSG_DEBUG,
7356 "nl80211: TX queue param set: queue=%d aifs=%d cw_min=%d cw_max=%d burst_time=%d --> res=%d",
7357 queue, aifs, cw_min, cw_max, burst_time, res);
7358 if (res == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007359 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007360 msg = NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007361fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007362 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007363 return -1;
7364}
7365
7366
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007367static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007368 const char *ifname, int vlan_id)
7369{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007370 struct wpa_driver_nl80211_data *drv = bss->drv;
7371 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007372 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007373
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007374 wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
7375 ", ifname=%s[%d], vlan_id=%d)",
7376 bss->ifname, if_nametoindex(bss->ifname),
7377 MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007378 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
7379 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Hai Shalom899fcc72020-10-19 14:38:18 -07007380 (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) &&
Hai Shalomfdcde762020-04-02 11:19:20 -07007381 nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007382 nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
7383 nlmsg_free(msg);
7384 return -ENOBUFS;
7385 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007386
Hai Shalom899fcc72020-10-19 14:38:18 -07007387 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007388 if (ret < 0) {
7389 wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
7390 MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
7391 MAC2STR(addr), ifname, vlan_id, ret,
7392 strerror(-ret));
7393 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007394 return ret;
7395}
7396
7397
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007398static int i802_get_inact_sec(void *priv, const u8 *addr)
7399{
7400 struct hostap_sta_driver_data data;
7401 int ret;
7402
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08007403 os_memset(&data, 0, sizeof(data));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007404 data.inactive_msec = (unsigned long) -1;
7405 ret = i802_read_sta_data(priv, &data, addr);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007406 if (ret == -ENOENT)
7407 return -ENOENT;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007408 if (ret || data.inactive_msec == (unsigned long) -1)
7409 return -1;
7410 return data.inactive_msec / 1000;
7411}
7412
7413
7414static int i802_sta_clear_stats(void *priv, const u8 *addr)
7415{
7416#if 0
7417 /* TODO */
7418#endif
7419 return 0;
7420}
7421
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007422
7423static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -07007424 u16 reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007425{
7426 struct i802_bss *bss = priv;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007427 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007428 struct ieee80211_mgmt mgmt;
Dmitry Shmidt29333592017-01-09 12:27:11 -08007429 u8 channel;
7430
7431 if (ieee80211_freq_to_chan(bss->freq, &channel) ==
7432 HOSTAPD_MODE_IEEE80211AD) {
7433 /* Deauthentication is not used in DMG/IEEE 802.11ad;
7434 * disassociate the STA instead. */
7435 return i802_sta_disassoc(priv, own_addr, addr, reason);
7436 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007437
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007438 if (is_mesh_interface(drv->nlmode))
7439 return -1;
7440
Dmitry Shmidt04949592012-07-19 12:16:46 -07007441 if (drv->device_ap_sme)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007442 return wpa_driver_nl80211_sta_remove(bss, addr, 1, reason);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007443
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007444 memset(&mgmt, 0, sizeof(mgmt));
7445 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
7446 WLAN_FC_STYPE_DEAUTH);
7447 memcpy(mgmt.da, addr, ETH_ALEN);
7448 memcpy(mgmt.sa, own_addr, ETH_ALEN);
7449 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
7450 mgmt.u.deauth.reason_code = host_to_le16(reason);
7451 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
7452 IEEE80211_HDRLEN +
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007453 sizeof(mgmt.u.deauth), 0, 0, 0, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -07007454 0, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007455}
7456
7457
7458static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -07007459 u16 reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007460{
7461 struct i802_bss *bss = priv;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007462 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007463 struct ieee80211_mgmt mgmt;
7464
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007465 if (is_mesh_interface(drv->nlmode))
7466 return -1;
7467
Dmitry Shmidt04949592012-07-19 12:16:46 -07007468 if (drv->device_ap_sme)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007469 return wpa_driver_nl80211_sta_remove(bss, addr, 0, reason);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007470
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007471 memset(&mgmt, 0, sizeof(mgmt));
7472 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
7473 WLAN_FC_STYPE_DISASSOC);
7474 memcpy(mgmt.da, addr, ETH_ALEN);
7475 memcpy(mgmt.sa, own_addr, ETH_ALEN);
7476 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
7477 mgmt.u.disassoc.reason_code = host_to_le16(reason);
7478 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
7479 IEEE80211_HDRLEN +
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007480 sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -07007481 0, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007482}
7483
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007484
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007485static void dump_ifidx(struct wpa_driver_nl80211_data *drv)
7486{
7487 char buf[200], *pos, *end;
7488 int i, res;
7489
7490 pos = buf;
7491 end = pos + sizeof(buf);
7492
7493 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007494 if (!drv->if_indices[i].ifindex)
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007495 continue;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007496 res = os_snprintf(pos, end - pos, " %d(%d)",
Hai Shalom81f62d82019-07-22 12:10:00 -07007497 drv->if_indices[i].ifindex,
7498 drv->if_indices[i].reason);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007499 if (os_snprintf_error(end - pos, res))
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007500 break;
7501 pos += res;
7502 }
7503 *pos = '\0';
7504
7505 wpa_printf(MSG_DEBUG, "nl80211: if_indices[%d]:%s",
7506 drv->num_if_indices, buf);
7507}
7508
7509
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007510static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
7511 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007512{
7513 int i;
Hai Shalom81f62d82019-07-22 12:10:00 -07007514 struct drv_nl80211_if_info *old;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007515
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007516 wpa_printf(MSG_DEBUG,
7517 "nl80211: Add own interface ifindex %d (ifidx_reason %d)",
7518 ifidx, ifidx_reason);
7519 if (have_ifidx(drv, ifidx, ifidx_reason)) {
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007520 wpa_printf(MSG_DEBUG, "nl80211: ifindex %d already in the list",
7521 ifidx);
7522 return;
7523 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07007524 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007525 if (drv->if_indices[i].ifindex == 0) {
7526 drv->if_indices[i].ifindex = ifidx;
7527 drv->if_indices[i].reason = ifidx_reason;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007528 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007529 return;
7530 }
7531 }
7532
7533 if (drv->if_indices != drv->default_if_indices)
7534 old = drv->if_indices;
7535 else
7536 old = NULL;
7537
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007538 drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
Hai Shalom81f62d82019-07-22 12:10:00 -07007539 sizeof(*old));
Jouni Malinen75ecf522011-06-27 15:19:46 -07007540 if (!drv->if_indices) {
7541 if (!old)
7542 drv->if_indices = drv->default_if_indices;
7543 else
7544 drv->if_indices = old;
7545 wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
7546 "interfaces");
7547 wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
7548 return;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007549 }
7550 if (!old)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007551 os_memcpy(drv->if_indices, drv->default_if_indices,
7552 sizeof(drv->default_if_indices));
Hai Shalom81f62d82019-07-22 12:10:00 -07007553 drv->if_indices[drv->num_if_indices].ifindex = ifidx;
7554 drv->if_indices[drv->num_if_indices].reason = ifidx_reason;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007555 drv->num_if_indices++;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007556 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007557}
7558
7559
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007560static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
7561 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007562{
7563 int i;
7564
7565 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007566 if ((drv->if_indices[i].ifindex == ifidx ||
7567 ifidx == IFIDX_ANY) &&
7568 (drv->if_indices[i].reason == ifidx_reason ||
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007569 ifidx_reason == IFIDX_ANY)) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007570 drv->if_indices[i].ifindex = 0;
7571 drv->if_indices[i].reason = 0;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007572 break;
7573 }
7574 }
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007575 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007576}
7577
7578
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007579static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
7580 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007581{
7582 int i;
7583
7584 for (i = 0; i < drv->num_if_indices; i++)
Hai Shalom81f62d82019-07-22 12:10:00 -07007585 if (drv->if_indices[i].ifindex == ifidx &&
7586 (drv->if_indices[i].reason == ifidx_reason ||
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007587 ifidx_reason == IFIDX_ANY))
Jouni Malinen75ecf522011-06-27 15:19:46 -07007588 return 1;
7589
7590 return 0;
7591}
7592
7593
7594static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07007595 const char *bridge_ifname, char *ifname_wds)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007596{
7597 struct i802_bss *bss = priv;
7598 struct wpa_driver_nl80211_data *drv = bss->drv;
7599 char name[IFNAMSIZ + 1];
Roshan Pius3a1667e2018-07-03 15:17:14 -07007600 union wpa_event_data event;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08007601 int ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007602
Hai Shalom39ba6fc2019-01-22 12:40:38 -08007603 ret = os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
7604 if (ret >= (int) sizeof(name))
7605 wpa_printf(MSG_WARNING,
7606 "nl80211: WDS interface name was truncated");
7607 else if (ret < 0)
7608 return ret;
7609
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07007610 if (ifname_wds)
7611 os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
7612
Jouni Malinen75ecf522011-06-27 15:19:46 -07007613 wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
7614 " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
7615 if (val) {
7616 if (!if_nametoindex(name)) {
7617 if (nl80211_create_iface(drv, name,
7618 NL80211_IFTYPE_AP_VLAN,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007619 bss->addr, 1, NULL, NULL, 0) <
7620 0)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007621 return -1;
7622 if (bridge_ifname &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007623 linux_br_add_if(drv->global->ioctl_sock,
7624 bridge_ifname, name) < 0)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007625 return -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007626
7627 os_memset(&event, 0, sizeof(event));
7628 event.wds_sta_interface.sta_addr = addr;
7629 event.wds_sta_interface.ifname = name;
7630 event.wds_sta_interface.istatus = INTERFACE_ADDED;
Hai Shalomce48b4a2018-09-05 11:41:35 -07007631 wpa_supplicant_event(bss->ctx,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007632 EVENT_WDS_STA_INTERFACE_STATUS,
7633 &event);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007634 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007635 if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
7636 wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
7637 "interface %s up", name);
7638 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07007639 return i802_set_sta_vlan(priv, addr, name, 0);
7640 } else {
Hai Shalom74f70d42019-02-11 14:42:39 -08007641 if (bridge_ifname &&
7642 linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
7643 name) < 0)
7644 wpa_printf(MSG_INFO,
7645 "nl80211: Failed to remove interface %s from bridge %s: %s",
7646 name, bridge_ifname, strerror(errno));
Dmitry Shmidtaa532512012-09-24 10:35:31 -07007647
Jouni Malinen75ecf522011-06-27 15:19:46 -07007648 i802_set_sta_vlan(priv, addr, bss->ifname, 0);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007649 nl80211_remove_iface(drv, if_nametoindex(name));
Roshan Pius3a1667e2018-07-03 15:17:14 -07007650 os_memset(&event, 0, sizeof(event));
7651 event.wds_sta_interface.sta_addr = addr;
7652 event.wds_sta_interface.ifname = name;
7653 event.wds_sta_interface.istatus = INTERFACE_REMOVED;
Hai Shalomce48b4a2018-09-05 11:41:35 -07007654 wpa_supplicant_event(bss->ctx, EVENT_WDS_STA_INTERFACE_STATUS,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007655 &event);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007656 return 0;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007657 }
7658}
7659
7660
7661static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
7662{
7663 struct wpa_driver_nl80211_data *drv = eloop_ctx;
7664 struct sockaddr_ll lladdr;
7665 unsigned char buf[3000];
7666 int len;
7667 socklen_t fromlen = sizeof(lladdr);
7668
7669 len = recvfrom(sock, buf, sizeof(buf), 0,
7670 (struct sockaddr *)&lladdr, &fromlen);
7671 if (len < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007672 wpa_printf(MSG_ERROR, "nl80211: EAPOL recv failed: %s",
7673 strerror(errno));
Jouni Malinen75ecf522011-06-27 15:19:46 -07007674 return;
7675 }
7676
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007677 if (have_ifidx(drv, lladdr.sll_ifindex, IFIDX_ANY))
Jouni Malinen75ecf522011-06-27 15:19:46 -07007678 drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
7679}
7680
7681
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007682static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
7683 struct i802_bss *bss,
7684 const char *brname, const char *ifname)
7685{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007686 int br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007687 char in_br[IFNAMSIZ];
7688
7689 os_strlcpy(bss->brname, brname, IFNAMSIZ);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007690 br_ifindex = if_nametoindex(brname);
7691 if (br_ifindex == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007692 /*
7693 * Bridge was configured, but the bridge device does
7694 * not exist. Try to add it now.
7695 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007696 if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007697 wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
7698 "bridge interface %s: %s",
7699 brname, strerror(errno));
7700 return -1;
7701 }
7702 bss->added_bridge = 1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007703 br_ifindex = if_nametoindex(brname);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007704 add_ifidx(drv, br_ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007705 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007706 bss->br_ifindex = br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007707
7708 if (linux_br_get(in_br, ifname) == 0) {
Hai Shalomc9e41a12018-07-31 14:41:42 -07007709 if (os_strcmp(in_br, brname) == 0) {
7710 bss->already_in_bridge = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007711 return 0; /* already in the bridge */
Hai Shalomc9e41a12018-07-31 14:41:42 -07007712 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007713
7714 wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
7715 "bridge %s", ifname, in_br);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007716 if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
7717 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007718 wpa_printf(MSG_ERROR, "nl80211: Failed to "
7719 "remove interface %s from bridge "
7720 "%s: %s",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007721 ifname, in_br, strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007722 return -1;
7723 }
7724 }
7725
7726 wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
7727 ifname, brname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007728 if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08007729 wpa_printf(MSG_WARNING,
7730 "nl80211: Failed to add interface %s into bridge %s: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007731 ifname, brname, strerror(errno));
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08007732 /* Try to continue without the interface being in a bridge. This
7733 * may be needed for some cases, e.g., with Open vSwitch, where
7734 * an external component will need to handle bridge
7735 * configuration. */
7736 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007737 }
7738 bss->added_if_into_bridge = 1;
7739
7740 return 0;
7741}
7742
7743
7744static void *i802_init(struct hostapd_data *hapd,
7745 struct wpa_init_params *params)
7746{
7747 struct wpa_driver_nl80211_data *drv;
7748 struct i802_bss *bss;
7749 size_t i;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007750 char master_ifname[IFNAMSIZ];
7751 int ifindex, br_ifindex = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007752 int br_added = 0;
7753
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08007754 bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
7755 params->global_priv, 1,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007756 params->bssid, params->driver_params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007757 if (bss == NULL)
7758 return NULL;
7759
7760 drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007761
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007762 if (linux_br_get(master_ifname, params->ifname) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007763 wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007764 params->ifname, master_ifname);
7765 br_ifindex = if_nametoindex(master_ifname);
7766 os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
7767 } else if ((params->num_bridge == 0 || !params->bridge[0]) &&
7768 linux_master_get(master_ifname, params->ifname) == 0) {
7769 wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in master %s",
7770 params->ifname, master_ifname);
7771 /* start listening for EAPOL on the master interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007772 add_ifidx(drv, if_nametoindex(master_ifname), drv->ifindex);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08007773
7774 /* check if master itself is under bridge */
7775 if (linux_br_get(master_ifname, master_ifname) == 0) {
7776 wpa_printf(MSG_DEBUG, "nl80211: which is in bridge %s",
7777 master_ifname);
7778 br_ifindex = if_nametoindex(master_ifname);
7779 os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
7780 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007781 } else {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007782 master_ifname[0] = '\0';
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007783 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007784
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007785 bss->br_ifindex = br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007786
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007787 for (i = 0; i < params->num_bridge; i++) {
7788 if (params->bridge[i]) {
7789 ifindex = if_nametoindex(params->bridge[i]);
7790 if (ifindex)
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007791 add_ifidx(drv, ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007792 if (ifindex == br_ifindex)
7793 br_added = 1;
7794 }
7795 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007796
7797 /* start listening for EAPOL on the default AP interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007798 add_ifidx(drv, drv->ifindex, IFIDX_ANY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007799
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007800 if (params->num_bridge && params->bridge[0]) {
7801 if (i802_check_bridge(drv, bss, params->bridge[0],
7802 params->ifname) < 0)
7803 goto failed;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007804 if (os_strcmp(params->bridge[0], master_ifname) != 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007805 br_added = 1;
7806 }
7807
7808 if (!br_added && br_ifindex &&
7809 (params->num_bridge == 0 || !params->bridge[0]))
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007810 add_ifidx(drv, br_ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007811
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007812#ifdef CONFIG_LIBNL3_ROUTE
Hai Shalomc9e41a12018-07-31 14:41:42 -07007813 if (bss->added_if_into_bridge || bss->already_in_bridge) {
Hai Shalomfdcde762020-04-02 11:19:20 -07007814 int err;
7815
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007816 drv->rtnl_sk = nl_socket_alloc();
7817 if (drv->rtnl_sk == NULL) {
7818 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
7819 goto failed;
7820 }
7821
Hai Shalomfdcde762020-04-02 11:19:20 -07007822 err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE);
7823 if (err) {
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007824 wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -07007825 nl_geterror(err));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007826 goto failed;
7827 }
7828 }
7829#endif /* CONFIG_LIBNL3_ROUTE */
7830
Hai Shalomb755a2a2020-04-23 21:49:02 -07007831 if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) {
7832 wpa_printf(MSG_DEBUG,
7833 "nl80211: Do not open EAPOL RX socket - using control port for RX");
7834 goto skip_eapol_sock;
7835 }
7836
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007837 drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
7838 if (drv->eapol_sock < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007839 wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
7840 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007841 goto failed;
7842 }
7843
7844 if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
7845 {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007846 wpa_printf(MSG_INFO, "nl80211: Could not register read socket for eapol");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007847 goto failed;
7848 }
Hai Shalomb755a2a2020-04-23 21:49:02 -07007849skip_eapol_sock:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007850
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007851 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
7852 params->own_addr))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007853 goto failed;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007854 os_memcpy(drv->perm_addr, params->own_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007855
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007856 memcpy(bss->addr, params->own_addr, ETH_ALEN);
7857
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007858 return bss;
7859
7860failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007861 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007862 return NULL;
7863}
7864
7865
7866static void i802_deinit(void *priv)
7867{
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007868 struct i802_bss *bss = priv;
7869 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007870}
7871
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007872
7873static enum nl80211_iftype wpa_driver_nl80211_if_type(
7874 enum wpa_driver_if_type type)
7875{
7876 switch (type) {
7877 case WPA_IF_STATION:
7878 return NL80211_IFTYPE_STATION;
7879 case WPA_IF_P2P_CLIENT:
7880 case WPA_IF_P2P_GROUP:
7881 return NL80211_IFTYPE_P2P_CLIENT;
7882 case WPA_IF_AP_VLAN:
7883 return NL80211_IFTYPE_AP_VLAN;
7884 case WPA_IF_AP_BSS:
7885 return NL80211_IFTYPE_AP;
7886 case WPA_IF_P2P_GO:
7887 return NL80211_IFTYPE_P2P_GO;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007888 case WPA_IF_P2P_DEVICE:
7889 return NL80211_IFTYPE_P2P_DEVICE;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007890 case WPA_IF_MESH:
7891 return NL80211_IFTYPE_MESH_POINT;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007892 default:
7893 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007894 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007895}
7896
7897
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007898static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
7899{
7900 struct wpa_driver_nl80211_data *drv;
7901 dl_list_for_each(drv, &global->interfaces,
7902 struct wpa_driver_nl80211_data, list) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007903 if (os_memcmp(addr, drv->first_bss->addr, ETH_ALEN) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007904 return 1;
7905 }
7906 return 0;
7907}
7908
7909
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007910static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007911{
7912 unsigned int idx;
7913
7914 if (!drv->global)
7915 return -1;
7916
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007917 os_memcpy(new_addr, drv->first_bss->addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007918 for (idx = 0; idx < 64; idx++) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007919 new_addr[0] = drv->first_bss->addr[0] | 0x02;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007920 new_addr[0] ^= idx << 2;
7921 if (!nl80211_addr_in_use(drv->global, new_addr))
7922 break;
7923 }
7924 if (idx == 64)
7925 return -1;
7926
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007927 wpa_printf(MSG_DEBUG, "nl80211: Assigned new virtual interface address "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007928 MACSTR, MAC2STR(new_addr));
7929
7930 return 0;
7931}
7932
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007933
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007934struct wdev_info {
7935 u64 wdev_id;
7936 int wdev_id_set;
7937 u8 macaddr[ETH_ALEN];
7938};
7939
7940static int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
7941{
7942 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7943 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7944 struct wdev_info *wi = arg;
7945
7946 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7947 genlmsg_attrlen(gnlh, 0), NULL);
7948 if (tb[NL80211_ATTR_WDEV]) {
7949 wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
7950 wi->wdev_id_set = 1;
7951 }
7952
7953 if (tb[NL80211_ATTR_MAC])
7954 os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
7955 ETH_ALEN);
7956
7957 return NL_SKIP;
7958}
7959
7960
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007961static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
7962 const char *ifname, const u8 *addr,
7963 void *bss_ctx, void **drv_priv,
7964 char *force_ifname, u8 *if_addr,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007965 const char *bridge, int use_existing,
7966 int setup_ap)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007967{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007968 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007969 struct i802_bss *bss = priv;
7970 struct wpa_driver_nl80211_data *drv = bss->drv;
7971 int ifidx;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007972 int added = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007973
7974 if (addr)
7975 os_memcpy(if_addr, addr, ETH_ALEN);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007976 nlmode = wpa_driver_nl80211_if_type(type);
7977 if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
7978 struct wdev_info p2pdev_info;
7979
7980 os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
7981 ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
7982 0, nl80211_wdev_handler,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007983 &p2pdev_info, use_existing);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007984 if (!p2pdev_info.wdev_id_set || ifidx != 0) {
7985 wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
7986 ifname);
7987 return -1;
7988 }
7989
7990 drv->global->if_add_wdevid = p2pdev_info.wdev_id;
7991 drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
Mir Ali8a8f1002020-10-06 22:41:40 +05307992 if (!is_zero_ether_addr(p2pdev_info.macaddr)) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007993 os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
Mir Ali8a8f1002020-10-06 22:41:40 +05307994 os_memcpy(drv->global->p2p_perm_addr, p2pdev_info.macaddr, ETH_ALEN);
7995 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007996 wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
7997 ifname,
7998 (long long unsigned int) p2pdev_info.wdev_id);
7999 } else {
8000 ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008001 0, NULL, NULL, use_existing);
8002 if (use_existing && ifidx == -ENFILE) {
8003 added = 0;
8004 ifidx = if_nametoindex(ifname);
8005 } else if (ifidx < 0) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008006 return -1;
8007 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008008 }
8009
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008010 if (!addr) {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07008011 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008012 os_memcpy(if_addr, bss->addr, ETH_ALEN);
8013 else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07008014 ifname, if_addr) < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008015 if (added)
8016 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008017 return -1;
8018 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008019 }
8020
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008021 if (!addr &&
8022 (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07008023 type == WPA_IF_P2P_GO || type == WPA_IF_MESH ||
8024 type == WPA_IF_STATION)) {
8025 /* Enforce unique address */
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008026 u8 new_addr[ETH_ALEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008027
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008028 if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008029 new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07008030 if (added)
8031 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008032 return -1;
8033 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008034 if (nl80211_addr_in_use(drv->global, new_addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008035 wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07008036 "for interface %s type %d", ifname, type);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008037 if (nl80211_vif_addr(drv, new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07008038 if (added)
8039 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008040 return -1;
8041 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008042 if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008043 new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07008044 if (added)
8045 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008046 return -1;
8047 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008048 }
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008049 os_memcpy(if_addr, new_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008050 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008051
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008052 if (type == WPA_IF_AP_BSS && setup_ap) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008053 struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
8054 if (new_bss == NULL) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008055 if (added)
8056 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008057 return -1;
8058 }
8059
8060 if (bridge &&
8061 i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
8062 wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
8063 "interface %s to a bridge %s",
8064 ifname, bridge);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008065 if (added)
8066 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008067 os_free(new_bss);
8068 return -1;
8069 }
8070
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008071 if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
8072 {
Dmitry Shmidt71757432014-06-02 13:50:35 -07008073 if (added)
8074 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008075 os_free(new_bss);
8076 return -1;
8077 }
8078 os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008079 os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008080 new_bss->ifindex = ifidx;
8081 new_bss->drv = drv;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008082 new_bss->next = drv->first_bss->next;
8083 new_bss->freq = drv->first_bss->freq;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08008084 new_bss->ctx = bss_ctx;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008085 new_bss->added_if = added;
8086 drv->first_bss->next = new_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008087 if (drv_priv)
8088 *drv_priv = new_bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008089 nl80211_init_bss(new_bss);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008090
8091 /* Subscribe management frames for this WPA_IF_AP_BSS */
8092 if (nl80211_setup_ap(new_bss))
8093 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008094 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008095
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008096 if (drv->global)
8097 drv->global->if_add_ifindex = ifidx;
8098
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07008099 /*
8100 * Some virtual interfaces need to process EAPOL packets and events on
8101 * the parent interface. This is used mainly with hostapd.
8102 */
8103 if (ifidx > 0 &&
8104 (drv->hostapd ||
8105 nlmode == NL80211_IFTYPE_AP_VLAN ||
8106 nlmode == NL80211_IFTYPE_WDS ||
8107 nlmode == NL80211_IFTYPE_MONITOR))
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008108 add_ifidx(drv, ifidx, IFIDX_ANY);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008109
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008110 return 0;
8111}
8112
8113
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008114static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008115 enum wpa_driver_if_type type,
8116 const char *ifname)
8117{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008118 struct wpa_driver_nl80211_data *drv = bss->drv;
8119 int ifindex = if_nametoindex(ifname);
8120
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008121 wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
8122 __func__, type, ifname, ifindex, bss->added_if);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08008123 if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
Dmitry Shmidt051af732013-10-22 13:52:46 -07008124 nl80211_remove_iface(drv, ifindex);
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07008125 else if (ifindex > 0 && !bss->added_if) {
8126 struct wpa_driver_nl80211_data *drv2;
8127 dl_list_for_each(drv2, &drv->global->interfaces,
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008128 struct wpa_driver_nl80211_data, list) {
8129 del_ifidx(drv2, ifindex, IFIDX_ANY);
8130 del_ifidx(drv2, IFIDX_ANY, ifindex);
8131 }
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07008132 }
Dmitry Shmidtaa532512012-09-24 10:35:31 -07008133
Dmitry Shmidtaa532512012-09-24 10:35:31 -07008134 if (type != WPA_IF_AP_BSS)
8135 return 0;
8136
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008137 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008138 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
8139 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008140 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
8141 "interface %s from bridge %s: %s",
8142 bss->ifname, bss->brname, strerror(errno));
8143 }
8144 if (bss->added_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008145 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008146 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
8147 "bridge %s: %s",
8148 bss->brname, strerror(errno));
8149 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008150
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008151 if (bss != drv->first_bss) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008152 struct i802_bss *tbss;
8153
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008154 wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it");
8155 for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008156 if (tbss->next == bss) {
8157 tbss->next = bss->next;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008158 /* Unsubscribe management frames */
8159 nl80211_teardown_ap(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008160 nl80211_destroy_bss(bss);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008161 if (!bss->added_if)
8162 i802_set_iface_flags(bss, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008163 os_free(bss);
8164 bss = NULL;
8165 break;
8166 }
8167 }
8168 if (bss)
8169 wpa_printf(MSG_INFO, "nl80211: %s - could not find "
8170 "BSS %p in the list", __func__, bss);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008171 } else {
8172 wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
8173 nl80211_teardown_ap(bss);
8174 if (!bss->added_if && !drv->first_bss->next)
Paul Stewart092955c2017-02-06 09:13:09 -08008175 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008176 nl80211_destroy_bss(bss);
8177 if (!bss->added_if)
8178 i802_set_iface_flags(bss, 0);
8179 if (drv->first_bss->next) {
8180 drv->first_bss = drv->first_bss->next;
8181 drv->ctx = drv->first_bss->ctx;
8182 os_free(bss);
8183 } else {
8184 wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
8185 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008186 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008187
8188 return 0;
8189}
8190
8191
8192static int cookie_handler(struct nl_msg *msg, void *arg)
8193{
8194 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8195 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8196 u64 *cookie = arg;
8197 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8198 genlmsg_attrlen(gnlh, 0), NULL);
8199 if (tb[NL80211_ATTR_COOKIE])
8200 *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
8201 return NL_SKIP;
8202}
8203
8204
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008205static int nl80211_send_frame_cmd(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008206 unsigned int freq, unsigned int wait,
8207 const u8 *buf, size_t buf_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07008208 int save_cookie, int no_cck, int no_ack,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008209 int offchanok, const u16 *csa_offs,
8210 size_t csa_offs_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008211{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008212 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008213 struct nl_msg *msg;
8214 u64 cookie;
8215 int ret = -1;
8216
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008217 wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
Dmitry Shmidt04949592012-07-19 12:16:46 -07008218 "no_ack=%d offchanok=%d",
8219 freq, wait, no_cck, no_ack, offchanok);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07008220 wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008221
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008222 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME)) ||
8223 (freq && nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
8224 (wait && nla_put_u32(msg, NL80211_ATTR_DURATION, wait)) ||
8225 (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
8226 drv->test_use_roc_tx) &&
8227 nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) ||
8228 (no_cck && nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) ||
8229 (no_ack && nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK)) ||
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008230 (csa_offs && nla_put(msg, NL80211_ATTR_CSA_C_OFFSETS_TX,
8231 csa_offs_len * sizeof(u16), csa_offs)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008232 nla_put(msg, NL80211_ATTR_FRAME, buf_len, buf))
8233 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008234
8235 cookie = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -07008236 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008237 msg = NULL;
8238 if (ret) {
8239 wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008240 "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
8241 freq, wait);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008242 } else {
8243 wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
8244 "cookie 0x%llx", no_ack ? " (no ACK)" : "",
8245 (long long unsigned int) cookie);
8246
Hai Shalomfdcde762020-04-02 11:19:20 -07008247 if (save_cookie)
8248 drv->send_frame_cookie = no_ack ? (u64) -1 : cookie;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008249
Hai Shalomfdcde762020-04-02 11:19:20 -07008250 if (drv->num_send_frame_cookies == MAX_SEND_FRAME_COOKIES) {
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008251 wpa_printf(MSG_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07008252 "nl80211: Drop oldest pending send frame cookie 0x%llx",
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008253 (long long unsigned int)
Hai Shalomfdcde762020-04-02 11:19:20 -07008254 drv->send_frame_cookies[0]);
8255 os_memmove(&drv->send_frame_cookies[0],
8256 &drv->send_frame_cookies[1],
8257 (MAX_SEND_FRAME_COOKIES - 1) *
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008258 sizeof(u64));
Hai Shalomfdcde762020-04-02 11:19:20 -07008259 drv->num_send_frame_cookies--;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008260 }
Hai Shalomfdcde762020-04-02 11:19:20 -07008261 drv->send_frame_cookies[drv->num_send_frame_cookies] = cookie;
8262 drv->num_send_frame_cookies++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008263 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008264
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008265fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008266 nlmsg_free(msg);
8267 return ret;
8268}
8269
8270
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008271static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
8272 unsigned int freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008273 unsigned int wait_time,
8274 const u8 *dst, const u8 *src,
8275 const u8 *bssid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008276 const u8 *data, size_t data_len,
8277 int no_cck)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008278{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008279 struct wpa_driver_nl80211_data *drv = bss->drv;
8280 int ret = -1;
8281 u8 *buf;
8282 struct ieee80211_hdr *hdr;
Hai Shalomfdcde762020-04-02 11:19:20 -07008283 int offchanok = 1;
8284
Hai Shalom4fbc08f2020-05-18 12:37:00 -07008285 if (is_ap_interface(drv->nlmode) && (int) freq == bss->freq &&
8286 bss->beacon_set)
Hai Shalomfdcde762020-04-02 11:19:20 -07008287 offchanok = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008288
8289 wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
Hai Shalomfdcde762020-04-02 11:19:20 -07008290 "freq=%u MHz wait=%d ms no_cck=%d offchanok=%d)",
8291 drv->ifindex, freq, wait_time, no_cck, offchanok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008292
8293 buf = os_zalloc(24 + data_len);
8294 if (buf == NULL)
8295 return ret;
8296 os_memcpy(buf + 24, data, data_len);
8297 hdr = (struct ieee80211_hdr *) buf;
8298 hdr->frame_control =
8299 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
8300 os_memcpy(hdr->addr1, dst, ETH_ALEN);
8301 os_memcpy(hdr->addr2, src, ETH_ALEN);
8302 os_memcpy(hdr->addr3, bssid, ETH_ALEN);
8303
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08008304 if (os_memcmp(bss->addr, src, ETH_ALEN) != 0) {
8305 wpa_printf(MSG_DEBUG, "nl80211: Use random TA " MACSTR,
8306 MAC2STR(src));
8307 os_memcpy(bss->rand_addr, src, ETH_ALEN);
8308 } else {
8309 os_memset(bss->rand_addr, 0, ETH_ALEN);
8310 }
8311
Hai Shalom60840252021-02-19 19:02:11 -08008312#ifdef CONFIG_MESH
8313 if (is_mesh_interface(drv->nlmode)) {
8314 struct hostapd_hw_modes *modes;
8315 u16 num_modes, flags;
8316 u8 dfs_domain;
8317 int i;
8318
8319 modes = nl80211_get_hw_feature_data(bss, &num_modes,
8320 &flags, &dfs_domain);
8321 if (dfs_domain != HOSTAPD_DFS_REGION_ETSI &&
8322 ieee80211_is_dfs(bss->freq, modes, num_modes))
8323 offchanok = 0;
8324 if (modes) {
8325 for (i = 0; i < num_modes; i++) {
8326 os_free(modes[i].channels);
8327 os_free(modes[i].rates);
8328 }
8329 os_free(modes);
8330 }
8331 }
8332#endif /* CONFIG_MESH */
8333
Dmitry Shmidt56052862013-10-04 10:23:25 -07008334 if (is_ap_interface(drv->nlmode) &&
8335 (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
8336 (int) freq == bss->freq || drv->device_ap_sme ||
8337 !drv->use_monitor))
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008338 ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07008339 0, freq, no_cck, offchanok,
8340 wait_time, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008341 else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008342 ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008343 24 + data_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07008344 1, no_cck, 0, offchanok, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008345
8346 os_free(buf);
8347 return ret;
8348}
8349
8350
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008351static void nl80211_frame_wait_cancel(struct i802_bss *bss, u64 cookie)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008352{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008353 struct wpa_driver_nl80211_data *drv = bss->drv;
8354 struct nl_msg *msg;
8355 int ret;
8356
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08008357 wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008358 (long long unsigned int) cookie);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008359 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME_WAIT_CANCEL)) ||
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008360 nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008361 nlmsg_free(msg);
8362 return;
8363 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008364
Hai Shalom899fcc72020-10-19 14:38:18 -07008365 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008366 if (ret)
8367 wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
8368 "(%s)", ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008369}
8370
8371
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008372static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
8373{
8374 struct i802_bss *bss = priv;
8375 struct wpa_driver_nl80211_data *drv = bss->drv;
8376 unsigned int i;
8377 u64 cookie;
8378
8379 /* Cancel the last pending TX cookie */
Hai Shalomfdcde762020-04-02 11:19:20 -07008380 nl80211_frame_wait_cancel(bss, drv->send_frame_cookie);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008381
8382 /*
8383 * Cancel the other pending TX cookies, if any. This is needed since
8384 * the driver may keep a list of all pending offchannel TX operations
8385 * and free up the radio only once they have expired or cancelled.
8386 */
Hai Shalomfdcde762020-04-02 11:19:20 -07008387 for (i = drv->num_send_frame_cookies; i > 0; i--) {
8388 cookie = drv->send_frame_cookies[i - 1];
8389 if (cookie != drv->send_frame_cookie)
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008390 nl80211_frame_wait_cancel(bss, cookie);
8391 }
Hai Shalomfdcde762020-04-02 11:19:20 -07008392 drv->num_send_frame_cookies = 0;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008393}
8394
8395
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008396static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
8397 unsigned int duration)
8398{
8399 struct i802_bss *bss = priv;
8400 struct wpa_driver_nl80211_data *drv = bss->drv;
8401 struct nl_msg *msg;
8402 int ret;
8403 u64 cookie;
8404
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008405 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REMAIN_ON_CHANNEL)) ||
8406 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
8407 nla_put_u32(msg, NL80211_ATTR_DURATION, duration)) {
8408 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008409 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008410 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008411
8412 cookie = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -07008413 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008414 if (ret == 0) {
8415 wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
8416 "0x%llx for freq=%u MHz duration=%u",
8417 (long long unsigned int) cookie, freq, duration);
8418 drv->remain_on_chan_cookie = cookie;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008419 drv->pending_remain_on_chan = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008420 return 0;
8421 }
8422 wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
8423 "(freq=%d duration=%u): %d (%s)",
8424 freq, duration, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008425 return -1;
8426}
8427
8428
8429static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
8430{
8431 struct i802_bss *bss = priv;
8432 struct wpa_driver_nl80211_data *drv = bss->drv;
8433 struct nl_msg *msg;
8434 int ret;
8435
8436 if (!drv->pending_remain_on_chan) {
8437 wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
8438 "to cancel");
8439 return -1;
8440 }
8441
8442 wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
8443 "0x%llx",
8444 (long long unsigned int) drv->remain_on_chan_cookie);
8445
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008446 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
8447 if (!msg ||
8448 nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie)) {
8449 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008450 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008451 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008452
Hai Shalom899fcc72020-10-19 14:38:18 -07008453 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008454 if (ret == 0)
8455 return 0;
8456 wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
8457 "%d (%s)", ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008458 return -1;
8459}
8460
8461
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008462static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008463{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008464 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008465
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008466 if (!report) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008467 if (bss->nl_preq && drv->device_ap_sme &&
Dmitry Shmidt03658832014-08-13 11:03:49 -07008468 is_ap_interface(drv->nlmode) && !bss->in_deinit &&
8469 !bss->static_ap) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008470 /*
8471 * Do not disable Probe Request reporting that was
8472 * enabled in nl80211_setup_ap().
8473 */
8474 wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
8475 "Probe Request reporting nl_preq=%p while "
8476 "in AP mode", bss->nl_preq);
8477 } else if (bss->nl_preq) {
8478 wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
8479 "reporting nl_preq=%p", bss->nl_preq);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008480 nl80211_destroy_eloop_handle(&bss->nl_preq, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008481 }
8482 return 0;
8483 }
8484
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008485 if (bss->nl_preq) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008486 wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008487 "already on! nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008488 return 0;
8489 }
8490
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008491 bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
8492 if (bss->nl_preq == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008493 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008494 wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
8495 "reporting nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008496
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008497 if (nl80211_register_frame(bss, bss->nl_preq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008498 (WLAN_FC_TYPE_MGMT << 2) |
8499 (WLAN_FC_STYPE_PROBE_REQ << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07008500 NULL, 0, false) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008501 goto out_err;
Dmitry Shmidt497c1d52011-07-21 15:19:46 -07008502
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008503 nl80211_register_eloop_read(&bss->nl_preq,
8504 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07008505 bss->nl_cb, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008506
8507 return 0;
8508
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008509 out_err:
8510 nl_destroy_handles(&bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008511 return -1;
8512}
8513
8514
8515static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
8516 int ifindex, int disabled)
8517{
8518 struct nl_msg *msg;
8519 struct nlattr *bands, *band;
8520 int ret;
8521
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008522 wpa_printf(MSG_DEBUG,
8523 "nl80211: NL80211_CMD_SET_TX_BITRATE_MASK (ifindex=%d %s)",
8524 ifindex, disabled ? "NL80211_TXRATE_LEGACY=OFDM-only" :
8525 "no NL80211_TXRATE_LEGACY constraint");
8526
8527 msg = nl80211_ifindex_msg(drv, ifindex, 0,
8528 NL80211_CMD_SET_TX_BITRATE_MASK);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008529 if (!msg)
8530 return -1;
8531
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008532 bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
8533 if (!bands)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008534 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008535
8536 /*
8537 * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
8538 * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
8539 * rates. All 5 GHz rates are left enabled.
8540 */
8541 band = nla_nest_start(msg, NL80211_BAND_2GHZ);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008542 if (!band ||
8543 (disabled && nla_put(msg, NL80211_TXRATE_LEGACY, 8,
8544 "\x0c\x12\x18\x24\x30\x48\x60\x6c")))
8545 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008546 nla_nest_end(msg, band);
8547
8548 nla_nest_end(msg, bands);
8549
Hai Shalom899fcc72020-10-19 14:38:18 -07008550 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008551 if (ret) {
8552 wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
8553 "(%s)", ret, strerror(-ret));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008554 } else
8555 drv->disabled_11b_rates = disabled;
8556
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008557 return ret;
8558
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008559fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008560 nlmsg_free(msg);
8561 return -1;
8562}
8563
8564
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008565static int wpa_driver_nl80211_deinit_ap(void *priv)
8566{
8567 struct i802_bss *bss = priv;
8568 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008569 if (!is_ap_interface(drv->nlmode))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008570 return -1;
Paul Stewart092955c2017-02-06 09:13:09 -08008571 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008572 bss->beacon_set = 0;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008573
8574 /*
8575 * If the P2P GO interface was dynamically added, then it is
8576 * possible that the interface change to station is not possible.
8577 */
8578 if (drv->nlmode == NL80211_IFTYPE_P2P_GO && bss->if_dynamic)
8579 return 0;
8580
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008581 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008582}
8583
8584
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008585static int wpa_driver_nl80211_stop_ap(void *priv)
8586{
8587 struct i802_bss *bss = priv;
8588 struct wpa_driver_nl80211_data *drv = bss->drv;
8589 if (!is_ap_interface(drv->nlmode))
8590 return -1;
Paul Stewart092955c2017-02-06 09:13:09 -08008591 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008592 bss->beacon_set = 0;
8593 return 0;
8594}
8595
8596
Dmitry Shmidt04949592012-07-19 12:16:46 -07008597static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
8598{
8599 struct i802_bss *bss = priv;
8600 struct wpa_driver_nl80211_data *drv = bss->drv;
8601 if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
8602 return -1;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008603
8604 /*
8605 * If the P2P Client interface was dynamically added, then it is
8606 * possible that the interface change to station is not possible.
8607 */
8608 if (bss->if_dynamic)
8609 return 0;
8610
Dmitry Shmidt04949592012-07-19 12:16:46 -07008611 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
8612}
8613
8614
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008615static void wpa_driver_nl80211_resume(void *priv)
8616{
8617 struct i802_bss *bss = priv;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008618 enum nl80211_iftype nlmode = nl80211_get_ifmode(bss);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008619
8620 if (i802_set_iface_flags(bss, 1))
8621 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event");
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008622
8623 if (is_p2p_net_interface(nlmode))
8624 nl80211_disable_11b_rates(bss->drv, bss->drv->ifindex, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008625}
8626
8627
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008628static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
8629{
8630 struct i802_bss *bss = priv;
8631 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008632 struct nl_msg *msg;
8633 struct nlattr *cqm;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008634
8635 wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
8636 "hysteresis=%d", threshold, hysteresis);
8637
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008638 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_CQM)) ||
8639 !(cqm = nla_nest_start(msg, NL80211_ATTR_CQM)) ||
8640 nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold) ||
8641 nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis)) {
8642 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008643 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008644 }
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008645 nla_nest_end(msg, cqm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008646
Hai Shalom899fcc72020-10-19 14:38:18 -07008647 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008648}
8649
8650
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008651static int get_channel_width(struct nl_msg *msg, void *arg)
8652{
8653 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8654 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8655 struct wpa_signal_info *sig_change = arg;
8656
8657 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8658 genlmsg_attrlen(gnlh, 0), NULL);
8659
8660 sig_change->center_frq1 = -1;
8661 sig_change->center_frq2 = -1;
8662 sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
8663
8664 if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
8665 sig_change->chanwidth = convert2width(
8666 nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
8667 if (tb[NL80211_ATTR_CENTER_FREQ1])
8668 sig_change->center_frq1 =
8669 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
8670 if (tb[NL80211_ATTR_CENTER_FREQ2])
8671 sig_change->center_frq2 =
8672 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
8673 }
8674
8675 return NL_SKIP;
8676}
8677
8678
8679static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
8680 struct wpa_signal_info *sig)
8681{
8682 struct nl_msg *msg;
8683
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008684 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
Hai Shalom899fcc72020-10-19 14:38:18 -07008685 return send_and_recv_msgs(drv, msg, get_channel_width, sig, NULL, NULL);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008686}
8687
8688
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008689static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
8690{
8691 struct i802_bss *bss = priv;
8692 struct wpa_driver_nl80211_data *drv = bss->drv;
8693 int res;
8694
8695 os_memset(si, 0, sizeof(*si));
8696 res = nl80211_get_link_signal(drv, si);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008697 if (res) {
8698 if (drv->nlmode != NL80211_IFTYPE_ADHOC &&
8699 drv->nlmode != NL80211_IFTYPE_MESH_POINT)
8700 return res;
8701 si->current_signal = 0;
8702 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008703
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008704 res = nl80211_get_channel_width(drv, si);
8705 if (res != 0)
8706 return res;
8707
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008708 return nl80211_get_link_noise(drv, si);
8709}
8710
8711
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008712static int nl80211_set_param(void *priv, const char *param)
8713{
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07008714 struct i802_bss *bss = priv;
8715 struct wpa_driver_nl80211_data *drv = bss->drv;
8716
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008717 if (param == NULL)
8718 return 0;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08008719 wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008720
8721#ifdef CONFIG_P2P
8722 if (os_strstr(param, "use_p2p_group_interface=1")) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008723 wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
8724 "interface");
8725 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
8726 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
8727 }
8728#endif /* CONFIG_P2P */
8729
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07008730 if (os_strstr(param, "use_monitor=1"))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008731 drv->use_monitor = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008732
8733 if (os_strstr(param, "force_connect_cmd=1")) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008734 drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07008735 drv->force_connect_cmd = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008736 }
8737
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07008738 if (os_strstr(param, "force_bss_selection=1"))
8739 drv->capa.flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
8740
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08008741 if (os_strstr(param, "no_offchannel_tx=1")) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08008742 drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
8743 drv->test_use_roc_tx = 1;
8744 }
8745
Hai Shalomb755a2a2020-04-23 21:49:02 -07008746 if (os_strstr(param, "control_port=0")) {
Hai Shalomfdcde762020-04-02 11:19:20 -07008747 drv->capa.flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
Hai Shalom899fcc72020-10-19 14:38:18 -07008748 drv->capa.flags2 &= ~(WPA_DRIVER_FLAGS2_CONTROL_PORT_RX |
8749 WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS);
8750 drv->control_port_ap = 0;
Hai Shalomb755a2a2020-04-23 21:49:02 -07008751 }
8752
8753 if (os_strstr(param, "control_port_ap=1"))
8754 drv->control_port_ap = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -07008755
Hai Shalom899fcc72020-10-19 14:38:18 -07008756 if (os_strstr(param, "control_port_ap=0")) {
8757 drv->capa.flags2 &= ~WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS;
8758 drv->control_port_ap = 0;
8759 }
8760
Hai Shalomfdcde762020-04-02 11:19:20 -07008761 if (os_strstr(param, "full_ap_client_state=0"))
8762 drv->capa.flags &= ~WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
8763
Hai Shalom899fcc72020-10-19 14:38:18 -07008764 if (os_strstr(param, "no_rrm=1")) {
8765 drv->no_rrm = 1;
8766
8767 if (!bss->in_deinit && !is_ap_interface(drv->nlmode) &&
8768 !is_mesh_interface(drv->nlmode)) {
8769 nl80211_mgmt_unsubscribe(bss, "no_rrm=1");
8770 if (nl80211_mgmt_subscribe_non_ap(bss) < 0)
8771 wpa_printf(MSG_DEBUG,
8772 "nl80211: Failed to re-register Action frame processing - ignore for now");
8773 }
8774 }
8775
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008776 return 0;
8777}
8778
8779
Dmitry Shmidte4663042016-04-04 10:07:49 -07008780static void * nl80211_global_init(void *ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008781{
8782 struct nl80211_global *global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008783 struct netlink_config *cfg;
8784
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008785 global = os_zalloc(sizeof(*global));
8786 if (global == NULL)
8787 return NULL;
Dmitry Shmidte4663042016-04-04 10:07:49 -07008788 global->ctx = ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008789 global->ioctl_sock = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008790 dl_list_init(&global->interfaces);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008791 global->if_add_ifindex = -1;
8792
8793 cfg = os_zalloc(sizeof(*cfg));
8794 if (cfg == NULL)
8795 goto err;
8796
8797 cfg->ctx = global;
8798 cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
8799 cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
8800 global->netlink = netlink_init(cfg);
8801 if (global->netlink == NULL) {
8802 os_free(cfg);
8803 goto err;
8804 }
8805
8806 if (wpa_driver_nl80211_init_nl_global(global) < 0)
8807 goto err;
8808
8809 global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
8810 if (global->ioctl_sock < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008811 wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s",
8812 strerror(errno));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008813 goto err;
8814 }
8815
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008816 return global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008817
8818err:
8819 nl80211_global_deinit(global);
8820 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008821}
8822
8823
8824static void nl80211_global_deinit(void *priv)
8825{
8826 struct nl80211_global *global = priv;
8827 if (global == NULL)
8828 return;
8829 if (!dl_list_empty(&global->interfaces)) {
8830 wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at "
8831 "nl80211_global_deinit",
8832 dl_list_len(&global->interfaces));
8833 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008834
8835 if (global->netlink)
8836 netlink_deinit(global->netlink);
8837
8838 nl_destroy_handles(&global->nl);
8839
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008840 if (global->nl_event)
Roshan Pius3a1667e2018-07-03 15:17:14 -07008841 nl80211_destroy_eloop_handle(&global->nl_event, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008842
8843 nl_cb_put(global->nl_cb);
8844
8845 if (global->ioctl_sock >= 0)
8846 close(global->ioctl_sock);
8847
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008848 os_free(global);
8849}
8850
8851
8852static const char * nl80211_get_radio_name(void *priv)
8853{
8854 struct i802_bss *bss = priv;
8855 struct wpa_driver_nl80211_data *drv = bss->drv;
8856 return drv->phyname;
8857}
8858
8859
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008860static int nl80211_pmkid(struct i802_bss *bss, int cmd,
8861 struct wpa_pmkid_params *params)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008862{
8863 struct nl_msg *msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008864 const size_t PMK_MAX_LEN = 48; /* current cfg80211 limit */
Jouni Malinen75ecf522011-06-27 15:19:46 -07008865
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008866 if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008867 (params->pmkid &&
8868 nla_put(msg, NL80211_ATTR_PMKID, 16, params->pmkid)) ||
8869 (params->bssid &&
8870 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid)) ||
8871 (params->ssid_len &&
8872 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
8873 (params->fils_cache_id &&
8874 nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2,
8875 params->fils_cache_id)) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07008876 (params->pmk_lifetime &&
8877 nla_put_u32(msg, NL80211_ATTR_PMK_LIFETIME,
8878 params->pmk_lifetime)) ||
8879 (params->pmk_reauth_threshold &&
8880 nla_put_u8(msg, NL80211_ATTR_PMK_REAUTH_THRESHOLD,
8881 params->pmk_reauth_threshold)) ||
Hai Shalom021b0b52019-04-10 11:17:58 -07008882 (cmd != NL80211_CMD_DEL_PMKSA &&
8883 params->pmk_len && params->pmk_len <= PMK_MAX_LEN &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008884 nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
Hai Shalom74f70d42019-02-11 14:42:39 -08008885 nl80211_nlmsg_clear(msg);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008886 nlmsg_free(msg);
8887 return -ENOBUFS;
8888 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07008889
Hai Shalom60840252021-02-19 19:02:11 -08008890 return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008891}
8892
8893
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008894static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008895{
8896 struct i802_bss *bss = priv;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008897 int ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008898
8899 if (params->bssid)
8900 wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR,
8901 MAC2STR(params->bssid));
8902 else if (params->fils_cache_id && params->ssid_len) {
8903 wpa_printf(MSG_DEBUG,
8904 "nl80211: Add PMKSA for cache id %02x%02x SSID %s",
8905 params->fils_cache_id[0], params->fils_cache_id[1],
8906 wpa_ssid_txt(params->ssid, params->ssid_len));
8907 }
8908
Roshan Pius3a1667e2018-07-03 15:17:14 -07008909 ret = nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params);
8910 if (ret < 0) {
8911 wpa_printf(MSG_DEBUG,
8912 "nl80211: NL80211_CMD_SET_PMKSA failed: %d (%s)",
8913 ret, strerror(-ret));
8914 }
8915
8916 return ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -07008917}
8918
8919
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008920static int nl80211_remove_pmkid(void *priv, struct wpa_pmkid_params *params)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008921{
8922 struct i802_bss *bss = priv;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008923 int ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008924
8925 if (params->bssid)
8926 wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
8927 MAC2STR(params->bssid));
8928 else if (params->fils_cache_id && params->ssid_len) {
8929 wpa_printf(MSG_DEBUG,
8930 "nl80211: Delete PMKSA for cache id %02x%02x SSID %s",
8931 params->fils_cache_id[0], params->fils_cache_id[1],
8932 wpa_ssid_txt(params->ssid, params->ssid_len));
8933 }
8934
Roshan Pius3a1667e2018-07-03 15:17:14 -07008935 ret = nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params);
8936 if (ret < 0) {
8937 wpa_printf(MSG_DEBUG,
8938 "nl80211: NL80211_CMD_DEL_PMKSA failed: %d (%s)",
8939 ret, strerror(-ret));
8940 }
8941
8942 return ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -07008943}
8944
8945
8946static int nl80211_flush_pmkid(void *priv)
8947{
8948 struct i802_bss *bss = priv;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008949 struct nl_msg *msg;
8950
Jouni Malinen75ecf522011-06-27 15:19:46 -07008951 wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008952 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_FLUSH_PMKSA);
8953 if (!msg)
8954 return -ENOBUFS;
Hai Shalom899fcc72020-10-19 14:38:18 -07008955 return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008956}
8957
8958
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008959static void clean_survey_results(struct survey_results *survey_results)
8960{
8961 struct freq_survey *survey, *tmp;
8962
8963 if (dl_list_empty(&survey_results->survey_list))
8964 return;
8965
8966 dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
8967 struct freq_survey, list) {
8968 dl_list_del(&survey->list);
8969 os_free(survey);
8970 }
8971}
8972
8973
8974static void add_survey(struct nlattr **sinfo, u32 ifidx,
8975 struct dl_list *survey_list)
8976{
8977 struct freq_survey *survey;
8978
8979 survey = os_zalloc(sizeof(struct freq_survey));
8980 if (!survey)
8981 return;
8982
8983 survey->ifidx = ifidx;
8984 survey->freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
8985 survey->filled = 0;
8986
8987 if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
8988 survey->nf = (int8_t)
8989 nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
8990 survey->filled |= SURVEY_HAS_NF;
8991 }
8992
8993 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) {
8994 survey->channel_time =
8995 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
8996 survey->filled |= SURVEY_HAS_CHAN_TIME;
8997 }
8998
8999 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
9000 survey->channel_time_busy =
9001 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
9002 survey->filled |= SURVEY_HAS_CHAN_TIME_BUSY;
9003 }
9004
9005 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) {
9006 survey->channel_time_rx =
9007 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]);
9008 survey->filled |= SURVEY_HAS_CHAN_TIME_RX;
9009 }
9010
9011 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) {
9012 survey->channel_time_tx =
9013 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]);
9014 survey->filled |= SURVEY_HAS_CHAN_TIME_TX;
9015 }
9016
9017 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)",
9018 survey->freq,
9019 survey->nf,
9020 (unsigned long int) survey->channel_time,
9021 (unsigned long int) survey->channel_time_busy,
9022 (unsigned long int) survey->channel_time_tx,
9023 (unsigned long int) survey->channel_time_rx,
9024 survey->filled);
9025
9026 dl_list_add_tail(survey_list, &survey->list);
9027}
9028
9029
9030static int check_survey_ok(struct nlattr **sinfo, u32 surveyed_freq,
9031 unsigned int freq_filter)
9032{
9033 if (!freq_filter)
9034 return 1;
9035
9036 return freq_filter == surveyed_freq;
9037}
9038
9039
9040static int survey_handler(struct nl_msg *msg, void *arg)
9041{
9042 struct nlattr *tb[NL80211_ATTR_MAX + 1];
9043 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
9044 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
9045 struct survey_results *survey_results;
9046 u32 surveyed_freq = 0;
9047 u32 ifidx;
9048
9049 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
9050 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
9051 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
9052 };
9053
9054 survey_results = (struct survey_results *) arg;
9055
9056 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
9057 genlmsg_attrlen(gnlh, 0), NULL);
9058
Dmitry Shmidt97672262014-02-03 13:02:54 -08009059 if (!tb[NL80211_ATTR_IFINDEX])
9060 return NL_SKIP;
9061
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009062 ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
9063
9064 if (!tb[NL80211_ATTR_SURVEY_INFO])
9065 return NL_SKIP;
9066
9067 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
9068 tb[NL80211_ATTR_SURVEY_INFO],
9069 survey_policy))
9070 return NL_SKIP;
9071
9072 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) {
9073 wpa_printf(MSG_ERROR, "nl80211: Invalid survey data");
9074 return NL_SKIP;
9075 }
9076
9077 surveyed_freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
9078
9079 if (!check_survey_ok(sinfo, surveyed_freq,
9080 survey_results->freq_filter))
9081 return NL_SKIP;
9082
9083 if (survey_results->freq_filter &&
9084 survey_results->freq_filter != surveyed_freq) {
9085 wpa_printf(MSG_EXCESSIVE, "nl80211: Ignoring survey data for freq %d MHz",
9086 surveyed_freq);
9087 return NL_SKIP;
9088 }
9089
9090 add_survey(sinfo, ifidx, &survey_results->survey_list);
9091
9092 return NL_SKIP;
9093}
9094
9095
9096static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
9097{
9098 struct i802_bss *bss = priv;
9099 struct wpa_driver_nl80211_data *drv = bss->drv;
9100 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009101 int err;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009102 union wpa_event_data data;
9103 struct survey_results *survey_results;
9104
9105 os_memset(&data, 0, sizeof(data));
9106 survey_results = &data.survey_results;
9107
9108 dl_list_init(&survey_results->survey_list);
9109
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009110 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009111 if (!msg)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009112 return -ENOBUFS;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009113
9114 if (freq)
9115 data.survey_results.freq_filter = freq;
9116
9117 do {
9118 wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
9119 err = send_and_recv_msgs(drv, msg, survey_handler,
Hai Shalom899fcc72020-10-19 14:38:18 -07009120 survey_results, NULL, NULL);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009121 } while (err > 0);
9122
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009123 if (err)
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009124 wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009125 else
9126 wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009127
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009128 clean_survey_results(survey_results);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009129 return err;
9130}
9131
9132
Dmitry Shmidt807291d2015-01-27 13:40:23 -08009133static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
9134 const u8 *kck, size_t kck_len,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009135 const u8 *replay_ctr)
9136{
9137 struct i802_bss *bss = priv;
9138 struct wpa_driver_nl80211_data *drv = bss->drv;
9139 struct nlattr *replay_nested;
9140 struct nl_msg *msg;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08009141 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009142
Dmitry Shmidtff787d52015-01-12 13:01:47 -08009143 if (!drv->set_rekey_offload)
9144 return;
9145
9146 wpa_printf(MSG_DEBUG, "nl80211: Set rekey offload");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009147 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
9148 !(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
Dmitry Shmidt807291d2015-01-27 13:40:23 -08009149 nla_put(msg, NL80211_REKEY_DATA_KEK, kek_len, kek) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009150 (kck_len && nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009151 nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
9152 replay_ctr)) {
9153 nl80211_nlmsg_clear(msg);
9154 nlmsg_free(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009155 return;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009156 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009157
9158 nla_nest_end(msg, replay_nested);
9159
Hai Shalom60840252021-02-19 19:02:11 -08009160 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08009161 if (ret == -EOPNOTSUPP) {
9162 wpa_printf(MSG_DEBUG,
9163 "nl80211: Driver does not support rekey offload");
9164 drv->set_rekey_offload = 0;
9165 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009166}
9167
9168
9169static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
9170 const u8 *addr, int qos)
9171{
9172 /* send data frame to poll STA and check whether
9173 * this frame is ACKed */
9174 struct {
9175 struct ieee80211_hdr hdr;
9176 u16 qos_ctl;
9177 } STRUCT_PACKED nulldata;
9178 size_t size;
9179
9180 /* Send data frame to poll STA and check whether this frame is ACKed */
9181
9182 os_memset(&nulldata, 0, sizeof(nulldata));
9183
9184 if (qos) {
9185 nulldata.hdr.frame_control =
9186 IEEE80211_FC(WLAN_FC_TYPE_DATA,
9187 WLAN_FC_STYPE_QOS_NULL);
9188 size = sizeof(nulldata);
9189 } else {
9190 nulldata.hdr.frame_control =
9191 IEEE80211_FC(WLAN_FC_TYPE_DATA,
9192 WLAN_FC_STYPE_NULLFUNC);
9193 size = sizeof(struct ieee80211_hdr);
9194 }
9195
9196 nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
9197 os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
9198 os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
9199 os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
9200
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009201 if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -07009202 0, 0, NULL, 0, 0) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009203 wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
9204 "send poll frame");
9205}
9206
9207static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
9208 int qos)
9209{
9210 struct i802_bss *bss = priv;
9211 struct wpa_driver_nl80211_data *drv = bss->drv;
9212 struct nl_msg *msg;
Hai Shalom5f92bc92019-04-18 11:54:11 -07009213 u64 cookie;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08009214 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009215
9216 if (!drv->poll_command_supported) {
9217 nl80211_send_null_frame(bss, own_addr, addr, qos);
9218 return;
9219 }
9220
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009221 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_PROBE_CLIENT)) ||
9222 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
9223 nlmsg_free(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009224 return;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009225 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009226
Hai Shalom899fcc72020-10-19 14:38:18 -07009227 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08009228 if (ret < 0) {
9229 wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
9230 MACSTR " failed: ret=%d (%s)",
9231 MAC2STR(addr), ret, strerror(-ret));
Hai Shalom5f92bc92019-04-18 11:54:11 -07009232 } else {
9233 wpa_printf(MSG_DEBUG,
9234 "nl80211: Client probe request addr=" MACSTR
9235 " cookie=%llu", MAC2STR(addr),
9236 (long long unsigned int) cookie);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08009237 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009238}
9239
9240
9241static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
9242{
9243 struct nl_msg *msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009244 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009245
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009246 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
9247 nla_put_u32(msg, NL80211_ATTR_PS_STATE,
9248 enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED)) {
9249 nlmsg_free(msg);
9250 return -ENOBUFS;
9251 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07009252
Hai Shalom899fcc72020-10-19 14:38:18 -07009253 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009254 if (ret < 0) {
9255 wpa_printf(MSG_DEBUG,
9256 "nl80211: Setting PS state %s failed: %d (%s)",
9257 enabled ? "enabled" : "disabled",
9258 ret, strerror(-ret));
9259 }
9260 return ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009261}
9262
9263
9264static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
9265 int ctwindow)
9266{
9267 struct i802_bss *bss = priv;
9268
9269 wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
9270 "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
9271
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08009272 if (opp_ps != -1 || ctwindow != -1) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009273#ifdef ANDROID_P2P
9274 wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08009275#else /* ANDROID_P2P */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009276 return -1; /* Not yet supported */
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08009277#endif /* ANDROID_P2P */
9278 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009279
9280 if (legacy_ps == -1)
9281 return 0;
9282 if (legacy_ps != 0 && legacy_ps != 1)
9283 return -1; /* Not yet supported */
9284
9285 return nl80211_set_power_save(bss, legacy_ps);
9286}
9287
9288
Dmitry Shmidt051af732013-10-22 13:52:46 -07009289static int nl80211_start_radar_detection(void *priv,
9290 struct hostapd_freq_params *freq)
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009291{
9292 struct i802_bss *bss = priv;
9293 struct wpa_driver_nl80211_data *drv = bss->drv;
9294 struct nl_msg *msg;
9295 int ret;
9296
Hai Shalom81f62d82019-07-22 12:10:00 -07009297 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)",
9298 freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
Dmitry Shmidt051af732013-10-22 13:52:46 -07009299 freq->bandwidth, freq->center_freq1, freq->center_freq2);
9300
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009301 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
9302 wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
9303 "detection");
9304 return -1;
9305 }
9306
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009307 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_RADAR_DETECT)) ||
9308 nl80211_put_freq_params(msg, freq) < 0) {
9309 nlmsg_free(msg);
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009310 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009311 }
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009312
Hai Shalom899fcc72020-10-19 14:38:18 -07009313 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009314 if (ret == 0)
9315 return 0;
9316 wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
9317 "%d (%s)", ret, strerror(-ret));
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009318 return -1;
9319}
9320
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009321#ifdef CONFIG_TDLS
9322
Hai Shalomc1a21442022-02-04 13:43:00 -08009323static int nl80211_add_peer_capab(struct nl_msg *msg,
9324 enum tdls_peer_capability capa)
9325{
9326 u32 peer_capab = 0;
9327
9328 if (!capa)
9329 return 0;
9330
9331 if (capa & TDLS_PEER_HT)
9332 peer_capab |= NL80211_TDLS_PEER_HT;
9333 if (capa & TDLS_PEER_VHT)
9334 peer_capab |= NL80211_TDLS_PEER_VHT;
9335 if (capa & TDLS_PEER_WMM)
9336 peer_capab |= NL80211_TDLS_PEER_WMM;
9337 if (capa & TDLS_PEER_HE)
9338 peer_capab |= NL80211_TDLS_PEER_HE;
9339
9340 return nla_put_u32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY,
9341 peer_capab);
9342}
9343
9344
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009345static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
9346 u8 dialog_token, u16 status_code,
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07009347 u32 peer_capab, int initiator, const u8 *buf,
9348 size_t len)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009349{
9350 struct i802_bss *bss = priv;
9351 struct wpa_driver_nl80211_data *drv = bss->drv;
9352 struct nl_msg *msg;
9353
9354 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
9355 return -EOPNOTSUPP;
9356
9357 if (!dst)
9358 return -EINVAL;
9359
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009360 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_MGMT)) ||
9361 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
9362 nla_put_u8(msg, NL80211_ATTR_TDLS_ACTION, action_code) ||
9363 nla_put_u8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token) ||
Hai Shalomc1a21442022-02-04 13:43:00 -08009364 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status_code) ||
9365 nl80211_add_peer_capab(msg, peer_capab) ||
9366 (initiator && nla_put_flag(msg, NL80211_ATTR_TDLS_INITIATOR)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009367 nla_put(msg, NL80211_ATTR_IE, len, buf))
9368 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009369
Hai Shalom899fcc72020-10-19 14:38:18 -07009370 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009371
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009372fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009373 nlmsg_free(msg);
9374 return -ENOBUFS;
9375}
9376
9377
9378static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
9379{
9380 struct i802_bss *bss = priv;
9381 struct wpa_driver_nl80211_data *drv = bss->drv;
9382 struct nl_msg *msg;
9383 enum nl80211_tdls_operation nl80211_oper;
Paul Stewart092955c2017-02-06 09:13:09 -08009384 int res;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009385
9386 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
9387 return -EOPNOTSUPP;
9388
9389 switch (oper) {
9390 case TDLS_DISCOVERY_REQ:
9391 nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
9392 break;
9393 case TDLS_SETUP:
9394 nl80211_oper = NL80211_TDLS_SETUP;
9395 break;
9396 case TDLS_TEARDOWN:
9397 nl80211_oper = NL80211_TDLS_TEARDOWN;
9398 break;
9399 case TDLS_ENABLE_LINK:
9400 nl80211_oper = NL80211_TDLS_ENABLE_LINK;
9401 break;
9402 case TDLS_DISABLE_LINK:
9403 nl80211_oper = NL80211_TDLS_DISABLE_LINK;
9404 break;
9405 case TDLS_ENABLE:
9406 return 0;
9407 case TDLS_DISABLE:
9408 return 0;
9409 default:
9410 return -EINVAL;
9411 }
9412
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009413 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_OPER)) ||
9414 nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper) ||
9415 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) {
9416 nlmsg_free(msg);
9417 return -ENOBUFS;
9418 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009419
Hai Shalom899fcc72020-10-19 14:38:18 -07009420 res = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Paul Stewart092955c2017-02-06 09:13:09 -08009421 wpa_printf(MSG_DEBUG, "nl80211: TDLS_OPER: oper=%d mac=" MACSTR
9422 " --> res=%d (%s)", nl80211_oper, MAC2STR(peer), res,
9423 strerror(-res));
9424 return res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009425}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009426
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009427
9428static int
9429nl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
9430 const struct hostapd_freq_params *params)
9431{
9432 struct i802_bss *bss = priv;
9433 struct wpa_driver_nl80211_data *drv = bss->drv;
9434 struct nl_msg *msg;
9435 int ret = -ENOBUFS;
9436
9437 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
9438 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
9439 return -EOPNOTSUPP;
9440
9441 wpa_printf(MSG_DEBUG, "nl80211: Enable TDLS channel switch " MACSTR
9442 " oper_class=%u freq=%u",
9443 MAC2STR(addr), oper_class, params->freq);
9444 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CHANNEL_SWITCH);
9445 if (!msg ||
9446 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
9447 nla_put_u8(msg, NL80211_ATTR_OPER_CLASS, oper_class) ||
9448 (ret = nl80211_put_freq_params(msg, params))) {
9449 nlmsg_free(msg);
9450 wpa_printf(MSG_DEBUG, "nl80211: Could not build TDLS chan switch");
9451 return ret;
9452 }
9453
Hai Shalom899fcc72020-10-19 14:38:18 -07009454 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009455}
9456
9457
9458static int
9459nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
9460{
9461 struct i802_bss *bss = priv;
9462 struct wpa_driver_nl80211_data *drv = bss->drv;
9463 struct nl_msg *msg;
9464
9465 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
9466 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
9467 return -EOPNOTSUPP;
9468
9469 wpa_printf(MSG_DEBUG, "nl80211: Disable TDLS channel switch " MACSTR,
9470 MAC2STR(addr));
9471 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH);
9472 if (!msg ||
9473 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
9474 nlmsg_free(msg);
9475 wpa_printf(MSG_DEBUG,
9476 "nl80211: Could not build TDLS cancel chan switch");
9477 return -ENOBUFS;
9478 }
9479
Hai Shalom899fcc72020-10-19 14:38:18 -07009480 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009481}
9482
9483#endif /* CONFIG TDLS */
9484
9485
Hai Shalomfdcde762020-04-02 11:19:20 -07009486static int driver_nl80211_set_key(void *priv,
9487 struct wpa_driver_set_key_params *params)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009488{
9489 struct i802_bss *bss = priv;
Hai Shalomfdcde762020-04-02 11:19:20 -07009490
9491 return wpa_driver_nl80211_set_key(bss, params);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009492}
9493
9494
9495static int driver_nl80211_scan2(void *priv,
9496 struct wpa_driver_scan_params *params)
9497{
9498 struct i802_bss *bss = priv;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009499#ifdef CONFIG_DRIVER_NL80211_QCA
9500 struct wpa_driver_nl80211_data *drv = bss->drv;
9501
9502 /*
9503 * Do a vendor specific scan if possible. If only_new_results is
9504 * set, do a normal scan since a kernel (cfg80211) BSS cache flush
9505 * cannot be achieved through a vendor scan. The below condition may
9506 * need to be modified if new scan flags are added in the future whose
9507 * functionality can only be achieved through a normal scan.
9508 */
9509 if (drv->scan_vendor_cmd_avail && !params->only_new_results)
9510 return wpa_driver_nl80211_vendor_scan(bss, params);
9511#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009512 return wpa_driver_nl80211_scan(bss, params);
9513}
9514
9515
9516static int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -07009517 u16 reason_code)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009518{
9519 struct i802_bss *bss = priv;
9520 return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
9521}
9522
9523
9524static int driver_nl80211_authenticate(void *priv,
9525 struct wpa_driver_auth_params *params)
9526{
9527 struct i802_bss *bss = priv;
9528 return wpa_driver_nl80211_authenticate(bss, params);
9529}
9530
9531
9532static void driver_nl80211_deinit(void *priv)
9533{
9534 struct i802_bss *bss = priv;
9535 wpa_driver_nl80211_deinit(bss);
9536}
9537
9538
9539static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
9540 const char *ifname)
9541{
9542 struct i802_bss *bss = priv;
9543 return wpa_driver_nl80211_if_remove(bss, type, ifname);
9544}
9545
9546
9547static int driver_nl80211_send_mlme(void *priv, const u8 *data,
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07009548 size_t data_len, int noack,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009549 unsigned int freq,
Hai Shalomfdcde762020-04-02 11:19:20 -07009550 const u16 *csa_offs, size_t csa_offs_len,
9551 int no_encrypt, unsigned int wait)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009552{
9553 struct i802_bss *bss = priv;
9554 return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
Hai Shalomfdcde762020-04-02 11:19:20 -07009555 freq, 0, 0, wait, csa_offs,
9556 csa_offs_len, no_encrypt);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009557}
9558
9559
9560static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
9561{
9562 struct i802_bss *bss = priv;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009563 return wpa_driver_nl80211_sta_remove(bss, addr, -1, 0);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009564}
9565
9566
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009567static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
9568 const char *ifname, int vlan_id)
9569{
9570 struct i802_bss *bss = priv;
9571 return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
9572}
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009573
9574
9575static int driver_nl80211_read_sta_data(void *priv,
9576 struct hostap_sta_driver_data *data,
9577 const u8 *addr)
9578{
9579 struct i802_bss *bss = priv;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08009580
9581 os_memset(data, 0, sizeof(*data));
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009582 return i802_read_sta_data(bss, data, addr);
9583}
9584
9585
9586static int driver_nl80211_send_action(void *priv, unsigned int freq,
9587 unsigned int wait_time,
9588 const u8 *dst, const u8 *src,
9589 const u8 *bssid,
9590 const u8 *data, size_t data_len,
9591 int no_cck)
9592{
9593 struct i802_bss *bss = priv;
9594 return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
9595 bssid, data, data_len, no_cck);
9596}
9597
9598
9599static int driver_nl80211_probe_req_report(void *priv, int report)
9600{
9601 struct i802_bss *bss = priv;
9602 return wpa_driver_nl80211_probe_req_report(bss, report);
9603}
9604
9605
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009606static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
9607 const u8 *ies, size_t ies_len)
9608{
9609 int ret;
9610 struct nl_msg *msg;
9611 struct i802_bss *bss = priv;
9612 struct wpa_driver_nl80211_data *drv = bss->drv;
9613 u16 mdid = WPA_GET_LE16(md);
9614
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009615 wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009616 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_FT_IES)) ||
9617 nla_put(msg, NL80211_ATTR_IE, ies_len, ies) ||
9618 nla_put_u16(msg, NL80211_ATTR_MDID, mdid)) {
9619 nlmsg_free(msg);
9620 return -ENOBUFS;
9621 }
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009622
Hai Shalom899fcc72020-10-19 14:38:18 -07009623 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009624 if (ret) {
9625 wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
9626 "err=%d (%s)", ret, strerror(-ret));
9627 }
9628
9629 return ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009630}
9631
9632
Hai Shalom81f62d82019-07-22 12:10:00 -07009633static int nl80211_update_dh_ie(void *priv, const u8 *peer_mac,
9634 u16 reason_code, const u8 *ie, size_t ie_len)
9635{
9636 int ret;
9637 struct nl_msg *msg;
9638 struct i802_bss *bss = priv;
9639 struct wpa_driver_nl80211_data *drv = bss->drv;
9640
9641 wpa_printf(MSG_DEBUG, "nl80211: Updating DH IE peer: " MACSTR
9642 " reason %u", MAC2STR(peer_mac), reason_code);
9643 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UPDATE_OWE_INFO)) ||
9644 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer_mac) ||
9645 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, reason_code) ||
9646 (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie))) {
9647 nlmsg_free(msg);
9648 return -ENOBUFS;
9649 }
9650
Hai Shalom899fcc72020-10-19 14:38:18 -07009651 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalom81f62d82019-07-22 12:10:00 -07009652 if (ret) {
9653 wpa_printf(MSG_DEBUG,
9654 "nl80211: update_dh_ie failed err=%d (%s)",
9655 ret, strerror(-ret));
9656 }
9657
9658 return ret;
9659}
9660
9661
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07009662static const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009663{
9664 struct i802_bss *bss = priv;
9665 struct wpa_driver_nl80211_data *drv = bss->drv;
9666
9667 if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
9668 return NULL;
9669
9670 return bss->addr;
9671}
9672
9673
Dmitry Shmidt56052862013-10-04 10:23:25 -07009674static const char * scan_state_str(enum scan_states scan_state)
9675{
9676 switch (scan_state) {
9677 case NO_SCAN:
9678 return "NO_SCAN";
9679 case SCAN_REQUESTED:
9680 return "SCAN_REQUESTED";
9681 case SCAN_STARTED:
9682 return "SCAN_STARTED";
9683 case SCAN_COMPLETED:
9684 return "SCAN_COMPLETED";
9685 case SCAN_ABORTED:
9686 return "SCAN_ABORTED";
9687 case SCHED_SCAN_STARTED:
9688 return "SCHED_SCAN_STARTED";
9689 case SCHED_SCAN_STOPPED:
9690 return "SCHED_SCAN_STOPPED";
9691 case SCHED_SCAN_RESULTS:
9692 return "SCHED_SCAN_RESULTS";
9693 }
9694
9695 return "??";
9696}
9697
9698
9699static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
9700{
9701 struct i802_bss *bss = priv;
9702 struct wpa_driver_nl80211_data *drv = bss->drv;
9703 int res;
9704 char *pos, *end;
Hai Shalom74f70d42019-02-11 14:42:39 -08009705 struct nl_msg *msg;
9706 char alpha2[3] = { 0, 0, 0 };
Dmitry Shmidt56052862013-10-04 10:23:25 -07009707
9708 pos = buf;
9709 end = buf + buflen;
9710
9711 res = os_snprintf(pos, end - pos,
9712 "ifindex=%d\n"
9713 "ifname=%s\n"
9714 "brname=%s\n"
9715 "addr=" MACSTR "\n"
9716 "freq=%d\n"
Hai Shalomc9e41a12018-07-31 14:41:42 -07009717 "%s%s%s%s%s%s",
Dmitry Shmidt56052862013-10-04 10:23:25 -07009718 bss->ifindex,
9719 bss->ifname,
9720 bss->brname,
9721 MAC2STR(bss->addr),
9722 bss->freq,
9723 bss->beacon_set ? "beacon_set=1\n" : "",
9724 bss->added_if_into_bridge ?
9725 "added_if_into_bridge=1\n" : "",
Hai Shalomc9e41a12018-07-31 14:41:42 -07009726 bss->already_in_bridge ? "already_in_bridge=1\n" : "",
Dmitry Shmidt56052862013-10-04 10:23:25 -07009727 bss->added_bridge ? "added_bridge=1\n" : "",
9728 bss->in_deinit ? "in_deinit=1\n" : "",
9729 bss->if_dynamic ? "if_dynamic=1\n" : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009730 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -07009731 return pos - buf;
9732 pos += res;
9733
9734 if (bss->wdev_id_set) {
9735 res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
9736 (unsigned long long) bss->wdev_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009737 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -07009738 return pos - buf;
9739 pos += res;
9740 }
9741
9742 res = os_snprintf(pos, end - pos,
9743 "phyname=%s\n"
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07009744 "perm_addr=" MACSTR "\n"
Dmitry Shmidt56052862013-10-04 10:23:25 -07009745 "drv_ifindex=%d\n"
9746 "operstate=%d\n"
9747 "scan_state=%s\n"
9748 "auth_bssid=" MACSTR "\n"
9749 "auth_attempt_bssid=" MACSTR "\n"
9750 "bssid=" MACSTR "\n"
9751 "prev_bssid=" MACSTR "\n"
9752 "associated=%d\n"
9753 "assoc_freq=%u\n"
9754 "monitor_sock=%d\n"
9755 "monitor_ifidx=%d\n"
9756 "monitor_refcount=%d\n"
9757 "last_mgmt_freq=%u\n"
9758 "eapol_tx_sock=%d\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009759 "%s%s%s%s%s%s%s%s%s%s%s%s%s",
Dmitry Shmidt56052862013-10-04 10:23:25 -07009760 drv->phyname,
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07009761 MAC2STR(drv->perm_addr),
Dmitry Shmidt56052862013-10-04 10:23:25 -07009762 drv->ifindex,
9763 drv->operstate,
9764 scan_state_str(drv->scan_state),
9765 MAC2STR(drv->auth_bssid),
9766 MAC2STR(drv->auth_attempt_bssid),
9767 MAC2STR(drv->bssid),
9768 MAC2STR(drv->prev_bssid),
9769 drv->associated,
9770 drv->assoc_freq,
9771 drv->monitor_sock,
9772 drv->monitor_ifidx,
9773 drv->monitor_refcount,
9774 drv->last_mgmt_freq,
9775 drv->eapol_tx_sock,
9776 drv->ignore_if_down_event ?
9777 "ignore_if_down_event=1\n" : "",
9778 drv->scan_complete_events ?
9779 "scan_complete_events=1\n" : "",
9780 drv->disabled_11b_rates ?
9781 "disabled_11b_rates=1\n" : "",
9782 drv->pending_remain_on_chan ?
9783 "pending_remain_on_chan=1\n" : "",
9784 drv->in_interface_list ? "in_interface_list=1\n" : "",
9785 drv->device_ap_sme ? "device_ap_sme=1\n" : "",
9786 drv->poll_command_supported ?
9787 "poll_command_supported=1\n" : "",
9788 drv->data_tx_status ? "data_tx_status=1\n" : "",
9789 drv->scan_for_auth ? "scan_for_auth=1\n" : "",
9790 drv->retry_auth ? "retry_auth=1\n" : "",
9791 drv->use_monitor ? "use_monitor=1\n" : "",
9792 drv->ignore_next_local_disconnect ?
9793 "ignore_next_local_disconnect=1\n" : "",
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07009794 drv->ignore_next_local_deauth ?
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009795 "ignore_next_local_deauth=1\n" : "");
9796 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -07009797 return pos - buf;
9798 pos += res;
9799
9800 if (drv->has_capability) {
9801 res = os_snprintf(pos, end - pos,
9802 "capa.key_mgmt=0x%x\n"
9803 "capa.enc=0x%x\n"
9804 "capa.auth=0x%x\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009805 "capa.flags=0x%llx\n"
9806 "capa.rrm_flags=0x%x\n"
Dmitry Shmidt56052862013-10-04 10:23:25 -07009807 "capa.max_scan_ssids=%d\n"
9808 "capa.max_sched_scan_ssids=%d\n"
9809 "capa.sched_scan_supported=%d\n"
9810 "capa.max_match_sets=%d\n"
9811 "capa.max_remain_on_chan=%u\n"
9812 "capa.max_stations=%u\n"
9813 "capa.probe_resp_offloads=0x%x\n"
9814 "capa.max_acl_mac_addrs=%u\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009815 "capa.num_multichan_concurrent=%u\n"
9816 "capa.mac_addr_rand_sched_scan_supported=%d\n"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009817 "capa.mac_addr_rand_scan_supported=%d\n"
9818 "capa.conc_capab=%u\n"
9819 "capa.max_conc_chan_2_4=%u\n"
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009820 "capa.max_conc_chan_5_0=%u\n"
9821 "capa.max_sched_scan_plans=%u\n"
9822 "capa.max_sched_scan_plan_interval=%u\n"
9823 "capa.max_sched_scan_plan_iterations=%u\n",
Dmitry Shmidt56052862013-10-04 10:23:25 -07009824 drv->capa.key_mgmt,
9825 drv->capa.enc,
9826 drv->capa.auth,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009827 (unsigned long long) drv->capa.flags,
9828 drv->capa.rrm_flags,
Dmitry Shmidt56052862013-10-04 10:23:25 -07009829 drv->capa.max_scan_ssids,
9830 drv->capa.max_sched_scan_ssids,
9831 drv->capa.sched_scan_supported,
9832 drv->capa.max_match_sets,
9833 drv->capa.max_remain_on_chan,
9834 drv->capa.max_stations,
9835 drv->capa.probe_resp_offloads,
9836 drv->capa.max_acl_mac_addrs,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009837 drv->capa.num_multichan_concurrent,
9838 drv->capa.mac_addr_rand_sched_scan_supported,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009839 drv->capa.mac_addr_rand_scan_supported,
9840 drv->capa.conc_capab,
9841 drv->capa.max_conc_chan_2_4,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009842 drv->capa.max_conc_chan_5_0,
9843 drv->capa.max_sched_scan_plans,
9844 drv->capa.max_sched_scan_plan_interval,
9845 drv->capa.max_sched_scan_plan_iterations);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009846 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -07009847 return pos - buf;
9848 pos += res;
9849 }
9850
Hai Shalom74f70d42019-02-11 14:42:39 -08009851 msg = nlmsg_alloc();
9852 if (msg &&
9853 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG) &&
9854 nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx) == 0) {
9855 if (send_and_recv_msgs(drv, msg, nl80211_get_country,
Hai Shalom899fcc72020-10-19 14:38:18 -07009856 alpha2, NULL, NULL) == 0 &&
Hai Shalom74f70d42019-02-11 14:42:39 -08009857 alpha2[0]) {
9858 res = os_snprintf(pos, end - pos, "country=%s\n",
9859 alpha2);
9860 if (os_snprintf_error(end - pos, res))
9861 return pos - buf;
9862 pos += res;
9863 }
9864 } else {
9865 nlmsg_free(msg);
9866 }
9867
Dmitry Shmidt56052862013-10-04 10:23:25 -07009868 return pos - buf;
9869}
9870
9871
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009872static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
9873{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009874 if ((settings->head &&
9875 nla_put(msg, NL80211_ATTR_BEACON_HEAD,
9876 settings->head_len, settings->head)) ||
9877 (settings->tail &&
9878 nla_put(msg, NL80211_ATTR_BEACON_TAIL,
9879 settings->tail_len, settings->tail)) ||
9880 (settings->beacon_ies &&
9881 nla_put(msg, NL80211_ATTR_IE,
9882 settings->beacon_ies_len, settings->beacon_ies)) ||
9883 (settings->proberesp_ies &&
9884 nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
9885 settings->proberesp_ies_len, settings->proberesp_ies)) ||
9886 (settings->assocresp_ies &&
9887 nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
9888 settings->assocresp_ies_len, settings->assocresp_ies)) ||
9889 (settings->probe_resp &&
9890 nla_put(msg, NL80211_ATTR_PROBE_RESP,
9891 settings->probe_resp_len, settings->probe_resp)))
9892 return -ENOBUFS;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009893
9894 return 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009895}
9896
9897
9898static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
9899{
9900 struct nl_msg *msg;
9901 struct i802_bss *bss = priv;
9902 struct wpa_driver_nl80211_data *drv = bss->drv;
9903 struct nlattr *beacon_csa;
9904 int ret = -ENOBUFS;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009905 int csa_off_len = 0;
9906 int i;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009907
Hai Shalomc1a21442022-02-04 13:43:00 -08009908 wpa_printf(MSG_DEBUG,
9909 "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 -08009910 settings->cs_count, settings->block_tx,
Hai Shalomc1a21442022-02-04 13:43:00 -08009911 settings->freq_params.freq,
9912 settings->freq_params.channel,
9913 settings->freq_params.sec_channel_offset,
9914 settings->freq_params.bandwidth,
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08009915 settings->freq_params.center_freq1,
Hai Shalomc1a21442022-02-04 13:43:00 -08009916 settings->freq_params.center_freq2,
9917 settings->freq_params.ht_enabled ? " ht" : "",
9918 settings->freq_params.vht_enabled ? " vht" : "",
9919 settings->freq_params.he_enabled ? " he" : "");
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009920
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009921 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_AP_CSA)) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009922 wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
9923 return -EOPNOTSUPP;
9924 }
9925
Roshan Pius3a1667e2018-07-03 15:17:14 -07009926 if (drv->nlmode != NL80211_IFTYPE_AP &&
9927 drv->nlmode != NL80211_IFTYPE_P2P_GO &&
9928 drv->nlmode != NL80211_IFTYPE_MESH_POINT)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009929 return -EOPNOTSUPP;
9930
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009931 /*
9932 * Remove empty counters, assuming Probe Response and Beacon frame
9933 * counters match. This implementation assumes that there are only two
9934 * counters.
9935 */
9936 if (settings->counter_offset_beacon[0] &&
9937 !settings->counter_offset_beacon[1]) {
9938 csa_off_len = 1;
9939 } else if (settings->counter_offset_beacon[1] &&
9940 !settings->counter_offset_beacon[0]) {
9941 csa_off_len = 1;
9942 settings->counter_offset_beacon[0] =
9943 settings->counter_offset_beacon[1];
9944 settings->counter_offset_presp[0] =
9945 settings->counter_offset_presp[1];
9946 } else if (settings->counter_offset_beacon[1] &&
9947 settings->counter_offset_beacon[0]) {
9948 csa_off_len = 2;
9949 } else {
9950 wpa_printf(MSG_ERROR, "nl80211: No CSA counters provided");
9951 return -EINVAL;
9952 }
9953
9954 /* Check CSA counters validity */
9955 if (drv->capa.max_csa_counters &&
9956 csa_off_len > drv->capa.max_csa_counters) {
9957 wpa_printf(MSG_ERROR,
9958 "nl80211: Too many CSA counters provided");
9959 return -EINVAL;
9960 }
9961
9962 if (!settings->beacon_csa.tail)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009963 return -EINVAL;
9964
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009965 for (i = 0; i < csa_off_len; i++) {
9966 u16 csa_c_off_bcn = settings->counter_offset_beacon[i];
9967 u16 csa_c_off_presp = settings->counter_offset_presp[i];
9968
9969 if ((settings->beacon_csa.tail_len <= csa_c_off_bcn) ||
9970 (settings->beacon_csa.tail[csa_c_off_bcn] !=
9971 settings->cs_count))
9972 return -EINVAL;
9973
9974 if (settings->beacon_csa.probe_resp &&
9975 ((settings->beacon_csa.probe_resp_len <=
9976 csa_c_off_presp) ||
9977 (settings->beacon_csa.probe_resp[csa_c_off_presp] !=
9978 settings->cs_count)))
9979 return -EINVAL;
9980 }
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009981
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009982 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CHANNEL_SWITCH)) ||
9983 nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT,
9984 settings->cs_count) ||
9985 (ret = nl80211_put_freq_params(msg, &settings->freq_params)) ||
9986 (settings->block_tx &&
9987 nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)))
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009988 goto error;
9989
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009990 /* beacon_after params */
9991 ret = set_beacon_data(msg, &settings->beacon_after);
9992 if (ret)
9993 goto error;
9994
9995 /* beacon_csa params */
9996 beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
9997 if (!beacon_csa)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009998 goto fail;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009999
10000 ret = set_beacon_data(msg, &settings->beacon_csa);
10001 if (ret)
10002 goto error;
10003
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010004 if (nla_put(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
10005 csa_off_len * sizeof(u16),
10006 settings->counter_offset_beacon) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010007 (settings->beacon_csa.probe_resp &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010008 nla_put(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
10009 csa_off_len * sizeof(u16),
10010 settings->counter_offset_presp)))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010011 goto fail;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010012
10013 nla_nest_end(msg, beacon_csa);
Hai Shalom899fcc72020-10-19 14:38:18 -070010014 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010015 if (ret) {
10016 wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
10017 ret, strerror(-ret));
10018 }
10019 return ret;
10020
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010021fail:
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080010022 ret = -ENOBUFS;
10023error:
10024 nlmsg_free(msg);
10025 wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request");
10026 return ret;
10027}
10028
10029
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010030static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr,
10031 u8 user_priority, u16 admitted_time)
10032{
10033 struct i802_bss *bss = priv;
10034 struct wpa_driver_nl80211_data *drv = bss->drv;
10035 struct nl_msg *msg;
10036 int ret;
10037
10038 wpa_printf(MSG_DEBUG,
10039 "nl80211: add_ts request: tsid=%u admitted_time=%u up=%d",
10040 tsid, admitted_time, user_priority);
10041
10042 if (!is_sta_interface(drv->nlmode))
10043 return -ENOTSUP;
10044
10045 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ADD_TX_TS);
10046 if (!msg ||
10047 nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
10048 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
10049 nla_put_u8(msg, NL80211_ATTR_USER_PRIO, user_priority) ||
10050 nla_put_u16(msg, NL80211_ATTR_ADMITTED_TIME, admitted_time)) {
10051 nlmsg_free(msg);
10052 return -ENOBUFS;
10053 }
10054
Hai Shalom899fcc72020-10-19 14:38:18 -070010055 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010056 if (ret)
10057 wpa_printf(MSG_DEBUG, "nl80211: add_ts failed err=%d (%s)",
10058 ret, strerror(-ret));
10059 return ret;
10060}
10061
10062
10063static int nl80211_del_ts(void *priv, u8 tsid, const u8 *addr)
10064{
10065 struct i802_bss *bss = priv;
10066 struct wpa_driver_nl80211_data *drv = bss->drv;
10067 struct nl_msg *msg;
10068 int ret;
10069
10070 wpa_printf(MSG_DEBUG, "nl80211: del_ts request: tsid=%u", tsid);
10071
10072 if (!is_sta_interface(drv->nlmode))
10073 return -ENOTSUP;
10074
10075 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_TX_TS)) ||
10076 nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
10077 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
10078 nlmsg_free(msg);
10079 return -ENOBUFS;
10080 }
10081
Hai Shalom899fcc72020-10-19 14:38:18 -070010082 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010083 if (ret)
10084 wpa_printf(MSG_DEBUG, "nl80211: del_ts failed err=%d (%s)",
10085 ret, strerror(-ret));
10086 return ret;
10087}
10088
10089
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010090#ifdef CONFIG_TESTING_OPTIONS
10091static int cmd_reply_handler(struct nl_msg *msg, void *arg)
10092{
10093 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
10094 struct wpabuf *buf = arg;
10095
10096 if (!buf)
10097 return NL_SKIP;
10098
10099 if ((size_t) genlmsg_attrlen(gnlh, 0) > wpabuf_tailroom(buf)) {
10100 wpa_printf(MSG_INFO, "nl80211: insufficient buffer space for reply");
10101 return NL_SKIP;
10102 }
10103
10104 wpabuf_put_data(buf, genlmsg_attrdata(gnlh, 0),
10105 genlmsg_attrlen(gnlh, 0));
10106
10107 return NL_SKIP;
10108}
10109#endif /* CONFIG_TESTING_OPTIONS */
10110
10111
10112static int vendor_reply_handler(struct nl_msg *msg, void *arg)
10113{
10114 struct nlattr *tb[NL80211_ATTR_MAX + 1];
10115 struct nlattr *nl_vendor_reply, *nl;
10116 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
10117 struct wpabuf *buf = arg;
10118 int rem;
10119
10120 if (!buf)
10121 return NL_SKIP;
10122
10123 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
10124 genlmsg_attrlen(gnlh, 0), NULL);
10125 nl_vendor_reply = tb[NL80211_ATTR_VENDOR_DATA];
10126
10127 if (!nl_vendor_reply)
10128 return NL_SKIP;
10129
10130 if ((size_t) nla_len(nl_vendor_reply) > wpabuf_tailroom(buf)) {
10131 wpa_printf(MSG_INFO, "nl80211: Vendor command: insufficient buffer space for reply");
10132 return NL_SKIP;
10133 }
10134
10135 nla_for_each_nested(nl, nl_vendor_reply, rem) {
10136 wpabuf_put_data(buf, nla_data(nl), nla_len(nl));
10137 }
10138
10139 return NL_SKIP;
10140}
10141
10142
Hai Shalom60840252021-02-19 19:02:11 -080010143static bool is_cmd_with_nested_attrs(unsigned int vendor_id,
10144 unsigned int subcmd)
10145{
10146 if (vendor_id != OUI_QCA)
10147 return true;
10148
10149 switch (subcmd) {
10150 case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
10151 case QCA_NL80211_VENDOR_SUBCMD_STATS_EXT:
10152 case QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI:
10153 case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY:
10154 case QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS:
10155 case QCA_NL80211_VENDOR_SUBCMD_NAN:
10156 return false;
10157 default:
10158 return true;
10159 }
10160}
10161
10162
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010163static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
10164 unsigned int subcmd, const u8 *data,
Hai Shalom60840252021-02-19 19:02:11 -080010165 size_t data_len, enum nested_attr nested_attr,
10166 struct wpabuf *buf)
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010167{
10168 struct i802_bss *bss = priv;
10169 struct wpa_driver_nl80211_data *drv = bss->drv;
10170 struct nl_msg *msg;
Hai Shalom60840252021-02-19 19:02:11 -080010171 int ret, nla_flag;
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010172
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010173#ifdef CONFIG_TESTING_OPTIONS
10174 if (vendor_id == 0xffffffff) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010175 msg = nlmsg_alloc();
10176 if (!msg)
10177 return -ENOMEM;
10178
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010179 nl80211_cmd(drv, msg, 0, subcmd);
10180 if (nlmsg_append(msg, (void *) data, data_len, NLMSG_ALIGNTO) <
10181 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010182 goto fail;
Hai Shalomb755a2a2020-04-23 21:49:02 -070010183 /* This test vendor_cmd can be used with nl80211 commands that
10184 * need the connect nl_sock, so use the owner-setting variant
10185 * of send_and_recv_msgs(). */
10186 ret = send_and_recv_msgs_owner(drv, msg,
10187 get_connect_handle(bss), 0,
Hai Shalom899fcc72020-10-19 14:38:18 -070010188 cmd_reply_handler, buf,
10189 NULL, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010190 if (ret)
10191 wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
10192 ret);
10193 return ret;
10194 }
10195#endif /* CONFIG_TESTING_OPTIONS */
10196
Hai Shalom60840252021-02-19 19:02:11 -080010197 if (nested_attr == NESTED_ATTR_USED)
10198 nla_flag = NLA_F_NESTED;
10199 else if (nested_attr == NESTED_ATTR_UNSPECIFIED &&
10200 is_cmd_with_nested_attrs(vendor_id, subcmd))
10201 nla_flag = NLA_F_NESTED;
10202 else
10203 nla_flag = 0;
10204
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010205 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
10206 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, vendor_id) ||
10207 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd) ||
10208 (data &&
Hai Shalom60840252021-02-19 19:02:11 -080010209 nla_put(msg, nla_flag | NL80211_ATTR_VENDOR_DATA,
10210 data_len, data)))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010211 goto fail;
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010212
Hai Shalom899fcc72020-10-19 14:38:18 -070010213 ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf,
10214 NULL, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010215 if (ret)
10216 wpa_printf(MSG_DEBUG, "nl80211: vendor command failed err=%d",
10217 ret);
10218 return ret;
10219
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010220fail:
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010221 nlmsg_free(msg);
10222 return -ENOBUFS;
10223}
10224
10225
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010226static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
10227 u8 qos_map_set_len)
10228{
10229 struct i802_bss *bss = priv;
10230 struct wpa_driver_nl80211_data *drv = bss->drv;
10231 struct nl_msg *msg;
10232 int ret;
10233
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010234 wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
10235 qos_map_set, qos_map_set_len);
10236
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010237 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_QOS_MAP)) ||
10238 nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) {
10239 nlmsg_free(msg);
10240 return -ENOBUFS;
10241 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010242
Hai Shalom899fcc72020-10-19 14:38:18 -070010243 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010244 if (ret)
10245 wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
10246
10247 return ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010248}
10249
10250
Hai Shalomfdcde762020-04-02 11:19:20 -070010251static int get_wowlan_handler(struct nl_msg *msg, void *arg)
10252{
10253 struct nlattr *tb[NL80211_ATTR_MAX + 1];
10254 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
10255 int *wowlan_enabled = arg;
10256
10257 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
10258 genlmsg_attrlen(gnlh, 0), NULL);
10259
10260 *wowlan_enabled = !!tb[NL80211_ATTR_WOWLAN_TRIGGERS];
10261
10262 return NL_SKIP;
10263}
10264
10265
10266static int nl80211_get_wowlan(void *priv)
10267{
10268 struct i802_bss *bss = priv;
10269 struct wpa_driver_nl80211_data *drv = bss->drv;
10270 struct nl_msg *msg;
10271 int wowlan_enabled;
10272 int ret;
10273
10274 wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status");
10275
10276 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_WOWLAN);
10277
Hai Shalom899fcc72020-10-19 14:38:18 -070010278 ret = send_and_recv_msgs(drv, msg, get_wowlan_handler, &wowlan_enabled,
10279 NULL, NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -070010280 if (ret) {
10281 wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status failed");
10282 return 0;
10283 }
10284
10285 wpa_printf(MSG_DEBUG, "nl80211: wowlan is %s",
10286 wowlan_enabled ? "enabled" : "disabled");
10287
10288 return wowlan_enabled;
10289}
10290
10291
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010292static int nl80211_set_wowlan(void *priv,
10293 const struct wowlan_triggers *triggers)
10294{
10295 struct i802_bss *bss = priv;
10296 struct wpa_driver_nl80211_data *drv = bss->drv;
10297 struct nl_msg *msg;
10298 struct nlattr *wowlan_triggers;
10299 int ret;
10300
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010301 wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
10302
Dmitry Shmidta3dc3092015-06-23 11:21:28 -070010303 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_WOWLAN)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010304 !(wowlan_triggers = nla_nest_start(msg,
10305 NL80211_ATTR_WOWLAN_TRIGGERS)) ||
10306 (triggers->any &&
10307 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
10308 (triggers->disconnect &&
10309 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
10310 (triggers->magic_pkt &&
10311 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
10312 (triggers->gtk_rekey_failure &&
10313 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
10314 (triggers->eap_identity_req &&
10315 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
10316 (triggers->four_way_handshake &&
10317 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
10318 (triggers->rfkill_release &&
10319 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) {
10320 nlmsg_free(msg);
10321 return -ENOBUFS;
10322 }
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010323
10324 nla_nest_end(msg, wowlan_triggers);
10325
Hai Shalom899fcc72020-10-19 14:38:18 -070010326 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010327 if (ret)
10328 wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
10329
10330 return ret;
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010331}
10332
10333
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010334#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010335static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
10336{
10337 struct i802_bss *bss = priv;
10338 struct wpa_driver_nl80211_data *drv = bss->drv;
10339 struct nl_msg *msg;
10340 struct nlattr *params;
10341
10342 wpa_printf(MSG_DEBUG, "nl80211: Roaming policy: allowed=%d", allowed);
10343
10344 if (!drv->roaming_vendor_cmd_avail) {
10345 wpa_printf(MSG_DEBUG,
10346 "nl80211: Ignore roaming policy change since driver does not provide command for setting it");
10347 return -1;
10348 }
10349
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010350 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10351 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10352 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10353 QCA_NL80211_VENDOR_SUBCMD_ROAMING) ||
10354 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10355 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
10356 allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
10357 QCA_ROAMING_NOT_ALLOWED) ||
10358 (bssid &&
10359 nla_put(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid))) {
10360 nlmsg_free(msg);
10361 return -1;
10362 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010363 nla_nest_end(msg, params);
10364
Hai Shalom899fcc72020-10-19 14:38:18 -070010365 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010366}
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010367
10368
Roshan Pius3a1667e2018-07-03 15:17:14 -070010369static int nl80211_disable_fils(void *priv, int disable)
10370{
10371 struct i802_bss *bss = priv;
10372 struct wpa_driver_nl80211_data *drv = bss->drv;
10373 struct nl_msg *msg;
10374 struct nlattr *params;
10375
10376 wpa_printf(MSG_DEBUG, "nl80211: Disable FILS=%d", disable);
10377
10378 if (!drv->set_wifi_conf_vendor_cmd_avail)
10379 return -1;
10380
10381 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10382 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10383 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10384 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION) ||
10385 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10386 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS,
10387 disable)) {
10388 nlmsg_free(msg);
10389 return -1;
10390 }
10391 nla_nest_end(msg, params);
10392
Hai Shalom899fcc72020-10-19 14:38:18 -070010393 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010394}
10395
10396
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010397/* Reserved QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID value for wpa_supplicant */
10398#define WPA_SUPPLICANT_CLIENT_ID 1
10399
Hai Shalom899fcc72020-10-19 14:38:18 -070010400static int nl80211_set_bssid_tmp_disallow(void *priv, unsigned int num_bssid,
10401 const u8 *bssid)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010402{
10403 struct i802_bss *bss = priv;
10404 struct wpa_driver_nl80211_data *drv = bss->drv;
10405 struct nl_msg *msg;
10406 struct nlattr *params, *nlbssids, *attr;
10407 unsigned int i;
10408
Hai Shalom899fcc72020-10-19 14:38:18 -070010409 wpa_printf(MSG_DEBUG,
10410 "nl80211: Set temporarily disallowed BSSIDs (num=%u)",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010411 num_bssid);
10412
10413 if (!drv->roam_vendor_cmd_avail)
10414 return -1;
10415
10416 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10417 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10418 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10419 QCA_NL80211_VENDOR_SUBCMD_ROAM) ||
10420 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10421 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
Hai Shalomc3565922019-10-28 11:58:20 -070010422 QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010423 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID,
10424 WPA_SUPPLICANT_CLIENT_ID) ||
10425 nla_put_u32(msg,
10426 QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID,
10427 num_bssid))
10428 goto fail;
10429
10430 nlbssids = nla_nest_start(
10431 msg, QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS);
10432 if (!nlbssids)
10433 goto fail;
10434
10435 for (i = 0; i < num_bssid; i++) {
10436 attr = nla_nest_start(msg, i);
10437 if (!attr)
10438 goto fail;
10439 if (nla_put(msg,
10440 QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID,
10441 ETH_ALEN, &bssid[i * ETH_ALEN]))
10442 goto fail;
10443 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%u]: " MACSTR, i,
10444 MAC2STR(&bssid[i * ETH_ALEN]));
10445 nla_nest_end(msg, attr);
10446 }
10447 nla_nest_end(msg, nlbssids);
10448 nla_nest_end(msg, params);
10449
Hai Shalom899fcc72020-10-19 14:38:18 -070010450 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010451
10452fail:
10453 nlmsg_free(msg);
10454 return -1;
10455}
10456
Hai Shalomc3565922019-10-28 11:58:20 -070010457
10458static int nl80211_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
10459{
10460 struct i802_bss *bss = priv;
10461 struct wpa_driver_nl80211_data *drv = bss->drv;
10462 struct nl_msg *msg;
10463 struct nlattr *params;
10464
10465 if (!drv->add_sta_node_vendor_cmd_avail)
10466 return -EOPNOTSUPP;
10467
10468 wpa_printf(MSG_DEBUG, "nl80211: Add STA node");
10469
10470 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10471 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10472 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10473 QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE) ||
10474 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10475 (addr &&
10476 nla_put(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_MAC_ADDR, ETH_ALEN,
10477 addr)) ||
10478 nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO,
10479 auth_alg)) {
10480 nlmsg_free(msg);
10481 wpa_printf(MSG_ERROR,
10482 "%s: err in adding vendor_cmd and vendor_data",
10483 __func__);
10484 return -1;
10485 }
10486 nla_nest_end(msg, params);
10487
Hai Shalom899fcc72020-10-19 14:38:18 -070010488 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalomc3565922019-10-28 11:58:20 -070010489}
10490
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010491#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010492
10493
10494static int nl80211_set_mac_addr(void *priv, const u8 *addr)
10495{
10496 struct i802_bss *bss = priv;
10497 struct wpa_driver_nl80211_data *drv = bss->drv;
10498 int new_addr = addr != NULL;
Mir Ali8a8f1002020-10-06 22:41:40 +053010499#ifdef CONFIG_DRIVER_NL80211_BRCM
10500 struct nl_msg *msg;
10501 struct nlattr *params;
10502 int ret;
10503#endif /* CONFIG_DRIVER_NL80211_BRCM */
10504 wpa_printf(MSG_DEBUG, "Enter: %s", __FUNCTION__);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010505
Dmitry Shmidt849734c2016-05-27 09:59:01 -070010506 if (TEST_FAIL())
10507 return -1;
Mir Ali8a8f1002020-10-06 22:41:40 +053010508 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
10509#ifdef CONFIG_DRIVER_NL80211_BRCM
10510 if (!addr ) {
10511 addr = drv->global->p2p_perm_addr;
10512 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -070010513
Mir Ali8a8f1002020-10-06 22:41:40 +053010514 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
10515 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
10516 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
Hai Shalomc1a21442022-02-04 13:43:00 -080010517 BRCM_VENDOR_SCMD_SET_MAC) ||
Mir Ali8a8f1002020-10-06 22:41:40 +053010518 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10519 nla_put(msg, BRCM_ATTR_DRIVER_MAC_ADDR, ETH_ALEN, addr)) {
10520 wpa_printf(MSG_ERROR, "failed to put p2p randmac");
10521 nl80211_nlmsg_clear(msg);
10522 nlmsg_free(msg);
10523 return -ENOBUFS;
10524 }
10525 nla_nest_end(msg, params);
10526
10527 ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
10528 if (ret) {
10529 wpa_printf(MSG_ERROR, "nl80211: p2p set macaddr failed: ret=%d (%s)",
10530 ret, strerror(-ret));
10531 }
10532 memcpy(bss->addr, addr, ETH_ALEN);
10533 return ret;
10534#else
10535 return -ENOTSUP;
10536#endif /* CONFIG_DRIVER_NL80211_BRCM */
10537 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010538 if (!addr)
10539 addr = drv->perm_addr;
10540
10541 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) < 0)
10542 return -1;
10543
10544 if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, addr) < 0)
10545 {
10546 wpa_printf(MSG_DEBUG,
Mir Ali8a8f1002020-10-06 22:41:40 +053010547 "nl80211: failed to set_mac_addr for %s to " MACSTR,
10548 bss->ifname, MAC2STR(addr));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010549 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
Mir Ali8a8f1002020-10-06 22:41:40 +053010550 1) < 0) {
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010551 wpa_printf(MSG_DEBUG,
Mir Ali8a8f1002020-10-06 22:41:40 +053010552 "nl80211: Could not restore interface UP after failed set_mac_addr");
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010553 }
10554 return -1;
10555 }
10556
10557 wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR,
Mir Ali8a8f1002020-10-06 22:41:40 +053010558 bss->ifname, MAC2STR(addr));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010559 drv->addr_changed = new_addr;
10560 os_memcpy(bss->addr, addr, ETH_ALEN);
10561
10562 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0)
10563 {
10564 wpa_printf(MSG_DEBUG,
Mir Ali8a8f1002020-10-06 22:41:40 +053010565 "nl80211: Could not restore interface UP after set_mac_addr");
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010566 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010567 return 0;
10568}
10569
10570
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010571#ifdef CONFIG_MESH
10572
10573static int wpa_driver_nl80211_init_mesh(void *priv)
10574{
10575 if (wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_MESH_POINT)) {
10576 wpa_printf(MSG_INFO,
10577 "nl80211: Failed to set interface into mesh mode");
10578 return -1;
10579 }
10580 return 0;
10581}
10582
10583
Dmitry Shmidtff787d52015-01-12 13:01:47 -080010584static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id,
10585 size_t mesh_id_len)
10586{
10587 if (mesh_id) {
Hai Shalom74f70d42019-02-11 14:42:39 -080010588 wpa_printf(MSG_DEBUG, " * Mesh ID (SSID)=%s",
10589 wpa_ssid_txt(mesh_id, mesh_id_len));
Dmitry Shmidtff787d52015-01-12 13:01:47 -080010590 return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
10591 }
10592
10593 return 0;
10594}
10595
10596
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070010597static int nl80211_put_mesh_config(struct nl_msg *msg,
10598 struct wpa_driver_mesh_bss_params *params)
10599{
10600 struct nlattr *container;
10601
10602 container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
10603 if (!container)
10604 return -1;
10605
10606 if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
Roshan Pius3a1667e2018-07-03 15:17:14 -070010607 nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
10608 params->auto_plinks)) ||
Hai Shalomc1a21442022-02-04 13:43:00 -080010609 ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_FORWARDING) &&
10610 nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
10611 params->forwarding)) ||
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070010612 ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) &&
10613 nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010614 params->max_peer_links)) ||
10615 ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD) &&
10616 nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
10617 params->rssi_threshold)))
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070010618 return -1;
10619
10620 /*
10621 * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
10622 * the timer could disconnect stations even in that case.
10623 */
10624 if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT) &&
10625 nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
10626 params->peer_link_timeout)) {
10627 wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
10628 return -1;
10629 }
10630
10631 if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE) &&
10632 nla_put_u16(msg, NL80211_MESHCONF_HT_OPMODE, params->ht_opmode)) {
10633 wpa_printf(MSG_ERROR, "nl80211: Failed to set HT_OP_MODE");
10634 return -1;
10635 }
10636
10637 nla_nest_end(msg, container);
10638
10639 return 0;
10640}
10641
10642
Dmitry Shmidt7f656022015-02-25 14:36:37 -080010643static int nl80211_join_mesh(struct i802_bss *bss,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010644 struct wpa_driver_mesh_join_params *params)
10645{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010646 struct wpa_driver_nl80211_data *drv = bss->drv;
10647 struct nl_msg *msg;
10648 struct nlattr *container;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -080010649 int ret = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010650
10651 wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
10652 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
Dmitry Shmidtff787d52015-01-12 13:01:47 -080010653 if (!msg ||
10654 nl80211_put_freq_params(msg, &params->freq) ||
10655 nl80211_put_basic_rates(msg, params->basic_rates) ||
10656 nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) ||
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070010657 nl80211_put_beacon_int(msg, params->beacon_int) ||
10658 nl80211_put_dtim_period(msg, params->dtim_period))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010659 goto fail;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010660
10661 wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags);
10662
Hai Shalom60840252021-02-19 19:02:11 -080010663 if (params->handle_dfs && nla_put_flag(msg, NL80211_ATTR_HANDLE_DFS))
10664 goto fail;
10665
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010666 container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
10667 if (!container)
10668 goto fail;
10669
10670 if (params->ies) {
10671 wpa_hexdump(MSG_DEBUG, " * IEs", params->ies, params->ie_len);
10672 if (nla_put(msg, NL80211_MESH_SETUP_IE, params->ie_len,
10673 params->ies))
10674 goto fail;
10675 }
10676 /* WPA_DRIVER_MESH_FLAG_OPEN_AUTH is treated as default by nl80211 */
10677 if (params->flags & WPA_DRIVER_MESH_FLAG_SAE_AUTH) {
10678 if (nla_put_u8(msg, NL80211_MESH_SETUP_AUTH_PROTOCOL, 0x1) ||
10679 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AUTH))
10680 goto fail;
10681 }
10682 if ((params->flags & WPA_DRIVER_MESH_FLAG_AMPE) &&
10683 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AMPE))
10684 goto fail;
10685 if ((params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) &&
10686 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_MPM))
10687 goto fail;
10688 nla_nest_end(msg, container);
10689
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070010690 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
10691 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT;
10692 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS;
10693 if (nl80211_put_mesh_config(msg, &params->conf) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010694 goto fail;
10695
Hai Shalomc1a21442022-02-04 13:43:00 -080010696 ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010697 msg = NULL;
10698 if (ret) {
10699 wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
10700 ret, strerror(-ret));
10701 goto fail;
10702 }
10703 ret = 0;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070010704 drv->assoc_freq = bss->freq = params->freq.freq;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010705 wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
10706
10707fail:
10708 nlmsg_free(msg);
10709 return ret;
10710}
10711
10712
Dmitry Shmidt7f656022015-02-25 14:36:37 -080010713static int
10714wpa_driver_nl80211_join_mesh(void *priv,
10715 struct wpa_driver_mesh_join_params *params)
10716{
10717 struct i802_bss *bss = priv;
10718 int ret, timeout;
10719
10720 timeout = params->conf.peer_link_timeout;
10721
10722 /* Disable kernel inactivity timer */
10723 if (params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM)
10724 params->conf.peer_link_timeout = 0;
10725
10726 ret = nl80211_join_mesh(bss, params);
10727 if (ret == -EINVAL && params->conf.peer_link_timeout == 0) {
10728 wpa_printf(MSG_DEBUG,
10729 "nl80211: Mesh join retry for peer_link_timeout");
10730 /*
10731 * Old kernel does not support setting
10732 * NL80211_MESHCONF_PLINK_TIMEOUT to zero, so set 60 seconds
10733 * into future from peer_link_timeout.
10734 */
10735 params->conf.peer_link_timeout = timeout + 60;
10736 ret = nl80211_join_mesh(priv, params);
10737 }
10738
10739 params->conf.peer_link_timeout = timeout;
10740 return ret;
10741}
10742
10743
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010744static int wpa_driver_nl80211_leave_mesh(void *priv)
10745{
10746 struct i802_bss *bss = priv;
10747 struct wpa_driver_nl80211_data *drv = bss->drv;
10748 struct nl_msg *msg;
10749 int ret;
10750
10751 wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
10752 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
Hai Shalomc1a21442022-02-04 13:43:00 -080010753 ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010754 if (ret) {
10755 wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
10756 ret, strerror(-ret));
10757 } else {
10758 wpa_printf(MSG_DEBUG,
10759 "nl80211: mesh leave request send successfully");
Hai Shalomc1a21442022-02-04 13:43:00 -080010760 drv->first_bss->freq = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010761 }
10762
Hai Shalomc1a21442022-02-04 13:43:00 -080010763 if (drv->start_mode_sta &&
10764 wpa_driver_nl80211_set_mode(drv->first_bss,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010765 NL80211_IFTYPE_STATION)) {
10766 wpa_printf(MSG_INFO,
10767 "nl80211: Failed to set interface into station mode");
10768 }
10769 return ret;
10770}
10771
Hai Shalom81f62d82019-07-22 12:10:00 -070010772
10773static int nl80211_probe_mesh_link(void *priv, const u8 *addr, const u8 *eth,
10774 size_t len)
10775{
10776 struct i802_bss *bss = priv;
10777 struct wpa_driver_nl80211_data *drv = bss->drv;
10778 struct nl_msg *msg;
10779 int ret;
10780
10781 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_PROBE_MESH_LINK);
10782 if (!msg ||
10783 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
10784 nla_put(msg, NL80211_ATTR_FRAME, len, eth)) {
10785 nlmsg_free(msg);
10786 return -ENOBUFS;
10787 }
10788
Hai Shalom899fcc72020-10-19 14:38:18 -070010789 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalom81f62d82019-07-22 12:10:00 -070010790 if (ret) {
10791 wpa_printf(MSG_DEBUG, "nl80211: mesh link probe to " MACSTR
10792 " failed: ret=%d (%s)",
10793 MAC2STR(addr), ret, strerror(-ret));
10794 } else {
10795 wpa_printf(MSG_DEBUG, "nl80211: Mesh link to " MACSTR
10796 " probed successfully", MAC2STR(addr));
10797 }
10798
10799 return ret;
10800}
10801
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010802#endif /* CONFIG_MESH */
10803
10804
10805static int wpa_driver_br_add_ip_neigh(void *priv, u8 version,
10806 const u8 *ipaddr, int prefixlen,
10807 const u8 *addr)
10808{
10809#ifdef CONFIG_LIBNL3_ROUTE
10810 struct i802_bss *bss = priv;
10811 struct wpa_driver_nl80211_data *drv = bss->drv;
10812 struct rtnl_neigh *rn;
10813 struct nl_addr *nl_ipaddr = NULL;
10814 struct nl_addr *nl_lladdr = NULL;
10815 int family, addrsize;
10816 int res;
10817
10818 if (!ipaddr || prefixlen == 0 || !addr)
10819 return -EINVAL;
10820
10821 if (bss->br_ifindex == 0) {
10822 wpa_printf(MSG_DEBUG,
10823 "nl80211: bridge must be set before adding an ip neigh to it");
10824 return -1;
10825 }
10826
10827 if (!drv->rtnl_sk) {
10828 wpa_printf(MSG_DEBUG,
10829 "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
10830 return -1;
10831 }
10832
10833 if (version == 4) {
10834 family = AF_INET;
10835 addrsize = 4;
10836 } else if (version == 6) {
10837 family = AF_INET6;
10838 addrsize = 16;
10839 } else {
10840 return -EINVAL;
10841 }
10842
10843 rn = rtnl_neigh_alloc();
10844 if (rn == NULL)
10845 return -ENOMEM;
10846
10847 /* set the destination ip address for neigh */
10848 nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
10849 if (nl_ipaddr == NULL) {
10850 wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
10851 res = -ENOMEM;
10852 goto errout;
10853 }
10854 nl_addr_set_prefixlen(nl_ipaddr, prefixlen);
10855 res = rtnl_neigh_set_dst(rn, nl_ipaddr);
10856 if (res) {
10857 wpa_printf(MSG_DEBUG,
10858 "nl80211: neigh set destination addr failed");
10859 goto errout;
10860 }
10861
10862 /* set the corresponding lladdr for neigh */
10863 nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN);
10864 if (nl_lladdr == NULL) {
10865 wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed");
10866 res = -ENOMEM;
10867 goto errout;
10868 }
10869 rtnl_neigh_set_lladdr(rn, nl_lladdr);
10870
10871 rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
10872 rtnl_neigh_set_state(rn, NUD_PERMANENT);
10873
10874 res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE);
10875 if (res) {
10876 wpa_printf(MSG_DEBUG,
10877 "nl80211: Adding bridge ip neigh failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070010878 nl_geterror(res));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010879 }
10880errout:
10881 if (nl_lladdr)
10882 nl_addr_put(nl_lladdr);
10883 if (nl_ipaddr)
10884 nl_addr_put(nl_ipaddr);
10885 if (rn)
10886 rtnl_neigh_put(rn);
10887 return res;
10888#else /* CONFIG_LIBNL3_ROUTE */
10889 return -1;
10890#endif /* CONFIG_LIBNL3_ROUTE */
10891}
10892
10893
10894static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version,
10895 const u8 *ipaddr)
10896{
10897#ifdef CONFIG_LIBNL3_ROUTE
10898 struct i802_bss *bss = priv;
10899 struct wpa_driver_nl80211_data *drv = bss->drv;
10900 struct rtnl_neigh *rn;
10901 struct nl_addr *nl_ipaddr;
10902 int family, addrsize;
10903 int res;
10904
10905 if (!ipaddr)
10906 return -EINVAL;
10907
10908 if (version == 4) {
10909 family = AF_INET;
10910 addrsize = 4;
10911 } else if (version == 6) {
10912 family = AF_INET6;
10913 addrsize = 16;
10914 } else {
10915 return -EINVAL;
10916 }
10917
10918 if (bss->br_ifindex == 0) {
10919 wpa_printf(MSG_DEBUG,
10920 "nl80211: bridge must be set to delete an ip neigh");
10921 return -1;
10922 }
10923
10924 if (!drv->rtnl_sk) {
10925 wpa_printf(MSG_DEBUG,
10926 "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
10927 return -1;
10928 }
10929
10930 rn = rtnl_neigh_alloc();
10931 if (rn == NULL)
10932 return -ENOMEM;
10933
10934 /* set the destination ip address for neigh */
10935 nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
10936 if (nl_ipaddr == NULL) {
10937 wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
10938 res = -ENOMEM;
10939 goto errout;
10940 }
10941 res = rtnl_neigh_set_dst(rn, nl_ipaddr);
10942 if (res) {
10943 wpa_printf(MSG_DEBUG,
10944 "nl80211: neigh set destination addr failed");
10945 goto errout;
10946 }
10947
10948 rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
10949
10950 res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
10951 if (res) {
10952 wpa_printf(MSG_DEBUG,
10953 "nl80211: Deleting bridge ip neigh failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070010954 nl_geterror(res));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010955 }
10956errout:
10957 if (nl_ipaddr)
10958 nl_addr_put(nl_ipaddr);
10959 if (rn)
10960 rtnl_neigh_put(rn);
10961 return res;
10962#else /* CONFIG_LIBNL3_ROUTE */
10963 return -1;
10964#endif /* CONFIG_LIBNL3_ROUTE */
10965}
10966
10967
10968static int linux_write_system_file(const char *path, unsigned int val)
10969{
10970 char buf[50];
10971 int fd, len;
10972
10973 len = os_snprintf(buf, sizeof(buf), "%u\n", val);
10974 if (os_snprintf_error(sizeof(buf), len))
10975 return -1;
10976
10977 fd = open(path, O_WRONLY);
10978 if (fd < 0)
10979 return -1;
10980
10981 if (write(fd, buf, len) < 0) {
10982 wpa_printf(MSG_DEBUG,
10983 "nl80211: Failed to write Linux system file: %s with the value of %d",
10984 path, val);
10985 close(fd);
10986 return -1;
10987 }
10988 close(fd);
10989
10990 return 0;
10991}
10992
10993
10994static const char * drv_br_port_attr_str(enum drv_br_port_attr attr)
10995{
10996 switch (attr) {
10997 case DRV_BR_PORT_ATTR_PROXYARP:
Dmitry Shmidt4dd28dc2015-03-10 11:21:43 -070010998 return "proxyarp_wifi";
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010999 case DRV_BR_PORT_ATTR_HAIRPIN_MODE:
11000 return "hairpin_mode";
11001 }
11002
11003 return NULL;
11004}
11005
11006
11007static int wpa_driver_br_port_set_attr(void *priv, enum drv_br_port_attr attr,
11008 unsigned int val)
11009{
11010 struct i802_bss *bss = priv;
11011 char path[128];
11012 const char *attr_txt;
11013
11014 attr_txt = drv_br_port_attr_str(attr);
11015 if (attr_txt == NULL)
11016 return -EINVAL;
11017
11018 os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/%s",
11019 bss->ifname, attr_txt);
11020
11021 if (linux_write_system_file(path, val))
11022 return -1;
11023
11024 return 0;
11025}
11026
11027
11028static const char * drv_br_net_param_str(enum drv_br_net_param param)
11029{
11030 switch (param) {
11031 case DRV_BR_NET_PARAM_GARP_ACCEPT:
11032 return "arp_accept";
Dmitry Shmidt83474442015-04-15 13:47:09 -070011033 default:
11034 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011035 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011036}
11037
11038
11039static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
11040 unsigned int val)
11041{
11042 struct i802_bss *bss = priv;
11043 char path[128];
11044 const char *param_txt;
11045 int ip_version = 4;
11046
Dmitry Shmidt83474442015-04-15 13:47:09 -070011047 if (param == DRV_BR_MULTICAST_SNOOPING) {
11048 os_snprintf(path, sizeof(path),
11049 "/sys/devices/virtual/net/%s/bridge/multicast_snooping",
11050 bss->brname);
11051 goto set_val;
11052 }
11053
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011054 param_txt = drv_br_net_param_str(param);
11055 if (param_txt == NULL)
11056 return -EINVAL;
11057
11058 switch (param) {
11059 case DRV_BR_NET_PARAM_GARP_ACCEPT:
11060 ip_version = 4;
11061 break;
11062 default:
11063 return -EINVAL;
11064 }
11065
11066 os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
11067 ip_version, bss->brname, param_txt);
11068
Dmitry Shmidt83474442015-04-15 13:47:09 -070011069set_val:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011070 if (linux_write_system_file(path, val))
11071 return -1;
11072
11073 return 0;
11074}
11075
11076
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011077#ifdef CONFIG_DRIVER_NL80211_QCA
11078
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011079static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
11080{
11081 switch (hw_mode) {
11082 case HOSTAPD_MODE_IEEE80211B:
11083 return QCA_ACS_MODE_IEEE80211B;
11084 case HOSTAPD_MODE_IEEE80211G:
11085 return QCA_ACS_MODE_IEEE80211G;
11086 case HOSTAPD_MODE_IEEE80211A:
11087 return QCA_ACS_MODE_IEEE80211A;
11088 case HOSTAPD_MODE_IEEE80211AD:
11089 return QCA_ACS_MODE_IEEE80211AD;
Dmitry Shmidtb1e52102015-05-29 12:36:29 -070011090 case HOSTAPD_MODE_IEEE80211ANY:
11091 return QCA_ACS_MODE_IEEE80211ANY;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011092 default:
11093 return -1;
11094 }
11095}
11096
11097
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080011098static int add_acs_ch_list(struct nl_msg *msg, const int *freq_list)
11099{
11100 int num_channels = 0, num_freqs;
11101 u8 *ch_list;
11102 enum hostapd_hw_mode hw_mode;
11103 int ret = 0;
11104 int i;
11105
11106 if (!freq_list)
11107 return 0;
11108
11109 num_freqs = int_array_len(freq_list);
11110 ch_list = os_malloc(sizeof(u8) * num_freqs);
11111 if (!ch_list)
11112 return -1;
11113
11114 for (i = 0; i < num_freqs; i++) {
11115 const int freq = freq_list[i];
11116
11117 if (freq == 0)
11118 break;
11119 /* Send 2.4 GHz and 5 GHz channels with
11120 * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST to maintain backwards
11121 * compatibility.
11122 */
11123 if (!(freq >= 2412 && freq <= 2484) &&
Hai Shalomc1a21442022-02-04 13:43:00 -080011124 !(freq >= 5180 && freq <= 5900) &&
11125 !(freq >= 5945 && freq <= 7115))
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080011126 continue;
11127 hw_mode = ieee80211_freq_to_chan(freq, &ch_list[num_channels]);
11128 if (hw_mode != NUM_HOSTAPD_MODES)
11129 num_channels++;
11130 }
11131
11132 if (num_channels)
11133 ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
11134 num_channels, ch_list);
11135
11136 os_free(ch_list);
11137 return ret;
11138}
11139
11140
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011141static int add_acs_freq_list(struct nl_msg *msg, const int *freq_list)
11142{
11143 int i, len, ret;
11144 u32 *freqs;
11145
11146 if (!freq_list)
11147 return 0;
11148 len = int_array_len(freq_list);
11149 freqs = os_malloc(sizeof(u32) * len);
11150 if (!freqs)
11151 return -1;
11152 for (i = 0; i < len; i++)
11153 freqs[i] = freq_list[i];
11154 ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
11155 sizeof(u32) * len, freqs);
11156 os_free(freqs);
11157 return ret;
11158}
11159
11160
Hai Shalomc1a21442022-02-04 13:43:00 -080011161static int nl80211_qca_do_acs(struct wpa_driver_nl80211_data *drv,
11162 struct drv_acs_params *params)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011163{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011164 struct nl_msg *msg;
11165 struct nlattr *data;
11166 int ret;
11167 int mode;
11168
11169 mode = hw_mode_to_qca_acs(params->hw_mode);
11170 if (mode < 0)
11171 return -1;
11172
11173 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11174 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11175 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11176 QCA_NL80211_VENDOR_SUBCMD_DO_ACS) ||
11177 !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
11178 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, mode) ||
11179 (params->ht_enabled &&
11180 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
11181 (params->ht40_enabled &&
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070011182 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) ||
11183 (params->vht_enabled &&
11184 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
11185 nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
11186 params->ch_width) ||
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080011187 add_acs_ch_list(msg, params->freq_list) ||
Hai Shalomfdcde762020-04-02 11:19:20 -070011188 add_acs_freq_list(msg, params->freq_list) ||
11189 (params->edmg_enabled &&
11190 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011191 nlmsg_free(msg);
11192 return -ENOBUFS;
11193 }
11194 nla_nest_end(msg, data);
11195
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070011196 wpa_printf(MSG_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -070011197 "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d EDMG: %d",
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070011198 params->hw_mode, params->ht_enabled, params->ht40_enabled,
Hai Shalomfdcde762020-04-02 11:19:20 -070011199 params->vht_enabled, params->ch_width, params->edmg_enabled);
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070011200
Hai Shalom899fcc72020-10-19 14:38:18 -070011201 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011202 if (ret) {
11203 wpa_printf(MSG_DEBUG,
11204 "nl80211: Failed to invoke driver ACS function: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070011205 strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011206 }
11207 return ret;
11208}
11209
11210
Hai Shalom60840252021-02-19 19:02:11 -080011211static int nl80211_set_band(void *priv, u32 band_mask)
Ravi Joshie6ccb162015-07-16 17:45:41 -070011212{
11213 struct i802_bss *bss = priv;
11214 struct wpa_driver_nl80211_data *drv = bss->drv;
11215 struct nl_msg *msg;
11216 struct nlattr *data;
11217 int ret;
Hai Shalom60840252021-02-19 19:02:11 -080011218 enum qca_set_band qca_band_value;
11219 u32 qca_band_mask = QCA_SETBAND_AUTO;
Ravi Joshie6ccb162015-07-16 17:45:41 -070011220
Hai Shalom60840252021-02-19 19:02:11 -080011221 if (!drv->setband_vendor_cmd_avail ||
11222 (band_mask > (WPA_SETBAND_2G | WPA_SETBAND_5G | WPA_SETBAND_6G)))
Ravi Joshie6ccb162015-07-16 17:45:41 -070011223 return -1;
11224
Hai Shalom60840252021-02-19 19:02:11 -080011225 if (band_mask & WPA_SETBAND_5G)
11226 qca_band_mask |= QCA_SETBAND_5G;
11227 if (band_mask & WPA_SETBAND_2G)
11228 qca_band_mask |= QCA_SETBAND_2G;
11229 if (band_mask & WPA_SETBAND_6G)
11230 qca_band_mask |= QCA_SETBAND_6G;
11231
11232 /*
11233 * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE is a legacy interface hence make
11234 * it suite to its values (AUTO/5G/2G) for backwards compatibility.
11235 */
11236 qca_band_value = ((qca_band_mask & QCA_SETBAND_5G) &&
11237 (qca_band_mask & QCA_SETBAND_2G)) ?
11238 QCA_SETBAND_AUTO :
11239 qca_band_mask & ~QCA_SETBAND_6G;
11240
11241 wpa_printf(MSG_DEBUG,
11242 "nl80211: QCA_BAND_MASK = 0x%x, QCA_BAND_VALUE = %d",
11243 qca_band_mask, qca_band_value);
Ravi Joshie6ccb162015-07-16 17:45:41 -070011244
11245 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11246 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11247 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11248 QCA_NL80211_VENDOR_SUBCMD_SETBAND) ||
11249 !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
Hai Shalom60840252021-02-19 19:02:11 -080011250 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE,
11251 qca_band_value) ||
11252 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_MASK,
11253 qca_band_mask)) {
Ravi Joshie6ccb162015-07-16 17:45:41 -070011254 nlmsg_free(msg);
11255 return -ENOBUFS;
11256 }
11257 nla_nest_end(msg, data);
11258
Hai Shalom899fcc72020-10-19 14:38:18 -070011259 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Ravi Joshie6ccb162015-07-16 17:45:41 -070011260 if (ret) {
11261 wpa_printf(MSG_DEBUG,
11262 "nl80211: Driver setband function failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070011263 strerror(-ret));
Ravi Joshie6ccb162015-07-16 17:45:41 -070011264 }
11265 return ret;
11266}
11267
11268
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011269struct nl80211_pcl {
11270 unsigned int num;
11271 unsigned int *freq_list;
11272};
11273
11274static int preferred_freq_info_handler(struct nl_msg *msg, void *arg)
11275{
11276 struct nlattr *tb[NL80211_ATTR_MAX + 1];
11277 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
11278 struct nl80211_pcl *param = arg;
11279 struct nlattr *nl_vend, *attr;
11280 enum qca_iface_type iface_type;
11281 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
11282 unsigned int num, max_num;
11283 u32 *freqs;
11284
11285 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
11286 genlmsg_attrlen(gnlh, 0), NULL);
11287
11288 nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
11289 if (!nl_vend)
11290 return NL_SKIP;
11291
11292 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
11293 nla_data(nl_vend), nla_len(nl_vend), NULL);
11294
11295 attr = tb_vendor[
11296 QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE];
11297 if (!attr) {
11298 wpa_printf(MSG_ERROR, "nl80211: iface_type couldn't be found");
11299 param->num = 0;
11300 return NL_SKIP;
11301 }
11302
11303 iface_type = (enum qca_iface_type) nla_get_u32(attr);
11304 wpa_printf(MSG_DEBUG, "nl80211: Driver returned iface_type=%d",
11305 iface_type);
11306
11307 attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST];
11308 if (!attr) {
11309 wpa_printf(MSG_ERROR,
11310 "nl80211: preferred_freq_list couldn't be found");
11311 param->num = 0;
11312 return NL_SKIP;
11313 }
11314
11315 /*
11316 * param->num has the maximum number of entries for which there
11317 * is room in the freq_list provided by the caller.
11318 */
11319 freqs = nla_data(attr);
11320 max_num = nla_len(attr) / sizeof(u32);
11321 if (max_num > param->num)
11322 max_num = param->num;
11323 for (num = 0; num < max_num; num++)
11324 param->freq_list[num] = freqs[num];
11325 param->num = num;
11326
11327 return NL_SKIP;
11328}
11329
11330
11331static int nl80211_get_pref_freq_list(void *priv,
11332 enum wpa_driver_if_type if_type,
11333 unsigned int *num,
11334 unsigned int *freq_list)
11335{
11336 struct i802_bss *bss = priv;
11337 struct wpa_driver_nl80211_data *drv = bss->drv;
11338 struct nl_msg *msg;
11339 int ret;
11340 unsigned int i;
11341 struct nlattr *params;
11342 struct nl80211_pcl param;
11343 enum qca_iface_type iface_type;
11344
11345 if (!drv->get_pref_freq_list)
11346 return -1;
11347
11348 switch (if_type) {
11349 case WPA_IF_STATION:
11350 iface_type = QCA_IFACE_TYPE_STA;
11351 break;
11352 case WPA_IF_AP_BSS:
11353 iface_type = QCA_IFACE_TYPE_AP;
11354 break;
11355 case WPA_IF_P2P_GO:
11356 iface_type = QCA_IFACE_TYPE_P2P_GO;
11357 break;
11358 case WPA_IF_P2P_CLIENT:
11359 iface_type = QCA_IFACE_TYPE_P2P_CLIENT;
11360 break;
11361 case WPA_IF_IBSS:
11362 iface_type = QCA_IFACE_TYPE_IBSS;
11363 break;
11364 case WPA_IF_TDLS:
11365 iface_type = QCA_IFACE_TYPE_TDLS;
11366 break;
11367 default:
11368 return -1;
11369 }
11370
11371 param.num = *num;
11372 param.freq_list = freq_list;
11373
11374 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11375 nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) ||
11376 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11377 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11378 QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST) ||
11379 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
11380 nla_put_u32(msg,
11381 QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE,
11382 iface_type)) {
11383 wpa_printf(MSG_ERROR,
11384 "%s: err in adding vendor_cmd and vendor_data",
11385 __func__);
11386 nlmsg_free(msg);
11387 return -1;
11388 }
11389 nla_nest_end(msg, params);
11390
11391 os_memset(freq_list, 0, *num * sizeof(freq_list[0]));
Hai Shalom899fcc72020-10-19 14:38:18 -070011392 ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, &param,
11393 NULL, NULL);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011394 if (ret) {
11395 wpa_printf(MSG_ERROR,
11396 "%s: err in send_and_recv_msgs", __func__);
11397 return ret;
11398 }
11399
11400 *num = param.num;
11401
11402 for (i = 0; i < *num; i++) {
11403 wpa_printf(MSG_DEBUG, "nl80211: preferred_channel_list[%d]=%d",
11404 i, freq_list[i]);
11405 }
11406
11407 return 0;
11408}
11409
11410
11411static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq)
11412{
11413 struct i802_bss *bss = priv;
11414 struct wpa_driver_nl80211_data *drv = bss->drv;
11415 struct nl_msg *msg;
11416 int ret;
11417 struct nlattr *params;
11418
11419 if (!drv->set_prob_oper_freq)
11420 return -1;
11421
11422 wpa_printf(MSG_DEBUG,
11423 "nl80211: Set P2P probable operating freq %u for ifindex %d",
11424 freq, bss->ifindex);
11425
11426 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11427 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11428 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11429 QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL) ||
11430 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
11431 nla_put_u32(msg,
11432 QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE,
11433 QCA_IFACE_TYPE_P2P_CLIENT) ||
11434 nla_put_u32(msg,
11435 QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ,
11436 freq)) {
11437 wpa_printf(MSG_ERROR,
11438 "%s: err in adding vendor_cmd and vendor_data",
11439 __func__);
11440 nlmsg_free(msg);
11441 return -1;
11442 }
11443 nla_nest_end(msg, params);
11444
Hai Shalom899fcc72020-10-19 14:38:18 -070011445 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011446 msg = NULL;
11447 if (ret) {
11448 wpa_printf(MSG_ERROR, "%s: err in send_and_recv_msgs",
11449 __func__);
11450 return ret;
11451 }
11452 nlmsg_free(msg);
11453 return 0;
11454}
11455
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070011456
11457static int nl80211_p2p_lo_start(void *priv, unsigned int freq,
11458 unsigned int period, unsigned int interval,
11459 unsigned int count, const u8 *device_types,
11460 size_t dev_types_len,
11461 const u8 *ies, size_t ies_len)
11462{
11463 struct i802_bss *bss = priv;
11464 struct wpa_driver_nl80211_data *drv = bss->drv;
11465 struct nl_msg *msg;
11466 struct nlattr *container;
11467 int ret;
11468
11469 wpa_printf(MSG_DEBUG,
11470 "nl80211: Start P2P Listen offload: freq=%u, period=%u, interval=%u, count=%u",
11471 freq, period, interval, count);
11472
11473 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
11474 return -1;
11475
11476 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11477 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11478 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11479 QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START))
11480 goto fail;
11481
11482 container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
11483 if (!container)
11484 goto fail;
11485
11486 if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL,
11487 freq) ||
11488 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD,
11489 period) ||
11490 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL,
11491 interval) ||
11492 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT,
11493 count) ||
11494 nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES,
11495 dev_types_len, device_types) ||
11496 nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE,
11497 ies_len, ies))
11498 goto fail;
11499
11500 nla_nest_end(msg, container);
Hai Shalom899fcc72020-10-19 14:38:18 -070011501 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070011502 msg = NULL;
11503 if (ret) {
11504 wpa_printf(MSG_DEBUG,
11505 "nl80211: Failed to send P2P Listen offload vendor command");
11506 goto fail;
11507 }
11508
11509 return 0;
11510
11511fail:
11512 nlmsg_free(msg);
11513 return -1;
11514}
11515
11516
11517static int nl80211_p2p_lo_stop(void *priv)
11518{
11519 struct i802_bss *bss = priv;
11520 struct wpa_driver_nl80211_data *drv = bss->drv;
11521 struct nl_msg *msg;
11522
11523 wpa_printf(MSG_DEBUG, "nl80211: Stop P2P Listen offload");
11524
11525 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
11526 return -1;
11527
11528 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11529 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11530 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11531 QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP)) {
11532 nlmsg_free(msg);
11533 return -1;
11534 }
11535
Hai Shalom899fcc72020-10-19 14:38:18 -070011536 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070011537}
11538
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080011539
11540static int nl80211_set_tdls_mode(void *priv, int tdls_external_control)
11541{
11542 struct i802_bss *bss = priv;
11543 struct wpa_driver_nl80211_data *drv = bss->drv;
11544 struct nl_msg *msg;
11545 struct nlattr *params;
11546 int ret;
11547 u32 tdls_mode;
11548
11549 wpa_printf(MSG_DEBUG,
11550 "nl80211: Set TDKS mode: tdls_external_control=%d",
11551 tdls_external_control);
11552
11553 if (tdls_external_control == 1)
11554 tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT |
11555 QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL;
11556 else
11557 tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT;
11558
11559 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11560 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11561 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11562 QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS))
11563 goto fail;
11564
11565 params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
11566 if (!params)
11567 goto fail;
11568
11569 if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE,
11570 tdls_mode))
11571 goto fail;
11572
11573 nla_nest_end(msg, params);
11574
Hai Shalom899fcc72020-10-19 14:38:18 -070011575 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080011576 msg = NULL;
11577 if (ret) {
11578 wpa_printf(MSG_ERROR,
11579 "nl80211: Set TDLS mode failed: ret=%d (%s)",
11580 ret, strerror(-ret));
11581 goto fail;
11582 }
11583 return 0;
11584fail:
11585 nlmsg_free(msg);
11586 return -1;
11587}
11588
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011589
11590#ifdef CONFIG_MBO
11591
11592static enum mbo_transition_reject_reason
11593nl80211_mbo_reject_reason_mapping(enum qca_wlan_btm_candidate_status status)
11594{
11595 switch (status) {
11596 case QCA_STATUS_REJECT_EXCESSIVE_FRAME_LOSS_EXPECTED:
11597 return MBO_TRANSITION_REJECT_REASON_FRAME_LOSS;
11598 case QCA_STATUS_REJECT_EXCESSIVE_DELAY_EXPECTED:
11599 return MBO_TRANSITION_REJECT_REASON_DELAY;
11600 case QCA_STATUS_REJECT_INSUFFICIENT_QOS_CAPACITY:
11601 return MBO_TRANSITION_REJECT_REASON_QOS_CAPACITY;
11602 case QCA_STATUS_REJECT_LOW_RSSI:
11603 return MBO_TRANSITION_REJECT_REASON_RSSI;
11604 case QCA_STATUS_REJECT_HIGH_INTERFERENCE:
11605 return MBO_TRANSITION_REJECT_REASON_INTERFERENCE;
11606 case QCA_STATUS_REJECT_UNKNOWN:
11607 default:
11608 return MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
11609 }
11610}
11611
11612
11613static void nl80211_parse_btm_candidate_info(struct candidate_list *candidate,
11614 struct nlattr *tb[], int num)
11615{
11616 enum qca_wlan_btm_candidate_status status;
11617 char buf[50];
11618
11619 os_memcpy(candidate->bssid,
11620 nla_data(tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]),
11621 ETH_ALEN);
11622
11623 status = nla_get_u32(
11624 tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS]);
11625 candidate->is_accept = status == QCA_STATUS_ACCEPT;
11626 candidate->reject_reason = nl80211_mbo_reject_reason_mapping(status);
11627
11628 if (candidate->is_accept)
11629 os_snprintf(buf, sizeof(buf), "Accepted");
11630 else
11631 os_snprintf(buf, sizeof(buf),
11632 "Rejected, Reject_reason: %d",
11633 candidate->reject_reason);
11634 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%d]: " MACSTR " %s",
11635 num, MAC2STR(candidate->bssid), buf);
11636}
11637
11638
11639static int
11640nl80211_get_bss_transition_status_handler(struct nl_msg *msg, void *arg)
11641{
11642 struct wpa_bss_candidate_info *info = arg;
11643 struct candidate_list *candidate = info->candidates;
11644 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
11645 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
11646 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1];
11647 static struct nla_policy policy[
11648 QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1] = {
11649 [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] = {
11650 .minlen = ETH_ALEN
11651 },
11652 [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS] = {
11653 .type = NLA_U32,
11654 },
11655 };
11656 struct nlattr *attr;
11657 int rem;
11658 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
11659 u8 num;
11660
11661 num = info->num; /* number of candidates sent to driver */
11662 info->num = 0;
11663 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
11664 genlmsg_attrlen(gnlh, 0), NULL);
11665
11666 if (!tb_msg[NL80211_ATTR_VENDOR_DATA] ||
11667 nla_parse_nested(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
11668 tb_msg[NL80211_ATTR_VENDOR_DATA], NULL) ||
11669 !tb_vendor[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO])
11670 return NL_SKIP;
11671
11672 wpa_printf(MSG_DEBUG,
11673 "nl80211: WNM Candidate list received from driver");
11674 nla_for_each_nested(attr,
11675 tb_vendor[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO],
11676 rem) {
11677 if (info->num >= num ||
11678 nla_parse_nested(
11679 tb, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX,
11680 attr, policy) ||
11681 !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] ||
11682 !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS])
11683 break;
11684
11685 nl80211_parse_btm_candidate_info(candidate, tb, info->num);
11686
11687 candidate++;
11688 info->num++;
11689 }
11690
11691 return NL_SKIP;
11692}
11693
11694
11695static struct wpa_bss_candidate_info *
11696nl80211_get_bss_transition_status(void *priv, struct wpa_bss_trans_info *params)
11697{
11698 struct i802_bss *bss = priv;
11699 struct wpa_driver_nl80211_data *drv = bss->drv;
11700 struct nl_msg *msg;
11701 struct nlattr *attr, *attr1, *attr2;
11702 struct wpa_bss_candidate_info *info;
11703 u8 i;
11704 int ret;
11705 u8 *pos;
11706
11707 if (!drv->fetch_bss_trans_status)
11708 return NULL;
11709
11710 info = os_zalloc(sizeof(*info));
11711 if (!info)
11712 return NULL;
11713 /* Allocate memory for number of candidates sent to driver */
11714 info->candidates = os_calloc(params->n_candidates,
11715 sizeof(*info->candidates));
11716 if (!info->candidates) {
11717 os_free(info);
11718 return NULL;
11719 }
11720
11721 /* Copy the number of candidates being sent to driver. This is used in
11722 * nl80211_get_bss_transition_status_handler() to limit the number of
11723 * candidates that can be populated in info->candidates and will be
11724 * later overwritten with the actual number of candidates received from
11725 * the driver.
11726 */
11727 info->num = params->n_candidates;
11728
11729 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11730 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11731 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11732 QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS))
11733 goto fail;
11734
11735 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
11736 if (!attr)
11737 goto fail;
11738
11739 if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON,
11740 params->mbo_transition_reason))
11741 goto fail;
11742
11743 attr1 = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO);
11744 if (!attr1)
11745 goto fail;
11746
11747 wpa_printf(MSG_DEBUG,
11748 "nl80211: WNM Candidate list info sending to driver: mbo_transition_reason: %d n_candidates: %d",
11749 params->mbo_transition_reason, params->n_candidates);
11750 pos = params->bssid;
11751 for (i = 0; i < params->n_candidates; i++) {
11752 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%d]: " MACSTR, i,
11753 MAC2STR(pos));
11754 attr2 = nla_nest_start(msg, i);
11755 if (!attr2 ||
11756 nla_put(msg, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID,
11757 ETH_ALEN, pos))
11758 goto fail;
11759 pos += ETH_ALEN;
11760 nla_nest_end(msg, attr2);
11761 }
11762
11763 nla_nest_end(msg, attr1);
11764 nla_nest_end(msg, attr);
11765
11766 ret = send_and_recv_msgs(drv, msg,
11767 nl80211_get_bss_transition_status_handler,
Hai Shalom899fcc72020-10-19 14:38:18 -070011768 info, NULL, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011769 msg = NULL;
11770 if (ret) {
11771 wpa_printf(MSG_ERROR,
11772 "nl80211: WNM Get BSS transition status failed: ret=%d (%s)",
11773 ret, strerror(-ret));
11774 goto fail;
11775 }
11776 return info;
11777
11778fail:
11779 nlmsg_free(msg);
11780 os_free(info->candidates);
11781 os_free(info);
11782 return NULL;
11783}
11784
11785
11786/**
11787 * nl80211_ignore_assoc_disallow - Configure driver to ignore assoc_disallow
11788 * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
11789 * @ignore_assoc_disallow: 0 to not ignore, 1 to ignore
11790 * Returns: 0 on success, -1 on failure
11791 */
11792static int nl80211_ignore_assoc_disallow(void *priv, int ignore_disallow)
11793{
11794 struct i802_bss *bss = priv;
11795 struct wpa_driver_nl80211_data *drv = bss->drv;
11796 struct nl_msg *msg;
11797 struct nlattr *attr;
11798 int ret = -1;
11799
11800 if (!drv->set_wifi_conf_vendor_cmd_avail)
11801 return -1;
11802
11803 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11804 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11805 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11806 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION))
11807 goto fail;
11808
11809 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
11810 if (!attr)
11811 goto fail;
11812
11813 wpa_printf(MSG_DEBUG, "nl80211: Set ignore_assoc_disallow %d",
11814 ignore_disallow);
11815 if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED,
11816 ignore_disallow))
11817 goto fail;
11818
11819 nla_nest_end(msg, attr);
11820
Hai Shalom899fcc72020-10-19 14:38:18 -070011821 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011822 msg = NULL;
11823 if (ret) {
11824 wpa_printf(MSG_ERROR,
11825 "nl80211: Set ignore_assoc_disallow failed: ret=%d (%s)",
11826 ret, strerror(-ret));
11827 goto fail;
11828 }
11829
11830fail:
11831 nlmsg_free(msg);
11832 return ret;
11833}
11834
11835#endif /* CONFIG_MBO */
11836
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011837#endif /* CONFIG_DRIVER_NL80211_QCA */
11838
Hai Shalomc1a21442022-02-04 13:43:00 -080011839static int nl80211_do_acs(void *priv, struct drv_acs_params *params)
11840{
11841#if defined(CONFIG_DRIVER_NL80211_QCA) || defined(CONFIG_DRIVER_NL80211_BRCM)
11842 struct i802_bss *bss = priv;
11843 struct wpa_driver_nl80211_data *drv = bss->drv;
11844#endif /* CONFIG_DRIVER_NL80211_QCA || CONFIG_DRIVER_NL80211_BRCM */
11845
11846#ifdef CONFIG_DRIVER_NL80211_QCA
11847 if (drv->qca_do_acs)
11848 return nl80211_qca_do_acs(drv, params);
11849#endif /* CONFIG_DRIVER_NL80211_QCA */
11850
11851#ifdef CONFIG_DRIVER_NL80211_BRCM
11852 if (drv->brcm_do_acs)
11853 return wpa_driver_do_broadcom_acs(drv, params);
11854#endif /* CONFIG_DRIVER_NL80211_BRCM */
11855
11856 return -1;
11857}
11858
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011859
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011860static int nl80211_write_to_file(const char *name, unsigned int val)
11861{
11862 int fd, len;
11863 char tmp[128];
Hai Shalomc3565922019-10-28 11:58:20 -070011864 int ret = 0;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011865
11866 fd = open(name, O_RDWR);
11867 if (fd < 0) {
Hai Shalomc3565922019-10-28 11:58:20 -070011868 int level;
11869 /*
11870 * Flags may not exist on older kernels, or while we're tearing
11871 * down a disappearing device.
11872 */
11873 if (errno == ENOENT) {
11874 ret = 0;
11875 level = MSG_DEBUG;
11876 } else {
11877 ret = -1;
11878 level = MSG_ERROR;
11879 }
11880 wpa_printf(level, "nl80211: Failed to open %s: %s",
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011881 name, strerror(errno));
Hai Shalomc3565922019-10-28 11:58:20 -070011882 return ret;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011883 }
11884
11885 len = os_snprintf(tmp, sizeof(tmp), "%u\n", val);
11886 len = write(fd, tmp, len);
Hai Shalomc3565922019-10-28 11:58:20 -070011887 if (len < 0) {
11888 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011889 wpa_printf(MSG_ERROR, "nl80211: Failed to write to %s: %s",
11890 name, strerror(errno));
Hai Shalomc3565922019-10-28 11:58:20 -070011891 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011892 close(fd);
11893
Hai Shalomc3565922019-10-28 11:58:20 -070011894 return ret;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011895}
11896
11897
11898static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags)
11899{
11900 struct i802_bss *bss = priv;
11901 char path[128];
11902 int ret;
11903
Hai Shalom60840252021-02-19 19:02:11 -080011904 /* P2P-Device has no netdev that can (or should) be configured here */
11905 if (nl80211_get_ifmode(bss) == NL80211_IFTYPE_P2P_DEVICE)
11906 return 0;
11907
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011908 wpa_printf(MSG_DEBUG, "nl80211: Data frame filter flags=0x%x",
11909 filter_flags);
11910
11911 /* Configure filtering of unicast frame encrypted using GTK */
11912 ret = os_snprintf(path, sizeof(path),
11913 "/proc/sys/net/ipv4/conf/%s/drop_unicast_in_l2_multicast",
11914 bss->ifname);
11915 if (os_snprintf_error(sizeof(path), ret))
11916 return -1;
11917
11918 ret = nl80211_write_to_file(path,
11919 !!(filter_flags &
11920 WPA_DATA_FRAME_FILTER_FLAG_GTK));
11921 if (ret) {
11922 wpa_printf(MSG_ERROR,
11923 "nl80211: Failed to set IPv4 unicast in multicast filter");
11924 return ret;
11925 }
11926
11927 os_snprintf(path, sizeof(path),
11928 "/proc/sys/net/ipv6/conf/%s/drop_unicast_in_l2_multicast",
11929 bss->ifname);
11930 ret = nl80211_write_to_file(path,
11931 !!(filter_flags &
11932 WPA_DATA_FRAME_FILTER_FLAG_GTK));
11933
11934 if (ret) {
11935 wpa_printf(MSG_ERROR,
11936 "nl80211: Failed to set IPv6 unicast in multicast filter");
11937 return ret;
11938 }
11939
11940 /* Configure filtering of unicast frame encrypted using GTK */
11941 os_snprintf(path, sizeof(path),
11942 "/proc/sys/net/ipv4/conf/%s/drop_gratuitous_arp",
11943 bss->ifname);
11944 ret = nl80211_write_to_file(path,
11945 !!(filter_flags &
11946 WPA_DATA_FRAME_FILTER_FLAG_ARP));
11947 if (ret) {
11948 wpa_printf(MSG_ERROR,
11949 "nl80211: Failed set gratuitous ARP filter");
11950 return ret;
11951 }
11952
11953 /* Configure filtering of IPv6 NA frames */
11954 os_snprintf(path, sizeof(path),
11955 "/proc/sys/net/ipv6/conf/%s/drop_unsolicited_na",
11956 bss->ifname);
11957 ret = nl80211_write_to_file(path,
11958 !!(filter_flags &
11959 WPA_DATA_FRAME_FILTER_FLAG_NA));
11960 if (ret) {
11961 wpa_printf(MSG_ERROR,
11962 "nl80211: Failed to set unsolicited NA filter");
11963 return ret;
11964 }
11965
11966 return 0;
11967}
11968
11969
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070011970static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type,
11971 const u8 **ext_capa, const u8 **ext_capa_mask,
11972 unsigned int *ext_capa_len)
11973{
11974 struct i802_bss *bss = priv;
11975 struct wpa_driver_nl80211_data *drv = bss->drv;
11976 enum nl80211_iftype nlmode;
11977 unsigned int i;
11978
11979 if (!ext_capa || !ext_capa_mask || !ext_capa_len)
11980 return -1;
11981
11982 nlmode = wpa_driver_nl80211_if_type(type);
11983
11984 /* By default, use the per-radio values */
11985 *ext_capa = drv->extended_capa;
11986 *ext_capa_mask = drv->extended_capa_mask;
11987 *ext_capa_len = drv->extended_capa_len;
11988
11989 /* Replace the default value if a per-interface type value exists */
11990 for (i = 0; i < drv->num_iface_ext_capa; i++) {
11991 if (nlmode == drv->iface_ext_capa[i].iftype) {
11992 *ext_capa = drv->iface_ext_capa[i].ext_capa;
11993 *ext_capa_mask = drv->iface_ext_capa[i].ext_capa_mask;
11994 *ext_capa_len = drv->iface_ext_capa[i].ext_capa_len;
11995 break;
11996 }
11997 }
11998
11999 return 0;
12000}
12001
12002
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012003static int nl80211_update_connection_params(
12004 void *priv, struct wpa_driver_associate_params *params,
12005 enum wpa_drv_update_connect_params_mask mask)
12006{
12007 struct i802_bss *bss = priv;
12008 struct wpa_driver_nl80211_data *drv = bss->drv;
12009 struct nl_msg *msg;
12010 int ret = -1;
12011 enum nl80211_auth_type type;
12012
Hai Shalomc3565922019-10-28 11:58:20 -070012013 /* Update Connection Params is intended for drivers that implement
12014 * internal SME and expect these updated connection params from
12015 * wpa_supplicant. Do not send this request for the drivers using
12016 * SME from wpa_supplicant.
12017 */
12018 if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
12019 return 0;
12020
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012021 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_CONNECT_PARAMS);
12022 if (!msg)
12023 goto fail;
12024
12025 wpa_printf(MSG_DEBUG, "nl80211: Update connection params (ifindex=%d)",
12026 drv->ifindex);
12027
12028 if ((mask & WPA_DRV_UPDATE_ASSOC_IES) && params->wpa_ie) {
12029 if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
12030 params->wpa_ie))
12031 goto fail;
12032 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie,
12033 params->wpa_ie_len);
12034 }
12035
12036 if (mask & WPA_DRV_UPDATE_AUTH_TYPE) {
12037 type = get_nl_auth_type(params->auth_alg);
12038 if (type == NL80211_AUTHTYPE_MAX ||
12039 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
12040 goto fail;
12041 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
12042 }
12043
12044 if ((mask & WPA_DRV_UPDATE_FILS_ERP_INFO) &&
12045 nl80211_put_fils_connect_params(drv, params, msg))
12046 goto fail;
12047
Hai Shalom899fcc72020-10-19 14:38:18 -070012048 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012049 msg = NULL;
12050 if (ret)
12051 wpa_dbg(drv->ctx, MSG_DEBUG,
12052 "nl80211: Update connect params command failed: ret=%d (%s)",
12053 ret, strerror(-ret));
12054
12055fail:
12056 nlmsg_free(msg);
12057 return ret;
12058}
12059
12060
Roshan Pius3a1667e2018-07-03 15:17:14 -070012061static int nl80211_send_external_auth_status(void *priv,
12062 struct external_auth *params)
12063{
12064 struct i802_bss *bss = priv;
12065 struct wpa_driver_nl80211_data *drv = bss->drv;
12066 struct nl_msg *msg = NULL;
12067 int ret = -1;
12068
Hai Shalom5f92bc92019-04-18 11:54:11 -070012069 /* External auth command/status is intended for drivers that implement
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080012070 * internal SME but want to offload authentication processing (e.g.,
12071 * SAE) to hostapd/wpa_supplicant. Do not send the status to drivers
Hai Shalom5f92bc92019-04-18 11:54:11 -070012072 * which do not support AP SME or use wpa_supplicant/hostapd SME.
12073 */
Hai Shalom81f62d82019-07-22 12:10:00 -070012074 if ((is_ap_interface(drv->nlmode) && !bss->drv->device_ap_sme) ||
Hai Shalom5f92bc92019-04-18 11:54:11 -070012075 (drv->capa.flags & WPA_DRIVER_FLAGS_SME))
12076 return -1;
12077
Roshan Pius3a1667e2018-07-03 15:17:14 -070012078 wpa_dbg(drv->ctx, MSG_DEBUG,
12079 "nl80211: External auth status: %u", params->status);
12080
12081 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_EXTERNAL_AUTH);
12082 if (!msg ||
12083 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, params->status) ||
Hai Shalom5f92bc92019-04-18 11:54:11 -070012084 (params->ssid && params->ssid_len &&
12085 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
12086 (params->pmkid &&
12087 nla_put(msg, NL80211_ATTR_PMKID, PMKID_LEN, params->pmkid)) ||
12088 (params->bssid &&
12089 nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid)))
Roshan Pius3a1667e2018-07-03 15:17:14 -070012090 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -070012091 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -070012092 msg = NULL;
12093 if (ret) {
12094 wpa_printf(MSG_DEBUG,
12095 "nl80211: External Auth status update failed: ret=%d (%s)",
12096 ret, strerror(-ret));
12097 goto fail;
12098 }
12099fail:
12100 nlmsg_free(msg);
12101 return ret;
12102}
12103
12104
Hai Shalom74f70d42019-02-11 14:42:39 -080012105static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname,
12106 int val)
12107{
12108 struct i802_bss *bss = priv;
12109 struct wpa_driver_nl80211_data *drv = bss->drv;
12110 struct nl_msg *msg;
12111 int ret = -ENOBUFS;
12112
12113 wpa_printf(MSG_DEBUG, "nl80211: %s 4addr mode (bridge_ifname: %s)",
12114 val ? "Enable" : "Disable", bridge_ifname);
12115
12116 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
12117 if (!msg || nla_put_u8(msg, NL80211_ATTR_4ADDR, val))
12118 goto fail;
12119
12120 if (bridge_ifname[0] && bss->added_if_into_bridge && !val) {
12121 if (linux_br_del_if(drv->global->ioctl_sock,
12122 bridge_ifname, bss->ifname)) {
12123 wpa_printf(MSG_ERROR,
12124 "nl80211: Failed to remove interface %s from bridge %s",
12125 bss->ifname, bridge_ifname);
12126 return -1;
12127 }
12128 bss->added_if_into_bridge = 0;
12129 }
12130
Hai Shalom899fcc72020-10-19 14:38:18 -070012131 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalom74f70d42019-02-11 14:42:39 -080012132 msg = NULL;
Hai Shalom60840252021-02-19 19:02:11 -080012133 if (ret && val && nl80211_get_4addr(bss) == 1) {
12134 wpa_printf(MSG_DEBUG,
12135 "nl80211: 4addr mode was already enabled");
12136 ret = 0;
12137 }
Hai Shalom74f70d42019-02-11 14:42:39 -080012138 if (!ret) {
12139 if (bridge_ifname[0] && val &&
12140 i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0)
12141 return -1;
12142 return 0;
12143 }
12144
12145fail:
12146 nlmsg_free(msg);
12147 wpa_printf(MSG_ERROR, "nl80211: Failed to enable/disable 4addr");
12148
12149 return ret;
12150}
12151
12152
Hai Shalome21d4e82020-04-29 16:34:06 -070012153#ifdef CONFIG_DPP
12154static int nl80211_dpp_listen(void *priv, bool enable)
12155{
12156 struct i802_bss *bss = priv;
12157 struct wpa_driver_nl80211_data *drv = bss->drv;
12158 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
12159 struct nl_sock *handle;
12160
12161 if (!drv->multicast_registrations || !bss->nl_mgmt)
12162 return 0; /* cannot do more than hope broadcast RX works */
12163
12164 wpa_printf(MSG_DEBUG,
12165 "nl80211: Update DPP Public Action frame registration (%s multicast RX)",
12166 enable ? "enable" : "disable");
12167 handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID);
12168 return nl80211_register_frame(bss, handle, type,
12169 (u8 *) "\x04\x09\x50\x6f\x9a\x1a", 6,
12170 enable);
12171}
12172#endif /* CONFIG_DPP */
12173
12174
Hai Shalomc1a21442022-02-04 13:43:00 -080012175#ifdef CONFIG_TESTING_OPTIONS
12176
12177static int testing_nl80211_register_frame(void *priv, u16 type,
12178 const u8 *match, size_t match_len,
12179 bool multicast)
12180{
12181 struct i802_bss *bss = priv;
12182 struct nl_sock *handle;
12183
12184 if (!bss->nl_mgmt)
12185 return -1;
12186 handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID);
12187 return nl80211_register_frame(bss, handle, type, match, match_len,
12188 multicast);
12189}
12190
12191
12192static int testing_nl80211_radio_disable(void *priv, int disabled)
12193{
12194 struct i802_bss *bss = priv;
12195 struct wpa_driver_nl80211_data *drv = bss->drv;
12196
12197 /* For now, this is supported only partially in station mode with
12198 * SME-in-wpa_supplicant case where the NL80211_ATTR_LOCAL_STATE_CHANGE
12199 * attribute can be used to avoid sending out the Deauthentication frame
12200 * to the currently associated AP. */
12201
12202 if (!disabled)
12203 return 0;
12204
12205 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
12206 return -1;
12207
12208 if (!drv->associated)
12209 return 0;
12210
12211 return wpa_driver_nl80211_mlme(drv, drv->bssid,
12212 NL80211_CMD_DEAUTHENTICATE,
12213 WLAN_REASON_PREV_AUTH_NOT_VALID, 1,
12214 drv->first_bss);
12215}
12216
12217#endif /* CONFIG_TESTING_OPTIONS */
12218
12219
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012220const struct wpa_driver_ops wpa_driver_nl80211_ops = {
12221 .name = "nl80211",
12222 .desc = "Linux nl80211/cfg80211",
12223 .get_bssid = wpa_driver_nl80211_get_bssid,
12224 .get_ssid = wpa_driver_nl80211_get_ssid,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012225 .set_key = driver_nl80211_set_key,
12226 .scan2 = driver_nl80211_scan2,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012227 .sched_scan = wpa_driver_nl80211_sched_scan,
12228 .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012229 .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080012230 .abort_scan = wpa_driver_nl80211_abort_scan,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012231 .deauthenticate = driver_nl80211_deauthenticate,
12232 .authenticate = driver_nl80211_authenticate,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012233 .associate = wpa_driver_nl80211_associate,
12234 .global_init = nl80211_global_init,
12235 .global_deinit = nl80211_global_deinit,
12236 .init2 = wpa_driver_nl80211_init,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012237 .deinit = driver_nl80211_deinit,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012238 .get_capa = wpa_driver_nl80211_get_capa,
12239 .set_operstate = wpa_driver_nl80211_set_operstate,
12240 .set_supp_port = wpa_driver_nl80211_set_supp_port,
12241 .set_country = wpa_driver_nl80211_set_country,
Dmitry Shmidtcce06662013-11-04 18:44:24 -080012242 .get_country = wpa_driver_nl80211_get_country,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012243 .set_ap = wpa_driver_nl80211_set_ap,
Dmitry Shmidt8bae4132013-06-06 11:25:10 -070012244 .set_acl = wpa_driver_nl80211_set_acl,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012245 .if_add = wpa_driver_nl80211_if_add,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012246 .if_remove = driver_nl80211_if_remove,
12247 .send_mlme = driver_nl80211_send_mlme,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012248 .get_hw_feature_data = nl80211_get_hw_feature_data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012249 .sta_add = wpa_driver_nl80211_sta_add,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012250 .sta_remove = driver_nl80211_sta_remove,
Hai Shalomfdcde762020-04-02 11:19:20 -070012251 .tx_control_port = nl80211_tx_control_port,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012252 .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
12253 .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
Hai Shalom81f62d82019-07-22 12:10:00 -070012254 .sta_set_airtime_weight = driver_nl80211_sta_set_airtime_weight,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012255 .hapd_init = i802_init,
12256 .hapd_deinit = i802_deinit,
Jouni Malinen75ecf522011-06-27 15:19:46 -070012257 .set_wds_sta = i802_set_wds_sta,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012258 .get_seqnum = i802_get_seqnum,
12259 .flush = i802_flush,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012260 .get_inact_sec = i802_get_inact_sec,
12261 .sta_clear_stats = i802_sta_clear_stats,
12262 .set_rts = i802_set_rts,
12263 .set_frag = i802_set_frag,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012264 .set_tx_queue_params = i802_set_tx_queue_params,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012265 .set_sta_vlan = driver_nl80211_set_sta_vlan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012266 .sta_deauth = i802_sta_deauth,
12267 .sta_disassoc = i802_sta_disassoc,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012268 .read_sta_data = driver_nl80211_read_sta_data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012269 .set_freq = i802_set_freq,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012270 .send_action = driver_nl80211_send_action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012271 .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
12272 .remain_on_channel = wpa_driver_nl80211_remain_on_channel,
12273 .cancel_remain_on_channel =
12274 wpa_driver_nl80211_cancel_remain_on_channel,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012275 .probe_req_report = driver_nl80211_probe_req_report,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012276 .deinit_ap = wpa_driver_nl80211_deinit_ap,
Dmitry Shmidt04949592012-07-19 12:16:46 -070012277 .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012278 .resume = wpa_driver_nl80211_resume,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012279 .signal_monitor = nl80211_signal_monitor,
12280 .signal_poll = nl80211_signal_poll,
Hai Shalom74f70d42019-02-11 14:42:39 -080012281 .channel_info = nl80211_channel_info,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012282 .set_param = nl80211_set_param,
12283 .get_radio_name = nl80211_get_radio_name,
Jouni Malinen75ecf522011-06-27 15:19:46 -070012284 .add_pmkid = nl80211_add_pmkid,
12285 .remove_pmkid = nl80211_remove_pmkid,
12286 .flush_pmkid = nl80211_flush_pmkid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012287 .set_rekey_info = nl80211_set_rekey_info,
12288 .poll_client = nl80211_poll_client,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012289 .set_p2p_powersave = nl80211_set_p2p_powersave,
Dmitry Shmidtea69e842013-05-13 14:52:28 -070012290 .start_dfs_cac = nl80211_start_radar_detection,
12291 .stop_ap = wpa_driver_nl80211_stop_ap,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012292#ifdef CONFIG_TDLS
12293 .send_tdls_mgmt = nl80211_send_tdls_mgmt,
12294 .tdls_oper = nl80211_tdls_oper,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012295 .tdls_enable_channel_switch = nl80211_tdls_enable_channel_switch,
12296 .tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012297#endif /* CONFIG_TDLS */
Dmitry Shmidt700a1372013-03-15 14:14:44 -070012298 .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
Hai Shalom81f62d82019-07-22 12:10:00 -070012299 .update_dh_ie = nl80211_update_dh_ie,
Dmitry Shmidt34af3062013-07-11 10:46:32 -070012300 .get_mac_addr = wpa_driver_nl80211_get_macaddr,
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070012301 .get_survey = wpa_driver_nl80211_get_survey,
Dmitry Shmidt56052862013-10-04 10:23:25 -070012302 .status = wpa_driver_nl80211_status,
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080012303 .switch_channel = nl80211_switch_channel,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012304#ifdef ANDROID_P2P
Dmitry Shmidt6e933c12011-09-27 12:29:26 -070012305 .set_noa = wpa_driver_set_p2p_noa,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012306 .get_noa = wpa_driver_get_p2p_noa,
Dmitry Shmidt6e933c12011-09-27 12:29:26 -070012307 .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
Dmitry Shmidt292b0c32013-11-22 12:54:42 -080012308#endif /* ANDROID_P2P */
Dmitry Shmidt738a26e2011-07-07 14:22:14 -070012309#ifdef ANDROID
Dmitry Shmidt41712582015-06-29 11:02:15 -070012310#ifndef ANDROID_LIB_STUB
Dmitry Shmidt738a26e2011-07-07 14:22:14 -070012311 .driver_cmd = wpa_driver_nl80211_driver_cmd,
Dmitry Shmidt41712582015-06-29 11:02:15 -070012312#endif /* !ANDROID_LIB_STUB */
Dmitry Shmidt292b0c32013-11-22 12:54:42 -080012313#endif /* ANDROID */
Dmitry Shmidta38abf92014-03-06 13:38:44 -080012314 .vendor_cmd = nl80211_vendor_cmd,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080012315 .set_qos_map = nl80211_set_qos_map,
Hai Shalomfdcde762020-04-02 11:19:20 -070012316 .get_wowlan = nl80211_get_wowlan,
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070012317 .set_wowlan = nl80211_set_wowlan,
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070012318 .set_mac_addr = nl80211_set_mac_addr,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012319#ifdef CONFIG_MESH
12320 .init_mesh = wpa_driver_nl80211_init_mesh,
12321 .join_mesh = wpa_driver_nl80211_join_mesh,
12322 .leave_mesh = wpa_driver_nl80211_leave_mesh,
Hai Shalom81f62d82019-07-22 12:10:00 -070012323 .probe_mesh_link = nl80211_probe_mesh_link,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012324#endif /* CONFIG_MESH */
12325 .br_add_ip_neigh = wpa_driver_br_add_ip_neigh,
12326 .br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh,
12327 .br_port_set_attr = wpa_driver_br_port_set_attr,
12328 .br_set_net_param = wpa_driver_br_set_net_param,
12329 .add_tx_ts = nl80211_add_ts,
12330 .del_tx_ts = nl80211_del_ts,
Dmitry Shmidte4663042016-04-04 10:07:49 -070012331 .get_ifindex = nl80211_get_ifindex,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012332#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070012333 .roaming = nl80211_roaming,
Roshan Pius3a1667e2018-07-03 15:17:14 -070012334 .disable_fils = nl80211_disable_fils,
Ravi Joshie6ccb162015-07-16 17:45:41 -070012335 .set_band = nl80211_set_band,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012336 .get_pref_freq_list = nl80211_get_pref_freq_list,
12337 .set_prob_oper_freq = nl80211_set_prob_oper_freq,
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070012338 .p2p_lo_start = nl80211_p2p_lo_start,
12339 .p2p_lo_stop = nl80211_p2p_lo_stop,
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -070012340 .set_default_scan_ies = nl80211_set_default_scan_ies,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080012341 .set_tdls_mode = nl80211_set_tdls_mode,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012342#ifdef CONFIG_MBO
12343 .get_bss_transition_status = nl80211_get_bss_transition_status,
12344 .ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
12345#endif /* CONFIG_MBO */
Hai Shalom899fcc72020-10-19 14:38:18 -070012346 .set_bssid_tmp_disallow = nl80211_set_bssid_tmp_disallow,
Hai Shalomc3565922019-10-28 11:58:20 -070012347 .add_sta_node = nl80211_add_sta_node,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012348#endif /* CONFIG_DRIVER_NL80211_QCA */
Hai Shalomc1a21442022-02-04 13:43:00 -080012349 .do_acs = nl80211_do_acs,
Dmitry Shmidt849734c2016-05-27 09:59:01 -070012350 .configure_data_frame_filters = nl80211_configure_data_frame_filters,
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070012351 .get_ext_capab = nl80211_get_ext_capab,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012352 .update_connect_params = nl80211_update_connection_params,
Roshan Pius3a1667e2018-07-03 15:17:14 -070012353 .send_external_auth_status = nl80211_send_external_auth_status,
Hai Shalom74f70d42019-02-11 14:42:39 -080012354 .set_4addr_mode = nl80211_set_4addr_mode,
Hai Shalome21d4e82020-04-29 16:34:06 -070012355#ifdef CONFIG_DPP
12356 .dpp_listen = nl80211_dpp_listen,
12357#endif /* CONFIG_DPP */
Hai Shalomc1a21442022-02-04 13:43:00 -080012358#ifdef CONFIG_TESTING_OPTIONS
12359 .register_frame = testing_nl80211_register_frame,
12360 .radio_disable = testing_nl80211_radio_disable,
12361#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012362};