blob: 6e3f6145e11f6973ca32f0d4c9048de2087e2eb9 [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"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070030#include "common/ieee802_11_defs.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080031#include "common/ieee802_11_common.h"
Paul Stewart092955c2017-02-06 09:13:09 -080032#include "common/wpa_common.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070033#include "netlink.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080034#include "linux_defines.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070035#include "linux_ioctl.h"
36#include "radiotap.h"
37#include "radiotap_iter.h"
38#include "rfkill.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080039#include "driver_nl80211.h"
Ajay Davanagerib921bb82020-09-16 12:49:08 +053040#ifdef CONFIG_DRIVER_NL80211_BRCM
41#include "common/brcm_vendor.h"
42#endif /* CONFIG_DRIVER_NL80211_BRCM */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080043
Hai Shalom74f70d42019-02-11 14:42:39 -080044#ifndef NETLINK_CAP_ACK
45#define NETLINK_CAP_ACK 10
46#endif /* NETLINK_CAP_ACK */
Hai Shalom39ba6fc2019-01-22 12:40:38 -080047/* support for extack if compilation headers are too old */
48#ifndef NETLINK_EXT_ACK
49#define NETLINK_EXT_ACK 11
50enum nlmsgerr_attrs {
51 NLMSGERR_ATTR_UNUSED,
52 NLMSGERR_ATTR_MSG,
53 NLMSGERR_ATTR_OFFS,
54 NLMSGERR_ATTR_COOKIE,
55
56 __NLMSGERR_ATTR_MAX,
57 NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
58};
59#endif
60#ifndef NLM_F_CAPPED
61#define NLM_F_CAPPED 0x100
62#endif
63#ifndef NLM_F_ACK_TLVS
64#define NLM_F_ACK_TLVS 0x200
65#endif
66#ifndef SOL_NETLINK
67#define SOL_NETLINK 270
68#endif
69
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070070
Dmitry Shmidt54605472013-11-08 11:10:19 -080071#ifdef ANDROID
72/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
Dmitry Shmidt54605472013-11-08 11:10:19 -080073#undef nl_socket_set_nonblocking
74#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080075
Dmitry Shmidt54605472013-11-08 11:10:19 -080076#endif /* ANDROID */
77
78
Hai Shalomfdcde762020-04-02 11:19:20 -070079static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080080{
Hai Shalomfdcde762020-04-02 11:19:20 -070081 struct nl_sock *handle;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080082
Hai Shalomfdcde762020-04-02 11:19:20 -070083 handle = nl_socket_alloc_cb(cb);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080084 if (handle == NULL) {
85 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
86 "callbacks (%s)", dbg);
87 return NULL;
88 }
89
90 if (genl_connect(handle)) {
91 wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
92 "netlink (%s)", dbg);
Hai Shalomfdcde762020-04-02 11:19:20 -070093 nl_socket_free(handle);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080094 return NULL;
95 }
96
97 return handle;
98}
99
100
Hai Shalomfdcde762020-04-02 11:19:20 -0700101static void nl_destroy_handles(struct nl_sock **handle)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800102{
103 if (*handle == NULL)
104 return;
Hai Shalomfdcde762020-04-02 11:19:20 -0700105 nl_socket_free(*handle);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800106 *handle = NULL;
107}
108
109
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700110#if __WORDSIZE == 64
111#define ELOOP_SOCKET_INVALID (intptr_t) 0x8888888888888889ULL
112#else
113#define ELOOP_SOCKET_INVALID (intptr_t) 0x88888889ULL
114#endif
115
Hai Shalomfdcde762020-04-02 11:19:20 -0700116static void nl80211_register_eloop_read(struct nl_sock **handle,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700117 eloop_sock_handler handler,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700118 void *eloop_data, int persist)
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700119{
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800120 /*
121 * libnl uses a pretty small buffer (32 kB that gets converted to 64 kB)
122 * by default. It is possible to hit that limit in some cases where
123 * operations are blocked, e.g., with a burst of Deauthentication frames
124 * to hostapd and STA entry deletion. Try to increase the buffer to make
125 * this less likely to occur.
126 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700127 int err;
128
129 err = nl_socket_set_buffer_size(*handle, 262144, 0);
130 if (err < 0) {
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800131 wpa_printf(MSG_DEBUG,
132 "nl80211: Could not set nl_socket RX buffer size: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -0700133 nl_geterror(err));
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800134 /* continue anyway with the default (smaller) buffer */
135 }
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800136
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700137 nl_socket_set_nonblocking(*handle);
138 eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
139 eloop_data, *handle);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700140 if (!persist)
141 *handle = (void *) (((intptr_t) *handle) ^
142 ELOOP_SOCKET_INVALID);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700143}
144
145
Hai Shalomfdcde762020-04-02 11:19:20 -0700146static void nl80211_destroy_eloop_handle(struct nl_sock **handle, int persist)
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700147{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700148 if (!persist)
149 *handle = (void *) (((intptr_t) *handle) ^
150 ELOOP_SOCKET_INVALID);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700151 eloop_unregister_read_sock(nl_socket_get_fd(*handle));
152 nl_destroy_handles(handle);
153}
154
155
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800156static void nl80211_global_deinit(void *priv);
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800157static void nl80211_check_global(struct nl80211_global *global);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800158
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800159static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -0700160static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
161 struct hostapd_freq_params *freq);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -0700162
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700163static int
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800164wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800165 const u8 *set_addr, int first,
166 const char *driver_params);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800167static int nl80211_send_frame_cmd(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700168 unsigned int freq, unsigned int wait,
Hai Shalomfdcde762020-04-02 11:19:20 -0700169 const u8 *buf, size_t buf_len,
170 int save_cookie,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800171 int no_cck, int no_ack, int offchanok,
172 const u16 *csa_offs, size_t csa_offs_len);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800173static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
174 int report);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700175
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800176#define IFIDX_ANY -1
177
178static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
179 int ifidx_reason);
180static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
181 int ifidx_reason);
182static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
183 int ifidx_reason);
Dmitry Shmidt738a26e2011-07-07 14:22:14 -0700184
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700185static int nl80211_set_channel(struct i802_bss *bss,
186 struct hostapd_freq_params *freq, int set_chan);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700187static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
188 int ifindex, int disabled);
189
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800190static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
191 int reset_mode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800192
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700193static int i802_set_iface_flags(struct i802_bss *bss, int up);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800194static int nl80211_set_param(void *priv, const char *param);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -0700195#ifdef CONFIG_MESH
196static int nl80211_put_mesh_config(struct nl_msg *msg,
197 struct wpa_driver_mesh_bss_params *params);
198#endif /* CONFIG_MESH */
Dmitry Shmidt29333592017-01-09 12:27:11 -0800199static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -0700200 u16 reason);
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700201
202
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800203/* Converts nl80211_chan_width to a common format */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800204enum chan_width convert2width(int width)
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800205{
206 switch (width) {
207 case NL80211_CHAN_WIDTH_20_NOHT:
208 return CHAN_WIDTH_20_NOHT;
209 case NL80211_CHAN_WIDTH_20:
210 return CHAN_WIDTH_20;
211 case NL80211_CHAN_WIDTH_40:
212 return CHAN_WIDTH_40;
213 case NL80211_CHAN_WIDTH_80:
214 return CHAN_WIDTH_80;
215 case NL80211_CHAN_WIDTH_80P80:
216 return CHAN_WIDTH_80P80;
217 case NL80211_CHAN_WIDTH_160:
218 return CHAN_WIDTH_160;
219 }
220 return CHAN_WIDTH_UNKNOWN;
221}
222
223
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800224int is_ap_interface(enum nl80211_iftype nlmode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800225{
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700226 return nlmode == NL80211_IFTYPE_AP ||
227 nlmode == NL80211_IFTYPE_P2P_GO;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800228}
229
230
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800231int is_sta_interface(enum nl80211_iftype nlmode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800232{
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700233 return nlmode == NL80211_IFTYPE_STATION ||
234 nlmode == NL80211_IFTYPE_P2P_CLIENT;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800235}
236
237
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700238static int is_p2p_net_interface(enum nl80211_iftype nlmode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800239{
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700240 return nlmode == NL80211_IFTYPE_P2P_CLIENT ||
241 nlmode == NL80211_IFTYPE_P2P_GO;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800242}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700243
244
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800245struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
246 int ifindex)
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -0700247{
248 struct i802_bss *bss;
249
250 for (bss = drv->first_bss; bss; bss = bss->next) {
251 if (bss->ifindex == ifindex)
252 return bss;
253 }
254
255 return NULL;
256}
257
258
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800259static int is_mesh_interface(enum nl80211_iftype nlmode)
260{
261 return nlmode == NL80211_IFTYPE_MESH_POINT;
262}
263
264
265void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
Dmitry Shmidt8bae4132013-06-06 11:25:10 -0700266{
267 if (drv->associated)
268 os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
269 drv->associated = 0;
270 os_memset(drv->bssid, 0, ETH_ALEN);
Hai Shalom5f92bc92019-04-18 11:54:11 -0700271 drv->first_bss->freq = 0;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -0700272}
273
274
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700275/* nl80211 code */
276static int ack_handler(struct nl_msg *msg, void *arg)
277{
278 int *err = arg;
279 *err = 0;
280 return NL_STOP;
281}
282
Hai Shalom899fcc72020-10-19 14:38:18 -0700283
284struct nl80211_ack_ext_arg {
285 int *err;
286 void *ext_data;
287};
288
289
290static int ack_handler_cookie(struct nl_msg *msg, void *arg)
291{
292 struct nl80211_ack_ext_arg *ext_arg = arg;
293 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
294 u64 *cookie = ext_arg->ext_data;
295 struct nlattr *attrs;
296 size_t ack_len, attr_len;
297
298 *ext_arg->err = 0;
299 ack_len = sizeof(struct nlmsghdr) + sizeof(int) +
300 sizeof(struct nlmsghdr);
301 attrs = (struct nlattr *)
302 ((u8 *) nlmsg_data(nlmsg_hdr(msg)) + sizeof(struct nlmsghdr) +
303 sizeof(int));
304 if (nlmsg_hdr(msg)->nlmsg_len <= ack_len)
305 return NL_STOP;
306
307 attr_len = nlmsg_hdr(msg)->nlmsg_len - ack_len;
308
309 if(!(nlmsg_hdr(msg)->nlmsg_flags & NLM_F_ACK_TLVS))
310 return NL_STOP;
311
312 nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, attr_len, NULL);
313 if (tb[NLMSGERR_ATTR_COOKIE])
314 *cookie = nla_get_u64(tb[NLMSGERR_ATTR_COOKIE]);
315
316 return NL_STOP;
317}
318
319
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700320static int finish_handler(struct nl_msg *msg, void *arg)
321{
322 int *ret = arg;
323 *ret = 0;
324 return NL_SKIP;
325}
326
327static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
328 void *arg)
329{
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800330 struct nlmsghdr *nlh = (struct nlmsghdr *) err - 1;
331 int len = nlh->nlmsg_len;
332 struct nlattr *attrs;
333 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700334 int *ret = arg;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800335 int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh);
336
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700337 *ret = err->error;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800338
339 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
340 return NL_SKIP;
341
342 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
343 ack_len += err->msg.nlmsg_len - sizeof(*nlh);
344
345 if (len <= ack_len)
346 return NL_STOP;
347
348 attrs = (void *) ((unsigned char *) nlh + ack_len);
349 len -= ack_len;
350
351 nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, len, NULL);
352 if (tb[NLMSGERR_ATTR_MSG]) {
353 len = strnlen((char *) nla_data(tb[NLMSGERR_ATTR_MSG]),
354 nla_len(tb[NLMSGERR_ATTR_MSG]));
355 wpa_printf(MSG_ERROR, "nl80211: kernel reports: %*s",
356 len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG]));
357 }
358
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700359 return NL_SKIP;
360}
361
362
363static int no_seq_check(struct nl_msg *msg, void *arg)
364{
365 return NL_OK;
366}
367
368
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800369static void nl80211_nlmsg_clear(struct nl_msg *msg)
370{
371 /*
372 * Clear nlmsg data, e.g., to make sure key material is not left in
373 * heap memory for unnecessarily long time.
374 */
375 if (msg) {
376 struct nlmsghdr *hdr = nlmsg_hdr(msg);
377 void *data = nlmsg_data(hdr);
378 /*
379 * This would use nlmsg_datalen() or the older nlmsg_len() if
380 * only libnl were to maintain a stable API.. Neither will work
381 * with all released versions, so just calculate the length
382 * here.
383 */
384 int len = hdr->nlmsg_len - NLMSG_HDRLEN;
385
386 os_memset(data, 0, len);
387 }
388}
389
390
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800391static int send_and_recv(struct nl80211_global *global,
Hai Shalomfdcde762020-04-02 11:19:20 -0700392 struct nl_sock *nl_handle, struct nl_msg *msg,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700393 int (*valid_handler)(struct nl_msg *, void *),
Hai Shalom899fcc72020-10-19 14:38:18 -0700394 void *valid_data,
395 int (*ack_handler_custom)(struct nl_msg *, void *),
396 void *ack_data)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700397{
398 struct nl_cb *cb;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800399 int err = -ENOMEM, opt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700400
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800401 if (!msg)
402 return -ENOMEM;
403
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800404 cb = nl_cb_clone(global->nl_cb);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700405 if (!cb)
406 goto out;
407
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800408 /* try to set NETLINK_EXT_ACK to 1, ignoring errors */
409 opt = 1;
410 setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
411 NETLINK_EXT_ACK, &opt, sizeof(opt));
412
Hai Shalom74f70d42019-02-11 14:42:39 -0800413 /* try to set NETLINK_CAP_ACK to 1, ignoring errors */
414 opt = 1;
415 setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
416 NETLINK_CAP_ACK, &opt, sizeof(opt));
417
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700418 err = nl_send_auto_complete(nl_handle, msg);
Hai Shalomfdcde762020-04-02 11:19:20 -0700419 if (err < 0) {
420 wpa_printf(MSG_INFO,
421 "nl80211: nl_send_auto_complete() failed: %s",
422 nl_geterror(err));
423 /* Need to convert libnl error code to an errno value. For now,
424 * just hardcode this to EBADF; the real error reason is shown
425 * in that error print above. */
426 err = -EBADF;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700427 goto out;
Hai Shalomfdcde762020-04-02 11:19:20 -0700428 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700429
430 err = 1;
431
432 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
433 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
Hai Shalom899fcc72020-10-19 14:38:18 -0700434 if (ack_handler_custom) {
435 struct nl80211_ack_ext_arg *ext_arg = ack_data;
436
437 ext_arg->err = &err;
438 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM,
439 ack_handler_custom, ack_data);
440 } else {
441 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
442 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700443
444 if (valid_handler)
445 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
446 valid_handler, valid_data);
447
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700448 while (err > 0) {
449 int res = nl_recvmsgs(nl_handle, cb);
Hai Shalomfdcde762020-04-02 11:19:20 -0700450
451 if (res == -NLE_DUMP_INTR) {
452 /* Most likely one of the nl80211 dump routines hit a
453 * case where internal results changed while the dump
454 * was being sent. The most common known case for this
455 * is scan results fetching while associated were every
456 * received Beacon frame from the AP may end up
457 * incrementing bss_generation. This
458 * NL80211_CMD_GET_SCAN case tries again in the caller;
459 * other cases (of which there are no known common ones)
460 * will stop and return an error. */
461 wpa_printf(MSG_DEBUG, "nl80211: %s; convert to -EAGAIN",
462 nl_geterror(res));
463 err = -EAGAIN;
464 } else if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700465 wpa_printf(MSG_INFO,
Hai Shalomfdcde762020-04-02 11:19:20 -0700466 "nl80211: %s->nl_recvmsgs failed: %d (%s)",
467 __func__, res, nl_geterror(res));
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700468 }
469 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700470 out:
471 nl_cb_put(cb);
Hai Shalom60840252021-02-19 19:02:11 -0800472 /* Always clear the message as it can potentially contain keys */
473 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700474 nlmsg_free(msg);
475 return err;
476}
477
478
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800479int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
480 struct nl_msg *msg,
481 int (*valid_handler)(struct nl_msg *, void *),
Hai Shalom899fcc72020-10-19 14:38:18 -0700482 void *valid_data,
483 int (*ack_handler_custom)(struct nl_msg *, void *),
484 void *ack_data)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700485{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800486 return send_and_recv(drv->global, drv->global->nl, msg,
Hai Shalom899fcc72020-10-19 14:38:18 -0700487 valid_handler, valid_data,
488 ack_handler_custom, ack_data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700489}
490
491
Hai Shalomb755a2a2020-04-23 21:49:02 -0700492/* Use this method to mark that it is necessary to own the connection/interface
493 * for this operation.
494 * handle may be set to NULL, to get the same behavior as send_and_recv_msgs().
495 * set_owner can be used to mark this socket for receiving control port frames.
496 */
497static int send_and_recv_msgs_owner(struct wpa_driver_nl80211_data *drv,
498 struct nl_msg *msg,
499 struct nl_sock *handle, int set_owner,
500 int (*valid_handler)(struct nl_msg *,
501 void *),
Hai Shalom899fcc72020-10-19 14:38:18 -0700502 void *valid_data,
503 int (*ack_handler_custom)(struct nl_msg *,
504 void *),
505 void *ack_data)
Hai Shalomb755a2a2020-04-23 21:49:02 -0700506{
Hai Shalom60840252021-02-19 19:02:11 -0800507 if (!msg)
508 return -ENOMEM;
509
Hai Shalomb755a2a2020-04-23 21:49:02 -0700510 /* Control port over nl80211 needs the flags and attributes below.
511 *
512 * The Linux kernel has initial checks for them (in nl80211.c) like:
513 * validate_pae_over_nl80211(...)
514 * or final checks like:
515 * dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid
516 *
517 * Final operations (e.g., disassociate) don't need to set these
518 * attributes, but they have to be performed on the socket, which has
519 * the connection owner property set in the kernel.
520 */
521 if ((drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) &&
522 handle && set_owner &&
523 (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) ||
524 nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER) ||
525 nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
526 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_PREAUTH)))
527 return -1;
528
529 return send_and_recv(drv->global, handle ? handle : drv->global->nl,
Hai Shalom899fcc72020-10-19 14:38:18 -0700530 msg, valid_handler, valid_data,
531 ack_handler_custom, ack_data);
Hai Shalomb755a2a2020-04-23 21:49:02 -0700532}
533
534
535struct nl_sock * get_connect_handle(struct i802_bss *bss)
536{
537 if ((bss->drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) ||
538 bss->use_nl_connect)
539 return bss->nl_connect;
540
541 return NULL;
542}
543
544
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700545struct family_data {
546 const char *group;
547 int id;
548};
549
550
551static int family_handler(struct nl_msg *msg, void *arg)
552{
553 struct family_data *res = arg;
554 struct nlattr *tb[CTRL_ATTR_MAX + 1];
555 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
556 struct nlattr *mcgrp;
557 int i;
558
559 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
560 genlmsg_attrlen(gnlh, 0), NULL);
561 if (!tb[CTRL_ATTR_MCAST_GROUPS])
562 return NL_SKIP;
563
564 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
565 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
566 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
567 nla_len(mcgrp), NULL);
568 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
569 !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
570 os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
571 res->group,
572 nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
573 continue;
574 res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
575 break;
576 };
577
578 return NL_SKIP;
579}
580
581
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800582static int nl_get_multicast_id(struct nl80211_global *global,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700583 const char *family, const char *group)
584{
585 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800586 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700587 struct family_data res = { group, -ENOENT };
588
589 msg = nlmsg_alloc();
590 if (!msg)
591 return -ENOMEM;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800592 if (!genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
593 0, 0, CTRL_CMD_GETFAMILY, 0) ||
594 nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family)) {
595 nlmsg_free(msg);
596 return -1;
597 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700598
Hai Shalom899fcc72020-10-19 14:38:18 -0700599 ret = send_and_recv(global, global->nl, msg, family_handler, &res,
600 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700601 if (ret == 0)
602 ret = res.id;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700603 return ret;
604}
605
606
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800607void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
608 struct nl_msg *msg, int flags, uint8_t cmd)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800609{
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700610 if (TEST_FAIL())
611 return NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800612 return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
613 0, flags, cmd, 0);
614}
615
616
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800617static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
618{
619 if (bss->wdev_id_set)
620 return nla_put_u64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
621 return nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
622}
623
624
625struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd)
626{
627 struct nl_msg *msg;
628
629 msg = nlmsg_alloc();
630 if (!msg)
631 return NULL;
632
633 if (!nl80211_cmd(bss->drv, msg, flags, cmd) ||
634 nl80211_set_iface_id(msg, bss) < 0) {
635 nlmsg_free(msg);
636 return NULL;
637 }
638
639 return msg;
640}
641
642
643static struct nl_msg *
644nl80211_ifindex_msg(struct wpa_driver_nl80211_data *drv, int ifindex,
645 int flags, uint8_t cmd)
646{
647 struct nl_msg *msg;
648
649 msg = nlmsg_alloc();
650 if (!msg)
651 return NULL;
652
653 if (!nl80211_cmd(drv, msg, flags, cmd) ||
654 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
655 nlmsg_free(msg);
656 return NULL;
657 }
658
659 return msg;
660}
661
662
663struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
664 uint8_t cmd)
665{
666 return nl80211_ifindex_msg(drv, drv->ifindex, flags, cmd);
667}
668
669
670struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd)
671{
672 return nl80211_ifindex_msg(bss->drv, bss->ifindex, flags, cmd);
673}
674
675
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800676struct wiphy_idx_data {
677 int wiphy_idx;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700678 enum nl80211_iftype nlmode;
679 u8 *macaddr;
Hai Shalom60840252021-02-19 19:02:11 -0800680 u8 use_4addr;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800681};
682
683
684static int netdev_info_handler(struct nl_msg *msg, void *arg)
685{
686 struct nlattr *tb[NL80211_ATTR_MAX + 1];
687 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
688 struct wiphy_idx_data *info = arg;
689
690 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
691 genlmsg_attrlen(gnlh, 0), NULL);
692
693 if (tb[NL80211_ATTR_WIPHY])
694 info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
695
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700696 if (tb[NL80211_ATTR_IFTYPE])
697 info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]);
698
699 if (tb[NL80211_ATTR_MAC] && info->macaddr)
700 os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
701 ETH_ALEN);
702
Hai Shalom60840252021-02-19 19:02:11 -0800703 if (tb[NL80211_ATTR_4ADDR])
704 info->use_4addr = nla_get_u8(tb[NL80211_ATTR_4ADDR]);
705
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800706 return NL_SKIP;
707}
708
709
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800710int nl80211_get_wiphy_index(struct i802_bss *bss)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800711{
712 struct nl_msg *msg;
713 struct wiphy_idx_data data = {
714 .wiphy_idx = -1,
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700715 .macaddr = NULL,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800716 };
717
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800718 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
719 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800720
Hai Shalom899fcc72020-10-19 14:38:18 -0700721 if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
722 NULL, NULL) == 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800723 return data.wiphy_idx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800724 return -1;
725}
726
727
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700728static enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
729{
730 struct nl_msg *msg;
731 struct wiphy_idx_data data = {
732 .nlmode = NL80211_IFTYPE_UNSPECIFIED,
733 .macaddr = NULL,
734 };
735
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800736 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
737 return NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700738
Hai Shalom899fcc72020-10-19 14:38:18 -0700739 if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
740 NULL, NULL) == 0)
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700741 return data.nlmode;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700742 return NL80211_IFTYPE_UNSPECIFIED;
743}
744
745
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700746static int nl80211_get_macaddr(struct i802_bss *bss)
747{
748 struct nl_msg *msg;
749 struct wiphy_idx_data data = {
750 .macaddr = bss->addr,
751 };
752
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800753 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
754 return -1;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700755
Hai Shalom899fcc72020-10-19 14:38:18 -0700756 return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
757 NULL, NULL);
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700758}
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700759
760
Hai Shalom60840252021-02-19 19:02:11 -0800761static int nl80211_get_4addr(struct i802_bss *bss)
762{
763 struct nl_msg *msg;
764 struct wiphy_idx_data data = {
765 .use_4addr = 0,
766 };
767
768 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)) ||
769 send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
770 NULL, NULL))
771 return -1;
772 return data.use_4addr;
773}
774
775
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800776static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
777 struct nl80211_wiphy_data *w)
778{
779 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800780 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800781
782 msg = nlmsg_alloc();
783 if (!msg)
784 return -1;
785
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800786 if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS) ||
787 nla_put_u32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx)) {
788 nlmsg_free(msg);
789 return -1;
790 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800791
Hai Shalom899fcc72020-10-19 14:38:18 -0700792 ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL,
793 NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800794 if (ret) {
795 wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
796 "failed: ret=%d (%s)",
797 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800798 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800799 return ret;
800}
801
802
803static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
804{
805 struct nl80211_wiphy_data *w = eloop_ctx;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700806 int res;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800807
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800808 wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800809
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700810 res = nl_recvmsgs(handle, w->nl_cb);
Dmitry Shmidt71757432014-06-02 13:50:35 -0700811 if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700812 wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
813 __func__, res);
814 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800815}
816
817
818static int process_beacon_event(struct nl_msg *msg, void *arg)
819{
820 struct nl80211_wiphy_data *w = arg;
821 struct wpa_driver_nl80211_data *drv;
822 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
823 struct nlattr *tb[NL80211_ATTR_MAX + 1];
824 union wpa_event_data event;
825
826 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
827 genlmsg_attrlen(gnlh, 0), NULL);
828
829 if (gnlh->cmd != NL80211_CMD_FRAME) {
830 wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
831 gnlh->cmd);
832 return NL_SKIP;
833 }
834
835 if (!tb[NL80211_ATTR_FRAME])
836 return NL_SKIP;
837
838 dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
839 wiphy_list) {
840 os_memset(&event, 0, sizeof(event));
841 event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
842 event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
843 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
844 }
845
846 return NL_SKIP;
847}
848
849
850static struct nl80211_wiphy_data *
851nl80211_get_wiphy_data_ap(struct i802_bss *bss)
852{
853 static DEFINE_DL_LIST(nl80211_wiphys);
854 struct nl80211_wiphy_data *w;
855 int wiphy_idx, found = 0;
856 struct i802_bss *tmp_bss;
Paul Stewart092955c2017-02-06 09:13:09 -0800857 u8 channel;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800858
859 if (bss->wiphy_data != NULL)
860 return bss->wiphy_data;
861
862 wiphy_idx = nl80211_get_wiphy_index(bss);
863
864 dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
865 if (w->wiphy_idx == wiphy_idx)
866 goto add;
867 }
868
869 /* alloc new one */
870 w = os_zalloc(sizeof(*w));
871 if (w == NULL)
872 return NULL;
873 w->wiphy_idx = wiphy_idx;
874 dl_list_init(&w->bsss);
875 dl_list_init(&w->drvs);
876
Paul Stewart092955c2017-02-06 09:13:09 -0800877 /* Beacon frames not supported in IEEE 802.11ad */
878 if (ieee80211_freq_to_chan(bss->freq, &channel) !=
879 HOSTAPD_MODE_IEEE80211AD) {
880 w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
881 if (!w->nl_cb) {
882 os_free(w);
883 return NULL;
884 }
885 nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
886 no_seq_check, NULL);
887 nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
888 process_beacon_event, w);
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000889
Paul Stewart092955c2017-02-06 09:13:09 -0800890 w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
891 "wiphy beacons");
892 if (w->nl_beacons == NULL) {
893 os_free(w);
894 return NULL;
895 }
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000896
Paul Stewart092955c2017-02-06 09:13:09 -0800897 if (nl80211_register_beacons(bss->drv, w)) {
898 nl_destroy_handles(&w->nl_beacons);
899 os_free(w);
900 return NULL;
901 }
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000902
Paul Stewart092955c2017-02-06 09:13:09 -0800903 nl80211_register_eloop_read(&w->nl_beacons,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700904 nl80211_recv_beacons, w, 0);
Paul Stewart092955c2017-02-06 09:13:09 -0800905 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800906
907 dl_list_add(&nl80211_wiphys, &w->list);
908
909add:
910 /* drv entry for this bss already there? */
911 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
912 if (tmp_bss->drv == bss->drv) {
913 found = 1;
914 break;
915 }
916 }
917 /* if not add it */
918 if (!found)
919 dl_list_add(&w->drvs, &bss->drv->wiphy_list);
920
921 dl_list_add(&w->bsss, &bss->wiphy_list);
922 bss->wiphy_data = w;
923 return w;
924}
925
926
927static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
928{
929 struct nl80211_wiphy_data *w = bss->wiphy_data;
930 struct i802_bss *tmp_bss;
931 int found = 0;
932
933 if (w == NULL)
934 return;
935 bss->wiphy_data = NULL;
936 dl_list_del(&bss->wiphy_list);
937
938 /* still any for this drv present? */
939 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
940 if (tmp_bss->drv == bss->drv) {
941 found = 1;
942 break;
943 }
944 }
945 /* if not remove it */
946 if (!found)
947 dl_list_del(&bss->drv->wiphy_list);
948
949 if (!dl_list_empty(&w->bsss))
950 return;
951
Paul Stewart092955c2017-02-06 09:13:09 -0800952 if (w->nl_beacons)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700953 nl80211_destroy_eloop_handle(&w->nl_beacons, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800954
955 nl_cb_put(w->nl_cb);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800956 dl_list_del(&w->list);
957 os_free(w);
958}
959
960
Dmitry Shmidte4663042016-04-04 10:07:49 -0700961static unsigned int nl80211_get_ifindex(void *priv)
962{
963 struct i802_bss *bss = priv;
964 struct wpa_driver_nl80211_data *drv = bss->drv;
965
966 return drv->ifindex;
967}
968
969
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700970static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
971{
972 struct i802_bss *bss = priv;
973 struct wpa_driver_nl80211_data *drv = bss->drv;
974 if (!drv->associated)
975 return -1;
976 os_memcpy(bssid, drv->bssid, ETH_ALEN);
977 return 0;
978}
979
980
981static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
982{
983 struct i802_bss *bss = priv;
984 struct wpa_driver_nl80211_data *drv = bss->drv;
985 if (!drv->associated)
986 return -1;
987 os_memcpy(ssid, drv->ssid, drv->ssid_len);
988 return drv->ssid_len;
989}
990
991
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800992static void wpa_driver_nl80211_event_newlink(
Dmitry Shmidte4663042016-04-04 10:07:49 -0700993 struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
994 int ifindex, const char *ifname)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700995{
996 union wpa_event_data event;
997
Dmitry Shmidte4663042016-04-04 10:07:49 -0700998 if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800999 if (if_nametoindex(drv->first_bss->ifname) == 0) {
1000 wpa_printf(MSG_DEBUG, "nl80211: Interface %s does not exist - ignore RTM_NEWLINK",
1001 drv->first_bss->ifname);
1002 return;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001003 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001004 if (!drv->if_removed)
1005 return;
1006 wpa_printf(MSG_DEBUG, "nl80211: Mark if_removed=0 for %s based on RTM_NEWLINK event",
1007 drv->first_bss->ifname);
1008 drv->if_removed = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001009 }
1010
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001011 os_memset(&event, 0, sizeof(event));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001012 event.interface_status.ifindex = ifindex;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001013 os_strlcpy(event.interface_status.ifname, ifname,
1014 sizeof(event.interface_status.ifname));
1015 event.interface_status.ievent = EVENT_INTERFACE_ADDED;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001016 if (drv)
1017 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
1018 else
1019 wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
1020 &event);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001021}
1022
1023
1024static void wpa_driver_nl80211_event_dellink(
Dmitry Shmidte4663042016-04-04 10:07:49 -07001025 struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
1026 int ifindex, const char *ifname)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001027{
1028 union wpa_event_data event;
1029
Dmitry Shmidte4663042016-04-04 10:07:49 -07001030 if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001031 if (drv->if_removed) {
1032 wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s",
1033 ifname);
1034 return;
1035 }
1036 wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed - mark if_removed=1",
1037 ifname);
1038 drv->if_removed = 1;
1039 } else {
1040 wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed",
1041 ifname);
1042 }
1043
1044 os_memset(&event, 0, sizeof(event));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001045 event.interface_status.ifindex = ifindex;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001046 os_strlcpy(event.interface_status.ifname, ifname,
1047 sizeof(event.interface_status.ifname));
1048 event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001049 if (drv)
1050 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
1051 else
1052 wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
1053 &event);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001054}
1055
1056
1057static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
1058 u8 *buf, size_t len)
1059{
1060 int attrlen, rta_len;
1061 struct rtattr *attr;
1062
1063 attrlen = len;
1064 attr = (struct rtattr *) buf;
1065
1066 rta_len = RTA_ALIGN(sizeof(struct rtattr));
1067 while (RTA_OK(attr, attrlen)) {
1068 if (attr->rta_type == IFLA_IFNAME) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001069 if (os_strcmp(((char *) attr) + rta_len,
1070 drv->first_bss->ifname) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001071 return 1;
1072 else
1073 break;
1074 }
1075 attr = RTA_NEXT(attr, attrlen);
1076 }
1077
1078 return 0;
1079}
1080
1081
1082static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
1083 int ifindex, u8 *buf, size_t len)
1084{
1085 if (drv->ifindex == ifindex)
1086 return 1;
1087
1088 if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001089 nl80211_check_global(drv->global);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001090 wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
1091 "interface");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001092 if (wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL) < 0)
1093 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001094 return 1;
1095 }
1096
1097 return 0;
1098}
1099
1100
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001101static struct wpa_driver_nl80211_data *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001102nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len,
1103 int *init_failed)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001104{
1105 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001106 int res;
1107
1108 if (init_failed)
1109 *init_failed = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001110 dl_list_for_each(drv, &global->interfaces,
1111 struct wpa_driver_nl80211_data, list) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001112 res = wpa_driver_nl80211_own_ifindex(drv, idx, buf, len);
1113 if (res < 0) {
1114 wpa_printf(MSG_DEBUG,
1115 "nl80211: Found matching own interface, but failed to complete reinitialization");
1116 if (init_failed)
1117 *init_failed = 1;
1118 return drv;
1119 }
1120 if (res > 0 || have_ifidx(drv, idx, IFIDX_ANY))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001121 return drv;
1122 }
1123 return NULL;
1124}
1125
1126
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001127static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001128 int ifindex, int notify)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001129{
1130 struct i802_bss *bss;
1131 u8 addr[ETH_ALEN];
1132
1133 bss = get_bss_ifindex(drv, ifindex);
1134 if (bss &&
1135 linux_get_ifhwaddr(drv->global->ioctl_sock,
1136 bss->ifname, addr) < 0) {
1137 wpa_printf(MSG_DEBUG,
1138 "nl80211: %s: failed to re-read MAC address",
1139 bss->ifname);
1140 } else if (bss && os_memcmp(addr, bss->addr, ETH_ALEN) != 0) {
1141 wpa_printf(MSG_DEBUG,
1142 "nl80211: Own MAC address on ifindex %d (%s) changed from "
1143 MACSTR " to " MACSTR,
1144 ifindex, bss->ifname,
1145 MAC2STR(bss->addr), MAC2STR(addr));
1146 os_memcpy(bss->addr, addr, ETH_ALEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001147 if (notify)
1148 wpa_supplicant_event(drv->ctx,
1149 EVENT_INTERFACE_MAC_CHANGED, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001150 }
1151}
1152
1153
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001154static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
1155 struct ifinfomsg *ifi,
1156 u8 *buf, size_t len)
1157{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001158 struct nl80211_global *global = ctx;
1159 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001160 int attrlen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001161 struct rtattr *attr;
1162 u32 brid = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001163 char namebuf[IFNAMSIZ];
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001164 char ifname[IFNAMSIZ + 1];
1165 char extra[100], *pos, *end;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001166 int init_failed;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001167
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001168 extra[0] = '\0';
1169 pos = extra;
1170 end = pos + sizeof(extra);
1171 ifname[0] = '\0';
1172
1173 attrlen = len;
1174 attr = (struct rtattr *) buf;
1175 while (RTA_OK(attr, attrlen)) {
1176 switch (attr->rta_type) {
1177 case IFLA_IFNAME:
Hai Shalomfdcde762020-04-02 11:19:20 -07001178 if (RTA_PAYLOAD(attr) > IFNAMSIZ)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001179 break;
1180 os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
1181 ifname[RTA_PAYLOAD(attr)] = '\0';
1182 break;
1183 case IFLA_MASTER:
1184 brid = nla_get_u32((struct nlattr *) attr);
1185 pos += os_snprintf(pos, end - pos, " master=%u", brid);
1186 break;
1187 case IFLA_WIRELESS:
1188 pos += os_snprintf(pos, end - pos, " wext");
1189 break;
1190 case IFLA_OPERSTATE:
1191 pos += os_snprintf(pos, end - pos, " operstate=%u",
1192 nla_get_u32((struct nlattr *) attr));
1193 break;
1194 case IFLA_LINKMODE:
1195 pos += os_snprintf(pos, end - pos, " linkmode=%u",
1196 nla_get_u32((struct nlattr *) attr));
1197 break;
1198 }
1199 attr = RTA_NEXT(attr, attrlen);
1200 }
1201 extra[sizeof(extra) - 1] = '\0';
1202
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001203 wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
1204 ifi->ifi_index, ifname, extra, ifi->ifi_family,
1205 ifi->ifi_flags,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001206 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
1207 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
1208 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
1209 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
1210
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001211 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, &init_failed);
Dmitry Shmidte4663042016-04-04 10:07:49 -07001212 if (!drv)
1213 goto event_newlink;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001214 if (init_failed)
1215 return; /* do not update interface state */
Dmitry Shmidte4663042016-04-04 10:07:49 -07001216
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001217 if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001218 namebuf[0] = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001219 if (if_indextoname(ifi->ifi_index, namebuf) &&
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001220 linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001221 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
1222 "event since interface %s is up", namebuf);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001223 drv->ignore_if_down_event = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001224 /* Re-read MAC address as it may have changed */
1225 nl80211_refresh_mac(drv, ifi->ifi_index, 1);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001226 return;
1227 }
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001228 wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
1229 namebuf, ifname);
1230 if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
1231 wpa_printf(MSG_DEBUG,
1232 "nl80211: Not the main interface (%s) - do not indicate interface down",
1233 drv->first_bss->ifname);
1234 } else if (drv->ignore_if_down_event) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001235 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
1236 "event generated by mode change");
1237 drv->ignore_if_down_event = 0;
1238 } else {
1239 drv->if_disabled = 1;
1240 wpa_supplicant_event(drv->ctx,
1241 EVENT_INTERFACE_DISABLED, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08001242
1243 /*
1244 * Try to get drv again, since it may be removed as
1245 * part of the EVENT_INTERFACE_DISABLED handling for
1246 * dynamic interfaces
1247 */
1248 drv = nl80211_find_drv(global, ifi->ifi_index,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001249 buf, len, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08001250 if (!drv)
1251 return;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001252 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001253 }
1254
1255 if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
Hai Shalomc9e41a12018-07-31 14:41:42 -07001256 namebuf[0] = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001257 if (if_indextoname(ifi->ifi_index, namebuf) &&
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001258 linux_iface_up(drv->global->ioctl_sock, namebuf) == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001259 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1260 "event since interface %s is down",
1261 namebuf);
Hai Shalomc9e41a12018-07-31 14:41:42 -07001262 return;
1263 }
1264 wpa_printf(MSG_DEBUG, "nl80211: Interface up (%s/%s)",
1265 namebuf, ifname);
1266 if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
1267 wpa_printf(MSG_DEBUG,
1268 "nl80211: Not the main interface (%s) - do not indicate interface up",
1269 drv->first_bss->ifname);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001270 } else if (if_nametoindex(drv->first_bss->ifname) == 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001271 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1272 "event since interface %s does not exist",
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001273 drv->first_bss->ifname);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001274 } else if (drv->if_removed) {
1275 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1276 "event since interface %s is marked "
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001277 "removed", drv->first_bss->ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001278 } else {
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07001279 /* Re-read MAC address as it may have changed */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001280 nl80211_refresh_mac(drv, ifi->ifi_index, 0);
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07001281
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001282 drv->if_disabled = 0;
1283 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
1284 NULL);
1285 }
Sunil Ravi90775442020-09-24 11:53:19 -07001286 } else if (ifi->ifi_flags & IFF_UP) {
1287 /* Re-read MAC address as it may have changed */
1288 nl80211_refresh_mac(drv, ifi->ifi_index, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001289 }
1290
1291 /*
1292 * Some drivers send the association event before the operup event--in
1293 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
1294 * fails. This will hit us when wpa_supplicant does not need to do
1295 * IEEE 802.1X authentication
1296 */
1297 if (drv->operstate == 1 &&
1298 (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001299 !(ifi->ifi_flags & IFF_RUNNING)) {
1300 wpa_printf(MSG_DEBUG, "nl80211: Set IF_OPER_UP again based on ifi_flags and expected operstate");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001301 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001302 -1, IF_OPER_UP);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001303 }
1304
Dmitry Shmidte4663042016-04-04 10:07:49 -07001305event_newlink:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001306 if (ifname[0])
Dmitry Shmidte4663042016-04-04 10:07:49 -07001307 wpa_driver_nl80211_event_newlink(global, drv, ifi->ifi_index,
1308 ifname);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001309
Dmitry Shmidte4663042016-04-04 10:07:49 -07001310 if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001311 struct i802_bss *bss;
1312
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001313 /* device has been added to bridge */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001314 if (!if_indextoname(brid, namebuf)) {
1315 wpa_printf(MSG_DEBUG,
1316 "nl80211: Could not find bridge ifname for ifindex %u",
1317 brid);
1318 return;
1319 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001320 wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
1321 brid, namebuf);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001322 add_ifidx(drv, brid, ifi->ifi_index);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001323
1324 for (bss = drv->first_bss; bss; bss = bss->next) {
1325 if (os_strcmp(ifname, bss->ifname) == 0) {
1326 os_strlcpy(bss->brname, namebuf, IFNAMSIZ);
1327 break;
1328 }
1329 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001330 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001331}
1332
1333
1334static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
1335 struct ifinfomsg *ifi,
1336 u8 *buf, size_t len)
1337{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001338 struct nl80211_global *global = ctx;
1339 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001340 int attrlen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001341 struct rtattr *attr;
1342 u32 brid = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001343 char ifname[IFNAMSIZ + 1];
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001344 char extra[100], *pos, *end;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001345
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001346 extra[0] = '\0';
1347 pos = extra;
1348 end = pos + sizeof(extra);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001349 ifname[0] = '\0';
1350
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001351 attrlen = len;
1352 attr = (struct rtattr *) buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001353 while (RTA_OK(attr, attrlen)) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001354 switch (attr->rta_type) {
1355 case IFLA_IFNAME:
Hai Shalomfdcde762020-04-02 11:19:20 -07001356 if (RTA_PAYLOAD(attr) > IFNAMSIZ)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001357 break;
1358 os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
1359 ifname[RTA_PAYLOAD(attr)] = '\0';
1360 break;
1361 case IFLA_MASTER:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001362 brid = nla_get_u32((struct nlattr *) attr);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001363 pos += os_snprintf(pos, end - pos, " master=%u", brid);
1364 break;
1365 case IFLA_OPERSTATE:
1366 pos += os_snprintf(pos, end - pos, " operstate=%u",
1367 nla_get_u32((struct nlattr *) attr));
1368 break;
1369 case IFLA_LINKMODE:
1370 pos += os_snprintf(pos, end - pos, " linkmode=%u",
1371 nla_get_u32((struct nlattr *) attr));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001372 break;
1373 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001374 attr = RTA_NEXT(attr, attrlen);
1375 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001376 extra[sizeof(extra) - 1] = '\0';
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001377
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001378 wpa_printf(MSG_DEBUG, "RTM_DELLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
1379 ifi->ifi_index, ifname, extra, ifi->ifi_family,
1380 ifi->ifi_flags,
1381 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
1382 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
1383 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
1384 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
1385
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001386 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001387
Dmitry Shmidte4663042016-04-04 10:07:49 -07001388 if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001389 /* device has been removed from bridge */
1390 char namebuf[IFNAMSIZ];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001391
1392 if (!if_indextoname(brid, namebuf)) {
1393 wpa_printf(MSG_DEBUG,
1394 "nl80211: Could not find bridge ifname for ifindex %u",
1395 brid);
1396 } else {
1397 wpa_printf(MSG_DEBUG,
1398 "nl80211: Remove ifindex %u for bridge %s",
1399 brid, namebuf);
1400 }
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001401 del_ifidx(drv, brid, ifi->ifi_index);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001402 }
Dmitry Shmidte4663042016-04-04 10:07:49 -07001403
1404 if (ifi->ifi_family != AF_BRIDGE || !brid)
1405 wpa_driver_nl80211_event_dellink(global, drv, ifi->ifi_index,
1406 ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001407}
1408
1409
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001410struct nl80211_get_assoc_freq_arg {
1411 struct wpa_driver_nl80211_data *drv;
1412 unsigned int assoc_freq;
1413 unsigned int ibss_freq;
1414 u8 assoc_bssid[ETH_ALEN];
1415 u8 assoc_ssid[SSID_MAX_LEN];
1416 u8 assoc_ssid_len;
1417};
1418
1419static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg)
1420{
1421 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1422 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1423 struct nlattr *bss[NL80211_BSS_MAX + 1];
1424 static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
1425 [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
1426 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
1427 [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
1428 [NL80211_BSS_STATUS] = { .type = NLA_U32 },
1429 };
1430 struct nl80211_get_assoc_freq_arg *ctx = arg;
1431 enum nl80211_bss_status status;
1432
1433 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1434 genlmsg_attrlen(gnlh, 0), NULL);
1435 if (!tb[NL80211_ATTR_BSS] ||
1436 nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
1437 bss_policy) ||
1438 !bss[NL80211_BSS_STATUS])
1439 return NL_SKIP;
1440
1441 status = nla_get_u32(bss[NL80211_BSS_STATUS]);
1442 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1443 bss[NL80211_BSS_FREQUENCY]) {
1444 ctx->assoc_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
1445 wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
1446 ctx->assoc_freq);
1447 }
1448 if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
1449 bss[NL80211_BSS_FREQUENCY]) {
1450 ctx->ibss_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
1451 wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
1452 ctx->ibss_freq);
1453 }
1454 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1455 bss[NL80211_BSS_BSSID]) {
1456 os_memcpy(ctx->assoc_bssid,
1457 nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
1458 wpa_printf(MSG_DEBUG, "nl80211: Associated with "
1459 MACSTR, MAC2STR(ctx->assoc_bssid));
1460 }
1461
1462 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1463 bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
1464 const u8 *ie, *ssid;
1465 size_t ie_len;
1466
1467 ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1468 ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1469 ssid = get_ie(ie, ie_len, WLAN_EID_SSID);
1470 if (ssid && ssid[1] > 0 && ssid[1] <= SSID_MAX_LEN) {
1471 ctx->assoc_ssid_len = ssid[1];
1472 os_memcpy(ctx->assoc_ssid, ssid + 2, ssid[1]);
1473 }
1474 }
1475
1476 return NL_SKIP;
1477}
1478
1479
1480int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid)
Jouni Malinen87fd2792011-05-16 18:35:42 +03001481{
1482 struct nl_msg *msg;
1483 int ret;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001484 struct nl80211_get_assoc_freq_arg arg;
Hai Shalomfdcde762020-04-02 11:19:20 -07001485 int count = 0;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001486
Hai Shalomfdcde762020-04-02 11:19:20 -07001487try_again:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001488 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
Jouni Malinen87fd2792011-05-16 18:35:42 +03001489 os_memset(&arg, 0, sizeof(arg));
Jouni Malinen87fd2792011-05-16 18:35:42 +03001490 arg.drv = drv;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001491 ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
Hai Shalom899fcc72020-10-19 14:38:18 -07001492 &arg, NULL, NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -07001493 if (ret == -EAGAIN) {
1494 count++;
1495 if (count >= 10) {
1496 wpa_printf(MSG_INFO,
1497 "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid");
1498 } else {
1499 wpa_printf(MSG_DEBUG,
1500 "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid - try again");
1501 goto try_again;
1502 }
1503 }
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001504 if (ret == 0) {
1505 os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len);
1506 return arg.assoc_ssid_len;
1507 }
1508 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d (%s)",
1509 ret, strerror(-ret));
1510 return ret;
1511}
1512
1513
1514unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
1515{
1516 struct nl_msg *msg;
1517 int ret;
1518 struct nl80211_get_assoc_freq_arg arg;
Hai Shalomfdcde762020-04-02 11:19:20 -07001519 int count = 0;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001520
Hai Shalomfdcde762020-04-02 11:19:20 -07001521try_again:
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001522 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
1523 os_memset(&arg, 0, sizeof(arg));
1524 arg.drv = drv;
1525 ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
Hai Shalom899fcc72020-10-19 14:38:18 -07001526 &arg, NULL, NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -07001527 if (ret == -EAGAIN) {
1528 count++;
1529 if (count >= 10) {
1530 wpa_printf(MSG_INFO,
1531 "nl80211: Failed to receive consistent scan result dump for get_assoc_freq");
1532 } else {
1533 wpa_printf(MSG_DEBUG,
1534 "nl80211: Failed to receive consistent scan result dump for get_assoc_freq - try again");
1535 goto try_again;
1536 }
1537 }
Jouni Malinen87fd2792011-05-16 18:35:42 +03001538 if (ret == 0) {
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07001539 unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
1540 arg.ibss_freq : arg.assoc_freq;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001541 wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07001542 "associated BSS from scan results: %u MHz", freq);
1543 if (freq)
1544 drv->assoc_freq = freq;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001545 return drv->assoc_freq;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001546 }
1547 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
1548 "(%s)", ret, strerror(-ret));
Jouni Malinen87fd2792011-05-16 18:35:42 +03001549 return drv->assoc_freq;
1550}
1551
1552
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001553static int get_link_signal(struct nl_msg *msg, void *arg)
1554{
1555 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1556 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1557 struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
1558 static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
1559 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
Dmitry Shmidt34af3062013-07-11 10:46:32 -07001560 [NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07001561 [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001562 };
1563 struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
1564 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
1565 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
1566 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
1567 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
1568 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
1569 };
1570 struct wpa_signal_info *sig_change = arg;
1571
1572 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1573 genlmsg_attrlen(gnlh, 0), NULL);
1574 if (!tb[NL80211_ATTR_STA_INFO] ||
1575 nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
1576 tb[NL80211_ATTR_STA_INFO], policy))
1577 return NL_SKIP;
1578 if (!sinfo[NL80211_STA_INFO_SIGNAL])
1579 return NL_SKIP;
1580
1581 sig_change->current_signal =
1582 (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
1583
Dmitry Shmidt34af3062013-07-11 10:46:32 -07001584 if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
1585 sig_change->avg_signal =
1586 (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
1587 else
1588 sig_change->avg_signal = 0;
1589
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07001590 if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG])
1591 sig_change->avg_beacon_signal =
1592 (s8)
1593 nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
1594 else
1595 sig_change->avg_beacon_signal = 0;
1596
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001597 if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
1598 if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
1599 sinfo[NL80211_STA_INFO_TX_BITRATE],
1600 rate_policy)) {
1601 sig_change->current_txrate = 0;
1602 } else {
1603 if (rinfo[NL80211_RATE_INFO_BITRATE]) {
1604 sig_change->current_txrate =
1605 nla_get_u16(rinfo[
1606 NL80211_RATE_INFO_BITRATE]) * 100;
1607 }
1608 }
1609 }
1610
1611 return NL_SKIP;
1612}
1613
1614
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001615int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
1616 struct wpa_signal_info *sig)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001617{
1618 struct nl_msg *msg;
1619
Hai Shalom74f70d42019-02-11 14:42:39 -08001620 sig->current_signal = -WPA_INVALID_NOISE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001621 sig->current_txrate = 0;
1622
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001623 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
1624 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid)) {
1625 nlmsg_free(msg);
1626 return -ENOBUFS;
1627 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001628
Hai Shalom899fcc72020-10-19 14:38:18 -07001629 return send_and_recv_msgs(drv, msg, get_link_signal, sig, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001630}
1631
1632
1633static int get_link_noise(struct nl_msg *msg, void *arg)
1634{
1635 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1636 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1637 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
1638 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
1639 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
1640 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
1641 };
1642 struct wpa_signal_info *sig_change = arg;
1643
1644 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1645 genlmsg_attrlen(gnlh, 0), NULL);
1646
1647 if (!tb[NL80211_ATTR_SURVEY_INFO]) {
1648 wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
1649 return NL_SKIP;
1650 }
1651
1652 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
1653 tb[NL80211_ATTR_SURVEY_INFO],
1654 survey_policy)) {
1655 wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested "
1656 "attributes!");
1657 return NL_SKIP;
1658 }
1659
1660 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
1661 return NL_SKIP;
1662
1663 if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
1664 sig_change->frequency)
1665 return NL_SKIP;
1666
1667 if (!sinfo[NL80211_SURVEY_INFO_NOISE])
1668 return NL_SKIP;
1669
1670 sig_change->current_noise =
1671 (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
1672
1673 return NL_SKIP;
1674}
1675
1676
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001677int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
1678 struct wpa_signal_info *sig_change)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001679{
1680 struct nl_msg *msg;
1681
Hai Shalom74f70d42019-02-11 14:42:39 -08001682 sig_change->current_noise = WPA_INVALID_NOISE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001683 sig_change->frequency = drv->assoc_freq;
1684
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001685 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
Hai Shalom899fcc72020-10-19 14:38:18 -07001686 return send_and_recv_msgs(drv, msg, get_link_noise, sig_change,
1687 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001688}
1689
1690
Hai Shalom74f70d42019-02-11 14:42:39 -08001691static int get_channel_info(struct nl_msg *msg, void *arg)
1692{
1693 struct nlattr *tb[NL80211_ATTR_MAX + 1] = { 0 };
1694 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1695 struct wpa_channel_info *chan_info = arg;
1696
1697 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1698 genlmsg_attrlen(gnlh, 0), NULL);
1699
1700 os_memset(chan_info, 0, sizeof(struct wpa_channel_info));
1701 chan_info->chanwidth = CHAN_WIDTH_UNKNOWN;
1702
1703 if (tb[NL80211_ATTR_WIPHY_FREQ])
1704 chan_info->frequency =
1705 nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
1706 if (tb[NL80211_ATTR_CHANNEL_WIDTH])
1707 chan_info->chanwidth = convert2width(
1708 nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
1709 if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
1710 enum nl80211_channel_type ct =
1711 nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
1712
1713 switch (ct) {
1714 case NL80211_CHAN_HT40MINUS:
1715 chan_info->sec_channel = -1;
1716 break;
1717 case NL80211_CHAN_HT40PLUS:
1718 chan_info->sec_channel = 1;
1719 break;
1720 default:
1721 chan_info->sec_channel = 0;
1722 break;
1723 }
1724 }
1725 if (tb[NL80211_ATTR_CENTER_FREQ1])
1726 chan_info->center_frq1 =
1727 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
1728 if (tb[NL80211_ATTR_CENTER_FREQ2])
1729 chan_info->center_frq2 =
1730 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
1731
1732 if (chan_info->center_frq2) {
1733 u8 seg1_idx = 0;
1734
1735 if (ieee80211_freq_to_chan(chan_info->center_frq2, &seg1_idx) !=
1736 NUM_HOSTAPD_MODES)
1737 chan_info->seg1_idx = seg1_idx;
1738 }
1739
1740 return NL_SKIP;
1741}
1742
1743
1744static int nl80211_channel_info(void *priv, struct wpa_channel_info *ci)
1745{
1746 struct i802_bss *bss = priv;
1747 struct wpa_driver_nl80211_data *drv = bss->drv;
1748 struct nl_msg *msg;
1749
1750 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
Hai Shalom899fcc72020-10-19 14:38:18 -07001751 return send_and_recv_msgs(drv, msg, get_channel_info, ci, NULL, NULL);
Hai Shalom74f70d42019-02-11 14:42:39 -08001752}
1753
1754
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001755static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
1756 void *handle)
1757{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001758 struct nl_cb *cb = eloop_ctx;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001759 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001760
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07001761 wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001762
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001763 res = nl_recvmsgs(handle, cb);
Dmitry Shmidt71757432014-06-02 13:50:35 -07001764 if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001765 wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
1766 __func__, res);
1767 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001768}
1769
1770
1771/**
1772 * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
1773 * @priv: driver_nl80211 private data
1774 * @alpha2_arg: country to which to switch to
1775 * Returns: 0 on success, -1 on failure
1776 *
1777 * This asks nl80211 to set the regulatory domain for given
1778 * country ISO / IEC alpha2.
1779 */
1780static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
1781{
1782 struct i802_bss *bss = priv;
1783 struct wpa_driver_nl80211_data *drv = bss->drv;
1784 char alpha2[3];
1785 struct nl_msg *msg;
1786
1787 msg = nlmsg_alloc();
1788 if (!msg)
1789 return -ENOMEM;
1790
1791 alpha2[0] = alpha2_arg[0];
1792 alpha2[1] = alpha2_arg[1];
1793 alpha2[2] = '\0';
1794
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001795 if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG) ||
1796 nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, alpha2)) {
1797 nlmsg_free(msg);
1798 return -EINVAL;
1799 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001800 if (send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001801 return -EINVAL;
1802 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001803}
1804
1805
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001806static int nl80211_get_country(struct nl_msg *msg, void *arg)
1807{
1808 char *alpha2 = arg;
1809 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
1810 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1811
1812 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1813 genlmsg_attrlen(gnlh, 0), NULL);
1814 if (!tb_msg[NL80211_ATTR_REG_ALPHA2]) {
1815 wpa_printf(MSG_DEBUG, "nl80211: No country information available");
1816 return NL_SKIP;
1817 }
1818 os_strlcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3);
1819 return NL_SKIP;
1820}
1821
1822
1823static int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
1824{
1825 struct i802_bss *bss = priv;
1826 struct wpa_driver_nl80211_data *drv = bss->drv;
1827 struct nl_msg *msg;
1828 int ret;
1829
1830 msg = nlmsg_alloc();
1831 if (!msg)
1832 return -ENOMEM;
1833
1834 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
1835 alpha2[0] = '\0';
Hai Shalom899fcc72020-10-19 14:38:18 -07001836 ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2,
1837 NULL, NULL);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001838 if (!alpha2[0])
1839 ret = -1;
1840
1841 return ret;
1842}
1843
1844
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001845static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001846{
1847 int ret;
1848
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001849 global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
1850 if (global->nl_cb == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001851 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
1852 "callbacks");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001853 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001854 }
1855
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001856 global->nl = nl_create_handle(global->nl_cb, "nl");
1857 if (global->nl == NULL)
1858 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001859
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001860 global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
1861 if (global->nl80211_id < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001862 wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
1863 "found");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001864 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001865 }
1866
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001867 global->nl_event = nl_create_handle(global->nl_cb, "event");
1868 if (global->nl_event == NULL)
1869 goto err;
1870
1871 ret = nl_get_multicast_id(global, "nl80211", "scan");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001872 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001873 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001874 if (ret < 0) {
1875 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
1876 "membership for scan events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001877 ret, nl_geterror(ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001878 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001879 }
1880
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001881 ret = nl_get_multicast_id(global, "nl80211", "mlme");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001882 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001883 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001884 if (ret < 0) {
1885 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
1886 "membership for mlme events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001887 ret, nl_geterror(ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001888 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001889 }
1890
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001891 ret = nl_get_multicast_id(global, "nl80211", "regulatory");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001892 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001893 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001894 if (ret < 0) {
1895 wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
1896 "membership for regulatory events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001897 ret, nl_geterror(ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001898 /* Continue without regulatory events */
1899 }
1900
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001901 ret = nl_get_multicast_id(global, "nl80211", "vendor");
1902 if (ret >= 0)
1903 ret = nl_socket_add_membership(global->nl_event, ret);
1904 if (ret < 0) {
1905 wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
1906 "membership for vendor events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001907 ret, nl_geterror(ret));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001908 /* Continue without vendor events */
1909 }
1910
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001911 nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
1912 no_seq_check, NULL);
1913 nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
1914 process_global_event, global);
1915
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001916 nl80211_register_eloop_read(&global->nl_event,
1917 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001918 global->nl_cb, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001919
1920 return 0;
1921
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001922err:
1923 nl_destroy_handles(&global->nl_event);
1924 nl_destroy_handles(&global->nl);
1925 nl_cb_put(global->nl_cb);
1926 global->nl_cb = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001927 return -1;
1928}
1929
1930
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001931static void nl80211_check_global(struct nl80211_global *global)
1932{
Hai Shalomfdcde762020-04-02 11:19:20 -07001933 struct nl_sock *handle;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001934 const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL };
1935 int ret;
1936 unsigned int i;
1937
1938 /*
1939 * Try to re-add memberships to handle case of cfg80211 getting reloaded
1940 * and all registration having been cleared.
1941 */
1942 handle = (void *) (((intptr_t) global->nl_event) ^
1943 ELOOP_SOCKET_INVALID);
1944
1945 for (i = 0; groups[i]; i++) {
1946 ret = nl_get_multicast_id(global, "nl80211", groups[i]);
1947 if (ret >= 0)
1948 ret = nl_socket_add_membership(handle, ret);
1949 if (ret < 0) {
1950 wpa_printf(MSG_INFO,
1951 "nl80211: Could not re-add multicast membership for %s events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001952 groups[i], ret, nl_geterror(ret));
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001953 }
1954 }
1955}
1956
1957
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001958static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
1959{
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08001960 struct wpa_driver_nl80211_data *drv = ctx;
1961
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001962 wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08001963
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001964 /*
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08001965 * rtnetlink ifdown handler will report interfaces other than the P2P
1966 * Device interface as disabled.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001967 */
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08001968 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
1969 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001970}
1971
1972
1973static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
1974{
1975 struct wpa_driver_nl80211_data *drv = ctx;
1976 wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001977 if (i802_set_iface_flags(drv->first_bss, 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001978 wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
1979 "after rfkill unblock");
1980 return;
1981 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001982
1983 if (is_p2p_net_interface(drv->nlmode))
1984 nl80211_disable_11b_rates(drv, drv->ifindex, 1);
1985
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08001986 /*
1987 * rtnetlink ifup handler will report interfaces other than the P2P
1988 * Device interface as enabled.
1989 */
1990 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
1991 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001992}
1993
1994
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001995static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
1996 void *eloop_ctx,
1997 void *handle)
1998{
1999 struct wpa_driver_nl80211_data *drv = eloop_ctx;
2000 u8 data[2048];
2001 struct msghdr msg;
2002 struct iovec entry;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002003 u8 control[512];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002004 struct cmsghdr *cmsg;
2005 int res, found_ee = 0, found_wifi = 0, acked = 0;
2006 union wpa_event_data event;
2007
2008 memset(&msg, 0, sizeof(msg));
2009 msg.msg_iov = &entry;
2010 msg.msg_iovlen = 1;
2011 entry.iov_base = data;
2012 entry.iov_len = sizeof(data);
2013 msg.msg_control = &control;
2014 msg.msg_controllen = sizeof(control);
2015
2016 res = recvmsg(sock, &msg, MSG_ERRQUEUE);
2017 /* if error or not fitting 802.3 header, return */
2018 if (res < 14)
2019 return;
2020
2021 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
2022 {
2023 if (cmsg->cmsg_level == SOL_SOCKET &&
2024 cmsg->cmsg_type == SCM_WIFI_STATUS) {
2025 int *ack;
2026
2027 found_wifi = 1;
2028 ack = (void *)CMSG_DATA(cmsg);
2029 acked = *ack;
2030 }
2031
2032 if (cmsg->cmsg_level == SOL_PACKET &&
2033 cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
2034 struct sock_extended_err *err =
2035 (struct sock_extended_err *)CMSG_DATA(cmsg);
2036
2037 if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
2038 found_ee = 1;
2039 }
2040 }
2041
2042 if (!found_ee || !found_wifi)
2043 return;
2044
2045 memset(&event, 0, sizeof(event));
2046 event.eapol_tx_status.dst = data;
2047 event.eapol_tx_status.data = data + 14;
2048 event.eapol_tx_status.data_len = res - 14;
2049 event.eapol_tx_status.ack = acked;
2050 wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
2051}
2052
2053
Hai Shalomb755a2a2020-04-23 21:49:02 -07002054static int nl80211_init_connect_handle(struct i802_bss *bss)
2055{
2056 if (bss->nl_connect) {
2057 wpa_printf(MSG_DEBUG,
2058 "nl80211: Connect handle already created (nl_connect=%p)",
2059 bss->nl_connect);
2060 return -1;
2061 }
2062
2063 bss->nl_connect = nl_create_handle(bss->nl_cb, "connect");
2064 if (!bss->nl_connect)
2065 return -1;
2066 nl80211_register_eloop_read(&bss->nl_connect,
2067 wpa_driver_nl80211_event_receive,
2068 bss->nl_cb, 1);
2069 return 0;
2070}
2071
2072
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002073static int nl80211_init_bss(struct i802_bss *bss)
2074{
2075 bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
2076 if (!bss->nl_cb)
2077 return -1;
2078
2079 nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
2080 no_seq_check, NULL);
2081 nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
2082 process_bss_event, bss);
2083
Hai Shalomb755a2a2020-04-23 21:49:02 -07002084 nl80211_init_connect_handle(bss);
2085
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002086 return 0;
2087}
2088
2089
2090static void nl80211_destroy_bss(struct i802_bss *bss)
2091{
2092 nl_cb_put(bss->nl_cb);
2093 bss->nl_cb = NULL;
Hai Shalomb755a2a2020-04-23 21:49:02 -07002094
2095 if (bss->nl_connect)
2096 nl80211_destroy_eloop_handle(&bss->nl_connect, 1);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002097}
2098
2099
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002100static void
2101wpa_driver_nl80211_drv_init_rfkill(struct wpa_driver_nl80211_data *drv)
2102{
2103 struct rfkill_config *rcfg;
2104
2105 if (drv->rfkill)
2106 return;
2107
2108 rcfg = os_zalloc(sizeof(*rcfg));
2109 if (!rcfg)
2110 return;
2111
2112 rcfg->ctx = drv;
2113
2114 /* rfkill uses netdev sysfs for initialization. However, P2P Device is
2115 * not associated with a netdev, so use the name of some other interface
2116 * sharing the same wiphy as the P2P Device interface.
2117 *
2118 * Note: This is valid, as a P2P Device interface is always dynamically
2119 * created and is created only once another wpa_s interface was added.
2120 */
2121 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
2122 struct nl80211_global *global = drv->global;
2123 struct wpa_driver_nl80211_data *tmp1;
2124
2125 dl_list_for_each(tmp1, &global->interfaces,
2126 struct wpa_driver_nl80211_data, list) {
2127 if (drv == tmp1 || drv->wiphy_idx != tmp1->wiphy_idx ||
2128 !tmp1->rfkill)
2129 continue;
2130
2131 wpa_printf(MSG_DEBUG,
2132 "nl80211: Use (%s) to initialize P2P Device rfkill",
2133 tmp1->first_bss->ifname);
2134 os_strlcpy(rcfg->ifname, tmp1->first_bss->ifname,
2135 sizeof(rcfg->ifname));
2136 break;
2137 }
2138 } else {
2139 os_strlcpy(rcfg->ifname, drv->first_bss->ifname,
2140 sizeof(rcfg->ifname));
2141 }
2142
2143 rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
2144 rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
2145 drv->rfkill = rfkill_init(rcfg);
2146 if (!drv->rfkill) {
2147 wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
2148 os_free(rcfg);
2149 }
2150}
2151
2152
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002153static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
2154 void *global_priv, int hostapd,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002155 const u8 *set_addr,
2156 const char *driver_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002157{
2158 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002159 struct i802_bss *bss;
2160
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002161 if (global_priv == NULL)
2162 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002163 drv = os_zalloc(sizeof(*drv));
2164 if (drv == NULL)
2165 return NULL;
2166 drv->global = global_priv;
2167 drv->ctx = ctx;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002168 drv->hostapd = !!hostapd;
2169 drv->eapol_sock = -1;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002170
2171 /*
2172 * There is no driver capability flag for this, so assume it is
2173 * supported and disable this on first attempt to use if the driver
2174 * rejects the command due to missing support.
2175 */
2176 drv->set_rekey_offload = 1;
2177
Hai Shalom81f62d82019-07-22 12:10:00 -07002178 drv->num_if_indices = ARRAY_SIZE(drv->default_if_indices);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002179 drv->if_indices = drv->default_if_indices;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002180
2181 drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
2182 if (!drv->first_bss) {
2183 os_free(drv);
2184 return NULL;
2185 }
2186 bss = drv->first_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002187 bss->drv = drv;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002188 bss->ctx = ctx;
2189
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002190 os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
2191 drv->monitor_ifidx = -1;
2192 drv->monitor_sock = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002193 drv->eapol_tx_sock = -1;
2194 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002195
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002196 if (nl80211_init_bss(bss))
2197 goto failed;
2198
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002199 if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002200 goto failed;
2201
Hai Shalom899fcc72020-10-19 14:38:18 -07002202 if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS) {
2203 drv->control_port_ap = 1;
2204 goto skip_wifi_status;
2205 }
2206
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002207 drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
2208 if (drv->eapol_tx_sock < 0)
2209 goto failed;
2210
2211 if (drv->data_tx_status) {
2212 int enabled = 1;
2213
2214 if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
2215 &enabled, sizeof(enabled)) < 0) {
2216 wpa_printf(MSG_DEBUG,
Hai Shalom899fcc72020-10-19 14:38:18 -07002217 "nl80211: wifi status sockopt failed: %s",
2218 strerror(errno));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002219 drv->data_tx_status = 0;
2220 if (!drv->use_monitor)
2221 drv->capa.flags &=
2222 ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
2223 } else {
Hai Shalom899fcc72020-10-19 14:38:18 -07002224 eloop_register_read_sock(
2225 drv->eapol_tx_sock,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002226 wpa_driver_nl80211_handle_eapol_tx_status,
2227 drv, NULL);
2228 }
2229 }
Hai Shalom899fcc72020-10-19 14:38:18 -07002230skip_wifi_status:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002231
2232 if (drv->global) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002233 nl80211_check_global(drv->global);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002234 dl_list_add(&drv->global->interfaces, &drv->list);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002235 drv->in_interface_list = 1;
2236 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002237
2238 return bss;
2239
2240failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002241 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002242 return NULL;
2243}
2244
2245
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002246/**
2247 * wpa_driver_nl80211_init - Initialize nl80211 driver interface
2248 * @ctx: context to be used when calling wpa_supplicant functions,
2249 * e.g., wpa_supplicant_event()
2250 * @ifname: interface name, e.g., wlan0
2251 * @global_priv: private driver global data from global_init()
2252 * Returns: Pointer to private data, %NULL on failure
2253 */
2254static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
2255 void *global_priv)
2256{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002257 return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL,
2258 NULL);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002259}
2260
2261
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002262static int nl80211_register_frame(struct i802_bss *bss,
Hai Shalomfdcde762020-04-02 11:19:20 -07002263 struct nl_sock *nl_handle,
Hai Shalome21d4e82020-04-29 16:34:06 -07002264 u16 type, const u8 *match, size_t match_len,
2265 bool multicast)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002266{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002267 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002268 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002269 int ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002270 char buf[30];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002271
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002272 buf[0] = '\0';
2273 wpa_snprintf_hex(buf, sizeof(buf), match, match_len);
Hai Shalome21d4e82020-04-29 16:34:06 -07002274 wpa_printf(MSG_DEBUG,
2275 "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s multicast=%d",
2276 type, fc2str(type), nl_handle, buf, multicast);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002277
Hai Shalomfdcde762020-04-02 11:19:20 -07002278 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_FRAME)) ||
Hai Shalome21d4e82020-04-29 16:34:06 -07002279 (multicast && nla_put_flag(msg, NL80211_ATTR_RECEIVE_MULTICAST)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002280 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type) ||
2281 nla_put(msg, NL80211_ATTR_FRAME_MATCH, match_len, match)) {
2282 nlmsg_free(msg);
2283 return -1;
2284 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002285
Hai Shalom899fcc72020-10-19 14:38:18 -07002286 ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL,
2287 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002288 if (ret) {
2289 wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
2290 "failed (type=%u): ret=%d (%s)",
2291 type, ret, strerror(-ret));
2292 wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
2293 match, match_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002294 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002295 return ret;
2296}
2297
2298
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002299static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
2300{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002301 if (bss->nl_mgmt) {
2302 wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
2303 "already on! (nl_mgmt=%p)", bss->nl_mgmt);
2304 return -1;
2305 }
2306
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002307 bss->nl_mgmt = nl_create_handle(bss->nl_cb, "mgmt");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002308 if (bss->nl_mgmt == NULL)
2309 return -1;
2310
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002311 return 0;
2312}
2313
2314
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002315static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss)
2316{
2317 nl80211_register_eloop_read(&bss->nl_mgmt,
2318 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002319 bss->nl_cb, 0);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002320}
2321
2322
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002323static int nl80211_register_action_frame(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002324 const u8 *match, size_t match_len)
2325{
2326 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002327 return nl80211_register_frame(bss, bss->nl_mgmt,
Hai Shalome21d4e82020-04-29 16:34:06 -07002328 type, match, match_len, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002329}
2330
2331
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002332static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002333{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002334 struct wpa_driver_nl80211_data *drv = bss->drv;
Hai Shalomfdcde762020-04-02 11:19:20 -07002335 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002336 int ret = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002337
2338 if (nl80211_alloc_mgmt_handle(bss))
2339 return -1;
2340 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
2341 "handle %p", bss->nl_mgmt);
2342
Hai Shalomfdcde762020-04-02 11:19:20 -07002343 if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002344 /* register for any AUTH message */
Hai Shalome21d4e82020-04-29 16:34:06 -07002345 nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0, false);
Hai Shalomfdcde762020-04-02 11:19:20 -07002346 } else if ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
2347 !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
2348 /* register for SAE Authentication frames */
2349 nl80211_register_frame(bss, bss->nl_mgmt, type,
Hai Shalome21d4e82020-04-29 16:34:06 -07002350 (u8 *) "\x03\x00", 2, false);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002351 }
2352
Hai Shalom60840252021-02-19 19:02:11 -08002353#ifdef CONFIG_PASN
2354 /* register for PASN Authentication frames */
2355 if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
2356 nl80211_register_frame(bss, bss->nl_mgmt, type,
2357 (u8 *) "\x07\x00", 2, false))
2358 ret = -1;
2359#endif /* CONFIG_PASN */
2360
Dmitry Shmidt051af732013-10-22 13:52:46 -07002361#ifdef CONFIG_INTERWORKING
2362 /* QoS Map Configure */
2363 if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002364 ret = -1;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002365#endif /* CONFIG_INTERWORKING */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002366#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002367 /* GAS Initial Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002368 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002369 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002370 /* GAS Initial Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002371 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002372 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002373 /* GAS Comeback Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002374 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002375 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002376 /* GAS Comeback Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002377 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002378 ret = -1;
Dmitry Shmidt18463232014-01-24 12:29:41 -08002379 /* Protected GAS Initial Request */
2380 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0a", 2) < 0)
2381 ret = -1;
2382 /* Protected GAS Initial Response */
2383 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0b", 2) < 0)
2384 ret = -1;
2385 /* Protected GAS Comeback Request */
2386 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0c", 2) < 0)
2387 ret = -1;
2388 /* Protected GAS Comeback Response */
2389 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0d", 2) < 0)
2390 ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002391#endif /* CONFIG_P2P || CONFIG_INTERWORKING || CONFIG_DPP */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002392#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002393 /* P2P Public Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002394 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002395 (u8 *) "\x04\x09\x50\x6f\x9a\x09",
2396 6) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002397 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002398 /* P2P Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002399 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002400 (u8 *) "\x7f\x50\x6f\x9a\x09",
2401 5) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002402 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002403#endif /* CONFIG_P2P */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002404#ifdef CONFIG_DPP
2405 /* DPP Public Action */
2406 if (nl80211_register_action_frame(bss,
2407 (u8 *) "\x04\x09\x50\x6f\x9a\x1a",
2408 6) < 0)
2409 ret = -1;
2410#endif /* CONFIG_DPP */
Hai Shalom74f70d42019-02-11 14:42:39 -08002411#ifdef CONFIG_OCV
2412 /* SA Query Request */
2413 if (nl80211_register_action_frame(bss, (u8 *) "\x08\x00", 2) < 0)
2414 ret = -1;
2415#endif /* CONFIG_OCV */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002416 /* SA Query Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002417 if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002418 ret = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002419#ifdef CONFIG_TDLS
2420 if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
2421 /* TDLS Discovery Response */
2422 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
2423 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002424 ret = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002425 }
2426#endif /* CONFIG_TDLS */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002427#ifdef CONFIG_FST
2428 /* FST Action frames */
2429 if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
2430 ret = -1;
2431#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002432
2433 /* FT Action frames */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002434 if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002435 ret = -1;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002436 else if (!drv->has_driver_key_mgmt) {
2437 int i;
2438
2439 /* Update supported AKMs only if the driver doesn't advertize
2440 * any AKM capabilities. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002441 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
2442 WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
2443
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002444 /* Update per interface supported AKMs */
2445 for (i = 0; i < WPA_IF_MAX; i++)
2446 drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt;
2447 }
2448
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002449 /* WNM - BSS Transition Management Request */
2450 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002451 ret = -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002452 /* WNM-Sleep Mode Response */
2453 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002454 ret = -1;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08002455#ifdef CONFIG_WNM
2456 /* WNM - Collocated Interference Request */
2457 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x0b", 2) < 0)
2458 ret = -1;
2459#endif /* CONFIG_WNM */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002460
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002461#ifdef CONFIG_HS20
2462 /* WNM-Notification */
2463 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x1a", 2) < 0)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002464 ret = -1;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002465#endif /* CONFIG_HS20 */
2466
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002467 /* WMM-AC ADDTS Response */
2468 if (nl80211_register_action_frame(bss, (u8 *) "\x11\x01", 2) < 0)
2469 ret = -1;
2470
2471 /* WMM-AC DELTS */
2472 if (nl80211_register_action_frame(bss, (u8 *) "\x11\x02", 2) < 0)
2473 ret = -1;
2474
2475 /* Radio Measurement - Neighbor Report Response */
2476 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
2477 ret = -1;
2478
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002479 /* Radio Measurement - Radio Measurement Request */
Hai Shalom899fcc72020-10-19 14:38:18 -07002480 if (!drv->no_rrm &&
2481 nl80211_register_action_frame(bss, (u8 *) "\x05\x00", 2) < 0)
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002482 ret = -1;
2483
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002484 /* Radio Measurement - Link Measurement Request */
2485 if ((drv->capa.rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) &&
2486 (nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
2487 ret = -1;
2488
Hai Shalom899fcc72020-10-19 14:38:18 -07002489 /* Robust AV MSCS Response */
2490 if (nl80211_register_action_frame(bss, (u8 *) "\x13\x05", 2) < 0)
2491 ret = -1;
2492
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002493 nl80211_mgmt_handle_register_eloop(bss);
2494
2495 return ret;
2496}
2497
2498
2499static int nl80211_mgmt_subscribe_mesh(struct i802_bss *bss)
2500{
2501 int ret = 0;
2502
2503 if (nl80211_alloc_mgmt_handle(bss))
2504 return -1;
2505
2506 wpa_printf(MSG_DEBUG,
2507 "nl80211: Subscribe to mgmt frames with mesh handle %p",
2508 bss->nl_mgmt);
2509
2510 /* Auth frames for mesh SAE */
2511 if (nl80211_register_frame(bss, bss->nl_mgmt,
2512 (WLAN_FC_TYPE_MGMT << 2) |
2513 (WLAN_FC_STYPE_AUTH << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07002514 NULL, 0, false) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002515 ret = -1;
2516
2517 /* Mesh peering open */
2518 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x01", 2) < 0)
2519 ret = -1;
2520 /* Mesh peering confirm */
2521 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x02", 2) < 0)
2522 ret = -1;
2523 /* Mesh peering close */
2524 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x03", 2) < 0)
2525 ret = -1;
2526
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002527 nl80211_mgmt_handle_register_eloop(bss);
2528
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002529 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002530}
2531
2532
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002533static int nl80211_register_spurious_class3(struct i802_bss *bss)
2534{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002535 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002536 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002537
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002538 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
Hai Shalom899fcc72020-10-19 14:38:18 -07002539 ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL,
2540 NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002541 if (ret) {
2542 wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
2543 "failed: ret=%d (%s)",
2544 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002545 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002546 return ret;
2547}
2548
2549
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002550static int nl80211_action_subscribe_ap(struct i802_bss *bss)
2551{
2552 int ret = 0;
2553
2554 /* Public Action frames */
2555 if (nl80211_register_action_frame(bss, (u8 *) "\x04", 1) < 0)
2556 ret = -1;
2557 /* RRM Measurement Report */
2558 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x01", 2) < 0)
2559 ret = -1;
Paul Stewart092955c2017-02-06 09:13:09 -08002560 /* RRM Link Measurement Report */
2561 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x03", 2) < 0)
2562 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002563 /* RRM Neighbor Report Request */
2564 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x04", 2) < 0)
2565 ret = -1;
2566 /* FT Action frames */
2567 if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
2568 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002569 /* SA Query */
2570 if (nl80211_register_action_frame(bss, (u8 *) "\x08", 1) < 0)
2571 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002572 /* Protected Dual of Public Action */
2573 if (nl80211_register_action_frame(bss, (u8 *) "\x09", 1) < 0)
2574 ret = -1;
2575 /* WNM */
2576 if (nl80211_register_action_frame(bss, (u8 *) "\x0a", 1) < 0)
2577 ret = -1;
2578 /* WMM */
2579 if (nl80211_register_action_frame(bss, (u8 *) "\x11", 1) < 0)
2580 ret = -1;
2581#ifdef CONFIG_FST
2582 /* FST Action frames */
2583 if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
2584 ret = -1;
2585#endif /* CONFIG_FST */
2586 /* Vendor-specific */
2587 if (nl80211_register_action_frame(bss, (u8 *) "\x7f", 1) < 0)
2588 ret = -1;
2589
2590 return ret;
2591}
2592
2593
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002594static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
2595{
2596 static const int stypes[] = {
2597 WLAN_FC_STYPE_AUTH,
2598 WLAN_FC_STYPE_ASSOC_REQ,
2599 WLAN_FC_STYPE_REASSOC_REQ,
2600 WLAN_FC_STYPE_DISASSOC,
2601 WLAN_FC_STYPE_DEAUTH,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002602 WLAN_FC_STYPE_PROBE_REQ,
2603/* Beacon doesn't work as mac80211 doesn't currently allow
2604 * it, but it wouldn't really be the right thing anyway as
2605 * it isn't per interface ... maybe just dump the scan
2606 * results periodically for OLBC?
2607 */
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002608 /* WLAN_FC_STYPE_BEACON, */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002609 };
2610 unsigned int i;
2611
2612 if (nl80211_alloc_mgmt_handle(bss))
2613 return -1;
2614 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
2615 "handle %p", bss->nl_mgmt);
2616
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002617 for (i = 0; i < ARRAY_SIZE(stypes); i++) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002618 if (nl80211_register_frame(bss, bss->nl_mgmt,
2619 (WLAN_FC_TYPE_MGMT << 2) |
2620 (stypes[i] << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07002621 NULL, 0, false) < 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002622 goto out_err;
2623 }
2624 }
2625
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002626 if (nl80211_action_subscribe_ap(bss))
2627 goto out_err;
2628
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002629 if (nl80211_register_spurious_class3(bss))
2630 goto out_err;
2631
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002632 nl80211_mgmt_handle_register_eloop(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002633 return 0;
2634
2635out_err:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002636 nl_destroy_handles(&bss->nl_mgmt);
2637 return -1;
2638}
2639
2640
2641static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
2642{
2643 if (nl80211_alloc_mgmt_handle(bss))
2644 return -1;
2645 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
2646 "handle %p (device SME)", bss->nl_mgmt);
2647
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002648 if (nl80211_action_subscribe_ap(bss))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002649 goto out_err;
2650
Hai Shalom5f92bc92019-04-18 11:54:11 -07002651 if (bss->drv->device_ap_sme) {
2652 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
2653
2654 /* Register for all Authentication frames */
Hai Shalome21d4e82020-04-29 16:34:06 -07002655 if (nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0,
2656 false) < 0)
Hai Shalom5f92bc92019-04-18 11:54:11 -07002657 wpa_printf(MSG_DEBUG,
2658 "nl80211: Failed to subscribe to handle Authentication frames - SAE offload may not work");
2659 }
2660
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002661 nl80211_mgmt_handle_register_eloop(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002662 return 0;
2663
2664out_err:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002665 nl_destroy_handles(&bss->nl_mgmt);
2666 return -1;
2667}
2668
2669
2670static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
2671{
2672 if (bss->nl_mgmt == NULL)
2673 return;
2674 wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
2675 "(%s)", bss->nl_mgmt, reason);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002676 nl80211_destroy_eloop_handle(&bss->nl_mgmt, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002677
2678 nl80211_put_wiphy_data_ap(bss);
2679}
2680
2681
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002682static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
2683{
2684 wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
2685}
2686
2687
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002688static void nl80211_del_p2pdev(struct i802_bss *bss)
2689{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002690 struct nl_msg *msg;
2691 int ret;
2692
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002693 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
Hai Shalom899fcc72020-10-19 14:38:18 -07002694 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002695
2696 wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
2697 bss->ifname, (long long unsigned int) bss->wdev_id,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002698 strerror(-ret));
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002699}
2700
2701
2702static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
2703{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002704 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002705 int ret;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002706
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002707 msg = nl80211_cmd_msg(bss, 0, start ? NL80211_CMD_START_P2P_DEVICE :
2708 NL80211_CMD_STOP_P2P_DEVICE);
Hai Shalom899fcc72020-10-19 14:38:18 -07002709 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002710
2711 wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
2712 start ? "Start" : "Stop",
2713 bss->ifname, (long long unsigned int) bss->wdev_id,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002714 strerror(-ret));
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002715 return ret;
2716}
2717
2718
2719static int i802_set_iface_flags(struct i802_bss *bss, int up)
2720{
2721 enum nl80211_iftype nlmode;
2722
2723 nlmode = nl80211_get_ifmode(bss);
2724 if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
2725 return linux_set_iface_flags(bss->drv->global->ioctl_sock,
2726 bss->ifname, up);
2727 }
2728
2729 /* P2P Device has start/stop which is equivalent */
2730 return nl80211_set_p2pdev(bss, up);
2731}
2732
2733
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002734#ifdef CONFIG_TESTING_OPTIONS
2735static int qca_vendor_test_cmd_handler(struct nl_msg *msg, void *arg)
2736{
2737 /* struct wpa_driver_nl80211_data *drv = arg; */
2738 struct nlattr *tb[NL80211_ATTR_MAX + 1];
2739 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2740
2741
2742 wpa_printf(MSG_DEBUG,
2743 "nl80211: QCA vendor test command response received");
2744
2745 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2746 genlmsg_attrlen(gnlh, 0), NULL);
2747 if (!tb[NL80211_ATTR_VENDOR_DATA]) {
2748 wpa_printf(MSG_DEBUG, "nl80211: No vendor data attribute");
2749 return NL_SKIP;
2750 }
2751
2752 wpa_hexdump(MSG_DEBUG,
2753 "nl80211: Received QCA vendor test command response",
2754 nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
2755 nla_len(tb[NL80211_ATTR_VENDOR_DATA]));
2756
2757 return NL_SKIP;
2758}
2759#endif /* CONFIG_TESTING_OPTIONS */
2760
2761
2762static void qca_vendor_test(struct wpa_driver_nl80211_data *drv)
2763{
2764#ifdef CONFIG_TESTING_OPTIONS
2765 struct nl_msg *msg;
2766 struct nlattr *params;
2767 int ret;
2768
2769 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
2770 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
2771 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
2772 QCA_NL80211_VENDOR_SUBCMD_TEST) ||
2773 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
2774 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TEST, 123)) {
2775 nlmsg_free(msg);
2776 return;
2777 }
2778 nla_nest_end(msg, params);
2779
Hai Shalom899fcc72020-10-19 14:38:18 -07002780 ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv,
2781 NULL, NULL);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002782 wpa_printf(MSG_DEBUG,
2783 "nl80211: QCA vendor test command returned %d (%s)",
2784 ret, strerror(-ret));
2785#endif /* CONFIG_TESTING_OPTIONS */
2786}
2787
2788
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002789static int
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002790wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002791 const u8 *set_addr, int first,
2792 const char *driver_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002793{
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002794 struct i802_bss *bss = drv->first_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002795 int send_rfkill_event = 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002796 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002797
2798 drv->ifindex = if_nametoindex(bss->ifname);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002799 bss->ifindex = drv->ifindex;
2800 bss->wdev_id = drv->global->if_add_wdevid;
2801 bss->wdev_id_set = drv->global->if_add_wdevid_set;
2802
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002803 bss->if_dynamic = drv->ifindex == drv->global->if_add_ifindex;
2804 bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002805 drv->global->if_add_wdevid_set = 0;
2806
Dmitry Shmidt03658832014-08-13 11:03:49 -07002807 if (!bss->if_dynamic && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
2808 bss->static_ap = 1;
2809
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08002810 if (first &&
2811 nl80211_get_ifmode(bss) != NL80211_IFTYPE_P2P_DEVICE &&
2812 linux_iface_up(drv->global->ioctl_sock, bss->ifname) > 0)
2813 drv->start_iface_up = 1;
2814
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002815 if (wpa_driver_nl80211_capa(drv))
2816 return -1;
2817
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002818 if (driver_params && nl80211_set_param(bss, driver_params) < 0)
2819 return -1;
2820
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002821 wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
2822 bss->ifname, drv->phyname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002823
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002824 if (set_addr &&
2825 (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) ||
2826 linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
2827 set_addr)))
2828 return -1;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002829
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002830 if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
2831 drv->start_mode_ap = 1;
2832
Dmitry Shmidt03658832014-08-13 11:03:49 -07002833 if (drv->hostapd || bss->static_ap)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002834 nlmode = NL80211_IFTYPE_AP;
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07002835 else if (bss->if_dynamic ||
2836 nl80211_get_ifmode(bss) == NL80211_IFTYPE_MESH_POINT)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002837 nlmode = nl80211_get_ifmode(bss);
2838 else
2839 nlmode = NL80211_IFTYPE_STATION;
2840
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002841 if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002842 wpa_printf(MSG_ERROR, "nl80211: Could not configure driver mode");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002843 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002844 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002845
Dmitry Shmidt98660862014-03-11 17:26:21 -07002846 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002847 nl80211_get_macaddr(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002848
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002849 wpa_driver_nl80211_drv_init_rfkill(drv);
2850
Dmitry Shmidt98660862014-03-11 17:26:21 -07002851 if (!rfkill_is_blocked(drv->rfkill)) {
2852 int ret = i802_set_iface_flags(bss, 1);
2853 if (ret) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002854 wpa_printf(MSG_ERROR, "nl80211: Could not set "
2855 "interface '%s' UP", bss->ifname);
Dmitry Shmidt98660862014-03-11 17:26:21 -07002856 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002857 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002858
2859 if (is_p2p_net_interface(nlmode))
2860 nl80211_disable_11b_rates(bss->drv,
2861 bss->drv->ifindex, 1);
2862
Dmitry Shmidt98660862014-03-11 17:26:21 -07002863 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
2864 return ret;
2865 } else {
2866 wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
2867 "interface '%s' due to rfkill", bss->ifname);
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002868 if (nlmode != NL80211_IFTYPE_P2P_DEVICE)
2869 drv->if_disabled = 1;
2870
Dmitry Shmidt98660862014-03-11 17:26:21 -07002871 send_rfkill_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002872 }
2873
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002874 if (!drv->hostapd && nlmode != NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002875 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
2876 1, IF_OPER_DORMANT);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002877
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002878 if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
2879 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
2880 bss->addr))
2881 return -1;
2882 os_memcpy(drv->perm_addr, bss->addr, ETH_ALEN);
2883 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002884
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002885 if (send_rfkill_event) {
2886 eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
2887 drv, drv->ctx);
2888 }
2889
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002890 if (drv->vendor_cmd_test_avail)
2891 qca_vendor_test(drv);
2892
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002893 return 0;
2894}
2895
2896
Paul Stewart092955c2017-02-06 09:13:09 -08002897static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002898{
2899 struct nl_msg *msg;
Paul Stewart092955c2017-02-06 09:13:09 -08002900 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002901
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002902 wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
2903 drv->ifindex);
Paul Stewart092955c2017-02-06 09:13:09 -08002904 nl80211_put_wiphy_data_ap(bss);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002905 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
Hai Shalom899fcc72020-10-19 14:38:18 -07002906 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002907}
2908
2909
2910/**
2911 * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08002912 * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002913 *
2914 * Shut down driver interface and processing of driver events. Free
2915 * private data buffer if one was allocated in wpa_driver_nl80211_init().
2916 */
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08002917static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002918{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002919 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07002920 unsigned int i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002921
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002922 wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
2923 bss->ifname, drv->disabled_11b_rates);
2924
Dmitry Shmidt04949592012-07-19 12:16:46 -07002925 bss->in_deinit = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002926 if (drv->data_tx_status)
2927 eloop_unregister_read_sock(drv->eapol_tx_sock);
2928 if (drv->eapol_tx_sock >= 0)
2929 close(drv->eapol_tx_sock);
2930
2931 if (bss->nl_preq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002932 wpa_driver_nl80211_probe_req_report(bss, 0);
2933 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002934 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
2935 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002936 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
2937 "interface %s from bridge %s: %s",
2938 bss->ifname, bss->brname, strerror(errno));
2939 }
Hai Shalomc9e41a12018-07-31 14:41:42 -07002940
2941 if (drv->rtnl_sk)
Hai Shalomfdcde762020-04-02 11:19:20 -07002942 nl_socket_free(drv->rtnl_sk);
Hai Shalomc9e41a12018-07-31 14:41:42 -07002943
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002944 if (bss->added_bridge) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002945 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
2946 0) < 0)
2947 wpa_printf(MSG_INFO,
2948 "nl80211: Could not set bridge %s down",
2949 bss->brname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002950 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002951 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
2952 "bridge %s: %s",
2953 bss->brname, strerror(errno));
2954 }
2955
2956 nl80211_remove_monitor_interface(drv);
2957
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002958 if (is_ap_interface(drv->nlmode))
Paul Stewart092955c2017-02-06 09:13:09 -08002959 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002960
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002961 if (drv->eapol_sock >= 0) {
2962 eloop_unregister_read_sock(drv->eapol_sock);
2963 close(drv->eapol_sock);
2964 }
2965
2966 if (drv->if_indices != drv->default_if_indices)
2967 os_free(drv->if_indices);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002968
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002969 if (drv->disabled_11b_rates)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002970 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
2971
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002972 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
2973 IF_OPER_UP);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07002974 eloop_cancel_timeout(wpa_driver_nl80211_send_rfkill, drv, drv->ctx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002975 rfkill_deinit(drv->rfkill);
2976
2977 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
2978
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002979 if (!drv->start_iface_up)
2980 (void) i802_set_iface_flags(bss, 0);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002981
2982 if (drv->addr_changed) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002983 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
2984 0) < 0) {
2985 wpa_printf(MSG_DEBUG,
2986 "nl80211: Could not set interface down to restore permanent MAC address");
2987 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002988 if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
2989 drv->perm_addr) < 0) {
2990 wpa_printf(MSG_DEBUG,
2991 "nl80211: Could not restore permanent MAC address");
2992 }
2993 }
2994
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002995 if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002996 if (!drv->hostapd || !drv->start_mode_ap)
2997 wpa_driver_nl80211_set_mode(bss,
2998 NL80211_IFTYPE_STATION);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002999 nl80211_mgmt_unsubscribe(bss, "deinit");
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003000 } else {
3001 nl80211_mgmt_unsubscribe(bss, "deinit");
3002 nl80211_del_p2pdev(bss);
3003 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003004
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003005 nl80211_destroy_bss(drv->first_bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003006
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003007 os_free(drv->filter_ssids);
3008
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003009 os_free(drv->auth_ie);
Hai Shalom60840252021-02-19 19:02:11 -08003010 os_free(drv->auth_data);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003011
3012 if (drv->in_interface_list)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003013 dl_list_del(&drv->list);
3014
Dmitry Shmidt444d5672013-04-01 13:08:44 -07003015 os_free(drv->extended_capa);
3016 os_free(drv->extended_capa_mask);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07003017 for (i = 0; i < drv->num_iface_ext_capa; i++) {
3018 os_free(drv->iface_ext_capa[i].ext_capa);
3019 os_free(drv->iface_ext_capa[i].ext_capa_mask);
3020 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003021 os_free(drv->first_bss);
Hai Shalom60840252021-02-19 19:02:11 -08003022#ifdef CONFIG_DRIVER_NL80211_QCA
3023 os_free(drv->pending_roam_data);
3024#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003025 os_free(drv);
3026}
3027
3028
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003029static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len)
3030{
3031 switch (alg) {
3032 case WPA_ALG_WEP:
3033 if (key_len == 5)
Paul Stewart092955c2017-02-06 09:13:09 -08003034 return RSN_CIPHER_SUITE_WEP40;
3035 return RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003036 case WPA_ALG_TKIP:
Paul Stewart092955c2017-02-06 09:13:09 -08003037 return RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003038 case WPA_ALG_CCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003039 return RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003040 case WPA_ALG_GCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003041 return RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003042 case WPA_ALG_CCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003043 return RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003044 case WPA_ALG_GCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003045 return RSN_CIPHER_SUITE_GCMP_256;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003046 case WPA_ALG_BIP_CMAC_128:
Paul Stewart092955c2017-02-06 09:13:09 -08003047 return RSN_CIPHER_SUITE_AES_128_CMAC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003048 case WPA_ALG_BIP_GMAC_128:
Paul Stewart092955c2017-02-06 09:13:09 -08003049 return RSN_CIPHER_SUITE_BIP_GMAC_128;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003050 case WPA_ALG_BIP_GMAC_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003051 return RSN_CIPHER_SUITE_BIP_GMAC_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003052 case WPA_ALG_BIP_CMAC_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003053 return RSN_CIPHER_SUITE_BIP_CMAC_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003054 case WPA_ALG_SMS4:
Paul Stewart092955c2017-02-06 09:13:09 -08003055 return RSN_CIPHER_SUITE_SMS4;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003056 case WPA_ALG_KRK:
Paul Stewart092955c2017-02-06 09:13:09 -08003057 return RSN_CIPHER_SUITE_KRK;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003058 case WPA_ALG_NONE:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003059 wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d",
3060 alg);
3061 return 0;
3062 }
3063
3064 wpa_printf(MSG_ERROR, "nl80211: Unsupported encryption algorithm %d",
3065 alg);
3066 return 0;
3067}
3068
3069
3070static u32 wpa_cipher_to_cipher_suite(unsigned int cipher)
3071{
3072 switch (cipher) {
3073 case WPA_CIPHER_CCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003074 return RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003075 case WPA_CIPHER_GCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003076 return RSN_CIPHER_SUITE_GCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003077 case WPA_CIPHER_CCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003078 return RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003079 case WPA_CIPHER_GCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003080 return RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003081 case WPA_CIPHER_TKIP:
Paul Stewart092955c2017-02-06 09:13:09 -08003082 return RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003083 case WPA_CIPHER_WEP104:
Paul Stewart092955c2017-02-06 09:13:09 -08003084 return RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003085 case WPA_CIPHER_WEP40:
Paul Stewart092955c2017-02-06 09:13:09 -08003086 return RSN_CIPHER_SUITE_WEP40;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003087 case WPA_CIPHER_GTK_NOT_USED:
Paul Stewart092955c2017-02-06 09:13:09 -08003088 return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003089 }
3090
3091 return 0;
3092}
3093
3094
3095static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[],
3096 int max_suites)
3097{
3098 int num_suites = 0;
3099
3100 if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP_256)
Paul Stewart092955c2017-02-06 09:13:09 -08003101 suites[num_suites++] = RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003102 if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP_256)
Paul Stewart092955c2017-02-06 09:13:09 -08003103 suites[num_suites++] = RSN_CIPHER_SUITE_GCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003104 if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP)
Paul Stewart092955c2017-02-06 09:13:09 -08003105 suites[num_suites++] = RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003106 if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP)
Paul Stewart092955c2017-02-06 09:13:09 -08003107 suites[num_suites++] = RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003108 if (num_suites < max_suites && ciphers & WPA_CIPHER_TKIP)
Paul Stewart092955c2017-02-06 09:13:09 -08003109 suites[num_suites++] = RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003110 if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP104)
Paul Stewart092955c2017-02-06 09:13:09 -08003111 suites[num_suites++] = RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003112 if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP40)
Paul Stewart092955c2017-02-06 09:13:09 -08003113 suites[num_suites++] = RSN_CIPHER_SUITE_WEP40;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003114
3115 return num_suites;
3116}
3117
3118
Hai Shalomfdcde762020-04-02 11:19:20 -07003119static int wpa_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
3120 int max_suites)
3121{
3122 int num_suites = 0;
3123
3124#define __AKM(a, b) \
3125 if (num_suites < max_suites && \
3126 (key_mgmt_suites & (WPA_KEY_MGMT_ ## a))) \
3127 suites[num_suites++] = (RSN_AUTH_KEY_MGMT_ ## b)
3128 __AKM(IEEE8021X, UNSPEC_802_1X);
3129 __AKM(PSK, PSK_OVER_802_1X);
3130 __AKM(FT_IEEE8021X, FT_802_1X);
3131 __AKM(FT_PSK, FT_PSK);
3132 __AKM(IEEE8021X_SHA256, 802_1X_SHA256);
3133 __AKM(PSK_SHA256, PSK_SHA256);
3134 __AKM(SAE, SAE);
3135 __AKM(FT_SAE, FT_SAE);
3136 __AKM(CCKM, CCKM);
3137 __AKM(OSEN, OSEN);
3138 __AKM(IEEE8021X_SUITE_B, 802_1X_SUITE_B);
3139 __AKM(IEEE8021X_SUITE_B_192, 802_1X_SUITE_B_192);
3140 __AKM(FILS_SHA256, FILS_SHA256);
3141 __AKM(FILS_SHA384, FILS_SHA384);
3142 __AKM(FT_FILS_SHA256, FT_FILS_SHA256);
3143 __AKM(FT_FILS_SHA384, FT_FILS_SHA384);
3144 __AKM(OWE, OWE);
3145 __AKM(DPP, DPP);
3146 __AKM(FT_IEEE8021X_SHA384, FT_802_1X_SHA384);
3147#undef __AKM
3148
3149 return num_suites;
3150}
3151
Ajay Davanagerib921bb82020-09-16 12:49:08 +05303152#ifdef CONFIG_DRIVER_NL80211_BRCM
3153static int wpa_driver_do_broadcom_acs(void *priv, struct drv_acs_params
3154 *params)
3155{
3156 struct i802_bss *bss = priv;
3157 struct wpa_driver_nl80211_data *drv = bss->drv;
3158 struct nl_msg *msg;
3159 struct nlattr *data;
3160 int freq_list_len;
3161 int ret = 0;
3162 do {
3163 freq_list_len =
3164 int_array_len(params->freq_list);
3165 wpa_printf(MSG_DEBUG, "%s: freq_list_len=%d",
3166 __FUNCTION__, freq_list_len);
3167 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
3168 if (!msg) {
3169 wpa_printf(MSG_ERROR, "%s: *errof, no memory for msg", __FUNCTION__);
3170 return ret;
3171 }
3172 if ((nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM))) {
3173 wpa_printf(MSG_ERROR, "%s: *errof, NL80211_ATTR_VENDOR_ID",
3174 __FUNCTION__);
3175 nlmsg_free(msg);
3176 return ret;
3177 }
3178
3179 if ((nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, BRCM_VENDOR_SCMD_ACS))) {
3180 wpa_printf(MSG_ERROR, "%s: *errof, NL80211_ATTR_VENDOR_SUBCMD",
3181 __FUNCTION__);
3182 nlmsg_free(msg);
3183 return ret;
3184 }
3185 if (!(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA))) {
3186 wpa_printf(MSG_ERROR, "%s: *errof, NL80211_ATTR_VENDOR_DATA", __FUNCTION__);
3187 nlmsg_free(msg);
3188 return ret;
3189 }
3190 if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HW_MODE, params->hw_mode))) {
3191 wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_HW_MODE",
3192 __FUNCTION__);
3193 nlmsg_free(msg);
3194 return ret;
3195 }
3196 if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT_ENABLED, params->ht_enabled))) {
3197 wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_HT_ENABLED",
3198 __FUNCTION__);
3199 nlmsg_free(msg);
3200 return ret;
3201 }
3202 if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED, params->ht40_enabled))) {
3203 wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED",
3204 __FUNCTION__);
3205 nlmsg_free(msg);
3206 return ret;
3207 }
3208 if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED, params->vht_enabled))) {
3209 wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED",
3210 __FUNCTION__);
3211 nlmsg_free(msg);
3212 return ret;
3213 }
3214 if ((nla_put_u16(msg, BRCM_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width))) {
3215 wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_CHWIDTH",
3216 __FUNCTION__);
3217 nlmsg_free(msg);
3218 return ret;
3219 }
3220 wpa_printf(MSG_DEBUG, "%s: ht40=%d, ch_width=%d\n",
3221 __FUNCTION__, params->ht40_enabled, params->ch_width);
3222 if ((freq_list_len > 0) && (nla_put(msg, BRCM_VENDOR_ATTR_ACS_FREQ_LIST,
3223 sizeof(int) * freq_list_len, params->freq_list))) {
3224 wpa_printf(MSG_ERROR, "%s: *error, BRCM_VENDOR_ATTR_ACS_FREQ_LIST,"
3225 "list_len=%d\n", __FUNCTION__, freq_list_len);
3226 nlmsg_free(msg);
3227 return ret;
3228 }
3229 nla_nest_end(msg, data);
3230 wpa_printf(MSG_DEBUG, "nl80211: ACS Params: HW_MODE: %d HT: %d HT40:"
3231 " %d VHT: %d BW: %d\n",
3232 params->hw_mode, params->ht_enabled, params->ht40_enabled,
3233 params->vht_enabled, params->ch_width);
Ahmed ElArabawy73c89ee2020-10-22 16:09:08 -07003234 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Ajay Davanagerib921bb82020-09-16 12:49:08 +05303235 if (ret) {
3236 wpa_printf(MSG_ERROR, "nl80211: Failed to invoke vendor"
3237 " driver ACS function: %s\n",
3238 strerror(errno));
3239 }
3240 } while (0);
3241 return ret;
3242}
3243#endif /* CONFIG_DRIVER_NL80211_BRCM */
Hai Shalomfdcde762020-04-02 11:19:20 -07003244
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003245#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003246static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
3247 const u8 *key, size_t key_len)
3248{
3249 struct nl_msg *msg;
3250 int ret;
3251
3252 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
3253 return 0;
3254
3255 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
3256 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
3257 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
3258 QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY) ||
3259 nla_put(msg, NL80211_ATTR_VENDOR_DATA, key_len, key)) {
3260 nl80211_nlmsg_clear(msg);
3261 nlmsg_free(msg);
3262 return -1;
3263 }
Hai Shalom60840252021-02-19 19:02:11 -08003264 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003265 if (ret) {
3266 wpa_printf(MSG_DEBUG,
3267 "nl80211: Key management set key failed: ret=%d (%s)",
3268 ret, strerror(-ret));
3269 }
3270
3271 return ret;
3272}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003273#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003274
3275
Mir Ali677e7482020-11-12 19:49:02 +05303276#ifdef CONFIG_DRIVER_NL80211_BRCM
3277static int key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
3278 const u8 *key, size_t key_len)
3279{
3280 struct nl_msg *msg;
3281 int ret;
3282 struct nlattr *params;
3283
3284 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
3285 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
3286 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
3287 BRCM_VENDOR_SUBCMD_SET_PMK) ||
3288 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
3289 nla_put(msg, BRCM_ATTR_DRIVER_KEY_PMK, key_len, key)) {
3290 nl80211_nlmsg_clear(msg);
3291 nlmsg_free(msg);
3292 return -ENOBUFS;
3293 }
3294 nla_nest_end(msg, params);
3295
3296 ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
3297 if (ret) {
3298 wpa_printf(MSG_DEBUG, "nl80211: Key mgmt set key failed: ret=%d (%s)",
3299 ret, strerror(-ret));
3300 }
3301
3302 return ret;
3303}
3304#endif /* CONFIG_DRIVER_NL80211_BRCM */
3305
Roshan Pius3a1667e2018-07-03 15:17:14 -07003306static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
3307 const u8 *key, size_t key_len,
3308 const u8 *addr)
3309{
3310 struct nl_msg *msg = NULL;
3311 int ret;
3312
3313 /*
3314 * If the authenticator address is not set, assume it is
3315 * the current BSSID.
3316 */
3317 if (!addr && drv->associated)
3318 addr = drv->bssid;
3319 else if (!addr)
3320 return -1;
3321
3322 wpa_printf(MSG_DEBUG, "nl80211: Set PMK to the driver for " MACSTR,
3323 MAC2STR(addr));
3324 wpa_hexdump_key(MSG_DEBUG, "nl80211: PMK", key, key_len);
3325 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_PMK);
3326 if (!msg ||
3327 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
3328 nla_put(msg, NL80211_ATTR_PMK, key_len, key)) {
3329 nl80211_nlmsg_clear(msg);
3330 nlmsg_free(msg);
3331 return -ENOBUFS;
3332 }
3333
Hai Shalom60840252021-02-19 19:02:11 -08003334 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003335 if (ret) {
3336 wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)",
3337 ret, strerror(-ret));
3338 }
3339
3340 return ret;
3341}
3342
3343
Hai Shalomfdcde762020-04-02 11:19:20 -07003344static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
3345 struct wpa_driver_set_key_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003346{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003347 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003348 int ifindex;
Hai Shalomc3565922019-10-28 11:58:20 -07003349 struct nl_msg *msg;
3350 struct nl_msg *key_msg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003351 int ret;
Hai Shalomfdcde762020-04-02 11:19:20 -07003352 int skip_set_key = 1;
3353 const char *ifname = params->ifname;
3354 enum wpa_alg alg = params->alg;
3355 const u8 *addr = params->addr;
3356 int key_idx = params->key_idx;
3357 int set_tx = params->set_tx;
3358 const u8 *seq = params->seq;
3359 size_t seq_len = params->seq_len;
3360 const u8 *key = params->key;
3361 size_t key_len = params->key_len;
3362 int vlan_id = params->vlan_id;
3363 enum key_flag key_flag = params->key_flag;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003364
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003365 /* Ignore for P2P Device */
3366 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
3367 return 0;
3368
3369 ifindex = if_nametoindex(ifname);
3370 wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
Hai Shalomfdcde762020-04-02 11:19:20 -07003371 "set_tx=%d seq_len=%lu key_len=%lu key_flag=0x%x",
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003372 __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
Hai Shalomfdcde762020-04-02 11:19:20 -07003373 (unsigned long) seq_len, (unsigned long) key_len, key_flag);
3374
3375 if (check_key_flag(key_flag)) {
3376 wpa_printf(MSG_DEBUG, "%s: invalid key_flag", __func__);
3377 return -EINVAL;
Dmitry Shmidtd5c075b2013-08-05 14:36:10 -07003378 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003379
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003380#ifdef CONFIG_DRIVER_NL80211_QCA
Hai Shalomfdcde762020-04-02 11:19:20 -07003381 if ((key_flag & KEY_FLAG_PMK) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003382 (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
3383 wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
3384 __func__);
3385 ret = issue_key_mgmt_set_key(drv, key, key_len);
3386 return ret;
3387 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003388#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003389
Hai Shalomfdcde762020-04-02 11:19:20 -07003390 if (key_flag & KEY_FLAG_PMK) {
3391 if (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)
3392 return nl80211_set_pmk(drv, key, key_len, addr);
Mir Ali677e7482020-11-12 19:49:02 +05303393#ifdef CONFIG_DRIVER_NL80211_BRCM
3394 if (drv->vendor_set_pmk) {
Jay Patel731adae2021-02-17 14:55:58 -08003395 wpa_printf(MSG_INFO, "nl80211: key_mgmt_set_key with key_len %lu", (unsigned long) key_len);
Mir Ali677e7482020-11-12 19:49:02 +05303396 return key_mgmt_set_key(drv, key, key_len);
3397 }
3398#endif /* CONFIG_DRIVER_NL80211_BRCM */
Hai Shalomfdcde762020-04-02 11:19:20 -07003399 /* The driver does not have any offload mechanism for PMK, so
3400 * there is no need to configure this key. */
3401 return 0;
3402 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003403
Hai Shalomfdcde762020-04-02 11:19:20 -07003404 ret = -ENOBUFS;
Hai Shalomc3565922019-10-28 11:58:20 -07003405 key_msg = nlmsg_alloc();
3406 if (!key_msg)
Hai Shalomfdcde762020-04-02 11:19:20 -07003407 return ret;
Hai Shalomc3565922019-10-28 11:58:20 -07003408
Hai Shalomfdcde762020-04-02 11:19:20 -07003409 if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3410 KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
3411 wpa_printf(MSG_DEBUG,
3412 "nl80211: SET_KEY (pairwise RX/TX modify)");
3413 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
3414 if (!msg)
3415 goto fail2;
3416 } else if (alg == WPA_ALG_NONE && (key_flag & KEY_FLAG_RX_TX)) {
3417 wpa_printf(MSG_DEBUG, "%s: invalid key_flag to delete key",
3418 __func__);
3419 ret = -EINVAL;
3420 goto fail2;
3421 } else if (alg == WPA_ALG_NONE) {
3422 wpa_printf(MSG_DEBUG, "nl80211: DEL_KEY");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003423 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
3424 if (!msg)
Hai Shalomc3565922019-10-28 11:58:20 -07003425 goto fail2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003426 } else {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003427 u32 suite;
3428
3429 suite = wpa_alg_to_cipher_suite(alg, key_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07003430 if (!suite) {
3431 ret = -EINVAL;
Hai Shalomc3565922019-10-28 11:58:20 -07003432 goto fail2;
Hai Shalomfdcde762020-04-02 11:19:20 -07003433 }
3434 wpa_printf(MSG_DEBUG, "nl80211: NEW_KEY");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003435 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
Hai Shalomc3565922019-10-28 11:58:20 -07003436 if (!msg)
3437 goto fail2;
3438 if (nla_put(key_msg, NL80211_KEY_DATA, key_len, key) ||
3439 nla_put_u32(key_msg, NL80211_KEY_CIPHER, suite))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003440 goto fail;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003441 wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003442
Hai Shalomfdcde762020-04-02 11:19:20 -07003443 if (seq && seq_len) {
3444 if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq))
3445 goto fail;
3446 wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ",
3447 seq, seq_len);
3448 }
Dmitry Shmidt98660862014-03-11 17:26:21 -07003449 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003450
3451 if (addr && !is_broadcast_ether_addr(addr)) {
3452 wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003453 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
3454 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003455
Hai Shalomfdcde762020-04-02 11:19:20 -07003456 if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3457 KEY_FLAG_PAIRWISE_RX ||
3458 (key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3459 KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
3460 if (nla_put_u8(key_msg, NL80211_KEY_MODE,
3461 key_flag == KEY_FLAG_PAIRWISE_RX ?
3462 NL80211_KEY_NO_TX : NL80211_KEY_SET_TX))
3463 goto fail;
3464 } else if ((key_flag & KEY_FLAG_GROUP_MASK) ==
3465 KEY_FLAG_GROUP_RX) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003466 wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
Hai Shalomc3565922019-10-28 11:58:20 -07003467 if (nla_put_u32(key_msg, NL80211_KEY_TYPE,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003468 NL80211_KEYTYPE_GROUP))
3469 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003470 } else if (!(key_flag & KEY_FLAG_PAIRWISE)) {
3471 wpa_printf(MSG_DEBUG,
3472 " key_flag missing PAIRWISE when setting a pairwise key");
3473 ret = -EINVAL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003474 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003475 } else if (alg == WPA_ALG_WEP &&
3476 (key_flag & KEY_FLAG_RX_TX) == KEY_FLAG_RX_TX) {
3477 wpa_printf(MSG_DEBUG, " unicast WEP key");
3478 skip_set_key = 0;
3479 } else {
3480 wpa_printf(MSG_DEBUG, " pairwise key");
3481 }
3482 } else if ((key_flag & KEY_FLAG_PAIRWISE) ||
3483 !(key_flag & KEY_FLAG_GROUP)) {
3484 wpa_printf(MSG_DEBUG,
3485 " invalid key_flag for a broadcast key");
3486 ret = -EINVAL;
3487 goto fail;
3488 } else {
3489 wpa_printf(MSG_DEBUG, " broadcast key");
3490 if (key_flag & KEY_FLAG_DEFAULT)
3491 skip_set_key = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003492 }
Hai Shalomc3565922019-10-28 11:58:20 -07003493 if (nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
3494 nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003495 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003496 nl80211_nlmsg_clear(key_msg);
3497 nlmsg_free(key_msg);
3498 key_msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003499
Hai Shalomfdcde762020-04-02 11:19:20 -07003500 if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
3501 wpa_printf(MSG_DEBUG, "nl80211: VLAN ID %d", vlan_id);
3502 if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
3503 goto fail;
3504 }
3505
Hai Shalom60840252021-02-19 19:02:11 -08003506 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003507 if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
3508 ret = 0;
3509 if (ret)
Hai Shalomfdcde762020-04-02 11:19:20 -07003510 wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003511 ret, strerror(-ret));
3512
3513 /*
Hai Shalomfdcde762020-04-02 11:19:20 -07003514 * If we failed or don't need to set the key as default (below),
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003515 * we're done here.
3516 */
Hai Shalomfdcde762020-04-02 11:19:20 -07003517 if (ret || skip_set_key)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003518 return ret;
Hai Shalomfdcde762020-04-02 11:19:20 -07003519 wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_SET_KEY - default key");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003520
Hai Shalomfdcde762020-04-02 11:19:20 -07003521 ret = -ENOBUFS;
Hai Shalomc3565922019-10-28 11:58:20 -07003522 key_msg = nlmsg_alloc();
3523 if (!key_msg)
Hai Shalomfdcde762020-04-02 11:19:20 -07003524 return ret;
Hai Shalomc3565922019-10-28 11:58:20 -07003525
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003526 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
Hai Shalomc3565922019-10-28 11:58:20 -07003527 if (!msg)
3528 goto fail2;
3529 if (!key_msg ||
3530 nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003531 nla_put_flag(key_msg, wpa_alg_bip(alg) ?
Hai Shalomfdcde762020-04-02 11:19:20 -07003532 (key_idx == 6 || key_idx == 7 ?
3533 NL80211_KEY_DEFAULT_BEACON :
3534 NL80211_KEY_DEFAULT_MGMT) :
3535 NL80211_KEY_DEFAULT))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003536 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003537 if (addr && is_broadcast_ether_addr(addr)) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003538 struct nlattr *types;
3539
Hai Shalomc3565922019-10-28 11:58:20 -07003540 types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003541 if (!types ||
Hai Shalomc3565922019-10-28 11:58:20 -07003542 nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003543 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003544 nla_nest_end(key_msg, types);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003545 } else if (addr) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003546 struct nlattr *types;
3547
Hai Shalomc3565922019-10-28 11:58:20 -07003548 types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003549 if (!types ||
Hai Shalomc3565922019-10-28 11:58:20 -07003550 nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003551 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003552 nla_nest_end(key_msg, types);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003553 }
3554
Hai Shalomc3565922019-10-28 11:58:20 -07003555 if (nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
3556 goto fail;
3557 nl80211_nlmsg_clear(key_msg);
3558 nlmsg_free(key_msg);
3559 key_msg = NULL;
3560
Hai Shalomfdcde762020-04-02 11:19:20 -07003561 if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
3562 wpa_printf(MSG_DEBUG, "nl80211: set_key default - VLAN ID %d",
3563 vlan_id);
3564 if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
3565 goto fail;
3566 }
3567
Hai Shalom899fcc72020-10-19 14:38:18 -07003568 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003569 if (ret)
Hai Shalomfdcde762020-04-02 11:19:20 -07003570 wpa_printf(MSG_DEBUG,
3571 "nl80211: set_key default failed; err=%d %s",
3572 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003573 return ret;
3574
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003575fail:
3576 nl80211_nlmsg_clear(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003577 nlmsg_free(msg);
Hai Shalomc3565922019-10-28 11:58:20 -07003578fail2:
3579 nl80211_nlmsg_clear(key_msg);
3580 nlmsg_free(key_msg);
Hai Shalomfdcde762020-04-02 11:19:20 -07003581 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003582}
3583
3584
3585static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
3586 int key_idx, int defkey,
3587 const u8 *seq, size_t seq_len,
3588 const u8 *key, size_t key_len)
3589{
3590 struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003591 u32 suite;
3592
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003593 if (!key_attr)
3594 return -1;
3595
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003596 suite = wpa_alg_to_cipher_suite(alg, key_len);
3597 if (!suite)
3598 return -1;
3599
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003600 if (defkey && wpa_alg_bip(alg)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003601 if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT))
3602 return -1;
3603 } else if (defkey) {
3604 if (nla_put_flag(msg, NL80211_KEY_DEFAULT))
3605 return -1;
3606 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003607
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003608 if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) ||
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003609 nla_put_u32(msg, NL80211_KEY_CIPHER, suite) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003610 (seq && seq_len &&
3611 nla_put(msg, NL80211_KEY_SEQ, seq_len, seq)) ||
3612 nla_put(msg, NL80211_KEY_DATA, key_len, key))
3613 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003614
3615 nla_nest_end(msg, key_attr);
3616
3617 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003618}
3619
3620
3621static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
3622 struct nl_msg *msg)
3623{
3624 int i, privacy = 0;
3625 struct nlattr *nl_keys, *nl_key;
3626
3627 for (i = 0; i < 4; i++) {
3628 if (!params->wep_key[i])
3629 continue;
3630 privacy = 1;
3631 break;
3632 }
3633 if (params->wps == WPS_MODE_PRIVACY)
3634 privacy = 1;
3635 if (params->pairwise_suite &&
3636 params->pairwise_suite != WPA_CIPHER_NONE)
3637 privacy = 1;
3638
3639 if (!privacy)
3640 return 0;
3641
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003642 if (nla_put_flag(msg, NL80211_ATTR_PRIVACY))
3643 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003644
3645 nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
3646 if (!nl_keys)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003647 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003648
3649 for (i = 0; i < 4; i++) {
3650 if (!params->wep_key[i])
3651 continue;
3652
3653 nl_key = nla_nest_start(msg, i);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003654 if (!nl_key ||
3655 nla_put(msg, NL80211_KEY_DATA, params->wep_key_len[i],
3656 params->wep_key[i]) ||
3657 nla_put_u32(msg, NL80211_KEY_CIPHER,
3658 params->wep_key_len[i] == 5 ?
Paul Stewart092955c2017-02-06 09:13:09 -08003659 RSN_CIPHER_SUITE_WEP40 :
3660 RSN_CIPHER_SUITE_WEP104) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003661 nla_put_u8(msg, NL80211_KEY_IDX, i) ||
3662 (i == params->wep_tx_keyidx &&
3663 nla_put_flag(msg, NL80211_KEY_DEFAULT)))
3664 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003665
3666 nla_nest_end(msg, nl_key);
3667 }
3668 nla_nest_end(msg, nl_keys);
3669
3670 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003671}
3672
3673
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003674int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
3675 const u8 *addr, int cmd, u16 reason_code,
Hai Shalom74f70d42019-02-11 14:42:39 -08003676 int local_state_change,
Hai Shalomfdcde762020-04-02 11:19:20 -07003677 struct nl_sock *nl_connect)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003678{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003679 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003680 struct nl_msg *msg;
3681
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 Shalom899fcc72020-10-19 14:38:18 -07003692 ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL,
3693 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 Shalomfdcde762020-04-02 11:19:20 -07003707 struct nl_sock *nl_connect)
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 Shalom74f70d42019-02-11 14:42:39 -08003716 reason_code, 0, nl_connect);
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 Shalom74f70d42019-02-11 14:42:39 -08003739 return wpa_driver_nl80211_disconnect(drv, reason_code,
Hai Shalomb755a2a2020-04-23 21:49:02 -07003740 get_connect_handle(bss));
Hai Shalom74f70d42019-02-11 14:42:39 -08003741 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003742 wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
3743 __func__, MAC2STR(addr), reason_code);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003744 nl80211_mark_disconnected(drv);
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003745 ret = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
Hai Shalomb755a2a2020-04-23 21:49:02 -07003746 reason_code, 0, get_connect_handle(bss));
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003747 /*
3748 * For locally generated deauthenticate, supplicant already generates a
3749 * DEAUTH event, so ignore the event from NL80211.
3750 */
Hai Shalomce48b4a2018-09-05 11:41:35 -07003751 drv->ignore_next_local_deauth = drv_associated && (ret == 0);
3752
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003753 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003754}
3755
3756
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003757static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
3758 struct wpa_driver_auth_params *params)
3759{
3760 int i;
3761
3762 drv->auth_freq = params->freq;
3763 drv->auth_alg = params->auth_alg;
3764 drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
3765 drv->auth_local_state_change = params->local_state_change;
3766 drv->auth_p2p = params->p2p;
3767
3768 if (params->bssid)
3769 os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
3770 else
3771 os_memset(drv->auth_bssid_, 0, ETH_ALEN);
3772
3773 if (params->ssid) {
3774 os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
3775 drv->auth_ssid_len = params->ssid_len;
3776 } else
3777 drv->auth_ssid_len = 0;
3778
3779
3780 os_free(drv->auth_ie);
3781 drv->auth_ie = NULL;
3782 drv->auth_ie_len = 0;
3783 if (params->ie) {
3784 drv->auth_ie = os_malloc(params->ie_len);
3785 if (drv->auth_ie) {
3786 os_memcpy(drv->auth_ie, params->ie, params->ie_len);
3787 drv->auth_ie_len = params->ie_len;
3788 }
3789 }
3790
Hai Shalom60840252021-02-19 19:02:11 -08003791 os_free(drv->auth_data);
3792 drv->auth_data = NULL;
3793 drv->auth_data_len = 0;
3794 if (params->auth_data) {
3795 drv->auth_data = os_memdup(params->auth_data,
3796 params->auth_data_len);
3797 if (drv->auth_data)
3798 drv->auth_data_len = params->auth_data_len;
3799 }
3800
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003801 for (i = 0; i < 4; i++) {
3802 if (params->wep_key[i] && params->wep_key_len[i] &&
3803 params->wep_key_len[i] <= 16) {
3804 os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
3805 params->wep_key_len[i]);
3806 drv->auth_wep_key_len[i] = params->wep_key_len[i];
3807 } else
3808 drv->auth_wep_key_len[i] = 0;
3809 }
3810}
3811
3812
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003813static void nl80211_unmask_11b_rates(struct i802_bss *bss)
3814{
3815 struct wpa_driver_nl80211_data *drv = bss->drv;
3816
3817 if (is_p2p_net_interface(drv->nlmode) || !drv->disabled_11b_rates)
3818 return;
3819
3820 /*
3821 * Looks like we failed to unmask 11b rates previously. This could
3822 * happen, e.g., if the interface was down at the point in time when a
3823 * P2P group was terminated.
3824 */
3825 wpa_printf(MSG_DEBUG,
3826 "nl80211: Interface %s mode is for non-P2P, but 11b rates were disabled - re-enable them",
3827 bss->ifname);
3828 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
3829}
3830
3831
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003832static enum nl80211_auth_type get_nl_auth_type(int wpa_auth_alg)
3833{
3834 if (wpa_auth_alg & WPA_AUTH_ALG_OPEN)
3835 return NL80211_AUTHTYPE_OPEN_SYSTEM;
3836 if (wpa_auth_alg & WPA_AUTH_ALG_SHARED)
3837 return NL80211_AUTHTYPE_SHARED_KEY;
3838 if (wpa_auth_alg & WPA_AUTH_ALG_LEAP)
3839 return NL80211_AUTHTYPE_NETWORK_EAP;
3840 if (wpa_auth_alg & WPA_AUTH_ALG_FT)
3841 return NL80211_AUTHTYPE_FT;
3842 if (wpa_auth_alg & WPA_AUTH_ALG_SAE)
3843 return NL80211_AUTHTYPE_SAE;
3844 if (wpa_auth_alg & WPA_AUTH_ALG_FILS)
3845 return NL80211_AUTHTYPE_FILS_SK;
3846 if (wpa_auth_alg & WPA_AUTH_ALG_FILS_SK_PFS)
3847 return NL80211_AUTHTYPE_FILS_SK_PFS;
3848
3849 return NL80211_AUTHTYPE_MAX;
3850}
3851
3852
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003853static int wpa_driver_nl80211_authenticate(
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003854 struct i802_bss *bss, struct wpa_driver_auth_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003855{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003856 struct wpa_driver_nl80211_data *drv = bss->drv;
3857 int ret = -1, i;
3858 struct nl_msg *msg;
3859 enum nl80211_auth_type type;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003860 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003861 int count = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003862 int is_retry;
Hai Shalomfdcde762020-04-02 11:19:20 -07003863 struct wpa_driver_set_key_params p;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003864
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003865 nl80211_unmask_11b_rates(bss);
3866
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003867 is_retry = drv->retry_auth;
3868 drv->retry_auth = 0;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003869 drv->ignore_deauth_event = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003870
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003871 nl80211_mark_disconnected(drv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003872 os_memset(drv->auth_bssid, 0, ETH_ALEN);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003873 if (params->bssid)
3874 os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
3875 else
3876 os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003877 /* FIX: IBSS mode */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003878 nlmode = params->p2p ?
3879 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
3880 if (drv->nlmode != nlmode &&
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003881 wpa_driver_nl80211_set_mode(bss, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003882 return -1;
3883
3884retry:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003885 wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
3886 drv->ifindex);
3887
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003888 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_AUTHENTICATE);
3889 if (!msg)
3890 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003891
Hai Shalomfdcde762020-04-02 11:19:20 -07003892 os_memset(&p, 0, sizeof(p));
3893 p.ifname = bss->ifname;
3894 p.alg = WPA_ALG_WEP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003895 for (i = 0; i < 4; i++) {
3896 if (!params->wep_key[i])
3897 continue;
Hai Shalomfdcde762020-04-02 11:19:20 -07003898 p.key_idx = i;
3899 p.set_tx = i == params->wep_tx_keyidx;
3900 p.key = params->wep_key[i];
3901 p.key_len = params->wep_key_len[i];
3902 p.key_flag = i == params->wep_tx_keyidx ?
3903 KEY_FLAG_GROUP_RX_TX_DEFAULT :
3904 KEY_FLAG_GROUP_RX_TX;
3905 wpa_driver_nl80211_set_key(bss, &p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003906 if (params->wep_tx_keyidx != i)
3907 continue;
3908 if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003909 params->wep_key[i], params->wep_key_len[i]))
3910 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003911 }
3912
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003913 if (params->bssid) {
3914 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
3915 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003916 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
3917 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003918 }
3919 if (params->freq) {
3920 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003921 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
3922 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003923 }
3924 if (params->ssid) {
Hai Shalom74f70d42019-02-11 14:42:39 -08003925 wpa_printf(MSG_DEBUG, " * SSID=%s",
3926 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003927 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
3928 params->ssid))
3929 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003930 }
3931 wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003932 if (params->ie &&
3933 nla_put(msg, NL80211_ATTR_IE, params->ie_len, params->ie))
3934 goto fail;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003935 if (params->auth_data) {
3936 wpa_hexdump(MSG_DEBUG, " * auth_data", params->auth_data,
3937 params->auth_data_len);
3938 if (nla_put(msg, NL80211_ATTR_SAE_DATA, params->auth_data_len,
3939 params->auth_data))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003940 goto fail;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003941 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003942 type = get_nl_auth_type(params->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003943 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003944 if (type == NL80211_AUTHTYPE_MAX ||
3945 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003946 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003947 if (params->local_state_change) {
3948 wpa_printf(MSG_DEBUG, " * Local state change only");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003949 if (nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))
3950 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003951 }
3952
Hai Shalom899fcc72020-10-19 14:38:18 -07003953 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003954 msg = NULL;
3955 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003956 wpa_dbg(drv->ctx, MSG_DEBUG,
Roshan Pius3a1667e2018-07-03 15:17:14 -07003957 "nl80211: MLME command failed (auth): count=%d ret=%d (%s)",
3958 count, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003959 count++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003960 if ((ret == -EALREADY || ret == -EEXIST) && count == 1 &&
3961 params->bssid && !params->local_state_change) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003962 /*
3963 * mac80211 does not currently accept new
3964 * authentication if we are already authenticated. As a
3965 * workaround, force deauthentication and try again.
3966 */
3967 wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
3968 "after forced deauthentication");
Dmitry Shmidt98660862014-03-11 17:26:21 -07003969 drv->ignore_deauth_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003970 wpa_driver_nl80211_deauthenticate(
3971 bss, params->bssid,
3972 WLAN_REASON_PREV_AUTH_NOT_VALID);
3973 nlmsg_free(msg);
3974 goto retry;
3975 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003976
3977 if (ret == -ENOENT && params->freq && !is_retry) {
3978 /*
3979 * cfg80211 has likely expired the BSS entry even
3980 * though it was previously available in our internal
3981 * BSS table. To recover quickly, start a single
3982 * channel scan on the specified channel.
3983 */
3984 struct wpa_driver_scan_params scan;
3985 int freqs[2];
3986
3987 os_memset(&scan, 0, sizeof(scan));
3988 scan.num_ssids = 1;
3989 if (params->ssid) {
3990 scan.ssids[0].ssid = params->ssid;
3991 scan.ssids[0].ssid_len = params->ssid_len;
3992 }
3993 freqs[0] = params->freq;
3994 freqs[1] = 0;
3995 scan.freqs = freqs;
3996 wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
3997 "channel scan to refresh cfg80211 BSS "
3998 "entry");
3999 ret = wpa_driver_nl80211_scan(bss, &scan);
4000 if (ret == 0) {
4001 nl80211_copy_auth_params(drv, params);
4002 drv->scan_for_auth = 1;
4003 }
4004 } else if (is_retry) {
4005 /*
4006 * Need to indicate this with an event since the return
4007 * value from the retry is not delivered to core code.
4008 */
4009 union wpa_event_data event;
4010 wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
4011 "failed");
4012 os_memset(&event, 0, sizeof(event));
4013 os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
4014 ETH_ALEN);
4015 wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
4016 &event);
4017 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004018 } else {
4019 wpa_printf(MSG_DEBUG,
4020 "nl80211: Authentication request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004021 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004022
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004023fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004024 nlmsg_free(msg);
4025 return ret;
4026}
4027
4028
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004029int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004030{
4031 struct wpa_driver_auth_params params;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08004032 struct i802_bss *bss = drv->first_bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004033 int i;
4034
4035 wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
4036
4037 os_memset(&params, 0, sizeof(params));
4038 params.freq = drv->auth_freq;
4039 params.auth_alg = drv->auth_alg;
4040 params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
4041 params.local_state_change = drv->auth_local_state_change;
4042 params.p2p = drv->auth_p2p;
4043
4044 if (!is_zero_ether_addr(drv->auth_bssid_))
4045 params.bssid = drv->auth_bssid_;
4046
4047 if (drv->auth_ssid_len) {
4048 params.ssid = drv->auth_ssid;
4049 params.ssid_len = drv->auth_ssid_len;
4050 }
4051
4052 params.ie = drv->auth_ie;
4053 params.ie_len = drv->auth_ie_len;
Hai Shalom60840252021-02-19 19:02:11 -08004054 params.auth_data = drv->auth_data;
4055 params.auth_data_len = drv->auth_data_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004056
4057 for (i = 0; i < 4; i++) {
4058 if (drv->auth_wep_key_len[i]) {
4059 params.wep_key[i] = drv->auth_wep_key[i];
4060 params.wep_key_len[i] = drv->auth_wep_key_len[i];
4061 }
4062 }
4063
4064 drv->retry_auth = 1;
4065 return wpa_driver_nl80211_authenticate(bss, &params);
4066}
4067
4068
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004069static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
4070 size_t data_len, int noack,
4071 unsigned int freq, int no_cck,
4072 int offchanok,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004073 unsigned int wait_time,
4074 const u16 *csa_offs,
Hai Shalomfdcde762020-04-02 11:19:20 -07004075 size_t csa_offs_len, int no_encrypt)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004076{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004077 struct wpa_driver_nl80211_data *drv = bss->drv;
4078 struct ieee80211_mgmt *mgmt;
Hai Shalomfdcde762020-04-02 11:19:20 -07004079 int encrypt = !no_encrypt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004080 u16 fc;
Hai Shalomfdcde762020-04-02 11:19:20 -07004081 int use_cookie = 1;
4082 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004083
4084 mgmt = (struct ieee80211_mgmt *) data;
4085 fc = le_to_host16(mgmt->frame_control);
Hai Shalomfdcde762020-04-02 11:19:20 -07004086 wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR
4087 " 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 -07004088 MAC2STR(mgmt->da), noack, freq, no_cck, offchanok, wait_time,
Hai Shalomfdcde762020-04-02 11:19:20 -07004089 no_encrypt, fc, fc2str(fc), drv->nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004090
Dmitry Shmidt34af3062013-07-11 10:46:32 -07004091 if ((is_sta_interface(drv->nlmode) ||
4092 drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004093 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4094 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
4095 /*
4096 * The use of last_mgmt_freq is a bit of a hack,
4097 * but it works due to the single-threaded nature
4098 * of wpa_supplicant.
4099 */
Dmitry Shmidt56052862013-10-04 10:23:25 -07004100 if (freq == 0) {
4101 wpa_printf(MSG_DEBUG, "nl80211: Use last_mgmt_freq=%d",
4102 drv->last_mgmt_freq);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004103 freq = drv->last_mgmt_freq;
Dmitry Shmidt56052862013-10-04 10:23:25 -07004104 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004105 wait_time = 0;
4106 use_cookie = 0;
4107 no_cck = 1;
4108 offchanok = 1;
4109 goto send_frame_cmd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004110 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004111
4112 if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
Dmitry Shmidt56052862013-10-04 10:23:25 -07004113 if (freq == 0) {
4114 wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d",
4115 bss->freq);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004116 freq = bss->freq;
Dmitry Shmidt56052862013-10-04 10:23:25 -07004117 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004118 if ((int) freq == bss->freq)
4119 wait_time = 0;
4120 goto send_frame_cmd;
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07004121 }
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07004122
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004123 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4124 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
4125 /*
4126 * Only one of the authentication frame types is encrypted.
4127 * In order for static WEP encryption to work properly (i.e.,
4128 * to not encrypt the frame), we need to tell mac80211 about
4129 * the frames that must not be encrypted.
4130 */
4131 u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
4132 u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
4133 if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
4134 encrypt = 0;
4135 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004136
Hai Shalom60840252021-02-19 19:02:11 -08004137 if (is_sta_interface(drv->nlmode) &&
Hai Shalomfdcde762020-04-02 11:19:20 -07004138 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4139 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
Hai Shalom60840252021-02-19 19:02:11 -08004140 if (freq == 0 &&
4141 (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
4142 !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
4143 freq = nl80211_get_assoc_freq(drv);
4144 wpa_printf(MSG_DEBUG,
4145 "nl80211: send_mlme - Use assoc_freq=%u for external auth",
4146 freq);
4147 }
4148
4149 /* Allow off channel for PASN authentication */
4150 if (data_len >= IEEE80211_HDRLEN + 2 &&
4151 WPA_GET_LE16(data + IEEE80211_HDRLEN) == WLAN_AUTH_PASN &&
4152 !offchanok) {
4153 wpa_printf(MSG_DEBUG,
4154 "nl80211: send_mlme: allow off channel for PASN");
4155 offchanok = 1;
4156 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004157 }
4158
4159 if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
4160 freq = nl80211_get_assoc_freq(drv);
4161 wpa_printf(MSG_DEBUG,
4162 "nl80211: send_mlme - Use assoc_freq=%u for IBSS",
4163 freq);
4164 }
4165 if (freq == 0) {
4166 wpa_printf(MSG_DEBUG, "nl80211: send_mlme - Use bss->freq=%u",
4167 bss->freq);
4168 freq = bss->freq;
4169 }
4170
4171 if (drv->use_monitor) {
4172 wpa_printf(MSG_DEBUG,
4173 "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
4174 freq, bss->freq);
4175 return nl80211_send_monitor(drv, data, data_len, encrypt,
4176 noack);
4177 }
4178
4179 if (noack || WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
4180 WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
4181 use_cookie = 0;
4182send_frame_cmd:
4183#ifdef CONFIG_TESTING_OPTIONS
4184 if (no_encrypt && !encrypt && !drv->use_monitor) {
4185 wpa_printf(MSG_DEBUG,
4186 "nl80211: Request to send an unencrypted frame - use a monitor interface for this");
4187 if (nl80211_create_monitor_interface(drv) < 0)
4188 return -1;
4189 res = nl80211_send_monitor(drv, data, data_len, encrypt,
4190 noack);
4191 nl80211_remove_monitor_interface(drv);
4192 return res;
4193 }
4194#endif /* CONFIG_TESTING_OPTIONS */
4195
4196 wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame_cmd");
4197 res = nl80211_send_frame_cmd(bss, freq, wait_time, data, data_len,
4198 use_cookie, no_cck, noack, offchanok,
4199 csa_offs, csa_offs_len);
4200
4201 return res;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004202}
4203
4204
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004205static int nl80211_put_basic_rates(struct nl_msg *msg, const int *basic_rates)
4206{
4207 u8 rates[NL80211_MAX_SUPP_RATES];
4208 u8 rates_len = 0;
4209 int i;
4210
4211 if (!basic_rates)
4212 return 0;
4213
4214 for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
4215 rates[rates_len++] = basic_rates[i] / 5;
4216
4217 return nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
4218}
4219
4220
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004221static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
4222 int slot, int ht_opmode, int ap_isolate,
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004223 const int *basic_rates)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004224{
4225 struct wpa_driver_nl80211_data *drv = bss->drv;
4226 struct nl_msg *msg;
4227
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004228 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_BSS)) ||
4229 (cts >= 0 &&
4230 nla_put_u8(msg, NL80211_ATTR_BSS_CTS_PROT, cts)) ||
4231 (preamble >= 0 &&
4232 nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble)) ||
4233 (slot >= 0 &&
4234 nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot)) ||
4235 (ht_opmode >= 0 &&
4236 nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) ||
4237 (ap_isolate >= 0 &&
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004238 nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)) ||
4239 nl80211_put_basic_rates(msg, basic_rates)) {
4240 nlmsg_free(msg);
4241 return -ENOBUFS;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004242 }
4243
Hai Shalom899fcc72020-10-19 14:38:18 -07004244 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004245}
4246
4247
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004248static int wpa_driver_nl80211_set_acl(void *priv,
4249 struct hostapd_acl_params *params)
4250{
4251 struct i802_bss *bss = priv;
4252 struct wpa_driver_nl80211_data *drv = bss->drv;
4253 struct nl_msg *msg;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004254 struct nl_msg *acl;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004255 unsigned int i;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004256 int ret;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004257
4258 if (!(drv->capa.max_acl_mac_addrs))
4259 return -ENOTSUP;
4260
4261 if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
4262 return -ENOTSUP;
4263
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004264 wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
4265 params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
4266
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004267 acl = nlmsg_alloc();
4268 if (!acl)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004269 return -ENOMEM;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004270 for (i = 0; i < params->num_mac_acl; i++) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004271 if (nla_put(acl, i + 1, ETH_ALEN, params->mac_acl[i].addr)) {
4272 nlmsg_free(acl);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004273 return -ENOMEM;
4274 }
4275 }
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004276
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004277 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MAC_ACL)) ||
4278 nla_put_u32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
4279 NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
4280 NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED) ||
4281 nla_put_nested(msg, NL80211_ATTR_MAC_ADDRS, acl)) {
4282 nlmsg_free(msg);
4283 nlmsg_free(acl);
4284 return -ENOMEM;
4285 }
4286 nlmsg_free(acl);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004287
Hai Shalom899fcc72020-10-19 14:38:18 -07004288 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004289 if (ret) {
4290 wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
4291 ret, strerror(-ret));
4292 }
4293
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004294 return ret;
4295}
4296
4297
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004298static int nl80211_put_beacon_int(struct nl_msg *msg, int beacon_int)
4299{
4300 if (beacon_int > 0) {
4301 wpa_printf(MSG_DEBUG, " * beacon_int=%d", beacon_int);
4302 return nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
4303 beacon_int);
4304 }
4305
4306 return 0;
4307}
4308
4309
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004310static int nl80211_put_dtim_period(struct nl_msg *msg, int dtim_period)
4311{
4312 if (dtim_period > 0) {
4313 wpa_printf(MSG_DEBUG, " * dtim_period=%d", dtim_period);
4314 return nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
4315 }
4316
4317 return 0;
4318}
4319
4320
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004321#ifdef CONFIG_MESH
4322static int nl80211_set_mesh_config(void *priv,
4323 struct wpa_driver_mesh_bss_params *params)
4324{
4325 struct i802_bss *bss = priv;
4326 struct wpa_driver_nl80211_data *drv = bss->drv;
4327 struct nl_msg *msg;
4328 int ret;
4329
4330 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MESH_CONFIG);
4331 if (!msg)
4332 return -1;
4333
4334 ret = nl80211_put_mesh_config(msg, params);
4335 if (ret < 0) {
4336 nlmsg_free(msg);
4337 return ret;
4338 }
4339
Hai Shalom899fcc72020-10-19 14:38:18 -07004340 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004341 if (ret) {
4342 wpa_printf(MSG_ERROR,
4343 "nl80211: Mesh config set failed: %d (%s)",
4344 ret, strerror(-ret));
4345 return ret;
4346 }
4347 return 0;
4348}
4349#endif /* CONFIG_MESH */
4350
4351
Hai Shalom60840252021-02-19 19:02:11 -08004352static int nl80211_put_beacon_rate(struct nl_msg *msg, u64 flags, u64 flags2,
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004353 struct wpa_driver_ap_params *params)
4354{
4355 struct nlattr *bands, *band;
4356 struct nl80211_txrate_vht vht_rate;
Hai Shalom60840252021-02-19 19:02:11 -08004357 struct nl80211_txrate_he he_rate;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004358
4359 if (!params->freq ||
4360 (params->beacon_rate == 0 &&
4361 params->rate_type == BEACON_RATE_LEGACY))
4362 return 0;
4363
4364 bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
4365 if (!bands)
4366 return -1;
4367
4368 switch (params->freq->mode) {
4369 case HOSTAPD_MODE_IEEE80211B:
4370 case HOSTAPD_MODE_IEEE80211G:
4371 band = nla_nest_start(msg, NL80211_BAND_2GHZ);
4372 break;
4373 case HOSTAPD_MODE_IEEE80211A:
Hai Shalom60840252021-02-19 19:02:11 -08004374 if (is_6ghz_freq(params->freq->freq))
4375 band = nla_nest_start(msg, NL80211_BAND_6GHZ);
4376 else
4377 band = nla_nest_start(msg, NL80211_BAND_5GHZ);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004378 break;
4379 case HOSTAPD_MODE_IEEE80211AD:
4380 band = nla_nest_start(msg, NL80211_BAND_60GHZ);
4381 break;
4382 default:
4383 return 0;
4384 }
4385
4386 if (!band)
4387 return -1;
4388
4389 os_memset(&vht_rate, 0, sizeof(vht_rate));
Hai Shalom60840252021-02-19 19:02:11 -08004390 os_memset(&he_rate, 0, sizeof(he_rate));
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004391
4392 switch (params->rate_type) {
4393 case BEACON_RATE_LEGACY:
4394 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY)) {
4395 wpa_printf(MSG_INFO,
4396 "nl80211: Driver does not support setting Beacon frame rate (legacy)");
4397 return -1;
4398 }
4399
4400 if (nla_put_u8(msg, NL80211_TXRATE_LEGACY,
4401 (u8) params->beacon_rate / 5) ||
4402 nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
4403 (params->freq->vht_enabled &&
4404 nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4405 &vht_rate)))
4406 return -1;
4407
4408 wpa_printf(MSG_DEBUG, " * beacon_rate = legacy:%u (* 100 kbps)",
4409 params->beacon_rate);
4410 break;
4411 case BEACON_RATE_HT:
4412 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_HT)) {
4413 wpa_printf(MSG_INFO,
4414 "nl80211: Driver does not support setting Beacon frame rate (HT)");
4415 return -1;
4416 }
4417 if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
4418 nla_put_u8(msg, NL80211_TXRATE_HT, params->beacon_rate) ||
4419 (params->freq->vht_enabled &&
4420 nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4421 &vht_rate)))
4422 return -1;
4423 wpa_printf(MSG_DEBUG, " * beacon_rate = HT-MCS %u",
4424 params->beacon_rate);
4425 break;
4426 case BEACON_RATE_VHT:
4427 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_VHT)) {
4428 wpa_printf(MSG_INFO,
4429 "nl80211: Driver does not support setting Beacon frame rate (VHT)");
4430 return -1;
4431 }
4432 vht_rate.mcs[0] = BIT(params->beacon_rate);
4433 if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL))
4434 return -1;
4435 if (nla_put(msg, NL80211_TXRATE_HT, 0, NULL))
4436 return -1;
4437 if (nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4438 &vht_rate))
4439 return -1;
4440 wpa_printf(MSG_DEBUG, " * beacon_rate = VHT-MCS %u",
4441 params->beacon_rate);
4442 break;
Hai Shalom60840252021-02-19 19:02:11 -08004443 case BEACON_RATE_HE:
4444 if (!(flags2 & WPA_DRIVER_FLAGS2_BEACON_RATE_HE)) {
4445 wpa_printf(MSG_INFO,
4446 "nl80211: Driver does not support setting Beacon frame rate (HE)");
4447 return -1;
4448 }
4449 he_rate.mcs[0] = BIT(params->beacon_rate);
4450 if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
4451 nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
4452 nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4453 &vht_rate) ||
4454 nla_put(msg, NL80211_TXRATE_HE, sizeof(he_rate), &he_rate))
4455 return -1;
4456 wpa_printf(MSG_DEBUG, " * beacon_rate = HE-MCS %u",
4457 params->beacon_rate);
4458 break;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004459 }
4460
4461 nla_nest_end(msg, band);
4462 nla_nest_end(msg, bands);
4463
4464 return 0;
4465}
4466
4467
4468static int nl80211_set_multicast_to_unicast(struct i802_bss *bss,
4469 int multicast_to_unicast)
4470{
4471 struct wpa_driver_nl80211_data *drv = bss->drv;
4472 struct nl_msg *msg;
4473 int ret;
4474
4475 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_MULTICAST_TO_UNICAST);
4476 if (!msg ||
4477 (multicast_to_unicast &&
4478 nla_put_flag(msg, NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED))) {
4479 wpa_printf(MSG_ERROR,
4480 "nl80211: Failed to build NL80211_CMD_SET_MULTICAST_TO_UNICAST msg for %s",
4481 bss->ifname);
4482 nlmsg_free(msg);
4483 return -ENOBUFS;
4484 }
4485
Hai Shalom899fcc72020-10-19 14:38:18 -07004486 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004487
4488 switch (ret) {
4489 case 0:
4490 wpa_printf(MSG_DEBUG,
4491 "nl80211: multicast to unicast %s on interface %s",
4492 multicast_to_unicast ? "enabled" : "disabled",
4493 bss->ifname);
4494 break;
4495 case -EOPNOTSUPP:
4496 if (!multicast_to_unicast)
4497 break;
4498 wpa_printf(MSG_INFO,
4499 "nl80211: multicast to unicast not supported on interface %s",
4500 bss->ifname);
4501 break;
4502 default:
4503 wpa_printf(MSG_ERROR,
4504 "nl80211: %s multicast to unicast failed with %d (%s) on interface %s",
4505 multicast_to_unicast ? "enabling" : "disabling",
4506 ret, strerror(-ret), bss->ifname);
4507 break;
4508 }
4509
4510 return ret;
4511}
4512
4513
Hai Shalom60840252021-02-19 19:02:11 -08004514#ifdef CONFIG_SAE
4515static int nl80211_put_sae_pwe(struct nl_msg *msg, int pwe)
4516{
4517 u8 sae_pwe;
4518
4519 wpa_printf(MSG_DEBUG, "nl802111: sae_pwe=%d", pwe);
4520 if (pwe == 0)
4521 sae_pwe = NL80211_SAE_PWE_HUNT_AND_PECK;
4522 else if (pwe == 1)
4523 sae_pwe = NL80211_SAE_PWE_HASH_TO_ELEMENT;
4524 else if (pwe == 2)
4525 sae_pwe = NL80211_SAE_PWE_BOTH;
4526 else if (pwe == 3)
4527 return 0; /* special test mode */
4528 else
4529 return -1;
4530 if (nla_put_u8(msg, NL80211_ATTR_SAE_PWE, sae_pwe))
4531 return -1;
4532
4533 return 0;
4534}
4535#endif /* CONFIG_SAE */
4536
4537
4538#ifdef CONFIG_FILS
4539static int nl80211_fils_discovery(struct i802_bss *bss, struct nl_msg *msg,
4540 struct wpa_driver_ap_params *params)
4541{
4542 struct nlattr *attr;
4543
4544 if (!bss->drv->fils_discovery) {
4545 wpa_printf(MSG_ERROR,
4546 "nl80211: Driver does not support FILS Discovery frame transmission for %s",
4547 bss->ifname);
4548 return -1;
4549 }
4550
4551 attr = nla_nest_start(msg, NL80211_ATTR_FILS_DISCOVERY);
4552 if (!attr ||
4553 nla_put_u32(msg, NL80211_FILS_DISCOVERY_ATTR_INT_MIN,
4554 params->fd_min_int) ||
4555 nla_put_u32(msg, NL80211_FILS_DISCOVERY_ATTR_INT_MAX,
4556 params->fd_max_int) ||
4557 (params->fd_frame_tmpl &&
4558 nla_put(msg, NL80211_FILS_DISCOVERY_ATTR_TMPL,
4559 params->fd_frame_tmpl_len, params->fd_frame_tmpl)))
4560 return -1;
4561
4562 nla_nest_end(msg, attr);
4563 return 0;
4564}
4565#endif /* CONFIG_FILS */
4566
4567
4568#ifdef CONFIG_IEEE80211AX
4569static int nl80211_unsol_bcast_probe_resp(struct i802_bss *bss,
4570 struct nl_msg *msg,
4571 struct wpa_driver_ap_params *params)
4572{
4573 struct nlattr *attr;
4574
4575 if (!bss->drv->unsol_bcast_probe_resp) {
4576 wpa_printf(MSG_ERROR,
4577 "nl80211: Driver does not support unsolicited broadcast Probe Response frame transmission for %s",
4578 bss->ifname);
4579 return -1;
4580 }
4581
4582 wpa_printf(MSG_DEBUG,
4583 "nl80211: Unsolicited broadcast Probe Response frame interval: %u",
4584 params->unsol_bcast_probe_resp_interval);
4585 attr = nla_nest_start(msg, NL80211_ATTR_UNSOL_BCAST_PROBE_RESP);
4586 if (!attr ||
4587 nla_put_u32(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT,
4588 params->unsol_bcast_probe_resp_interval) ||
4589 (params->unsol_bcast_probe_resp_tmpl &&
4590 nla_put(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL,
4591 params->unsol_bcast_probe_resp_tmpl_len,
4592 params->unsol_bcast_probe_resp_tmpl)))
4593 return -1;
4594
4595 nla_nest_end(msg, attr);
4596 return 0;
4597}
4598#endif /* CONFIG_IEEE80211AX */
4599
4600
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004601static int wpa_driver_nl80211_set_ap(void *priv,
4602 struct wpa_driver_ap_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004603{
4604 struct i802_bss *bss = priv;
4605 struct wpa_driver_nl80211_data *drv = bss->drv;
4606 struct nl_msg *msg;
4607 u8 cmd = NL80211_CMD_NEW_BEACON;
Hai Shalom74f70d42019-02-11 14:42:39 -08004608 int ret = -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004609 int beacon_set;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004610 int num_suites;
Hai Shalomfdcde762020-04-02 11:19:20 -07004611 u32 suites[20], suite;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004612 u32 ver;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004613#ifdef CONFIG_MESH
4614 struct wpa_driver_mesh_bss_params mesh_params;
4615#endif /* CONFIG_MESH */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004616
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004617 beacon_set = params->reenable ? 0 : bss->beacon_set;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004618
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004619 wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
4620 beacon_set);
4621 if (beacon_set)
4622 cmd = NL80211_CMD_SET_BEACON;
Paul Stewart092955c2017-02-06 09:13:09 -08004623 else if (!drv->device_ap_sme && !drv->use_monitor &&
4624 !nl80211_get_wiphy_data_ap(bss))
4625 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004626
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004627 wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
4628 params->head, params->head_len);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004629 wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
4630 params->tail, params->tail_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004631 wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004632 wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004633 wpa_printf(MSG_DEBUG, "nl80211: beacon_rate=%u", params->beacon_rate);
4634 wpa_printf(MSG_DEBUG, "nl80211: rate_type=%d", params->rate_type);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004635 wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
Hai Shalom74f70d42019-02-11 14:42:39 -08004636 wpa_printf(MSG_DEBUG, "nl80211: ssid=%s",
4637 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004638 if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
4639 nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
4640 params->head) ||
4641 nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
4642 params->tail) ||
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004643 nl80211_put_beacon_int(msg, params->beacon_int) ||
Hai Shalom60840252021-02-19 19:02:11 -08004644 nl80211_put_beacon_rate(msg, drv->capa.flags, drv->capa.flags2,
4645 params) ||
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004646 nl80211_put_dtim_period(msg, params->dtim_period) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004647 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
4648 goto fail;
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004649 if (params->proberesp && params->proberesp_len) {
4650 wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
4651 params->proberesp, params->proberesp_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004652 if (nla_put(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
4653 params->proberesp))
4654 goto fail;
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004655 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004656 switch (params->hide_ssid) {
4657 case NO_SSID_HIDING:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004658 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004659 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
4660 NL80211_HIDDEN_SSID_NOT_IN_USE))
4661 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004662 break;
4663 case HIDDEN_SSID_ZERO_LEN:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004664 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004665 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
4666 NL80211_HIDDEN_SSID_ZERO_LEN))
4667 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004668 break;
4669 case HIDDEN_SSID_ZERO_CONTENTS:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004670 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004671 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
4672 NL80211_HIDDEN_SSID_ZERO_CONTENTS))
4673 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004674 break;
4675 }
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004676 wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004677 if (params->privacy &&
4678 nla_put_flag(msg, NL80211_ATTR_PRIVACY))
4679 goto fail;
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004680 wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004681 if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
4682 (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
4683 /* Leave out the attribute */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004684 } else if (params->auth_algs & WPA_AUTH_ALG_SHARED) {
4685 if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
4686 NL80211_AUTHTYPE_SHARED_KEY))
4687 goto fail;
4688 } else {
4689 if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
4690 NL80211_AUTHTYPE_OPEN_SYSTEM))
4691 goto fail;
4692 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004693
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004694 wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004695 ver = 0;
4696 if (params->wpa_version & WPA_PROTO_WPA)
4697 ver |= NL80211_WPA_VERSION_1;
4698 if (params->wpa_version & WPA_PROTO_RSN)
4699 ver |= NL80211_WPA_VERSION_2;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004700 if (ver &&
4701 nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
4702 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004703
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004704 wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
4705 params->key_mgmt_suites);
Hai Shalomfdcde762020-04-02 11:19:20 -07004706 num_suites = wpa_key_mgmt_to_suites(params->key_mgmt_suites,
4707 suites, ARRAY_SIZE(suites));
4708 if (num_suites > NL80211_MAX_NR_AKM_SUITES)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004709 wpa_printf(MSG_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07004710 "nl80211: Not enough room for all AKM suites (num_suites=%d > NL80211_MAX_NR_AKM_SUITES)",
4711 num_suites);
4712 else if (num_suites &&
4713 nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
4714 suites))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004715 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004716
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004717 if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004718 (!params->pairwise_ciphers ||
4719 params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
4720 (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
4721 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004722 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004723
Hai Shalom81f62d82019-07-22 12:10:00 -07004724 if (drv->device_ap_sme &&
4725 (params->key_mgmt_suites & WPA_KEY_MGMT_SAE) &&
4726 nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
4727 goto fail;
Hai Shalom5f92bc92019-04-18 11:54:11 -07004728
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004729 wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
4730 params->pairwise_ciphers);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004731 num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers,
4732 suites, ARRAY_SIZE(suites));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004733 if (num_suites &&
4734 nla_put(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
4735 num_suites * sizeof(u32), suites))
4736 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004737
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004738 wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
4739 params->group_cipher);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004740 suite = wpa_cipher_to_cipher_suite(params->group_cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004741 if (suite &&
4742 nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
4743 goto fail;
4744
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004745 if (params->beacon_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004746 wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
4747 params->beacon_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004748 if (nla_put(msg, NL80211_ATTR_IE,
4749 wpabuf_len(params->beacon_ies),
4750 wpabuf_head(params->beacon_ies)))
4751 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004752 }
4753 if (params->proberesp_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004754 wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
4755 params->proberesp_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004756 if (nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
4757 wpabuf_len(params->proberesp_ies),
4758 wpabuf_head(params->proberesp_ies)))
4759 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004760 }
4761 if (params->assocresp_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004762 wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
4763 params->assocresp_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004764 if (nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
4765 wpabuf_len(params->assocresp_ies),
4766 wpabuf_head(params->assocresp_ies)))
4767 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004768 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004769
Dmitry Shmidt04949592012-07-19 12:16:46 -07004770 if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004771 wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
4772 params->ap_max_inactivity);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004773 if (nla_put_u16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
4774 params->ap_max_inactivity))
4775 goto fail;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004776 }
4777
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004778#ifdef CONFIG_P2P
4779 if (params->p2p_go_ctwindow > 0) {
4780 if (drv->p2p_go_ctwindow_supported) {
4781 wpa_printf(MSG_DEBUG, "nl80211: P2P GO ctwindow=%d",
4782 params->p2p_go_ctwindow);
4783 if (nla_put_u8(msg, NL80211_ATTR_P2P_CTWINDOW,
4784 params->p2p_go_ctwindow))
4785 goto fail;
4786 } else {
4787 wpa_printf(MSG_INFO,
4788 "nl80211: Driver does not support CTWindow configuration - ignore this parameter");
4789 }
4790 }
4791#endif /* CONFIG_P2P */
4792
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004793 if (params->pbss) {
4794 wpa_printf(MSG_DEBUG, "nl80211: PBSS");
4795 if (nla_put_flag(msg, NL80211_ATTR_PBSS))
4796 goto fail;
4797 }
4798
Hai Shalom74f70d42019-02-11 14:42:39 -08004799 if (params->ftm_responder) {
4800 struct nlattr *ftm;
4801
4802 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_FTM_RESPONDER)) {
4803 ret = -ENOTSUP;
4804 goto fail;
4805 }
4806
4807 ftm = nla_nest_start(msg, NL80211_ATTR_FTM_RESPONDER);
4808 if (!ftm ||
4809 nla_put_flag(msg, NL80211_FTM_RESP_ATTR_ENABLED) ||
4810 (params->lci &&
4811 nla_put(msg, NL80211_FTM_RESP_ATTR_LCI,
4812 wpabuf_len(params->lci),
4813 wpabuf_head(params->lci))) ||
4814 (params->civic &&
4815 nla_put(msg, NL80211_FTM_RESP_ATTR_CIVICLOC,
4816 wpabuf_len(params->civic),
4817 wpabuf_head(params->civic))))
4818 goto fail;
4819 nla_nest_end(msg, ftm);
4820 }
4821
Hai Shalomc3565922019-10-28 11:58:20 -07004822#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08004823 if (params->he_spr_ctrl) {
Hai Shalomc3565922019-10-28 11:58:20 -07004824 struct nlattr *spr;
4825
4826 spr = nla_nest_start(msg, NL80211_ATTR_HE_OBSS_PD);
Hai Shalom60840252021-02-19 19:02:11 -08004827 wpa_printf(MSG_DEBUG, "nl80211: he_spr_ctrl=0x%x",
4828 params->he_spr_ctrl);
Hai Shalomc3565922019-10-28 11:58:20 -07004829
Hai Shalomfdcde762020-04-02 11:19:20 -07004830 if (!spr ||
Hai Shalom60840252021-02-19 19:02:11 -08004831 nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_SR_CTRL,
4832 params->he_spr_ctrl) ||
4833 ((params->he_spr_ctrl &
4834 SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) &&
4835 nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET,
4836 params->he_spr_non_srg_obss_pd_max_offset)))
4837 goto fail;
4838
4839 if ((params->he_spr_ctrl &
4840 SPATIAL_REUSE_SRG_INFORMATION_PRESENT) &&
4841 (nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
4842 params->he_spr_srg_obss_pd_min_offset) ||
4843 nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
4844 params->he_spr_srg_obss_pd_max_offset) ||
4845 nla_put(msg, NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP,
4846 sizeof(params->he_spr_bss_color_bitmap),
4847 params->he_spr_bss_color_bitmap) ||
4848 nla_put(msg, NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP,
4849 sizeof(params->he_spr_partial_bssid_bitmap),
4850 params->he_spr_partial_bssid_bitmap)))
Hai Shalomc3565922019-10-28 11:58:20 -07004851 goto fail;
4852
4853 nla_nest_end(msg, spr);
4854 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004855
4856 if (params->freq && params->freq->he_enabled) {
4857 struct nlattr *bss_color;
4858
4859 bss_color = nla_nest_start(msg, NL80211_ATTR_HE_BSS_COLOR);
4860 if (!bss_color ||
4861 (params->he_bss_color_disabled &&
4862 nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_DISABLED)) ||
4863 (params->he_bss_color_partial &&
4864 nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_PARTIAL)) ||
4865 nla_put_u8(msg, NL80211_HE_BSS_COLOR_ATTR_COLOR,
4866 params->he_bss_color))
4867 goto fail;
4868 nla_nest_end(msg, bss_color);
4869 }
4870
4871 if (params->twt_responder) {
4872 wpa_printf(MSG_DEBUG, "nl80211: twt_responder=%d",
4873 params->twt_responder);
4874 if (nla_put_flag(msg, NL80211_ATTR_TWT_RESPONDER))
4875 goto fail;
4876 }
Hai Shalom60840252021-02-19 19:02:11 -08004877
4878 if (params->unsol_bcast_probe_resp_interval &&
4879 nl80211_unsol_bcast_probe_resp(bss, msg, params) < 0)
4880 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07004881#endif /* CONFIG_IEEE80211AX */
4882
Hai Shalom60840252021-02-19 19:02:11 -08004883#ifdef CONFIG_SAE
4884 if (((params->key_mgmt_suites & WPA_KEY_MGMT_SAE) ||
4885 (params->key_mgmt_suites & WPA_KEY_MGMT_FT_SAE)) &&
4886 nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
4887 goto fail;
4888#endif /* CONFIG_SAE */
4889
4890#ifdef CONFIG_FILS
4891 if (params->fd_max_int && nl80211_fils_discovery(bss, msg, params) < 0)
4892 goto fail;
4893#endif /* CONFIG_FILS */
4894
Hai Shalomb755a2a2020-04-23 21:49:02 -07004895 ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1,
Hai Shalom899fcc72020-10-19 14:38:18 -07004896 NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004897 if (ret) {
4898 wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
4899 ret, strerror(-ret));
4900 } else {
4901 bss->beacon_set = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004902 nl80211_set_bss(bss, params->cts_protect, params->preamble,
4903 params->short_slot_time, params->ht_opmode,
4904 params->isolate, params->basic_rates);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004905 nl80211_set_multicast_to_unicast(bss,
4906 params->multicast_to_unicast);
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004907 if (beacon_set && params->freq &&
4908 params->freq->bandwidth != bss->bandwidth) {
4909 wpa_printf(MSG_DEBUG,
4910 "nl80211: Update BSS %s bandwidth: %d -> %d",
4911 bss->ifname, bss->bandwidth,
4912 params->freq->bandwidth);
4913 ret = nl80211_set_channel(bss, params->freq, 1);
4914 if (ret) {
4915 wpa_printf(MSG_DEBUG,
4916 "nl80211: Frequency set failed: %d (%s)",
4917 ret, strerror(-ret));
4918 } else {
4919 wpa_printf(MSG_DEBUG,
4920 "nl80211: Frequency set succeeded for ht2040 coex");
4921 bss->bandwidth = params->freq->bandwidth;
4922 }
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004923 } else if (!beacon_set && params->freq) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004924 /*
4925 * cfg80211 updates the driver on frequence change in AP
4926 * mode only at the point when beaconing is started, so
4927 * set the initial value here.
4928 */
4929 bss->bandwidth = params->freq->bandwidth;
4930 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004931 }
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004932
4933#ifdef CONFIG_MESH
4934 if (is_mesh_interface(drv->nlmode) && params->ht_opmode != -1) {
4935 os_memset(&mesh_params, 0, sizeof(mesh_params));
4936 mesh_params.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
4937 mesh_params.ht_opmode = params->ht_opmode;
4938 ret = nl80211_set_mesh_config(priv, &mesh_params);
4939 if (ret < 0)
4940 return ret;
4941 }
4942#endif /* CONFIG_MESH */
4943
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004944 return ret;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004945fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004946 nlmsg_free(msg);
Hai Shalom74f70d42019-02-11 14:42:39 -08004947 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004948}
4949
4950
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08004951static int nl80211_put_freq_params(struct nl_msg *msg,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004952 const struct hostapd_freq_params *freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004953{
Hai Shalomc3565922019-10-28 11:58:20 -07004954 enum hostapd_hw_mode hw_mode;
4955 int is_24ghz;
4956 u8 channel;
4957
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004958 wpa_printf(MSG_DEBUG, " * freq=%d", freq->freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004959 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
4960 return -ENOBUFS;
4961
Hai Shalom81f62d82019-07-22 12:10:00 -07004962 wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004963 wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
4964 wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
4965
Hai Shalomc3565922019-10-28 11:58:20 -07004966 hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
4967 is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
4968 hw_mode == HOSTAPD_MODE_IEEE80211B;
4969
4970 if (freq->vht_enabled || (freq->he_enabled && !is_24ghz)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004971 enum nl80211_chan_width cw;
4972
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004973 wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004974 switch (freq->bandwidth) {
4975 case 20:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004976 cw = NL80211_CHAN_WIDTH_20;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004977 break;
4978 case 40:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004979 cw = NL80211_CHAN_WIDTH_40;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004980 break;
4981 case 80:
4982 if (freq->center_freq2)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004983 cw = NL80211_CHAN_WIDTH_80P80;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004984 else
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004985 cw = NL80211_CHAN_WIDTH_80;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004986 break;
4987 case 160:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004988 cw = NL80211_CHAN_WIDTH_160;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004989 break;
4990 default:
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08004991 return -EINVAL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004992 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004993
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004994 wpa_printf(MSG_DEBUG, " * channel_width=%d", cw);
4995 wpa_printf(MSG_DEBUG, " * center_freq1=%d",
4996 freq->center_freq1);
4997 wpa_printf(MSG_DEBUG, " * center_freq2=%d",
4998 freq->center_freq2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004999 if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) ||
5000 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1,
5001 freq->center_freq1) ||
5002 (freq->center_freq2 &&
5003 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2,
5004 freq->center_freq2)))
5005 return -ENOBUFS;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005006 } else if (freq->ht_enabled) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005007 enum nl80211_channel_type ct;
5008
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005009 wpa_printf(MSG_DEBUG, " * sec_channel_offset=%d",
5010 freq->sec_channel_offset);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005011 switch (freq->sec_channel_offset) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005012 case -1:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005013 ct = NL80211_CHAN_HT40MINUS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005014 break;
5015 case 1:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005016 ct = NL80211_CHAN_HT40PLUS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005017 break;
5018 default:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005019 ct = NL80211_CHAN_HT20;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005020 break;
5021 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005022
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005023 wpa_printf(MSG_DEBUG, " * channel_type=%d", ct);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005024 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
5025 return -ENOBUFS;
Hai Shalomc3565922019-10-28 11:58:20 -07005026 } else if (freq->edmg.channels && freq->edmg.bw_config) {
5027 wpa_printf(MSG_DEBUG,
5028 " * EDMG configuration: channels=0x%x bw_config=%d",
5029 freq->edmg.channels, freq->edmg.bw_config);
5030 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
5031 freq->edmg.channels) ||
5032 nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
5033 freq->edmg.bw_config))
5034 return -1;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005035 } else {
5036 wpa_printf(MSG_DEBUG, " * channel_type=%d",
5037 NL80211_CHAN_NO_HT);
5038 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
5039 NL80211_CHAN_NO_HT))
5040 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005041 }
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005042 return 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005043}
5044
5045
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005046static int nl80211_set_channel(struct i802_bss *bss,
5047 struct hostapd_freq_params *freq, int set_chan)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005048{
5049 struct wpa_driver_nl80211_data *drv = bss->drv;
5050 struct nl_msg *msg;
5051 int ret;
5052
5053 wpa_printf(MSG_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07005054 "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
5055 freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005056 freq->bandwidth, freq->center_freq1, freq->center_freq2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005057
5058 msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
5059 NL80211_CMD_SET_WIPHY);
5060 if (!msg || nl80211_put_freq_params(msg, freq) < 0) {
5061 nlmsg_free(msg);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005062 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005063 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005064
Hai Shalom899fcc72020-10-19 14:38:18 -07005065 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005066 if (ret == 0) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005067 bss->freq = freq->freq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005068 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005069 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005070 wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005071 "%d (%s)", freq->freq, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005072 return -1;
5073}
5074
5075
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005076static u32 sta_flags_nl80211(int flags)
5077{
5078 u32 f = 0;
5079
5080 if (flags & WPA_STA_AUTHORIZED)
5081 f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
5082 if (flags & WPA_STA_WMM)
5083 f |= BIT(NL80211_STA_FLAG_WME);
5084 if (flags & WPA_STA_SHORT_PREAMBLE)
5085 f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
5086 if (flags & WPA_STA_MFP)
5087 f |= BIT(NL80211_STA_FLAG_MFP);
5088 if (flags & WPA_STA_TDLS_PEER)
5089 f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005090 if (flags & WPA_STA_AUTHENTICATED)
5091 f |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005092 if (flags & WPA_STA_ASSOCIATED)
5093 f |= BIT(NL80211_STA_FLAG_ASSOCIATED);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005094
5095 return f;
5096}
5097
5098
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005099#ifdef CONFIG_MESH
5100static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
5101{
5102 switch (state) {
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005103 case PLINK_IDLE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005104 return NL80211_PLINK_LISTEN;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005105 case PLINK_OPN_SNT:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005106 return NL80211_PLINK_OPN_SNT;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005107 case PLINK_OPN_RCVD:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005108 return NL80211_PLINK_OPN_RCVD;
5109 case PLINK_CNF_RCVD:
5110 return NL80211_PLINK_CNF_RCVD;
5111 case PLINK_ESTAB:
5112 return NL80211_PLINK_ESTAB;
5113 case PLINK_HOLDING:
5114 return NL80211_PLINK_HOLDING;
5115 case PLINK_BLOCKED:
5116 return NL80211_PLINK_BLOCKED;
5117 default:
5118 wpa_printf(MSG_ERROR, "nl80211: Invalid mesh plink state %d",
5119 state);
5120 }
5121 return -1;
5122}
5123#endif /* CONFIG_MESH */
5124
5125
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005126static int wpa_driver_nl80211_sta_add(void *priv,
5127 struct hostapd_sta_add_params *params)
5128{
5129 struct i802_bss *bss = priv;
5130 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005131 struct nl_msg *msg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005132 struct nl80211_sta_flag_update upd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005133 int ret = -ENOBUFS;
5134
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005135 if ((params->flags & WPA_STA_TDLS_PEER) &&
5136 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
5137 return -EOPNOTSUPP;
5138
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005139 wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
5140 params->set ? "Set" : "Add", MAC2STR(params->addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005141 msg = nl80211_bss_msg(bss, 0, params->set ? NL80211_CMD_SET_STATION :
5142 NL80211_CMD_NEW_STATION);
5143 if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
5144 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005145
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005146 /*
5147 * Set the below properties only in one of the following cases:
5148 * 1. New station is added, already associated.
5149 * 2. Set WPA_STA_TDLS_PEER station.
5150 * 3. Set an already added unassociated station, if driver supports
5151 * full AP client state. (Set these properties after station became
5152 * associated will be rejected by the driver).
5153 */
5154 if (!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
5155 (params->set && FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags) &&
5156 (params->flags & WPA_STA_ASSOCIATED))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005157 wpa_hexdump(MSG_DEBUG, " * supported rates",
5158 params->supp_rates, params->supp_rates_len);
5159 wpa_printf(MSG_DEBUG, " * capability=0x%x",
5160 params->capability);
5161 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_RATES,
5162 params->supp_rates_len, params->supp_rates) ||
5163 nla_put_u16(msg, NL80211_ATTR_STA_CAPABILITY,
5164 params->capability))
5165 goto fail;
5166
5167 if (params->ht_capabilities) {
5168 wpa_hexdump(MSG_DEBUG, " * ht_capabilities",
5169 (u8 *) params->ht_capabilities,
5170 sizeof(*params->ht_capabilities));
5171 if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY,
5172 sizeof(*params->ht_capabilities),
5173 params->ht_capabilities))
5174 goto fail;
5175 }
5176
5177 if (params->vht_capabilities) {
5178 wpa_hexdump(MSG_DEBUG, " * vht_capabilities",
5179 (u8 *) params->vht_capabilities,
5180 sizeof(*params->vht_capabilities));
5181 if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY,
5182 sizeof(*params->vht_capabilities),
5183 params->vht_capabilities))
5184 goto fail;
5185 }
5186
Hai Shalom81f62d82019-07-22 12:10:00 -07005187 if (params->he_capab) {
5188 wpa_hexdump(MSG_DEBUG, " * he_capab",
5189 params->he_capab, params->he_capab_len);
5190 if (nla_put(msg, NL80211_ATTR_HE_CAPABILITY,
5191 params->he_capab_len, params->he_capab))
5192 goto fail;
5193 }
5194
Hai Shalom60840252021-02-19 19:02:11 -08005195 if (params->he_6ghz_capab) {
5196 wpa_hexdump(MSG_DEBUG, " * he_6ghz_capab",
5197 params->he_6ghz_capab,
5198 sizeof(*params->he_6ghz_capab));
5199 if (nla_put(msg, NL80211_ATTR_HE_6GHZ_CAPABILITY,
5200 sizeof(*params->he_6ghz_capab),
5201 params->he_6ghz_capab))
5202 goto fail;
5203 }
5204
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005205 if (params->ext_capab) {
5206 wpa_hexdump(MSG_DEBUG, " * ext_capab",
5207 params->ext_capab, params->ext_capab_len);
5208 if (nla_put(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
5209 params->ext_capab_len, params->ext_capab))
5210 goto fail;
5211 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005212
5213 if (is_ap_interface(drv->nlmode) &&
5214 nla_put_u8(msg, NL80211_ATTR_STA_SUPPORT_P2P_PS,
5215 params->support_p2p_ps ?
5216 NL80211_P2P_PS_SUPPORTED :
5217 NL80211_P2P_PS_UNSUPPORTED))
5218 goto fail;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005219 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005220 if (!params->set) {
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005221 if (params->aid) {
5222 wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005223 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid))
5224 goto fail;
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005225 } else {
5226 /*
5227 * cfg80211 validates that AID is non-zero, so we have
5228 * to make this a non-zero value for the TDLS case where
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005229 * a dummy STA entry is used for now and for a station
5230 * that is still not associated.
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005231 */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005232 wpa_printf(MSG_DEBUG, " * aid=1 (%s workaround)",
5233 (params->flags & WPA_STA_TDLS_PEER) ?
5234 "TDLS" : "UNASSOC_STA");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005235 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, 1))
5236 goto fail;
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005237 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005238 wpa_printf(MSG_DEBUG, " * listen_interval=%u",
5239 params->listen_interval);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005240 if (nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
5241 params->listen_interval))
5242 goto fail;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07005243 } else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
5244 wpa_printf(MSG_DEBUG, " * peer_aid=%u", params->aid);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005245 if (nla_put_u16(msg, NL80211_ATTR_PEER_AID, params->aid))
5246 goto fail;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005247 } else if (FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags) &&
5248 (params->flags & WPA_STA_ASSOCIATED)) {
5249 wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
5250 wpa_printf(MSG_DEBUG, " * listen_interval=%u",
5251 params->listen_interval);
5252 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid) ||
5253 nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
5254 params->listen_interval))
5255 goto fail;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005256 }
5257
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08005258 if (params->vht_opmode_enabled) {
5259 wpa_printf(MSG_DEBUG, " * opmode=%u", params->vht_opmode);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005260 if (nla_put_u8(msg, NL80211_ATTR_OPMODE_NOTIF,
5261 params->vht_opmode))
5262 goto fail;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005263 }
5264
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005265 if (params->supp_channels) {
5266 wpa_hexdump(MSG_DEBUG, " * supported channels",
5267 params->supp_channels, params->supp_channels_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005268 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
5269 params->supp_channels_len, params->supp_channels))
5270 goto fail;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005271 }
5272
5273 if (params->supp_oper_classes) {
5274 wpa_hexdump(MSG_DEBUG, " * supported operating classes",
5275 params->supp_oper_classes,
5276 params->supp_oper_classes_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005277 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
5278 params->supp_oper_classes_len,
5279 params->supp_oper_classes))
5280 goto fail;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005281 }
5282
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005283 os_memset(&upd, 0, sizeof(upd));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005284 upd.set = sta_flags_nl80211(params->flags);
5285 upd.mask = upd.set | sta_flags_nl80211(params->flags_mask);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005286
5287 /*
5288 * If the driver doesn't support full AP client state, ignore ASSOC/AUTH
5289 * flags, as nl80211 driver moves a new station, by default, into
5290 * associated state.
5291 *
5292 * On the other hand, if the driver supports that feature and the
5293 * station is added in unauthenticated state, set the
5294 * authenticated/associated bits in the mask to prevent moving this
5295 * station to associated state before it is actually associated.
5296 *
5297 * This is irrelevant for mesh mode where the station is added to the
5298 * driver as authenticated already, and ASSOCIATED isn't part of the
5299 * nl80211 API.
5300 */
5301 if (!is_mesh_interface(drv->nlmode)) {
5302 if (!FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) {
5303 wpa_printf(MSG_DEBUG,
5304 "nl80211: Ignore ASSOC/AUTH flags since driver doesn't support full AP client state");
5305 upd.mask &= ~(BIT(NL80211_STA_FLAG_ASSOCIATED) |
5306 BIT(NL80211_STA_FLAG_AUTHENTICATED));
5307 } else if (!params->set &&
5308 !(params->flags & WPA_STA_TDLS_PEER)) {
5309 if (!(params->flags & WPA_STA_AUTHENTICATED))
5310 upd.mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
5311 if (!(params->flags & WPA_STA_ASSOCIATED))
5312 upd.mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
5313 }
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005314#ifdef CONFIG_MESH
5315 } else {
5316 if (params->plink_state == PLINK_ESTAB && params->peer_aid) {
5317 ret = nla_put_u16(msg, NL80211_ATTR_MESH_PEER_AID,
5318 params->peer_aid);
5319 if (ret)
5320 goto fail;
5321 }
5322#endif /* CONFIG_MESH */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005323 }
5324
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005325 wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x",
5326 upd.set, upd.mask);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005327 if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
5328 goto fail;
5329
5330#ifdef CONFIG_MESH
5331 if (params->plink_state &&
5332 nla_put_u8(msg, NL80211_ATTR_STA_PLINK_STATE,
5333 sta_plink_state_nl80211(params->plink_state)))
5334 goto fail;
5335#endif /* CONFIG_MESH */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005336
Hai Shalomc3565922019-10-28 11:58:20 -07005337 if ((!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
5338 FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) &&
5339 (params->flags & WPA_STA_WMM)) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005340 struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
5341
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005342 wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005343 if (!wme ||
5344 nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
5345 params->qosinfo & WMM_QOSINFO_STA_AC_MASK) ||
5346 nla_put_u8(msg, NL80211_STA_WME_MAX_SP,
5347 (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
5348 WMM_QOSINFO_STA_SP_MASK))
5349 goto fail;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005350 nla_nest_end(msg, wme);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005351 }
5352
Hai Shalom899fcc72020-10-19 14:38:18 -07005353 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005354 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005355 if (ret)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005356 wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
5357 "result: %d (%s)", params->set ? "SET" : "NEW", ret,
5358 strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005359 if (ret == -EEXIST)
5360 ret = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005361fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005362 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005363 return ret;
5364}
5365
5366
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005367static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr)
5368{
5369#ifdef CONFIG_LIBNL3_ROUTE
5370 struct wpa_driver_nl80211_data *drv = bss->drv;
5371 struct rtnl_neigh *rn;
5372 struct nl_addr *nl_addr;
5373 int err;
5374
5375 rn = rtnl_neigh_alloc();
5376 if (!rn)
5377 return;
5378
5379 rtnl_neigh_set_family(rn, AF_BRIDGE);
5380 rtnl_neigh_set_ifindex(rn, bss->ifindex);
5381 nl_addr = nl_addr_build(AF_BRIDGE, (void *) addr, ETH_ALEN);
5382 if (!nl_addr) {
5383 rtnl_neigh_put(rn);
5384 return;
5385 }
5386 rtnl_neigh_set_lladdr(rn, nl_addr);
5387
5388 err = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
5389 if (err < 0) {
5390 wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for "
5391 MACSTR " ifindex=%d failed: %s", MAC2STR(addr),
5392 bss->ifindex, nl_geterror(err));
5393 } else {
5394 wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry for "
5395 MACSTR, MAC2STR(addr));
5396 }
5397
5398 nl_addr_put(nl_addr);
5399 rtnl_neigh_put(rn);
5400#endif /* CONFIG_LIBNL3_ROUTE */
5401}
5402
5403
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005404static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
5405 int deauth, u16 reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005406{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005407 struct wpa_driver_nl80211_data *drv = bss->drv;
5408 struct nl_msg *msg;
5409 int ret;
5410
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005411 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION)) ||
5412 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
5413 (deauth == 0 &&
5414 nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
5415 WLAN_FC_STYPE_DISASSOC)) ||
5416 (deauth == 1 &&
5417 nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
5418 WLAN_FC_STYPE_DEAUTH)) ||
5419 (reason_code &&
5420 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code))) {
5421 nlmsg_free(msg);
5422 return -ENOBUFS;
5423 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005424
Hai Shalom899fcc72020-10-19 14:38:18 -07005425 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07005426 wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
5427 " --> %d (%s)",
5428 bss->ifname, MAC2STR(addr), ret, strerror(-ret));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005429
5430 if (drv->rtnl_sk)
5431 rtnl_neigh_delete_fdb_entry(bss, addr);
5432
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005433 if (ret == -ENOENT)
5434 return 0;
5435 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005436}
5437
5438
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005439void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005440{
5441 struct nl_msg *msg;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005442 struct wpa_driver_nl80211_data *drv2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005443
5444 wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
5445
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005446 /* stop listening for EAPOL on this interface */
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005447 dl_list_for_each(drv2, &drv->global->interfaces,
5448 struct wpa_driver_nl80211_data, list)
Dmitry Shmidt9c175262016-03-03 10:20:07 -08005449 {
5450 del_ifidx(drv2, ifidx, IFIDX_ANY);
5451 /* Remove all bridges learned for this iface */
5452 del_ifidx(drv2, IFIDX_ANY, ifidx);
5453 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005454
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005455 msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
Hai Shalom899fcc72020-10-19 14:38:18 -07005456 if (send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005457 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005458 wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
5459}
5460
5461
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07005462const char * nl80211_iftype_str(enum nl80211_iftype mode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005463{
5464 switch (mode) {
5465 case NL80211_IFTYPE_ADHOC:
5466 return "ADHOC";
5467 case NL80211_IFTYPE_STATION:
5468 return "STATION";
5469 case NL80211_IFTYPE_AP:
5470 return "AP";
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07005471 case NL80211_IFTYPE_AP_VLAN:
5472 return "AP_VLAN";
5473 case NL80211_IFTYPE_WDS:
5474 return "WDS";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005475 case NL80211_IFTYPE_MONITOR:
5476 return "MONITOR";
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07005477 case NL80211_IFTYPE_MESH_POINT:
5478 return "MESH_POINT";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005479 case NL80211_IFTYPE_P2P_CLIENT:
5480 return "P2P_CLIENT";
5481 case NL80211_IFTYPE_P2P_GO:
5482 return "P2P_GO";
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005483 case NL80211_IFTYPE_P2P_DEVICE:
5484 return "P2P_DEVICE";
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005485 case NL80211_IFTYPE_OCB:
5486 return "OCB";
5487 case NL80211_IFTYPE_NAN:
5488 return "NAN";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005489 default:
5490 return "unknown";
5491 }
5492}
5493
5494
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005495static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
5496 const char *ifname,
5497 enum nl80211_iftype iftype,
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005498 const u8 *addr, int wds,
5499 int (*handler)(struct nl_msg *, void *),
5500 void *arg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005501{
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005502 struct nl_msg *msg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005503 int ifidx;
5504 int ret = -ENOBUFS;
5505
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005506 wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
5507 iftype, nl80211_iftype_str(iftype));
5508
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005509 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_NEW_INTERFACE);
5510 if (!msg ||
5511 nla_put_string(msg, NL80211_ATTR_IFNAME, ifname) ||
5512 nla_put_u32(msg, NL80211_ATTR_IFTYPE, iftype))
5513 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005514
5515 if (iftype == NL80211_IFTYPE_MONITOR) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005516 struct nlattr *flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005517
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005518 flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005519 if (!flags ||
5520 nla_put_flag(msg, NL80211_MNTR_FLAG_COOK_FRAMES))
5521 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005522
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005523 nla_nest_end(msg, flags);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005524 } else if (wds) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005525 if (nla_put_u8(msg, NL80211_ATTR_4ADDR, wds))
5526 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005527 }
5528
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07005529 /*
5530 * Tell cfg80211 that the interface belongs to the socket that created
5531 * it, and the interface should be deleted when the socket is closed.
5532 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005533 if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
5534 goto fail;
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07005535
Hai Shalom60840252021-02-19 19:02:11 -08005536 if ((addr && iftype == NL80211_IFTYPE_P2P_DEVICE) &&
5537 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
5538 goto fail;
5539
Hai Shalom899fcc72020-10-19 14:38:18 -07005540 ret = send_and_recv_msgs(drv, msg, handler, arg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005541 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005542 if (ret) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005543 fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005544 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005545 wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
5546 ifname, ret, strerror(-ret));
5547 return ret;
5548 }
5549
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005550 if (iftype == NL80211_IFTYPE_P2P_DEVICE)
5551 return 0;
5552
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005553 ifidx = if_nametoindex(ifname);
5554 wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
5555 ifname, ifidx);
5556
5557 if (ifidx <= 0)
5558 return -1;
5559
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005560 /*
5561 * Some virtual interfaces need to process EAPOL packets and events on
5562 * the parent interface. This is used mainly with hostapd.
5563 */
5564 if (drv->hostapd ||
5565 iftype == NL80211_IFTYPE_AP_VLAN ||
5566 iftype == NL80211_IFTYPE_WDS ||
5567 iftype == NL80211_IFTYPE_MONITOR) {
5568 /* start listening for EAPOL on this interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08005569 add_ifidx(drv, ifidx, IFIDX_ANY);
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005570 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005571
5572 if (addr && iftype != NL80211_IFTYPE_MONITOR &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005573 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005574 nl80211_remove_iface(drv, ifidx);
5575 return -1;
5576 }
5577
5578 return ifidx;
5579}
5580
5581
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005582int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
5583 const char *ifname, enum nl80211_iftype iftype,
5584 const u8 *addr, int wds,
5585 int (*handler)(struct nl_msg *, void *),
5586 void *arg, int use_existing)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005587{
5588 int ret;
5589
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005590 ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
5591 arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005592
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005593 /* if error occurred and interface exists already */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005594 if (ret == -ENFILE && if_nametoindex(ifname)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005595 if (use_existing) {
5596 wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s",
5597 ifname);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07005598 if (addr && iftype != NL80211_IFTYPE_MONITOR &&
5599 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
5600 addr) < 0 &&
5601 (linux_set_iface_flags(drv->global->ioctl_sock,
5602 ifname, 0) < 0 ||
5603 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
5604 addr) < 0 ||
5605 linux_set_iface_flags(drv->global->ioctl_sock,
5606 ifname, 1) < 0))
5607 return -1;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005608 return -ENFILE;
5609 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005610 wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
5611
5612 /* Try to remove the interface that was already there. */
5613 nl80211_remove_iface(drv, if_nametoindex(ifname));
5614
5615 /* Try to create the interface again */
5616 ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005617 wds, handler, arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005618 }
5619
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005620 if (ret >= 0 && is_p2p_net_interface(iftype)) {
5621 wpa_printf(MSG_DEBUG,
5622 "nl80211: Interface %s created for P2P - disable 11b rates",
5623 ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005624 nl80211_disable_11b_rates(drv, ret, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005625 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005626
5627 return ret;
5628}
5629
5630
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005631static int nl80211_setup_ap(struct i802_bss *bss)
5632{
5633 struct wpa_driver_nl80211_data *drv = bss->drv;
5634
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005635 wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d use_monitor=%d",
5636 bss->ifname, drv->device_ap_sme, drv->use_monitor);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005637
5638 /*
5639 * Disable Probe Request reporting unless we need it in this way for
5640 * devices that include the AP SME, in the other case (unless using
5641 * monitor iface) we'll get it through the nl_mgmt socket instead.
5642 */
5643 if (!drv->device_ap_sme)
5644 wpa_driver_nl80211_probe_req_report(bss, 0);
5645
5646 if (!drv->device_ap_sme && !drv->use_monitor)
5647 if (nl80211_mgmt_subscribe_ap(bss))
5648 return -1;
5649
5650 if (drv->device_ap_sme && !drv->use_monitor)
5651 if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005652 wpa_printf(MSG_DEBUG,
5653 "nl80211: Failed to subscribe for mgmt frames from SME driver - trying to run without it");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005654
5655 if (!drv->device_ap_sme && drv->use_monitor &&
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005656 nl80211_create_monitor_interface(drv) &&
5657 !drv->device_ap_sme)
Dmitry Shmidt04949592012-07-19 12:16:46 -07005658 return -1;
5659
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005660 if (drv->device_ap_sme &&
5661 wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
5662 wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
5663 "Probe Request frame reporting in AP mode");
5664 /* Try to survive without this */
5665 }
5666
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005667 return 0;
5668}
5669
5670
5671static void nl80211_teardown_ap(struct i802_bss *bss)
5672{
5673 struct wpa_driver_nl80211_data *drv = bss->drv;
5674
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005675 wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d use_monitor=%d",
5676 bss->ifname, drv->device_ap_sme, drv->use_monitor);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005677 if (drv->device_ap_sme) {
5678 wpa_driver_nl80211_probe_req_report(bss, 0);
5679 if (!drv->use_monitor)
5680 nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
5681 } else if (drv->use_monitor)
5682 nl80211_remove_monitor_interface(drv);
5683 else
5684 nl80211_mgmt_unsubscribe(bss, "AP teardown");
5685
Paul Stewart092955c2017-02-06 09:13:09 -08005686 nl80211_put_wiphy_data_ap(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005687 bss->beacon_set = 0;
5688}
5689
5690
Hai Shalomfdcde762020-04-02 11:19:20 -07005691static int nl80211_tx_control_port(void *priv, const u8 *dest,
5692 u16 proto, const u8 *buf, size_t len,
5693 int no_encrypt)
5694{
Hai Shalom899fcc72020-10-19 14:38:18 -07005695 struct nl80211_ack_ext_arg ext_arg;
Hai Shalomfdcde762020-04-02 11:19:20 -07005696 struct i802_bss *bss = priv;
5697 struct nl_msg *msg;
Hai Shalom899fcc72020-10-19 14:38:18 -07005698 u64 cookie = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07005699 int ret;
5700
5701 wpa_printf(MSG_DEBUG,
5702 "nl80211: Send over control port dest=" MACSTR
5703 " proto=0x%04x len=%u no_encrypt=%d",
5704 MAC2STR(dest), proto, (unsigned int) len, no_encrypt);
5705
5706 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CONTROL_PORT_FRAME);
5707 if (!msg ||
5708 nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
5709 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dest) ||
5710 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
5711 (no_encrypt &&
5712 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) {
5713 nlmsg_free(msg);
5714 return -ENOBUFS;
5715 }
5716
Hai Shalom899fcc72020-10-19 14:38:18 -07005717 os_memset(&ext_arg, 0, sizeof(struct nl80211_ack_ext_arg));
5718 ext_arg.ext_data = &cookie;
5719 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL,
5720 ack_handler_cookie, &ext_arg);
5721 if (ret) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005722 wpa_printf(MSG_DEBUG,
5723 "nl80211: tx_control_port failed: ret=%d (%s)",
5724 ret, strerror(-ret));
Hai Shalom899fcc72020-10-19 14:38:18 -07005725 } else {
5726 struct wpa_driver_nl80211_data *drv = bss->drv;
5727
5728 wpa_printf(MSG_DEBUG,
5729 "nl80211: tx_control_port cookie=0x%llx",
5730 (long long unsigned int) cookie);
5731 drv->eapol_tx_cookie = cookie;
5732 }
Hai Shalomfdcde762020-04-02 11:19:20 -07005733
5734 return ret;
5735}
5736
5737
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005738static int nl80211_send_eapol_data(struct i802_bss *bss,
5739 const u8 *addr, const u8 *data,
5740 size_t data_len)
5741{
5742 struct sockaddr_ll ll;
5743 int ret;
5744
5745 if (bss->drv->eapol_tx_sock < 0) {
5746 wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
5747 return -1;
5748 }
5749
5750 os_memset(&ll, 0, sizeof(ll));
5751 ll.sll_family = AF_PACKET;
5752 ll.sll_ifindex = bss->ifindex;
5753 ll.sll_protocol = htons(ETH_P_PAE);
5754 ll.sll_halen = ETH_ALEN;
5755 os_memcpy(ll.sll_addr, addr, ETH_ALEN);
5756 ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
5757 (struct sockaddr *) &ll, sizeof(ll));
5758 if (ret < 0)
5759 wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
5760 strerror(errno));
5761
5762 return ret;
5763}
5764
5765
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005766static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
5767
5768static int wpa_driver_nl80211_hapd_send_eapol(
5769 void *priv, const u8 *addr, const u8 *data,
5770 size_t data_len, int encrypt, const u8 *own_addr, u32 flags)
5771{
5772 struct i802_bss *bss = priv;
5773 struct wpa_driver_nl80211_data *drv = bss->drv;
5774 struct ieee80211_hdr *hdr;
5775 size_t len;
5776 u8 *pos;
5777 int res;
5778 int qos = flags & WPA_STA_WMM;
Dmitry Shmidt641185e2013-11-06 15:17:13 -08005779
Hai Shalomb755a2a2020-04-23 21:49:02 -07005780 /* For now, disable EAPOL TX over control port in AP mode by default
5781 * since it does not provide TX status notifications. */
5782 if (drv->control_port_ap &&
5783 (drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT))
Hai Shalomfdcde762020-04-02 11:19:20 -07005784 return nl80211_tx_control_port(bss, addr, ETH_P_EAPOL,
5785 data, data_len, !encrypt);
5786
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005787 if (drv->device_ap_sme || !drv->use_monitor)
5788 return nl80211_send_eapol_data(bss, addr, data, data_len);
5789
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005790 len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
5791 data_len;
5792 hdr = os_zalloc(len);
5793 if (hdr == NULL) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005794 wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)",
5795 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005796 return -1;
5797 }
5798
5799 hdr->frame_control =
5800 IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
5801 hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
5802 if (encrypt)
5803 hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
5804 if (qos) {
5805 hdr->frame_control |=
5806 host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
5807 }
5808
5809 memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
5810 memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
5811 memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
5812 pos = (u8 *) (hdr + 1);
5813
5814 if (qos) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07005815 /* Set highest priority in QoS header */
5816 pos[0] = 7;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005817 pos[1] = 0;
5818 pos += 2;
5819 }
5820
5821 memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
5822 pos += sizeof(rfc1042_header);
5823 WPA_PUT_BE16(pos, ETH_P_PAE);
5824 pos += 2;
5825 memcpy(pos, data, data_len);
5826
Hai Shalomfdcde762020-04-02 11:19:20 -07005827 res = nl80211_send_monitor(drv, hdr, len, encrypt, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005828 if (res < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005829 wpa_printf(MSG_ERROR,
5830 "hapd_send_eapol - packet len: %lu - failed",
5831 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005832 }
5833 os_free(hdr);
5834
5835 return res;
5836}
5837
5838
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005839static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005840 unsigned int total_flags,
5841 unsigned int flags_or,
5842 unsigned int flags_and)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005843{
5844 struct i802_bss *bss = priv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005845 struct nl_msg *msg;
5846 struct nlattr *flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005847 struct nl80211_sta_flag_update upd;
5848
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005849 wpa_printf(MSG_DEBUG, "nl80211: Set STA flags - ifname=%s addr=" MACSTR
5850 " total_flags=0x%x flags_or=0x%x flags_and=0x%x authorized=%d",
5851 bss->ifname, MAC2STR(addr), total_flags, flags_or, flags_and,
5852 !!(total_flags & WPA_STA_AUTHORIZED));
5853
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005854 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
5855 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
5856 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005857
5858 /*
5859 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
5860 * can be removed eventually.
5861 */
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005862 flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005863 if (!flags ||
5864 ((total_flags & WPA_STA_AUTHORIZED) &&
5865 nla_put_flag(msg, NL80211_STA_FLAG_AUTHORIZED)) ||
5866 ((total_flags & WPA_STA_WMM) &&
5867 nla_put_flag(msg, NL80211_STA_FLAG_WME)) ||
5868 ((total_flags & WPA_STA_SHORT_PREAMBLE) &&
5869 nla_put_flag(msg, NL80211_STA_FLAG_SHORT_PREAMBLE)) ||
5870 ((total_flags & WPA_STA_MFP) &&
5871 nla_put_flag(msg, NL80211_STA_FLAG_MFP)) ||
5872 ((total_flags & WPA_STA_TDLS_PEER) &&
5873 nla_put_flag(msg, NL80211_STA_FLAG_TDLS_PEER)))
5874 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005875
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005876 nla_nest_end(msg, flags);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005877
5878 os_memset(&upd, 0, sizeof(upd));
5879 upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
5880 upd.set = sta_flags_nl80211(flags_or);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005881 if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
5882 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005883
Hai Shalom899fcc72020-10-19 14:38:18 -07005884 return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005885fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005886 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005887 return -ENOBUFS;
5888}
5889
5890
Hai Shalom81f62d82019-07-22 12:10:00 -07005891static int driver_nl80211_sta_set_airtime_weight(void *priv, const u8 *addr,
5892 unsigned int weight)
5893{
5894 struct i802_bss *bss = priv;
5895 struct nl_msg *msg;
5896
5897 wpa_printf(MSG_DEBUG,
5898 "nl80211: Set STA airtime weight - ifname=%s addr=" MACSTR
5899 " weight=%u", bss->ifname, MAC2STR(addr), weight);
5900
5901 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
5902 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
5903 nla_put_u16(msg, NL80211_ATTR_AIRTIME_WEIGHT, weight))
5904 goto fail;
5905
Hai Shalom899fcc72020-10-19 14:38:18 -07005906 return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Hai Shalom81f62d82019-07-22 12:10:00 -07005907fail:
5908 nlmsg_free(msg);
5909 return -ENOBUFS;
5910}
5911
5912
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005913static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
5914 struct wpa_driver_associate_params *params)
5915{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005916 enum nl80211_iftype nlmode, old_mode;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005917
5918 if (params->p2p) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005919 wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
5920 "group (GO)");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005921 nlmode = NL80211_IFTYPE_P2P_GO;
5922 } else
5923 nlmode = NL80211_IFTYPE_AP;
5924
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005925 old_mode = drv->nlmode;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005926 if (wpa_driver_nl80211_set_mode(drv->first_bss, nlmode)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005927 nl80211_remove_monitor_interface(drv);
5928 return -1;
5929 }
5930
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08005931 if (params->freq.freq &&
5932 nl80211_set_channel(drv->first_bss, &params->freq, 0)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005933 if (old_mode != nlmode)
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005934 wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005935 nl80211_remove_monitor_interface(drv);
5936 return -1;
5937 }
5938
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005939 return 0;
5940}
5941
5942
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005943static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
5944 int reset_mode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005945{
5946 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005947 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005948
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005949 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
Hai Shalomb755a2a2020-04-23 21:49:02 -07005950 ret = send_and_recv_msgs_owner(drv, msg,
5951 get_connect_handle(drv->first_bss), 1,
Hai Shalom899fcc72020-10-19 14:38:18 -07005952 NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005953 if (ret) {
5954 wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
5955 "(%s)", ret, strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005956 } else {
5957 wpa_printf(MSG_DEBUG,
5958 "nl80211: Leave IBSS request sent successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005959 }
5960
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005961 if (reset_mode &&
5962 wpa_driver_nl80211_set_mode(drv->first_bss,
Dmitry Shmidt56052862013-10-04 10:23:25 -07005963 NL80211_IFTYPE_STATION)) {
5964 wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
5965 "station mode");
5966 }
5967
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005968 return ret;
5969}
5970
5971
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005972static int nl80211_ht_vht_overrides(struct nl_msg *msg,
5973 struct wpa_driver_associate_params *params)
5974{
5975 if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
5976 return -1;
5977
5978 if (params->htcaps && params->htcaps_mask) {
5979 int sz = sizeof(struct ieee80211_ht_capabilities);
5980 wpa_hexdump(MSG_DEBUG, " * htcaps", params->htcaps, sz);
5981 wpa_hexdump(MSG_DEBUG, " * htcaps_mask",
5982 params->htcaps_mask, sz);
5983 if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
5984 params->htcaps) ||
5985 nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
5986 params->htcaps_mask))
5987 return -1;
5988 }
5989
5990#ifdef CONFIG_VHT_OVERRIDES
5991 if (params->disable_vht) {
5992 wpa_printf(MSG_DEBUG, " * VHT disabled");
5993 if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
5994 return -1;
5995 }
5996
5997 if (params->vhtcaps && params->vhtcaps_mask) {
5998 int sz = sizeof(struct ieee80211_vht_capabilities);
5999 wpa_hexdump(MSG_DEBUG, " * vhtcaps", params->vhtcaps, sz);
6000 wpa_hexdump(MSG_DEBUG, " * vhtcaps_mask",
6001 params->vhtcaps_mask, sz);
6002 if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
6003 params->vhtcaps) ||
6004 nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
6005 params->vhtcaps_mask))
6006 return -1;
6007 }
6008#endif /* CONFIG_VHT_OVERRIDES */
6009
6010 return 0;
6011}
6012
6013
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006014static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
6015 struct wpa_driver_associate_params *params)
6016{
6017 struct nl_msg *msg;
6018 int ret = -1;
6019 int count = 0;
6020
6021 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
6022
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006023 if (wpa_driver_nl80211_set_mode_ibss(drv->first_bss, &params->freq)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006024 wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
6025 "IBSS mode");
6026 return -1;
6027 }
6028
6029retry:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006030 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_IBSS)) ||
6031 params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
6032 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006033
Hai Shalom74f70d42019-02-11 14:42:39 -08006034 wpa_printf(MSG_DEBUG, " * SSID=%s",
6035 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006036 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
6037 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006038 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6039 drv->ssid_len = params->ssid_len;
6040
Dmitry Shmidtff787d52015-01-12 13:01:47 -08006041 if (nl80211_put_freq_params(msg, &params->freq) < 0 ||
6042 nl80211_put_beacon_int(msg, params->beacon_int))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006043 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006044
6045 ret = nl80211_set_conn_keys(params, msg);
6046 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006047 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006048
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006049 if (params->bssid && params->fixed_bssid) {
6050 wpa_printf(MSG_DEBUG, " * BSSID=" MACSTR,
6051 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006052 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
6053 goto fail;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006054 }
6055
Dmitry Shmidt7f656022015-02-25 14:36:37 -08006056 if (params->fixed_freq) {
6057 wpa_printf(MSG_DEBUG, " * fixed_freq");
6058 if (nla_put_flag(msg, NL80211_ATTR_FREQ_FIXED))
6059 goto fail;
6060 }
6061
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006062 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
6063 params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
6064 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
6065 params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006066 wpa_printf(MSG_DEBUG, " * control port");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006067 if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
6068 goto fail;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006069 }
6070
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006071 if (params->wpa_ie) {
6072 wpa_hexdump(MSG_DEBUG,
6073 " * Extra IEs for Beacon/Probe Response frames",
6074 params->wpa_ie, params->wpa_ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006075 if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
6076 params->wpa_ie))
6077 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006078 }
6079
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08006080 ret = nl80211_ht_vht_overrides(msg, params);
6081 if (ret < 0)
6082 goto fail;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006083
Hai Shalomb755a2a2020-04-23 21:49:02 -07006084 ret = send_and_recv_msgs_owner(drv, msg,
6085 get_connect_handle(drv->first_bss), 1,
Hai Shalom899fcc72020-10-19 14:38:18 -07006086 NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006087 msg = NULL;
6088 if (ret) {
6089 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
6090 ret, strerror(-ret));
6091 count++;
6092 if (ret == -EALREADY && count == 1) {
6093 wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
6094 "forced leave");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006095 nl80211_leave_ibss(drv, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006096 nlmsg_free(msg);
6097 goto retry;
6098 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006099 } else {
6100 wpa_printf(MSG_DEBUG,
6101 "nl80211: Join IBSS request sent successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006102 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006103
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006104fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006105 nlmsg_free(msg);
6106 return ret;
6107}
6108
6109
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006110static int nl80211_put_fils_connect_params(struct wpa_driver_nl80211_data *drv,
6111 struct wpa_driver_associate_params *params,
6112 struct nl_msg *msg)
6113{
6114 if (params->fils_erp_username_len) {
6115 wpa_hexdump_ascii(MSG_DEBUG, " * FILS ERP EMSKname/username",
6116 params->fils_erp_username,
6117 params->fils_erp_username_len);
6118 if (nla_put(msg, NL80211_ATTR_FILS_ERP_USERNAME,
6119 params->fils_erp_username_len,
6120 params->fils_erp_username))
6121 return -1;
6122 }
6123
6124 if (params->fils_erp_realm_len) {
6125 wpa_hexdump_ascii(MSG_DEBUG, " * FILS ERP Realm",
6126 params->fils_erp_realm,
6127 params->fils_erp_realm_len);
6128 if (nla_put(msg, NL80211_ATTR_FILS_ERP_REALM,
6129 params->fils_erp_realm_len, params->fils_erp_realm))
6130 return -1;
6131 }
6132
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006133 if (params->fils_erp_rrk_len) {
Vinita S. Maloo3a5b4412020-05-19 17:43:22 +05306134 wpa_printf(MSG_DEBUG, " * FILS ERP next seq %u",
6135 params->fils_erp_next_seq_num);
6136 if (nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
6137 params->fils_erp_next_seq_num))
6138 return -1;
6139
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006140 wpa_printf(MSG_DEBUG, " * FILS ERP rRK (len=%lu)",
6141 (unsigned long) params->fils_erp_rrk_len);
6142 if (nla_put(msg, NL80211_ATTR_FILS_ERP_RRK,
6143 params->fils_erp_rrk_len, params->fils_erp_rrk))
6144 return -1;
6145 }
6146
6147 return 0;
6148}
6149
6150
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006151static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
6152 struct wpa_driver_associate_params *params,
6153 struct nl_msg *msg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006154{
Paul Stewart092955c2017-02-06 09:13:09 -08006155 if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
6156 return -1;
6157
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006158 if (params->bssid) {
6159 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
6160 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006161 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
6162 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006163 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006164
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006165 if (params->bssid_hint) {
6166 wpa_printf(MSG_DEBUG, " * bssid_hint=" MACSTR,
6167 MAC2STR(params->bssid_hint));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006168 if (nla_put(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
6169 params->bssid_hint))
6170 return -1;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006171 }
6172
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006173 if (params->freq.freq) {
6174 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq.freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006175 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
6176 params->freq.freq))
6177 return -1;
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006178 drv->assoc_freq = params->freq.freq;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07006179 } else
6180 drv->assoc_freq = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006181
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006182 if (params->freq_hint) {
6183 wpa_printf(MSG_DEBUG, " * freq_hint=%d", params->freq_hint);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006184 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_HINT,
6185 params->freq_hint))
6186 return -1;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006187 }
6188
Hai Shalomc3565922019-10-28 11:58:20 -07006189 if (params->freq.edmg.channels && params->freq.edmg.bw_config) {
6190 wpa_printf(MSG_DEBUG,
6191 " * EDMG configuration: channels=0x%x bw_config=%d",
6192 params->freq.edmg.channels,
6193 params->freq.edmg.bw_config);
6194 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
6195 params->freq.edmg.channels) ||
6196 nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
6197 params->freq.edmg.bw_config))
6198 return -1;
6199 }
6200
Dmitry Shmidt04949592012-07-19 12:16:46 -07006201 if (params->bg_scan_period >= 0) {
6202 wpa_printf(MSG_DEBUG, " * bg scan period=%d",
6203 params->bg_scan_period);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006204 if (nla_put_u16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
6205 params->bg_scan_period))
6206 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07006207 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006208
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006209 if (params->ssid) {
Hai Shalom74f70d42019-02-11 14:42:39 -08006210 wpa_printf(MSG_DEBUG, " * SSID=%s",
6211 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006212 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
6213 params->ssid))
6214 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006215 if (params->ssid_len > sizeof(drv->ssid))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006216 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006217 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6218 drv->ssid_len = params->ssid_len;
6219 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006220
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006221 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006222 if (params->wpa_ie &&
6223 nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie))
6224 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006225
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006226 if (params->wpa_proto) {
6227 enum nl80211_wpa_versions ver = 0;
6228
6229 if (params->wpa_proto & WPA_PROTO_WPA)
6230 ver |= NL80211_WPA_VERSION_1;
6231 if (params->wpa_proto & WPA_PROTO_RSN)
6232 ver |= NL80211_WPA_VERSION_2;
6233
6234 wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006235 if (nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
6236 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006237 }
6238
6239 if (params->pairwise_suite != WPA_CIPHER_NONE) {
6240 u32 cipher = wpa_cipher_to_cipher_suite(params->pairwise_suite);
6241 wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006242 if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
6243 cipher))
6244 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006245 }
6246
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08006247 if (params->group_suite == WPA_CIPHER_GTK_NOT_USED &&
6248 !(drv->capa.enc & WPA_DRIVER_CAPA_ENC_GTK_NOT_USED)) {
6249 /*
6250 * This is likely to work even though many drivers do not
6251 * advertise support for operations without GTK.
6252 */
6253 wpa_printf(MSG_DEBUG, " * skip group cipher configuration for GTK_NOT_USED due to missing driver support advertisement");
6254 } else if (params->group_suite != WPA_CIPHER_NONE) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006255 u32 cipher = wpa_cipher_to_cipher_suite(params->group_suite);
6256 wpa_printf(MSG_DEBUG, " * group=0x%x", cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006257 if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher))
6258 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006259 }
6260
6261 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
6262 params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
6263 params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X ||
6264 params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
Dmitry Shmidt15907092014-03-25 10:42:57 -07006265 params->key_mgmt_suite == WPA_KEY_MGMT_CCKM ||
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07006266 params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
6267 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006268 params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
Hai Shalom021b0b52019-04-10 11:17:58 -07006269 params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
6270 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE ||
Dmitry Shmidt807291d2015-01-27 13:40:23 -08006271 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006272 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ||
Hai Shalom021b0b52019-04-10 11:17:58 -07006273 params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006274 params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA256 ||
6275 params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA384 ||
6276 params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA256 ||
Roshan Pius3a1667e2018-07-03 15:17:14 -07006277 params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384 ||
6278 params->key_mgmt_suite == WPA_KEY_MGMT_OWE ||
6279 params->key_mgmt_suite == WPA_KEY_MGMT_DPP) {
Paul Stewart092955c2017-02-06 09:13:09 -08006280 int mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006281
6282 switch (params->key_mgmt_suite) {
6283 case WPA_KEY_MGMT_CCKM:
Paul Stewart092955c2017-02-06 09:13:09 -08006284 mgmt = RSN_AUTH_KEY_MGMT_CCKM;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006285 break;
6286 case WPA_KEY_MGMT_IEEE8021X:
Paul Stewart092955c2017-02-06 09:13:09 -08006287 mgmt = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006288 break;
6289 case WPA_KEY_MGMT_FT_IEEE8021X:
Paul Stewart092955c2017-02-06 09:13:09 -08006290 mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006291 break;
6292 case WPA_KEY_MGMT_FT_PSK:
Paul Stewart092955c2017-02-06 09:13:09 -08006293 mgmt = RSN_AUTH_KEY_MGMT_FT_PSK;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006294 break;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07006295 case WPA_KEY_MGMT_IEEE8021X_SHA256:
Paul Stewart092955c2017-02-06 09:13:09 -08006296 mgmt = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07006297 break;
6298 case WPA_KEY_MGMT_PSK_SHA256:
Paul Stewart092955c2017-02-06 09:13:09 -08006299 mgmt = RSN_AUTH_KEY_MGMT_PSK_SHA256;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07006300 break;
Dmitry Shmidt15907092014-03-25 10:42:57 -07006301 case WPA_KEY_MGMT_OSEN:
Paul Stewart092955c2017-02-06 09:13:09 -08006302 mgmt = RSN_AUTH_KEY_MGMT_OSEN;
Dmitry Shmidt15907092014-03-25 10:42:57 -07006303 break;
Hai Shalom021b0b52019-04-10 11:17:58 -07006304 case WPA_KEY_MGMT_SAE:
6305 mgmt = RSN_AUTH_KEY_MGMT_SAE;
6306 break;
6307 case WPA_KEY_MGMT_FT_SAE:
6308 mgmt = RSN_AUTH_KEY_MGMT_FT_SAE;
6309 break;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006310 case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
Paul Stewart092955c2017-02-06 09:13:09 -08006311 mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006312 break;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08006313 case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
Paul Stewart092955c2017-02-06 09:13:09 -08006314 mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08006315 break;
Hai Shalom021b0b52019-04-10 11:17:58 -07006316 case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
6317 mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
6318 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006319 case WPA_KEY_MGMT_FILS_SHA256:
6320 mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA256;
6321 break;
6322 case WPA_KEY_MGMT_FILS_SHA384:
6323 mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA384;
6324 break;
6325 case WPA_KEY_MGMT_FT_FILS_SHA256:
6326 mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
6327 break;
6328 case WPA_KEY_MGMT_FT_FILS_SHA384:
6329 mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
6330 break;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006331 case WPA_KEY_MGMT_OWE:
6332 mgmt = RSN_AUTH_KEY_MGMT_OWE;
6333 break;
6334 case WPA_KEY_MGMT_DPP:
6335 mgmt = RSN_AUTH_KEY_MGMT_DPP;
6336 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006337 case WPA_KEY_MGMT_PSK:
6338 default:
Paul Stewart092955c2017-02-06 09:13:09 -08006339 mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006340 break;
6341 }
Dmitry Shmidt15907092014-03-25 10:42:57 -07006342 wpa_printf(MSG_DEBUG, " * akm=0x%x", mgmt);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006343 if (nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, mgmt))
6344 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006345 }
6346
Hai Shalomc3565922019-10-28 11:58:20 -07006347 if (params->req_handshake_offload &&
Hai Shalom74f70d42019-02-11 14:42:39 -08006348 (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) {
6349 wpa_printf(MSG_DEBUG, " * WANT_1X_4WAY_HS");
6350 if (nla_put_flag(msg, NL80211_ATTR_WANT_1X_4WAY_HS))
6351 return -1;
6352 }
6353
Roshan Pius3a1667e2018-07-03 15:17:14 -07006354 /* Add PSK in case of 4-way handshake offload */
6355 if (params->psk &&
Hai Shalom74f70d42019-02-11 14:42:39 -08006356 (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006357 wpa_hexdump_key(MSG_DEBUG, " * PSK", params->psk, 32);
6358 if (nla_put(msg, NL80211_ATTR_PMK, 32, params->psk))
6359 return -1;
6360 }
6361
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006362 if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
6363 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006364
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006365 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
6366 (params->pairwise_suite == WPA_CIPHER_NONE ||
6367 params->pairwise_suite == WPA_CIPHER_WEP104 ||
6368 params->pairwise_suite == WPA_CIPHER_WEP40) &&
6369 (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
6370 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
6371 return -1;
6372
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006373 if (params->rrm_used) {
6374 u32 drv_rrm_flags = drv->capa.rrm_flags;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006375 if ((!((drv_rrm_flags &
6376 WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) &&
6377 (drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) &&
6378 !(drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006379 nla_put_flag(msg, NL80211_ATTR_USE_RRM))
6380 return -1;
6381 }
6382
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006383 if (nl80211_ht_vht_overrides(msg, params) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006384 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006385
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006386 if (params->p2p)
6387 wpa_printf(MSG_DEBUG, " * P2P group");
6388
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006389 if (params->pbss) {
6390 wpa_printf(MSG_DEBUG, " * PBSS");
6391 if (nla_put_flag(msg, NL80211_ATTR_PBSS))
6392 return -1;
6393 }
6394
Dmitry Shmidte4663042016-04-04 10:07:49 -07006395 drv->connect_reassoc = 0;
6396 if (params->prev_bssid) {
6397 wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR,
6398 MAC2STR(params->prev_bssid));
6399 if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
6400 params->prev_bssid))
6401 return -1;
6402 drv->connect_reassoc = 1;
6403 }
6404
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006405 if ((params->auth_alg & WPA_AUTH_ALG_FILS) &&
6406 nl80211_put_fils_connect_params(drv, params, msg) != 0)
6407 return -1;
6408
Hai Shalomc3565922019-10-28 11:58:20 -07006409 if ((params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
6410 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) &&
Roshan Pius3a1667e2018-07-03 15:17:14 -07006411 (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
6412 nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
6413 return -1;
6414
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006415 return 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006416}
6417
6418
6419static int wpa_driver_nl80211_try_connect(
6420 struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006421 struct wpa_driver_associate_params *params,
Hai Shalomfdcde762020-04-02 11:19:20 -07006422 struct nl_sock *nl_connect)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006423{
6424 struct nl_msg *msg;
6425 enum nl80211_auth_type type;
6426 int ret;
6427 int algs;
6428
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006429#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006430 if (params->req_key_mgmt_offload && params->psk &&
6431 (params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
6432 params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
6433 params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
6434 wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK");
6435 ret = issue_key_mgmt_set_key(drv, params->psk, 32);
6436 if (ret)
6437 return ret;
6438 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006439#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006440
6441 wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
6442 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_CONNECT);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006443 if (!msg)
6444 return -1;
6445
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006446 ret = nl80211_connect_common(drv, params, msg);
6447 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006448 goto fail;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006449
Roshan Pius3a1667e2018-07-03 15:17:14 -07006450 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
6451 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
6452 goto fail;
6453
6454 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_OPTIONAL &&
6455 (drv->capa.flags & WPA_DRIVER_FLAGS_MFP_OPTIONAL) &&
6456 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_OPTIONAL))
6457 goto fail;
6458
Hai Shalom60840252021-02-19 19:02:11 -08006459#ifdef CONFIG_SAE
6460 if ((params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
6461 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) &&
6462 nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
6463 goto fail;
6464#endif /* CONFIG_SAE */
6465
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006466 algs = 0;
6467 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
6468 algs++;
6469 if (params->auth_alg & WPA_AUTH_ALG_SHARED)
6470 algs++;
6471 if (params->auth_alg & WPA_AUTH_ALG_LEAP)
6472 algs++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006473 if (params->auth_alg & WPA_AUTH_ALG_FILS)
6474 algs++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006475 if (params->auth_alg & WPA_AUTH_ALG_FT)
6476 algs++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006477 if (algs > 1) {
6478 wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic "
6479 "selection");
6480 goto skip_auth_type;
6481 }
6482
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006483 type = get_nl_auth_type(params->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006484 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006485 if (type == NL80211_AUTHTYPE_MAX ||
6486 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006487 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006488
6489skip_auth_type:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006490 ret = nl80211_set_conn_keys(params, msg);
6491 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006492 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006493
Hai Shalomb755a2a2020-04-23 21:49:02 -07006494 ret = send_and_recv_msgs_owner(drv, msg, nl_connect, 1, NULL,
Hai Shalom60840252021-02-19 19:02:11 -08006495 NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006496 msg = NULL;
6497 if (ret) {
6498 wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
6499 "(%s)", ret, strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006500 } else {
Hai Shalom60840252021-02-19 19:02:11 -08006501#ifdef CONFIG_DRIVER_NL80211_QCA
6502 drv->roam_indication_done = false;
6503#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006504 wpa_printf(MSG_DEBUG,
6505 "nl80211: Connect request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006506 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006507
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006508fail:
Hai Shalom74f70d42019-02-11 14:42:39 -08006509 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006510 nlmsg_free(msg);
6511 return ret;
6512
6513}
6514
6515
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006516static int wpa_driver_nl80211_connect(
6517 struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006518 struct wpa_driver_associate_params *params,
Hai Shalomfdcde762020-04-02 11:19:20 -07006519 struct nl_sock *nl_connect)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006520{
Jithu Jancea7c60b42014-12-03 18:54:40 +05306521 int ret;
6522
6523 /* Store the connection attempted bssid for future use */
6524 if (params->bssid)
6525 os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
6526 else
6527 os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
6528
Roshan Pius3a1667e2018-07-03 15:17:14 -07006529 ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006530 if (ret == -EALREADY) {
6531 /*
6532 * cfg80211 does not currently accept new connections if
6533 * we are already connected. As a workaround, force
6534 * disconnection and try again.
6535 */
6536 wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
6537 "disconnecting before reassociation "
6538 "attempt");
6539 if (wpa_driver_nl80211_disconnect(
Hai Shalom74f70d42019-02-11 14:42:39 -08006540 drv, WLAN_REASON_PREV_AUTH_NOT_VALID, nl_connect))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006541 return -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006542 ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006543 }
6544 return ret;
6545}
6546
6547
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006548static int wpa_driver_nl80211_associate(
6549 void *priv, struct wpa_driver_associate_params *params)
6550{
6551 struct i802_bss *bss = priv;
6552 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006553 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006554 struct nl_msg *msg;
6555
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006556 nl80211_unmask_11b_rates(bss);
6557
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006558 if (params->mode == IEEE80211_MODE_AP)
6559 return wpa_driver_nl80211_ap(drv, params);
6560
6561 if (params->mode == IEEE80211_MODE_IBSS)
6562 return wpa_driver_nl80211_ibss(drv, params);
6563
6564 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006565 enum nl80211_iftype nlmode = params->p2p ?
6566 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
6567
6568 if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006569 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07006570 if (params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
Hai Shalomb755a2a2020-04-23 21:49:02 -07006571 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE)
Hai Shalom74f70d42019-02-11 14:42:39 -08006572 bss->use_nl_connect = 1;
Hai Shalomb755a2a2020-04-23 21:49:02 -07006573 else
Hai Shalom74f70d42019-02-11 14:42:39 -08006574 bss->use_nl_connect = 0;
Hai Shalom74f70d42019-02-11 14:42:39 -08006575
Hai Shalomb755a2a2020-04-23 21:49:02 -07006576 return wpa_driver_nl80211_connect(drv, params,
6577 get_connect_handle(bss));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006578 }
6579
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07006580 nl80211_mark_disconnected(drv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006581
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006582 wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
6583 drv->ifindex);
6584 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ASSOCIATE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006585 if (!msg)
6586 return -1;
6587
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006588 ret = nl80211_connect_common(drv, params, msg);
6589 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006590 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006591
Roshan Pius3a1667e2018-07-03 15:17:14 -07006592 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
6593 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
6594 goto fail;
6595
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006596 if (params->fils_kek) {
6597 wpa_printf(MSG_DEBUG, " * FILS KEK (len=%u)",
6598 (unsigned int) params->fils_kek_len);
6599 if (nla_put(msg, NL80211_ATTR_FILS_KEK, params->fils_kek_len,
6600 params->fils_kek))
6601 goto fail;
6602 }
6603 if (params->fils_nonces) {
6604 wpa_hexdump(MSG_DEBUG, " * FILS nonces (for AAD)",
6605 params->fils_nonces,
6606 params->fils_nonces_len);
6607 if (nla_put(msg, NL80211_ATTR_FILS_NONCES,
6608 params->fils_nonces_len, params->fils_nonces))
6609 goto fail;
6610 }
6611
Hai Shalomb755a2a2020-04-23 21:49:02 -07006612 ret = send_and_recv_msgs_owner(drv, msg,
6613 get_connect_handle(drv->first_bss), 1,
Hai Shalom899fcc72020-10-19 14:38:18 -07006614 NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006615 msg = NULL;
6616 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006617 wpa_dbg(drv->ctx, MSG_DEBUG,
6618 "nl80211: MLME command failed (assoc): ret=%d (%s)",
6619 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006620 nl80211_dump_scan(drv);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006621 } else {
6622 wpa_printf(MSG_DEBUG,
6623 "nl80211: Association request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006624 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006625
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006626fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006627 nlmsg_free(msg);
6628 return ret;
6629}
6630
6631
6632static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006633 int ifindex, enum nl80211_iftype mode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006634{
6635 struct nl_msg *msg;
6636 int ret = -ENOBUFS;
6637
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006638 wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
6639 ifindex, mode, nl80211_iftype_str(mode));
6640
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006641 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
6642 if (!msg || nla_put_u32(msg, NL80211_ATTR_IFTYPE, mode))
6643 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006644
Hai Shalom899fcc72020-10-19 14:38:18 -07006645 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006646 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006647 if (!ret)
6648 return 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006649fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006650 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006651 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
6652 " %d (%s)", ifindex, mode, ret, strerror(-ret));
6653 return ret;
6654}
6655
6656
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006657static int wpa_driver_nl80211_set_mode_impl(
6658 struct i802_bss *bss,
6659 enum nl80211_iftype nlmode,
6660 struct hostapd_freq_params *desired_freq_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006661{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006662 struct wpa_driver_nl80211_data *drv = bss->drv;
6663 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006664 int i;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006665 int was_ap = is_ap_interface(drv->nlmode);
6666 int res;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006667 int mode_switch_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006668
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07006669 if (TEST_FAIL())
6670 return -1;
6671
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006672 mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
6673 if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))
6674 mode_switch_res = 0;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006675
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006676 if (mode_switch_res == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006677 drv->nlmode = nlmode;
6678 ret = 0;
6679 goto done;
6680 }
6681
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006682 if (mode_switch_res == -ENODEV)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006683 return -1;
6684
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006685 if (nlmode == drv->nlmode) {
6686 wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
6687 "requested mode - ignore error");
6688 ret = 0;
6689 goto done; /* Already in the requested mode */
6690 }
6691
6692 /* mac80211 doesn't allow mode changes while the device is up, so
6693 * take the device down, try to set the mode again, and bring the
6694 * device back up.
6695 */
6696 wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
6697 "interface down");
6698 for (i = 0; i < 10; i++) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006699 res = i802_set_iface_flags(bss, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006700 if (res == -EACCES || res == -ENODEV)
6701 break;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006702 if (res != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006703 wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
6704 "interface down");
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006705 os_sleep(0, 100000);
6706 continue;
6707 }
6708
6709 /*
6710 * Setting the mode will fail for some drivers if the phy is
6711 * on a frequency that the mode is disallowed in.
6712 */
6713 if (desired_freq_params) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006714 res = nl80211_set_channel(bss, desired_freq_params, 0);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006715 if (res) {
6716 wpa_printf(MSG_DEBUG,
6717 "nl80211: Failed to set frequency on interface");
6718 }
6719 }
6720
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006721 if (i == 0 && was_ap && !is_ap_interface(nlmode) &&
6722 bss->brname[0] &&
6723 (bss->added_if_into_bridge || bss->already_in_bridge)) {
6724 wpa_printf(MSG_DEBUG,
6725 "nl80211: Remove AP interface %s temporarily from the bridge %s to allow its mode to be set to STATION",
6726 bss->ifname, bss->brname);
6727 if (linux_br_del_if(drv->global->ioctl_sock,
6728 bss->brname, bss->ifname) < 0)
6729 wpa_printf(MSG_INFO,
6730 "nl80211: Failed to remove interface %s from bridge %s: %s",
6731 bss->ifname, bss->brname,
6732 strerror(errno));
6733 }
6734
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006735 /* Try to set the mode again while the interface is down */
6736 mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
6737 if (mode_switch_res == -EBUSY) {
6738 wpa_printf(MSG_DEBUG,
6739 "nl80211: Delaying mode set while interface going down");
6740 os_sleep(0, 100000);
6741 continue;
6742 }
6743 ret = mode_switch_res;
6744 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006745 }
6746
6747 if (!ret) {
6748 wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
6749 "interface is down");
6750 drv->nlmode = nlmode;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006751 drv->ignore_if_down_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006752 }
6753
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006754 /* Bring the interface back up */
6755 res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
6756 if (res != 0) {
6757 wpa_printf(MSG_DEBUG,
6758 "nl80211: Failed to set interface up after switching mode");
6759 ret = -1;
6760 }
6761
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006762done:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006763 if (ret) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006764 wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
6765 "from %d failed", nlmode, drv->nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006766 return ret;
6767 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006768
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006769 if (is_p2p_net_interface(nlmode)) {
6770 wpa_printf(MSG_DEBUG,
6771 "nl80211: Interface %s mode change to P2P - disable 11b rates",
6772 bss->ifname);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006773 nl80211_disable_11b_rates(drv, drv->ifindex, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006774 } else if (drv->disabled_11b_rates) {
6775 wpa_printf(MSG_DEBUG,
6776 "nl80211: Interface %s mode changed to non-P2P - re-enable 11b rates",
6777 bss->ifname);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006778 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006779 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006780
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006781 if (is_ap_interface(nlmode)) {
6782 nl80211_mgmt_unsubscribe(bss, "start AP");
6783 /* Setup additional AP mode functionality if needed */
6784 if (nl80211_setup_ap(bss))
6785 return -1;
6786 } else if (was_ap) {
6787 /* Remove additional AP mode functionality */
6788 nl80211_teardown_ap(bss);
6789 } else {
6790 nl80211_mgmt_unsubscribe(bss, "mode change");
6791 }
6792
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006793 if (is_mesh_interface(nlmode) &&
6794 nl80211_mgmt_subscribe_mesh(bss))
6795 return -1;
6796
Dmitry Shmidt04949592012-07-19 12:16:46 -07006797 if (!bss->in_deinit && !is_ap_interface(nlmode) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006798 !is_mesh_interface(nlmode) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006799 nl80211_mgmt_subscribe_non_ap(bss) < 0)
6800 wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
6801 "frame processing - ignore for now");
6802
6803 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006804}
6805
6806
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006807void nl80211_restore_ap_mode(struct i802_bss *bss)
6808{
6809 struct wpa_driver_nl80211_data *drv = bss->drv;
6810 int was_ap = is_ap_interface(drv->nlmode);
leslc3979c32021-03-29 22:34:02 +08006811 int br_ifindex;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006812
6813 wpa_driver_nl80211_set_mode(bss, drv->ap_scan_as_station);
6814 if (!was_ap && is_ap_interface(drv->ap_scan_as_station) &&
6815 bss->brname[0] &&
6816 (bss->added_if_into_bridge || bss->already_in_bridge)) {
6817 wpa_printf(MSG_DEBUG,
6818 "nl80211: Add AP interface %s back into the bridge %s",
6819 bss->ifname, bss->brname);
6820 if (linux_br_add_if(drv->global->ioctl_sock, bss->brname,
6821 bss->ifname) < 0) {
6822 wpa_printf(MSG_WARNING,
6823 "nl80211: Failed to add interface %s into bridge %s: %s",
6824 bss->ifname, bss->brname, strerror(errno));
6825 }
leslc3979c32021-03-29 22:34:02 +08006826 br_ifindex = if_nametoindex(bss->brname);
6827 add_ifidx(drv, br_ifindex, drv->ifindex);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006828 }
6829 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
6830}
6831
6832
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006833int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
6834 enum nl80211_iftype nlmode)
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006835{
6836 return wpa_driver_nl80211_set_mode_impl(bss, nlmode, NULL);
6837}
6838
6839
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006840static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
6841 struct hostapd_freq_params *freq)
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006842{
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006843 return wpa_driver_nl80211_set_mode_impl(bss, NL80211_IFTYPE_ADHOC,
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006844 freq);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006845}
6846
6847
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006848static int wpa_driver_nl80211_get_capa(void *priv,
6849 struct wpa_driver_capa *capa)
6850{
6851 struct i802_bss *bss = priv;
6852 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07006853
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006854 if (!drv->has_capability)
6855 return -1;
6856 os_memcpy(capa, &drv->capa, sizeof(*capa));
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006857 if (drv->extended_capa && drv->extended_capa_mask) {
6858 capa->extended_capa = drv->extended_capa;
6859 capa->extended_capa_mask = drv->extended_capa_mask;
6860 capa->extended_capa_len = drv->extended_capa_len;
6861 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006862
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006863 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006864}
6865
6866
6867static int wpa_driver_nl80211_set_operstate(void *priv, int state)
6868{
6869 struct i802_bss *bss = priv;
6870 struct wpa_driver_nl80211_data *drv = bss->drv;
6871
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006872 wpa_printf(MSG_DEBUG, "nl80211: Set %s operstate %d->%d (%s)",
6873 bss->ifname, drv->operstate, state,
6874 state ? "UP" : "DORMANT");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006875 drv->operstate = state;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006876 return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006877 state ? IF_OPER_UP : IF_OPER_DORMANT);
6878}
6879
6880
6881static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
6882{
6883 struct i802_bss *bss = priv;
6884 struct wpa_driver_nl80211_data *drv = bss->drv;
6885 struct nl_msg *msg;
6886 struct nl80211_sta_flag_update upd;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006887 int ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006888
6889 if (!drv->associated && is_zero_ether_addr(drv->bssid) && !authorized) {
6890 wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated");
6891 return 0;
6892 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006893
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07006894 wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
6895 MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
6896
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006897 os_memset(&upd, 0, sizeof(upd));
6898 upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
6899 if (authorized)
6900 upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006901
6902 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
6903 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid) ||
6904 nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd)) {
6905 nlmsg_free(msg);
6906 return -ENOBUFS;
6907 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006908
Hai Shalom899fcc72020-10-19 14:38:18 -07006909 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006910 if (!ret)
6911 return 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006912 wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)",
6913 ret, strerror(-ret));
6914 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006915}
6916
6917
Jouni Malinen75ecf522011-06-27 15:19:46 -07006918/* Set kernel driver on given frequency (MHz) */
6919static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006920{
Jouni Malinen75ecf522011-06-27 15:19:46 -07006921 struct i802_bss *bss = priv;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006922 return nl80211_set_channel(bss, freq, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006923}
6924
6925
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006926static inline int min_int(int a, int b)
6927{
6928 if (a < b)
6929 return a;
6930 return b;
6931}
6932
6933
6934static int get_key_handler(struct nl_msg *msg, void *arg)
6935{
6936 struct nlattr *tb[NL80211_ATTR_MAX + 1];
6937 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
6938
6939 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
6940 genlmsg_attrlen(gnlh, 0), NULL);
6941
6942 /*
6943 * TODO: validate the key index and mac address!
6944 * Otherwise, there's a race condition as soon as
6945 * the kernel starts sending key notifications.
6946 */
6947
6948 if (tb[NL80211_ATTR_KEY_SEQ])
6949 memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
6950 min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
Hai Shalom021b0b52019-04-10 11:17:58 -07006951 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006952 return NL_SKIP;
6953}
6954
6955
6956static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
6957 int idx, u8 *seq)
6958{
6959 struct i802_bss *bss = priv;
6960 struct wpa_driver_nl80211_data *drv = bss->drv;
6961 struct nl_msg *msg;
6962
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006963 msg = nl80211_ifindex_msg(drv, if_nametoindex(iface), 0,
6964 NL80211_CMD_GET_KEY);
6965 if (!msg ||
6966 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
6967 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, idx)) {
6968 nlmsg_free(msg);
6969 return -ENOBUFS;
6970 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006971
6972 memset(seq, 0, 6);
6973
Hai Shalom899fcc72020-10-19 14:38:18 -07006974 return send_and_recv_msgs(drv, msg, get_key_handler, seq, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006975}
6976
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006977
6978static int i802_set_rts(void *priv, int rts)
6979{
6980 struct i802_bss *bss = priv;
6981 struct wpa_driver_nl80211_data *drv = bss->drv;
6982 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006983 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006984 u32 val;
6985
Hai Shalom021b0b52019-04-10 11:17:58 -07006986 if (rts >= 2347 || rts == -1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006987 val = (u32) -1;
6988 else
6989 val = rts;
6990
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006991 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
6992 nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val)) {
6993 nlmsg_free(msg);
6994 return -ENOBUFS;
6995 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006996
Hai Shalom899fcc72020-10-19 14:38:18 -07006997 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006998 if (!ret)
6999 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007000 wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
7001 "%d (%s)", rts, ret, strerror(-ret));
7002 return ret;
7003}
7004
7005
7006static int i802_set_frag(void *priv, int frag)
7007{
7008 struct i802_bss *bss = priv;
7009 struct wpa_driver_nl80211_data *drv = bss->drv;
7010 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007011 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007012 u32 val;
7013
Hai Shalom021b0b52019-04-10 11:17:58 -07007014 if (frag >= 2346 || frag == -1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007015 val = (u32) -1;
7016 else
7017 val = frag;
7018
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007019 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
7020 nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val)) {
7021 nlmsg_free(msg);
7022 return -ENOBUFS;
7023 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007024
Hai Shalom899fcc72020-10-19 14:38:18 -07007025 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007026 if (!ret)
7027 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007028 wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
7029 "%d: %d (%s)", frag, ret, strerror(-ret));
7030 return ret;
7031}
7032
7033
7034static int i802_flush(void *priv)
7035{
7036 struct i802_bss *bss = priv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007037 struct nl_msg *msg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007038 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007039
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07007040 wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
7041 bss->ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007042
7043 /*
7044 * XXX: FIX! this needs to flush all VLANs too
7045 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007046 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
Hai Shalom899fcc72020-10-19 14:38:18 -07007047 res = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007048 if (res) {
7049 wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
7050 "(%s)", res, strerror(-res));
7051 }
7052 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007053}
7054
7055
Hai Shalom81f62d82019-07-22 12:10:00 -07007056static void get_sta_tid_stats(struct hostap_sta_driver_data *data,
7057 struct nlattr *attr)
7058{
7059 struct nlattr *tid_stats[NL80211_TID_STATS_MAX + 1], *tidattr;
7060 struct nlattr *txq_stats[NL80211_TXQ_STATS_MAX + 1];
7061 static struct nla_policy txq_stats_policy[NL80211_TXQ_STATS_MAX + 1] = {
7062 [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 },
7063 [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 },
7064 };
7065 int rem;
7066
7067 nla_for_each_nested(tidattr, attr, rem) {
7068 if (nla_parse_nested(tid_stats, NL80211_TID_STATS_MAX,
7069 tidattr, NULL) != 0 ||
7070 !tid_stats[NL80211_TID_STATS_TXQ_STATS] ||
7071 nla_parse_nested(txq_stats, NL80211_TXQ_STATS_MAX,
7072 tid_stats[NL80211_TID_STATS_TXQ_STATS],
7073 txq_stats_policy) != 0)
7074 continue;
7075 /* sum the backlogs over all TIDs for station */
7076 if (txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES])
7077 data->backlog_bytes += nla_get_u32(
7078 txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES]);
7079 if (txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS])
7080 data->backlog_bytes += nla_get_u32(
7081 txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS]);
7082 }
7083}
7084
7085
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007086static int get_sta_handler(struct nl_msg *msg, void *arg)
7087{
7088 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7089 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7090 struct hostap_sta_driver_data *data = arg;
7091 struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
7092 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
7093 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
7094 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
7095 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
7096 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
7097 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007098 [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007099 [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
7100 [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007101 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
Roshan Pius3a1667e2018-07-03 15:17:14 -07007102 [NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 },
Hai Shalom81f62d82019-07-22 12:10:00 -07007103 [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 },
7104 [NL80211_STA_INFO_TX_DURATION] = { .type = NLA_U64 },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007105 };
7106 struct nlattr *rate[NL80211_RATE_INFO_MAX + 1];
7107 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
7108 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
7109 [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 },
7110 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
7111 [NL80211_RATE_INFO_VHT_MCS] = { .type = NLA_U8 },
7112 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
7113 [NL80211_RATE_INFO_VHT_NSS] = { .type = NLA_U8 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007114 };
7115
7116 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7117 genlmsg_attrlen(gnlh, 0), NULL);
7118
7119 /*
7120 * TODO: validate the interface and mac address!
7121 * Otherwise, there's a race condition as soon as
7122 * the kernel starts sending station notifications.
7123 */
7124
7125 if (!tb[NL80211_ATTR_STA_INFO]) {
7126 wpa_printf(MSG_DEBUG, "sta stats missing!");
7127 return NL_SKIP;
7128 }
7129 if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
7130 tb[NL80211_ATTR_STA_INFO],
7131 stats_policy)) {
7132 wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
7133 return NL_SKIP;
7134 }
7135
7136 if (stats[NL80211_STA_INFO_INACTIVE_TIME])
7137 data->inactive_msec =
7138 nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007139 /* For backwards compatibility, fetch the 32-bit counters first. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007140 if (stats[NL80211_STA_INFO_RX_BYTES])
7141 data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
7142 if (stats[NL80211_STA_INFO_TX_BYTES])
7143 data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007144 if (stats[NL80211_STA_INFO_RX_BYTES64] &&
7145 stats[NL80211_STA_INFO_TX_BYTES64]) {
7146 /*
7147 * The driver supports 64-bit counters, so use them to override
7148 * the 32-bit values.
7149 */
7150 data->rx_bytes =
7151 nla_get_u64(stats[NL80211_STA_INFO_RX_BYTES64]);
7152 data->tx_bytes =
7153 nla_get_u64(stats[NL80211_STA_INFO_TX_BYTES64]);
7154 data->bytes_64bit = 1;
7155 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007156 if (stats[NL80211_STA_INFO_RX_PACKETS])
7157 data->rx_packets =
7158 nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
7159 if (stats[NL80211_STA_INFO_TX_PACKETS])
7160 data->tx_packets =
7161 nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
Hai Shalom81f62d82019-07-22 12:10:00 -07007162 if (stats[NL80211_STA_INFO_RX_DURATION])
7163 data->rx_airtime =
7164 nla_get_u64(stats[NL80211_STA_INFO_RX_DURATION]);
7165 if (stats[NL80211_STA_INFO_TX_DURATION])
7166 data->tx_airtime =
7167 nla_get_u64(stats[NL80211_STA_INFO_TX_DURATION]);
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007168 if (stats[NL80211_STA_INFO_TX_FAILED])
7169 data->tx_retry_failed =
7170 nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007171 if (stats[NL80211_STA_INFO_SIGNAL])
7172 data->signal = nla_get_u8(stats[NL80211_STA_INFO_SIGNAL]);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007173 if (stats[NL80211_STA_INFO_ACK_SIGNAL]) {
7174 data->last_ack_rssi =
7175 nla_get_u8(stats[NL80211_STA_INFO_ACK_SIGNAL]);
7176 data->flags |= STA_DRV_DATA_LAST_ACK_RSSI;
7177 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007178
7179 if (stats[NL80211_STA_INFO_TX_BITRATE] &&
7180 nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
7181 stats[NL80211_STA_INFO_TX_BITRATE],
7182 rate_policy) == 0) {
7183 if (rate[NL80211_RATE_INFO_BITRATE32])
7184 data->current_tx_rate =
7185 nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
7186 else if (rate[NL80211_RATE_INFO_BITRATE])
7187 data->current_tx_rate =
7188 nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
7189
7190 if (rate[NL80211_RATE_INFO_MCS]) {
7191 data->tx_mcs = nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
7192 data->flags |= STA_DRV_DATA_TX_MCS;
7193 }
7194 if (rate[NL80211_RATE_INFO_VHT_MCS]) {
7195 data->tx_vhtmcs =
7196 nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
7197 data->flags |= STA_DRV_DATA_TX_VHT_MCS;
7198 }
7199 if (rate[NL80211_RATE_INFO_SHORT_GI])
7200 data->flags |= STA_DRV_DATA_TX_SHORT_GI;
7201 if (rate[NL80211_RATE_INFO_VHT_NSS]) {
7202 data->tx_vht_nss =
7203 nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
7204 data->flags |= STA_DRV_DATA_TX_VHT_NSS;
7205 }
7206 }
7207
7208 if (stats[NL80211_STA_INFO_RX_BITRATE] &&
7209 nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
7210 stats[NL80211_STA_INFO_RX_BITRATE],
7211 rate_policy) == 0) {
7212 if (rate[NL80211_RATE_INFO_BITRATE32])
7213 data->current_rx_rate =
7214 nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
7215 else if (rate[NL80211_RATE_INFO_BITRATE])
7216 data->current_rx_rate =
7217 nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
7218
7219 if (rate[NL80211_RATE_INFO_MCS]) {
7220 data->rx_mcs =
7221 nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
7222 data->flags |= STA_DRV_DATA_RX_MCS;
7223 }
7224 if (rate[NL80211_RATE_INFO_VHT_MCS]) {
7225 data->rx_vhtmcs =
7226 nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
7227 data->flags |= STA_DRV_DATA_RX_VHT_MCS;
7228 }
7229 if (rate[NL80211_RATE_INFO_SHORT_GI])
7230 data->flags |= STA_DRV_DATA_RX_SHORT_GI;
7231 if (rate[NL80211_RATE_INFO_VHT_NSS]) {
7232 data->rx_vht_nss =
7233 nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
7234 data->flags |= STA_DRV_DATA_RX_VHT_NSS;
7235 }
7236 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007237
Hai Shalom81f62d82019-07-22 12:10:00 -07007238 if (stats[NL80211_STA_INFO_TID_STATS])
7239 get_sta_tid_stats(data, stats[NL80211_STA_INFO_TID_STATS]);
7240
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007241 return NL_SKIP;
7242}
7243
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007244static int i802_read_sta_data(struct i802_bss *bss,
7245 struct hostap_sta_driver_data *data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007246 const u8 *addr)
7247{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007248 struct nl_msg *msg;
7249
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007250 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_STATION)) ||
7251 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
7252 nlmsg_free(msg);
7253 return -ENOBUFS;
7254 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007255
Hai Shalom899fcc72020-10-19 14:38:18 -07007256 return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data,
7257 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007258}
7259
7260
7261static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
7262 int cw_min, int cw_max, int burst_time)
7263{
7264 struct i802_bss *bss = priv;
7265 struct wpa_driver_nl80211_data *drv = bss->drv;
7266 struct nl_msg *msg;
7267 struct nlattr *txq, *params;
Hai Shalom74f70d42019-02-11 14:42:39 -08007268 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007269
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007270 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007271 if (!msg)
7272 return -1;
7273
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007274 txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
7275 if (!txq)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007276 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007277
7278 /* We are only sending parameters for a single TXQ at a time */
7279 params = nla_nest_start(msg, 1);
7280 if (!params)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007281 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007282
7283 switch (queue) {
7284 case 0:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007285 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO))
7286 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007287 break;
7288 case 1:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007289 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI))
7290 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007291 break;
7292 case 2:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007293 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE))
7294 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007295 break;
7296 case 3:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007297 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK))
7298 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007299 break;
7300 }
7301 /* Burst time is configured in units of 0.1 msec and TXOP parameter in
7302 * 32 usec, so need to convert the value here. */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007303 if (nla_put_u16(msg, NL80211_TXQ_ATTR_TXOP,
7304 (burst_time * 100 + 16) / 32) ||
7305 nla_put_u16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min) ||
7306 nla_put_u16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max) ||
7307 nla_put_u8(msg, NL80211_TXQ_ATTR_AIFS, aifs))
7308 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007309
7310 nla_nest_end(msg, params);
7311
7312 nla_nest_end(msg, txq);
7313
Hai Shalom899fcc72020-10-19 14:38:18 -07007314 res = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalom74f70d42019-02-11 14:42:39 -08007315 wpa_printf(MSG_DEBUG,
7316 "nl80211: TX queue param set: queue=%d aifs=%d cw_min=%d cw_max=%d burst_time=%d --> res=%d",
7317 queue, aifs, cw_min, cw_max, burst_time, res);
7318 if (res == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007319 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007320 msg = NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007321fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007322 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007323 return -1;
7324}
7325
7326
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007327static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007328 const char *ifname, int vlan_id)
7329{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007330 struct wpa_driver_nl80211_data *drv = bss->drv;
7331 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007332 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007333
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007334 wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
7335 ", ifname=%s[%d], vlan_id=%d)",
7336 bss->ifname, if_nametoindex(bss->ifname),
7337 MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007338 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
7339 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Hai Shalom899fcc72020-10-19 14:38:18 -07007340 (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) &&
Hai Shalomfdcde762020-04-02 11:19:20 -07007341 nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007342 nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
7343 nlmsg_free(msg);
7344 return -ENOBUFS;
7345 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007346
Hai Shalom899fcc72020-10-19 14:38:18 -07007347 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007348 if (ret < 0) {
7349 wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
7350 MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
7351 MAC2STR(addr), ifname, vlan_id, ret,
7352 strerror(-ret));
7353 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007354 return ret;
7355}
7356
7357
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007358static int i802_get_inact_sec(void *priv, const u8 *addr)
7359{
7360 struct hostap_sta_driver_data data;
7361 int ret;
7362
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08007363 os_memset(&data, 0, sizeof(data));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007364 data.inactive_msec = (unsigned long) -1;
7365 ret = i802_read_sta_data(priv, &data, addr);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007366 if (ret == -ENOENT)
7367 return -ENOENT;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007368 if (ret || data.inactive_msec == (unsigned long) -1)
7369 return -1;
7370 return data.inactive_msec / 1000;
7371}
7372
7373
7374static int i802_sta_clear_stats(void *priv, const u8 *addr)
7375{
7376#if 0
7377 /* TODO */
7378#endif
7379 return 0;
7380}
7381
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007382
7383static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -07007384 u16 reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007385{
7386 struct i802_bss *bss = priv;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007387 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007388 struct ieee80211_mgmt mgmt;
Dmitry Shmidt29333592017-01-09 12:27:11 -08007389 u8 channel;
7390
7391 if (ieee80211_freq_to_chan(bss->freq, &channel) ==
7392 HOSTAPD_MODE_IEEE80211AD) {
7393 /* Deauthentication is not used in DMG/IEEE 802.11ad;
7394 * disassociate the STA instead. */
7395 return i802_sta_disassoc(priv, own_addr, addr, reason);
7396 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007397
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007398 if (is_mesh_interface(drv->nlmode))
7399 return -1;
7400
Dmitry Shmidt04949592012-07-19 12:16:46 -07007401 if (drv->device_ap_sme)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007402 return wpa_driver_nl80211_sta_remove(bss, addr, 1, reason);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007403
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007404 memset(&mgmt, 0, sizeof(mgmt));
7405 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
7406 WLAN_FC_STYPE_DEAUTH);
7407 memcpy(mgmt.da, addr, ETH_ALEN);
7408 memcpy(mgmt.sa, own_addr, ETH_ALEN);
7409 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
7410 mgmt.u.deauth.reason_code = host_to_le16(reason);
7411 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
7412 IEEE80211_HDRLEN +
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007413 sizeof(mgmt.u.deauth), 0, 0, 0, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -07007414 0, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007415}
7416
7417
7418static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -07007419 u16 reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007420{
7421 struct i802_bss *bss = priv;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007422 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007423 struct ieee80211_mgmt mgmt;
7424
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007425 if (is_mesh_interface(drv->nlmode))
7426 return -1;
7427
Dmitry Shmidt04949592012-07-19 12:16:46 -07007428 if (drv->device_ap_sme)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007429 return wpa_driver_nl80211_sta_remove(bss, addr, 0, reason);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007430
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007431 memset(&mgmt, 0, sizeof(mgmt));
7432 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
7433 WLAN_FC_STYPE_DISASSOC);
7434 memcpy(mgmt.da, addr, ETH_ALEN);
7435 memcpy(mgmt.sa, own_addr, ETH_ALEN);
7436 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
7437 mgmt.u.disassoc.reason_code = host_to_le16(reason);
7438 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
7439 IEEE80211_HDRLEN +
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007440 sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -07007441 0, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007442}
7443
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007444
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007445static void dump_ifidx(struct wpa_driver_nl80211_data *drv)
7446{
7447 char buf[200], *pos, *end;
7448 int i, res;
7449
7450 pos = buf;
7451 end = pos + sizeof(buf);
7452
7453 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007454 if (!drv->if_indices[i].ifindex)
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007455 continue;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007456 res = os_snprintf(pos, end - pos, " %d(%d)",
Hai Shalom81f62d82019-07-22 12:10:00 -07007457 drv->if_indices[i].ifindex,
7458 drv->if_indices[i].reason);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007459 if (os_snprintf_error(end - pos, res))
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007460 break;
7461 pos += res;
7462 }
7463 *pos = '\0';
7464
7465 wpa_printf(MSG_DEBUG, "nl80211: if_indices[%d]:%s",
7466 drv->num_if_indices, buf);
7467}
7468
7469
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007470static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
7471 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007472{
7473 int i;
Hai Shalom81f62d82019-07-22 12:10:00 -07007474 struct drv_nl80211_if_info *old;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007475
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007476 wpa_printf(MSG_DEBUG,
7477 "nl80211: Add own interface ifindex %d (ifidx_reason %d)",
7478 ifidx, ifidx_reason);
7479 if (have_ifidx(drv, ifidx, ifidx_reason)) {
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007480 wpa_printf(MSG_DEBUG, "nl80211: ifindex %d already in the list",
7481 ifidx);
7482 return;
7483 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07007484 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007485 if (drv->if_indices[i].ifindex == 0) {
7486 drv->if_indices[i].ifindex = ifidx;
7487 drv->if_indices[i].reason = ifidx_reason;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007488 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007489 return;
7490 }
7491 }
7492
7493 if (drv->if_indices != drv->default_if_indices)
7494 old = drv->if_indices;
7495 else
7496 old = NULL;
7497
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007498 drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
Hai Shalom81f62d82019-07-22 12:10:00 -07007499 sizeof(*old));
Jouni Malinen75ecf522011-06-27 15:19:46 -07007500 if (!drv->if_indices) {
7501 if (!old)
7502 drv->if_indices = drv->default_if_indices;
7503 else
7504 drv->if_indices = old;
7505 wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
7506 "interfaces");
7507 wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
7508 return;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007509 }
7510 if (!old)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007511 os_memcpy(drv->if_indices, drv->default_if_indices,
7512 sizeof(drv->default_if_indices));
Hai Shalom81f62d82019-07-22 12:10:00 -07007513 drv->if_indices[drv->num_if_indices].ifindex = ifidx;
7514 drv->if_indices[drv->num_if_indices].reason = ifidx_reason;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007515 drv->num_if_indices++;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007516 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007517}
7518
7519
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007520static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
7521 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007522{
7523 int i;
7524
7525 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007526 if ((drv->if_indices[i].ifindex == ifidx ||
7527 ifidx == IFIDX_ANY) &&
7528 (drv->if_indices[i].reason == ifidx_reason ||
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007529 ifidx_reason == IFIDX_ANY)) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007530 drv->if_indices[i].ifindex = 0;
7531 drv->if_indices[i].reason = 0;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007532 break;
7533 }
7534 }
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007535 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007536}
7537
7538
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007539static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
7540 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007541{
7542 int i;
7543
7544 for (i = 0; i < drv->num_if_indices; i++)
Hai Shalom81f62d82019-07-22 12:10:00 -07007545 if (drv->if_indices[i].ifindex == ifidx &&
7546 (drv->if_indices[i].reason == ifidx_reason ||
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007547 ifidx_reason == IFIDX_ANY))
Jouni Malinen75ecf522011-06-27 15:19:46 -07007548 return 1;
7549
7550 return 0;
7551}
7552
7553
7554static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07007555 const char *bridge_ifname, char *ifname_wds)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007556{
7557 struct i802_bss *bss = priv;
7558 struct wpa_driver_nl80211_data *drv = bss->drv;
7559 char name[IFNAMSIZ + 1];
Roshan Pius3a1667e2018-07-03 15:17:14 -07007560 union wpa_event_data event;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08007561 int ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007562
Hai Shalom39ba6fc2019-01-22 12:40:38 -08007563 ret = os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
7564 if (ret >= (int) sizeof(name))
7565 wpa_printf(MSG_WARNING,
7566 "nl80211: WDS interface name was truncated");
7567 else if (ret < 0)
7568 return ret;
7569
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07007570 if (ifname_wds)
7571 os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
7572
Jouni Malinen75ecf522011-06-27 15:19:46 -07007573 wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
7574 " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
7575 if (val) {
7576 if (!if_nametoindex(name)) {
7577 if (nl80211_create_iface(drv, name,
7578 NL80211_IFTYPE_AP_VLAN,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007579 bss->addr, 1, NULL, NULL, 0) <
7580 0)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007581 return -1;
7582 if (bridge_ifname &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007583 linux_br_add_if(drv->global->ioctl_sock,
7584 bridge_ifname, name) < 0)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007585 return -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007586
7587 os_memset(&event, 0, sizeof(event));
7588 event.wds_sta_interface.sta_addr = addr;
7589 event.wds_sta_interface.ifname = name;
7590 event.wds_sta_interface.istatus = INTERFACE_ADDED;
Hai Shalomce48b4a2018-09-05 11:41:35 -07007591 wpa_supplicant_event(bss->ctx,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007592 EVENT_WDS_STA_INTERFACE_STATUS,
7593 &event);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007594 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007595 if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
7596 wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
7597 "interface %s up", name);
7598 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07007599 return i802_set_sta_vlan(priv, addr, name, 0);
7600 } else {
Hai Shalom74f70d42019-02-11 14:42:39 -08007601 if (bridge_ifname &&
7602 linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
7603 name) < 0)
7604 wpa_printf(MSG_INFO,
7605 "nl80211: Failed to remove interface %s from bridge %s: %s",
7606 name, bridge_ifname, strerror(errno));
Dmitry Shmidtaa532512012-09-24 10:35:31 -07007607
Jouni Malinen75ecf522011-06-27 15:19:46 -07007608 i802_set_sta_vlan(priv, addr, bss->ifname, 0);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007609 nl80211_remove_iface(drv, if_nametoindex(name));
Roshan Pius3a1667e2018-07-03 15:17:14 -07007610 os_memset(&event, 0, sizeof(event));
7611 event.wds_sta_interface.sta_addr = addr;
7612 event.wds_sta_interface.ifname = name;
7613 event.wds_sta_interface.istatus = INTERFACE_REMOVED;
Hai Shalomce48b4a2018-09-05 11:41:35 -07007614 wpa_supplicant_event(bss->ctx, EVENT_WDS_STA_INTERFACE_STATUS,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007615 &event);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007616 return 0;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007617 }
7618}
7619
7620
7621static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
7622{
7623 struct wpa_driver_nl80211_data *drv = eloop_ctx;
7624 struct sockaddr_ll lladdr;
7625 unsigned char buf[3000];
7626 int len;
7627 socklen_t fromlen = sizeof(lladdr);
7628
7629 len = recvfrom(sock, buf, sizeof(buf), 0,
7630 (struct sockaddr *)&lladdr, &fromlen);
7631 if (len < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007632 wpa_printf(MSG_ERROR, "nl80211: EAPOL recv failed: %s",
7633 strerror(errno));
Jouni Malinen75ecf522011-06-27 15:19:46 -07007634 return;
7635 }
7636
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007637 if (have_ifidx(drv, lladdr.sll_ifindex, IFIDX_ANY))
Jouni Malinen75ecf522011-06-27 15:19:46 -07007638 drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
7639}
7640
7641
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007642static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
7643 struct i802_bss *bss,
7644 const char *brname, const char *ifname)
7645{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007646 int br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007647 char in_br[IFNAMSIZ];
7648
7649 os_strlcpy(bss->brname, brname, IFNAMSIZ);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007650 br_ifindex = if_nametoindex(brname);
7651 if (br_ifindex == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007652 /*
7653 * Bridge was configured, but the bridge device does
7654 * not exist. Try to add it now.
7655 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007656 if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007657 wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
7658 "bridge interface %s: %s",
7659 brname, strerror(errno));
7660 return -1;
7661 }
7662 bss->added_bridge = 1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007663 br_ifindex = if_nametoindex(brname);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007664 add_ifidx(drv, br_ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007665 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007666 bss->br_ifindex = br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007667
7668 if (linux_br_get(in_br, ifname) == 0) {
Hai Shalomc9e41a12018-07-31 14:41:42 -07007669 if (os_strcmp(in_br, brname) == 0) {
7670 bss->already_in_bridge = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007671 return 0; /* already in the bridge */
Hai Shalomc9e41a12018-07-31 14:41:42 -07007672 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007673
7674 wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
7675 "bridge %s", ifname, in_br);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007676 if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
7677 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007678 wpa_printf(MSG_ERROR, "nl80211: Failed to "
7679 "remove interface %s from bridge "
7680 "%s: %s",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007681 ifname, in_br, strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007682 return -1;
7683 }
7684 }
7685
7686 wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
7687 ifname, brname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007688 if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08007689 wpa_printf(MSG_WARNING,
7690 "nl80211: Failed to add interface %s into bridge %s: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007691 ifname, brname, strerror(errno));
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08007692 /* Try to continue without the interface being in a bridge. This
7693 * may be needed for some cases, e.g., with Open vSwitch, where
7694 * an external component will need to handle bridge
7695 * configuration. */
7696 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007697 }
7698 bss->added_if_into_bridge = 1;
7699
7700 return 0;
7701}
7702
7703
7704static void *i802_init(struct hostapd_data *hapd,
7705 struct wpa_init_params *params)
7706{
7707 struct wpa_driver_nl80211_data *drv;
7708 struct i802_bss *bss;
7709 size_t i;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007710 char master_ifname[IFNAMSIZ];
7711 int ifindex, br_ifindex = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007712 int br_added = 0;
7713
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08007714 bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
7715 params->global_priv, 1,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007716 params->bssid, params->driver_params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007717 if (bss == NULL)
7718 return NULL;
7719
7720 drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007721
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007722 if (linux_br_get(master_ifname, params->ifname) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007723 wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007724 params->ifname, master_ifname);
7725 br_ifindex = if_nametoindex(master_ifname);
7726 os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
7727 } else if ((params->num_bridge == 0 || !params->bridge[0]) &&
7728 linux_master_get(master_ifname, params->ifname) == 0) {
7729 wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in master %s",
7730 params->ifname, master_ifname);
7731 /* start listening for EAPOL on the master interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007732 add_ifidx(drv, if_nametoindex(master_ifname), drv->ifindex);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08007733
7734 /* check if master itself is under bridge */
7735 if (linux_br_get(master_ifname, master_ifname) == 0) {
7736 wpa_printf(MSG_DEBUG, "nl80211: which is in bridge %s",
7737 master_ifname);
7738 br_ifindex = if_nametoindex(master_ifname);
7739 os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
7740 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007741 } else {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007742 master_ifname[0] = '\0';
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007743 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007744
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007745 bss->br_ifindex = br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007746
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007747 for (i = 0; i < params->num_bridge; i++) {
7748 if (params->bridge[i]) {
7749 ifindex = if_nametoindex(params->bridge[i]);
7750 if (ifindex)
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007751 add_ifidx(drv, ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007752 if (ifindex == br_ifindex)
7753 br_added = 1;
7754 }
7755 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007756
7757 /* start listening for EAPOL on the default AP interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007758 add_ifidx(drv, drv->ifindex, IFIDX_ANY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007759
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007760 if (params->num_bridge && params->bridge[0]) {
7761 if (i802_check_bridge(drv, bss, params->bridge[0],
7762 params->ifname) < 0)
7763 goto failed;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007764 if (os_strcmp(params->bridge[0], master_ifname) != 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007765 br_added = 1;
7766 }
7767
7768 if (!br_added && br_ifindex &&
7769 (params->num_bridge == 0 || !params->bridge[0]))
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007770 add_ifidx(drv, br_ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007771
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007772#ifdef CONFIG_LIBNL3_ROUTE
Hai Shalomc9e41a12018-07-31 14:41:42 -07007773 if (bss->added_if_into_bridge || bss->already_in_bridge) {
Hai Shalomfdcde762020-04-02 11:19:20 -07007774 int err;
7775
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007776 drv->rtnl_sk = nl_socket_alloc();
7777 if (drv->rtnl_sk == NULL) {
7778 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
7779 goto failed;
7780 }
7781
Hai Shalomfdcde762020-04-02 11:19:20 -07007782 err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE);
7783 if (err) {
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007784 wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -07007785 nl_geterror(err));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007786 goto failed;
7787 }
7788 }
7789#endif /* CONFIG_LIBNL3_ROUTE */
7790
Hai Shalomb755a2a2020-04-23 21:49:02 -07007791 if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) {
7792 wpa_printf(MSG_DEBUG,
7793 "nl80211: Do not open EAPOL RX socket - using control port for RX");
7794 goto skip_eapol_sock;
7795 }
7796
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007797 drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
7798 if (drv->eapol_sock < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007799 wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
7800 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007801 goto failed;
7802 }
7803
7804 if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
7805 {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007806 wpa_printf(MSG_INFO, "nl80211: Could not register read socket for eapol");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007807 goto failed;
7808 }
Hai Shalomb755a2a2020-04-23 21:49:02 -07007809skip_eapol_sock:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007810
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007811 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
7812 params->own_addr))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007813 goto failed;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007814 os_memcpy(drv->perm_addr, params->own_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007815
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007816 memcpy(bss->addr, params->own_addr, ETH_ALEN);
7817
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007818 return bss;
7819
7820failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007821 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007822 return NULL;
7823}
7824
7825
7826static void i802_deinit(void *priv)
7827{
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007828 struct i802_bss *bss = priv;
7829 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007830}
7831
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007832
7833static enum nl80211_iftype wpa_driver_nl80211_if_type(
7834 enum wpa_driver_if_type type)
7835{
7836 switch (type) {
7837 case WPA_IF_STATION:
7838 return NL80211_IFTYPE_STATION;
7839 case WPA_IF_P2P_CLIENT:
7840 case WPA_IF_P2P_GROUP:
7841 return NL80211_IFTYPE_P2P_CLIENT;
7842 case WPA_IF_AP_VLAN:
7843 return NL80211_IFTYPE_AP_VLAN;
7844 case WPA_IF_AP_BSS:
7845 return NL80211_IFTYPE_AP;
7846 case WPA_IF_P2P_GO:
7847 return NL80211_IFTYPE_P2P_GO;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007848 case WPA_IF_P2P_DEVICE:
7849 return NL80211_IFTYPE_P2P_DEVICE;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007850 case WPA_IF_MESH:
7851 return NL80211_IFTYPE_MESH_POINT;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007852 default:
7853 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007854 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007855}
7856
7857
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007858static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
7859{
7860 struct wpa_driver_nl80211_data *drv;
7861 dl_list_for_each(drv, &global->interfaces,
7862 struct wpa_driver_nl80211_data, list) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007863 if (os_memcmp(addr, drv->first_bss->addr, ETH_ALEN) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007864 return 1;
7865 }
7866 return 0;
7867}
7868
7869
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007870static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007871{
7872 unsigned int idx;
7873
7874 if (!drv->global)
7875 return -1;
7876
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007877 os_memcpy(new_addr, drv->first_bss->addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007878 for (idx = 0; idx < 64; idx++) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007879 new_addr[0] = drv->first_bss->addr[0] | 0x02;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007880 new_addr[0] ^= idx << 2;
7881 if (!nl80211_addr_in_use(drv->global, new_addr))
7882 break;
7883 }
7884 if (idx == 64)
7885 return -1;
7886
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007887 wpa_printf(MSG_DEBUG, "nl80211: Assigned new virtual interface address "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007888 MACSTR, MAC2STR(new_addr));
7889
7890 return 0;
7891}
7892
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007893
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007894struct wdev_info {
7895 u64 wdev_id;
7896 int wdev_id_set;
7897 u8 macaddr[ETH_ALEN];
7898};
7899
7900static int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
7901{
7902 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7903 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7904 struct wdev_info *wi = arg;
7905
7906 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7907 genlmsg_attrlen(gnlh, 0), NULL);
7908 if (tb[NL80211_ATTR_WDEV]) {
7909 wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
7910 wi->wdev_id_set = 1;
7911 }
7912
7913 if (tb[NL80211_ATTR_MAC])
7914 os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
7915 ETH_ALEN);
7916
7917 return NL_SKIP;
7918}
7919
7920
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007921static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
7922 const char *ifname, const u8 *addr,
7923 void *bss_ctx, void **drv_priv,
7924 char *force_ifname, u8 *if_addr,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007925 const char *bridge, int use_existing,
7926 int setup_ap)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007927{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007928 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007929 struct i802_bss *bss = priv;
7930 struct wpa_driver_nl80211_data *drv = bss->drv;
7931 int ifidx;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007932 int added = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007933
7934 if (addr)
7935 os_memcpy(if_addr, addr, ETH_ALEN);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007936 nlmode = wpa_driver_nl80211_if_type(type);
7937 if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
7938 struct wdev_info p2pdev_info;
7939
7940 os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
7941 ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
7942 0, nl80211_wdev_handler,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007943 &p2pdev_info, use_existing);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007944 if (!p2pdev_info.wdev_id_set || ifidx != 0) {
7945 wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
7946 ifname);
7947 return -1;
7948 }
7949
7950 drv->global->if_add_wdevid = p2pdev_info.wdev_id;
7951 drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
Mir Ali8a8f1002020-10-06 22:41:40 +05307952 if (!is_zero_ether_addr(p2pdev_info.macaddr)) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007953 os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
Mir Ali8a8f1002020-10-06 22:41:40 +05307954 os_memcpy(drv->global->p2p_perm_addr, p2pdev_info.macaddr, ETH_ALEN);
7955 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007956 wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
7957 ifname,
7958 (long long unsigned int) p2pdev_info.wdev_id);
7959 } else {
7960 ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007961 0, NULL, NULL, use_existing);
7962 if (use_existing && ifidx == -ENFILE) {
7963 added = 0;
7964 ifidx = if_nametoindex(ifname);
7965 } else if (ifidx < 0) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007966 return -1;
7967 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007968 }
7969
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007970 if (!addr) {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07007971 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007972 os_memcpy(if_addr, bss->addr, ETH_ALEN);
7973 else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07007974 ifname, if_addr) < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007975 if (added)
7976 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007977 return -1;
7978 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007979 }
7980
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007981 if (!addr &&
7982 (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07007983 type == WPA_IF_P2P_GO || type == WPA_IF_MESH ||
7984 type == WPA_IF_STATION)) {
7985 /* Enforce unique address */
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007986 u8 new_addr[ETH_ALEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007987
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007988 if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007989 new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07007990 if (added)
7991 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007992 return -1;
7993 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007994 if (nl80211_addr_in_use(drv->global, new_addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007995 wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07007996 "for interface %s type %d", ifname, type);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007997 if (nl80211_vif_addr(drv, new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07007998 if (added)
7999 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008000 return -1;
8001 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008002 if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008003 new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07008004 if (added)
8005 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008006 return -1;
8007 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008008 }
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008009 os_memcpy(if_addr, new_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008010 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008011
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008012 if (type == WPA_IF_AP_BSS && setup_ap) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008013 struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
8014 if (new_bss == NULL) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008015 if (added)
8016 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008017 return -1;
8018 }
8019
8020 if (bridge &&
8021 i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
8022 wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
8023 "interface %s to a bridge %s",
8024 ifname, bridge);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008025 if (added)
8026 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008027 os_free(new_bss);
8028 return -1;
8029 }
8030
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008031 if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
8032 {
Dmitry Shmidt71757432014-06-02 13:50:35 -07008033 if (added)
8034 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008035 os_free(new_bss);
8036 return -1;
8037 }
8038 os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008039 os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008040 new_bss->ifindex = ifidx;
8041 new_bss->drv = drv;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008042 new_bss->next = drv->first_bss->next;
8043 new_bss->freq = drv->first_bss->freq;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08008044 new_bss->ctx = bss_ctx;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008045 new_bss->added_if = added;
8046 drv->first_bss->next = new_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008047 if (drv_priv)
8048 *drv_priv = new_bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008049 nl80211_init_bss(new_bss);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008050
8051 /* Subscribe management frames for this WPA_IF_AP_BSS */
8052 if (nl80211_setup_ap(new_bss))
8053 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008054 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008055
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008056 if (drv->global)
8057 drv->global->if_add_ifindex = ifidx;
8058
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07008059 /*
8060 * Some virtual interfaces need to process EAPOL packets and events on
8061 * the parent interface. This is used mainly with hostapd.
8062 */
8063 if (ifidx > 0 &&
8064 (drv->hostapd ||
8065 nlmode == NL80211_IFTYPE_AP_VLAN ||
8066 nlmode == NL80211_IFTYPE_WDS ||
8067 nlmode == NL80211_IFTYPE_MONITOR))
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008068 add_ifidx(drv, ifidx, IFIDX_ANY);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008069
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008070 return 0;
8071}
8072
8073
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008074static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008075 enum wpa_driver_if_type type,
8076 const char *ifname)
8077{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008078 struct wpa_driver_nl80211_data *drv = bss->drv;
8079 int ifindex = if_nametoindex(ifname);
8080
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008081 wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
8082 __func__, type, ifname, ifindex, bss->added_if);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08008083 if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
Dmitry Shmidt051af732013-10-22 13:52:46 -07008084 nl80211_remove_iface(drv, ifindex);
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07008085 else if (ifindex > 0 && !bss->added_if) {
8086 struct wpa_driver_nl80211_data *drv2;
8087 dl_list_for_each(drv2, &drv->global->interfaces,
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008088 struct wpa_driver_nl80211_data, list) {
8089 del_ifidx(drv2, ifindex, IFIDX_ANY);
8090 del_ifidx(drv2, IFIDX_ANY, ifindex);
8091 }
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07008092 }
Dmitry Shmidtaa532512012-09-24 10:35:31 -07008093
Dmitry Shmidtaa532512012-09-24 10:35:31 -07008094 if (type != WPA_IF_AP_BSS)
8095 return 0;
8096
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008097 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008098 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
8099 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008100 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
8101 "interface %s from bridge %s: %s",
8102 bss->ifname, bss->brname, strerror(errno));
8103 }
8104 if (bss->added_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008105 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008106 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
8107 "bridge %s: %s",
8108 bss->brname, strerror(errno));
8109 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008110
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008111 if (bss != drv->first_bss) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008112 struct i802_bss *tbss;
8113
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008114 wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it");
8115 for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008116 if (tbss->next == bss) {
8117 tbss->next = bss->next;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008118 /* Unsubscribe management frames */
8119 nl80211_teardown_ap(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008120 nl80211_destroy_bss(bss);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008121 if (!bss->added_if)
8122 i802_set_iface_flags(bss, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008123 os_free(bss);
8124 bss = NULL;
8125 break;
8126 }
8127 }
8128 if (bss)
8129 wpa_printf(MSG_INFO, "nl80211: %s - could not find "
8130 "BSS %p in the list", __func__, bss);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008131 } else {
8132 wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
8133 nl80211_teardown_ap(bss);
8134 if (!bss->added_if && !drv->first_bss->next)
Paul Stewart092955c2017-02-06 09:13:09 -08008135 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008136 nl80211_destroy_bss(bss);
8137 if (!bss->added_if)
8138 i802_set_iface_flags(bss, 0);
8139 if (drv->first_bss->next) {
8140 drv->first_bss = drv->first_bss->next;
8141 drv->ctx = drv->first_bss->ctx;
8142 os_free(bss);
8143 } else {
8144 wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
8145 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008146 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008147
8148 return 0;
8149}
8150
8151
8152static int cookie_handler(struct nl_msg *msg, void *arg)
8153{
8154 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8155 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8156 u64 *cookie = arg;
8157 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8158 genlmsg_attrlen(gnlh, 0), NULL);
8159 if (tb[NL80211_ATTR_COOKIE])
8160 *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
8161 return NL_SKIP;
8162}
8163
8164
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008165static int nl80211_send_frame_cmd(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008166 unsigned int freq, unsigned int wait,
8167 const u8 *buf, size_t buf_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07008168 int save_cookie, int no_cck, int no_ack,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008169 int offchanok, const u16 *csa_offs,
8170 size_t csa_offs_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008171{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008172 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008173 struct nl_msg *msg;
8174 u64 cookie;
8175 int ret = -1;
8176
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008177 wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
Dmitry Shmidt04949592012-07-19 12:16:46 -07008178 "no_ack=%d offchanok=%d",
8179 freq, wait, no_cck, no_ack, offchanok);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07008180 wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008181
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008182 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME)) ||
8183 (freq && nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
8184 (wait && nla_put_u32(msg, NL80211_ATTR_DURATION, wait)) ||
8185 (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
8186 drv->test_use_roc_tx) &&
8187 nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) ||
8188 (no_cck && nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) ||
8189 (no_ack && nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK)) ||
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008190 (csa_offs && nla_put(msg, NL80211_ATTR_CSA_C_OFFSETS_TX,
8191 csa_offs_len * sizeof(u16), csa_offs)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008192 nla_put(msg, NL80211_ATTR_FRAME, buf_len, buf))
8193 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008194
8195 cookie = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -07008196 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008197 msg = NULL;
8198 if (ret) {
8199 wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008200 "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
8201 freq, wait);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008202 } else {
8203 wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
8204 "cookie 0x%llx", no_ack ? " (no ACK)" : "",
8205 (long long unsigned int) cookie);
8206
Hai Shalomfdcde762020-04-02 11:19:20 -07008207 if (save_cookie)
8208 drv->send_frame_cookie = no_ack ? (u64) -1 : cookie;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008209
Hai Shalomfdcde762020-04-02 11:19:20 -07008210 if (drv->num_send_frame_cookies == MAX_SEND_FRAME_COOKIES) {
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008211 wpa_printf(MSG_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07008212 "nl80211: Drop oldest pending send frame cookie 0x%llx",
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008213 (long long unsigned int)
Hai Shalomfdcde762020-04-02 11:19:20 -07008214 drv->send_frame_cookies[0]);
8215 os_memmove(&drv->send_frame_cookies[0],
8216 &drv->send_frame_cookies[1],
8217 (MAX_SEND_FRAME_COOKIES - 1) *
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008218 sizeof(u64));
Hai Shalomfdcde762020-04-02 11:19:20 -07008219 drv->num_send_frame_cookies--;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008220 }
Hai Shalomfdcde762020-04-02 11:19:20 -07008221 drv->send_frame_cookies[drv->num_send_frame_cookies] = cookie;
8222 drv->num_send_frame_cookies++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008223 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008224
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008225fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008226 nlmsg_free(msg);
8227 return ret;
8228}
8229
8230
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008231static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
8232 unsigned int freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008233 unsigned int wait_time,
8234 const u8 *dst, const u8 *src,
8235 const u8 *bssid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008236 const u8 *data, size_t data_len,
8237 int no_cck)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008238{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008239 struct wpa_driver_nl80211_data *drv = bss->drv;
8240 int ret = -1;
8241 u8 *buf;
8242 struct ieee80211_hdr *hdr;
Hai Shalomfdcde762020-04-02 11:19:20 -07008243 int offchanok = 1;
8244
Hai Shalom4fbc08f2020-05-18 12:37:00 -07008245 if (is_ap_interface(drv->nlmode) && (int) freq == bss->freq &&
8246 bss->beacon_set)
Hai Shalomfdcde762020-04-02 11:19:20 -07008247 offchanok = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008248
8249 wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
Hai Shalomfdcde762020-04-02 11:19:20 -07008250 "freq=%u MHz wait=%d ms no_cck=%d offchanok=%d)",
8251 drv->ifindex, freq, wait_time, no_cck, offchanok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008252
8253 buf = os_zalloc(24 + data_len);
8254 if (buf == NULL)
8255 return ret;
8256 os_memcpy(buf + 24, data, data_len);
8257 hdr = (struct ieee80211_hdr *) buf;
8258 hdr->frame_control =
8259 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
8260 os_memcpy(hdr->addr1, dst, ETH_ALEN);
8261 os_memcpy(hdr->addr2, src, ETH_ALEN);
8262 os_memcpy(hdr->addr3, bssid, ETH_ALEN);
8263
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08008264 if (os_memcmp(bss->addr, src, ETH_ALEN) != 0) {
8265 wpa_printf(MSG_DEBUG, "nl80211: Use random TA " MACSTR,
8266 MAC2STR(src));
8267 os_memcpy(bss->rand_addr, src, ETH_ALEN);
8268 } else {
8269 os_memset(bss->rand_addr, 0, ETH_ALEN);
8270 }
8271
Hai Shalom60840252021-02-19 19:02:11 -08008272#ifdef CONFIG_MESH
8273 if (is_mesh_interface(drv->nlmode)) {
8274 struct hostapd_hw_modes *modes;
8275 u16 num_modes, flags;
8276 u8 dfs_domain;
8277 int i;
8278
8279 modes = nl80211_get_hw_feature_data(bss, &num_modes,
8280 &flags, &dfs_domain);
8281 if (dfs_domain != HOSTAPD_DFS_REGION_ETSI &&
8282 ieee80211_is_dfs(bss->freq, modes, num_modes))
8283 offchanok = 0;
8284 if (modes) {
8285 for (i = 0; i < num_modes; i++) {
8286 os_free(modes[i].channels);
8287 os_free(modes[i].rates);
8288 }
8289 os_free(modes);
8290 }
8291 }
8292#endif /* CONFIG_MESH */
8293
Dmitry Shmidt56052862013-10-04 10:23:25 -07008294 if (is_ap_interface(drv->nlmode) &&
8295 (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
8296 (int) freq == bss->freq || drv->device_ap_sme ||
8297 !drv->use_monitor))
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008298 ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07008299 0, freq, no_cck, offchanok,
8300 wait_time, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008301 else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008302 ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008303 24 + data_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07008304 1, no_cck, 0, offchanok, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008305
8306 os_free(buf);
8307 return ret;
8308}
8309
8310
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008311static void nl80211_frame_wait_cancel(struct i802_bss *bss, u64 cookie)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008312{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008313 struct wpa_driver_nl80211_data *drv = bss->drv;
8314 struct nl_msg *msg;
8315 int ret;
8316
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08008317 wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008318 (long long unsigned int) cookie);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008319 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME_WAIT_CANCEL)) ||
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008320 nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008321 nlmsg_free(msg);
8322 return;
8323 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008324
Hai Shalom899fcc72020-10-19 14:38:18 -07008325 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008326 if (ret)
8327 wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
8328 "(%s)", ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008329}
8330
8331
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008332static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
8333{
8334 struct i802_bss *bss = priv;
8335 struct wpa_driver_nl80211_data *drv = bss->drv;
8336 unsigned int i;
8337 u64 cookie;
8338
8339 /* Cancel the last pending TX cookie */
Hai Shalomfdcde762020-04-02 11:19:20 -07008340 nl80211_frame_wait_cancel(bss, drv->send_frame_cookie);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008341
8342 /*
8343 * Cancel the other pending TX cookies, if any. This is needed since
8344 * the driver may keep a list of all pending offchannel TX operations
8345 * and free up the radio only once they have expired or cancelled.
8346 */
Hai Shalomfdcde762020-04-02 11:19:20 -07008347 for (i = drv->num_send_frame_cookies; i > 0; i--) {
8348 cookie = drv->send_frame_cookies[i - 1];
8349 if (cookie != drv->send_frame_cookie)
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008350 nl80211_frame_wait_cancel(bss, cookie);
8351 }
Hai Shalomfdcde762020-04-02 11:19:20 -07008352 drv->num_send_frame_cookies = 0;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008353}
8354
8355
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008356static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
8357 unsigned int duration)
8358{
8359 struct i802_bss *bss = priv;
8360 struct wpa_driver_nl80211_data *drv = bss->drv;
8361 struct nl_msg *msg;
8362 int ret;
8363 u64 cookie;
8364
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008365 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REMAIN_ON_CHANNEL)) ||
8366 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
8367 nla_put_u32(msg, NL80211_ATTR_DURATION, duration)) {
8368 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008369 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008370 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008371
8372 cookie = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -07008373 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008374 if (ret == 0) {
8375 wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
8376 "0x%llx for freq=%u MHz duration=%u",
8377 (long long unsigned int) cookie, freq, duration);
8378 drv->remain_on_chan_cookie = cookie;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008379 drv->pending_remain_on_chan = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008380 return 0;
8381 }
8382 wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
8383 "(freq=%d duration=%u): %d (%s)",
8384 freq, duration, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008385 return -1;
8386}
8387
8388
8389static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
8390{
8391 struct i802_bss *bss = priv;
8392 struct wpa_driver_nl80211_data *drv = bss->drv;
8393 struct nl_msg *msg;
8394 int ret;
8395
8396 if (!drv->pending_remain_on_chan) {
8397 wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
8398 "to cancel");
8399 return -1;
8400 }
8401
8402 wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
8403 "0x%llx",
8404 (long long unsigned int) drv->remain_on_chan_cookie);
8405
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008406 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
8407 if (!msg ||
8408 nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie)) {
8409 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008410 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008411 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008412
Hai Shalom899fcc72020-10-19 14:38:18 -07008413 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008414 if (ret == 0)
8415 return 0;
8416 wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
8417 "%d (%s)", ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008418 return -1;
8419}
8420
8421
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008422static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008423{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008424 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008425
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008426 if (!report) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008427 if (bss->nl_preq && drv->device_ap_sme &&
Dmitry Shmidt03658832014-08-13 11:03:49 -07008428 is_ap_interface(drv->nlmode) && !bss->in_deinit &&
8429 !bss->static_ap) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008430 /*
8431 * Do not disable Probe Request reporting that was
8432 * enabled in nl80211_setup_ap().
8433 */
8434 wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
8435 "Probe Request reporting nl_preq=%p while "
8436 "in AP mode", bss->nl_preq);
8437 } else if (bss->nl_preq) {
8438 wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
8439 "reporting nl_preq=%p", bss->nl_preq);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008440 nl80211_destroy_eloop_handle(&bss->nl_preq, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008441 }
8442 return 0;
8443 }
8444
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008445 if (bss->nl_preq) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008446 wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008447 "already on! nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008448 return 0;
8449 }
8450
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008451 bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
8452 if (bss->nl_preq == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008453 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008454 wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
8455 "reporting nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008456
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008457 if (nl80211_register_frame(bss, bss->nl_preq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008458 (WLAN_FC_TYPE_MGMT << 2) |
8459 (WLAN_FC_STYPE_PROBE_REQ << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07008460 NULL, 0, false) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008461 goto out_err;
Dmitry Shmidt497c1d52011-07-21 15:19:46 -07008462
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008463 nl80211_register_eloop_read(&bss->nl_preq,
8464 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07008465 bss->nl_cb, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008466
8467 return 0;
8468
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008469 out_err:
8470 nl_destroy_handles(&bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008471 return -1;
8472}
8473
8474
8475static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
8476 int ifindex, int disabled)
8477{
8478 struct nl_msg *msg;
8479 struct nlattr *bands, *band;
8480 int ret;
8481
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008482 wpa_printf(MSG_DEBUG,
8483 "nl80211: NL80211_CMD_SET_TX_BITRATE_MASK (ifindex=%d %s)",
8484 ifindex, disabled ? "NL80211_TXRATE_LEGACY=OFDM-only" :
8485 "no NL80211_TXRATE_LEGACY constraint");
8486
8487 msg = nl80211_ifindex_msg(drv, ifindex, 0,
8488 NL80211_CMD_SET_TX_BITRATE_MASK);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008489 if (!msg)
8490 return -1;
8491
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008492 bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
8493 if (!bands)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008494 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008495
8496 /*
8497 * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
8498 * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
8499 * rates. All 5 GHz rates are left enabled.
8500 */
8501 band = nla_nest_start(msg, NL80211_BAND_2GHZ);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008502 if (!band ||
8503 (disabled && nla_put(msg, NL80211_TXRATE_LEGACY, 8,
8504 "\x0c\x12\x18\x24\x30\x48\x60\x6c")))
8505 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008506 nla_nest_end(msg, band);
8507
8508 nla_nest_end(msg, bands);
8509
Hai Shalom899fcc72020-10-19 14:38:18 -07008510 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008511 if (ret) {
8512 wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
8513 "(%s)", ret, strerror(-ret));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008514 } else
8515 drv->disabled_11b_rates = disabled;
8516
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008517 return ret;
8518
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008519fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008520 nlmsg_free(msg);
8521 return -1;
8522}
8523
8524
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008525static int wpa_driver_nl80211_deinit_ap(void *priv)
8526{
8527 struct i802_bss *bss = priv;
8528 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008529 if (!is_ap_interface(drv->nlmode))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008530 return -1;
Paul Stewart092955c2017-02-06 09:13:09 -08008531 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008532 bss->beacon_set = 0;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008533
8534 /*
8535 * If the P2P GO interface was dynamically added, then it is
8536 * possible that the interface change to station is not possible.
8537 */
8538 if (drv->nlmode == NL80211_IFTYPE_P2P_GO && bss->if_dynamic)
8539 return 0;
8540
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008541 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008542}
8543
8544
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008545static int wpa_driver_nl80211_stop_ap(void *priv)
8546{
8547 struct i802_bss *bss = priv;
8548 struct wpa_driver_nl80211_data *drv = bss->drv;
8549 if (!is_ap_interface(drv->nlmode))
8550 return -1;
Paul Stewart092955c2017-02-06 09:13:09 -08008551 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008552 bss->beacon_set = 0;
8553 return 0;
8554}
8555
8556
Dmitry Shmidt04949592012-07-19 12:16:46 -07008557static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
8558{
8559 struct i802_bss *bss = priv;
8560 struct wpa_driver_nl80211_data *drv = bss->drv;
8561 if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
8562 return -1;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008563
8564 /*
8565 * If the P2P Client interface was dynamically added, then it is
8566 * possible that the interface change to station is not possible.
8567 */
8568 if (bss->if_dynamic)
8569 return 0;
8570
Dmitry Shmidt04949592012-07-19 12:16:46 -07008571 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
8572}
8573
8574
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008575static void wpa_driver_nl80211_resume(void *priv)
8576{
8577 struct i802_bss *bss = priv;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008578 enum nl80211_iftype nlmode = nl80211_get_ifmode(bss);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008579
8580 if (i802_set_iface_flags(bss, 1))
8581 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event");
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008582
8583 if (is_p2p_net_interface(nlmode))
8584 nl80211_disable_11b_rates(bss->drv, bss->drv->ifindex, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008585}
8586
8587
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008588static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
8589{
8590 struct i802_bss *bss = priv;
8591 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008592 struct nl_msg *msg;
8593 struct nlattr *cqm;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008594
8595 wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
8596 "hysteresis=%d", threshold, hysteresis);
8597
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008598 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_CQM)) ||
8599 !(cqm = nla_nest_start(msg, NL80211_ATTR_CQM)) ||
8600 nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold) ||
8601 nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis)) {
8602 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008603 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008604 }
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008605 nla_nest_end(msg, cqm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008606
Hai Shalom899fcc72020-10-19 14:38:18 -07008607 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008608}
8609
8610
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008611static int get_channel_width(struct nl_msg *msg, void *arg)
8612{
8613 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8614 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8615 struct wpa_signal_info *sig_change = arg;
8616
8617 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8618 genlmsg_attrlen(gnlh, 0), NULL);
8619
8620 sig_change->center_frq1 = -1;
8621 sig_change->center_frq2 = -1;
8622 sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
8623
8624 if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
8625 sig_change->chanwidth = convert2width(
8626 nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
8627 if (tb[NL80211_ATTR_CENTER_FREQ1])
8628 sig_change->center_frq1 =
8629 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
8630 if (tb[NL80211_ATTR_CENTER_FREQ2])
8631 sig_change->center_frq2 =
8632 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
8633 }
8634
8635 return NL_SKIP;
8636}
8637
8638
8639static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
8640 struct wpa_signal_info *sig)
8641{
8642 struct nl_msg *msg;
8643
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008644 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
Hai Shalom899fcc72020-10-19 14:38:18 -07008645 return send_and_recv_msgs(drv, msg, get_channel_width, sig, NULL, NULL);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008646}
8647
8648
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008649static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
8650{
8651 struct i802_bss *bss = priv;
8652 struct wpa_driver_nl80211_data *drv = bss->drv;
8653 int res;
8654
8655 os_memset(si, 0, sizeof(*si));
8656 res = nl80211_get_link_signal(drv, si);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008657 if (res) {
8658 if (drv->nlmode != NL80211_IFTYPE_ADHOC &&
8659 drv->nlmode != NL80211_IFTYPE_MESH_POINT)
8660 return res;
8661 si->current_signal = 0;
8662 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008663
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008664 res = nl80211_get_channel_width(drv, si);
8665 if (res != 0)
8666 return res;
8667
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008668 return nl80211_get_link_noise(drv, si);
8669}
8670
8671
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008672static int nl80211_set_param(void *priv, const char *param)
8673{
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07008674 struct i802_bss *bss = priv;
8675 struct wpa_driver_nl80211_data *drv = bss->drv;
8676
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008677 if (param == NULL)
8678 return 0;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08008679 wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008680
8681#ifdef CONFIG_P2P
8682 if (os_strstr(param, "use_p2p_group_interface=1")) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008683 wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
8684 "interface");
8685 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
8686 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
8687 }
8688#endif /* CONFIG_P2P */
8689
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07008690 if (os_strstr(param, "use_monitor=1"))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008691 drv->use_monitor = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008692
8693 if (os_strstr(param, "force_connect_cmd=1")) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008694 drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07008695 drv->force_connect_cmd = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008696 }
8697
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07008698 if (os_strstr(param, "force_bss_selection=1"))
8699 drv->capa.flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
8700
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08008701 if (os_strstr(param, "no_offchannel_tx=1")) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08008702 drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
8703 drv->test_use_roc_tx = 1;
8704 }
8705
Hai Shalomb755a2a2020-04-23 21:49:02 -07008706 if (os_strstr(param, "control_port=0")) {
Hai Shalomfdcde762020-04-02 11:19:20 -07008707 drv->capa.flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
Hai Shalom899fcc72020-10-19 14:38:18 -07008708 drv->capa.flags2 &= ~(WPA_DRIVER_FLAGS2_CONTROL_PORT_RX |
8709 WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS);
8710 drv->control_port_ap = 0;
Hai Shalomb755a2a2020-04-23 21:49:02 -07008711 }
8712
8713 if (os_strstr(param, "control_port_ap=1"))
8714 drv->control_port_ap = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -07008715
Hai Shalom899fcc72020-10-19 14:38:18 -07008716 if (os_strstr(param, "control_port_ap=0")) {
8717 drv->capa.flags2 &= ~WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS;
8718 drv->control_port_ap = 0;
8719 }
8720
Hai Shalomfdcde762020-04-02 11:19:20 -07008721 if (os_strstr(param, "full_ap_client_state=0"))
8722 drv->capa.flags &= ~WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
8723
Hai Shalom899fcc72020-10-19 14:38:18 -07008724 if (os_strstr(param, "no_rrm=1")) {
8725 drv->no_rrm = 1;
8726
8727 if (!bss->in_deinit && !is_ap_interface(drv->nlmode) &&
8728 !is_mesh_interface(drv->nlmode)) {
8729 nl80211_mgmt_unsubscribe(bss, "no_rrm=1");
8730 if (nl80211_mgmt_subscribe_non_ap(bss) < 0)
8731 wpa_printf(MSG_DEBUG,
8732 "nl80211: Failed to re-register Action frame processing - ignore for now");
8733 }
8734 }
8735
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008736 return 0;
8737}
8738
8739
Dmitry Shmidte4663042016-04-04 10:07:49 -07008740static void * nl80211_global_init(void *ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008741{
8742 struct nl80211_global *global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008743 struct netlink_config *cfg;
8744
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008745 global = os_zalloc(sizeof(*global));
8746 if (global == NULL)
8747 return NULL;
Dmitry Shmidte4663042016-04-04 10:07:49 -07008748 global->ctx = ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008749 global->ioctl_sock = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008750 dl_list_init(&global->interfaces);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008751 global->if_add_ifindex = -1;
8752
8753 cfg = os_zalloc(sizeof(*cfg));
8754 if (cfg == NULL)
8755 goto err;
8756
8757 cfg->ctx = global;
8758 cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
8759 cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
8760 global->netlink = netlink_init(cfg);
8761 if (global->netlink == NULL) {
8762 os_free(cfg);
8763 goto err;
8764 }
8765
8766 if (wpa_driver_nl80211_init_nl_global(global) < 0)
8767 goto err;
8768
8769 global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
8770 if (global->ioctl_sock < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008771 wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s",
8772 strerror(errno));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008773 goto err;
8774 }
8775
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008776 return global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008777
8778err:
8779 nl80211_global_deinit(global);
8780 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008781}
8782
8783
8784static void nl80211_global_deinit(void *priv)
8785{
8786 struct nl80211_global *global = priv;
8787 if (global == NULL)
8788 return;
8789 if (!dl_list_empty(&global->interfaces)) {
8790 wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at "
8791 "nl80211_global_deinit",
8792 dl_list_len(&global->interfaces));
8793 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008794
8795 if (global->netlink)
8796 netlink_deinit(global->netlink);
8797
8798 nl_destroy_handles(&global->nl);
8799
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008800 if (global->nl_event)
Roshan Pius3a1667e2018-07-03 15:17:14 -07008801 nl80211_destroy_eloop_handle(&global->nl_event, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008802
8803 nl_cb_put(global->nl_cb);
8804
8805 if (global->ioctl_sock >= 0)
8806 close(global->ioctl_sock);
8807
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008808 os_free(global);
8809}
8810
8811
8812static const char * nl80211_get_radio_name(void *priv)
8813{
8814 struct i802_bss *bss = priv;
8815 struct wpa_driver_nl80211_data *drv = bss->drv;
8816 return drv->phyname;
8817}
8818
8819
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008820static int nl80211_pmkid(struct i802_bss *bss, int cmd,
8821 struct wpa_pmkid_params *params)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008822{
8823 struct nl_msg *msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008824 const size_t PMK_MAX_LEN = 48; /* current cfg80211 limit */
Jouni Malinen75ecf522011-06-27 15:19:46 -07008825
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008826 if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008827 (params->pmkid &&
8828 nla_put(msg, NL80211_ATTR_PMKID, 16, params->pmkid)) ||
8829 (params->bssid &&
8830 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid)) ||
8831 (params->ssid_len &&
8832 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
8833 (params->fils_cache_id &&
8834 nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2,
8835 params->fils_cache_id)) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07008836 (params->pmk_lifetime &&
8837 nla_put_u32(msg, NL80211_ATTR_PMK_LIFETIME,
8838 params->pmk_lifetime)) ||
8839 (params->pmk_reauth_threshold &&
8840 nla_put_u8(msg, NL80211_ATTR_PMK_REAUTH_THRESHOLD,
8841 params->pmk_reauth_threshold)) ||
Hai Shalom021b0b52019-04-10 11:17:58 -07008842 (cmd != NL80211_CMD_DEL_PMKSA &&
8843 params->pmk_len && params->pmk_len <= PMK_MAX_LEN &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008844 nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
Hai Shalom74f70d42019-02-11 14:42:39 -08008845 nl80211_nlmsg_clear(msg);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008846 nlmsg_free(msg);
8847 return -ENOBUFS;
8848 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07008849
Hai Shalom60840252021-02-19 19:02:11 -08008850 return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008851}
8852
8853
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008854static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008855{
8856 struct i802_bss *bss = priv;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008857 int ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008858
8859 if (params->bssid)
8860 wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR,
8861 MAC2STR(params->bssid));
8862 else if (params->fils_cache_id && params->ssid_len) {
8863 wpa_printf(MSG_DEBUG,
8864 "nl80211: Add PMKSA for cache id %02x%02x SSID %s",
8865 params->fils_cache_id[0], params->fils_cache_id[1],
8866 wpa_ssid_txt(params->ssid, params->ssid_len));
8867 }
8868
Roshan Pius3a1667e2018-07-03 15:17:14 -07008869 ret = nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params);
8870 if (ret < 0) {
8871 wpa_printf(MSG_DEBUG,
8872 "nl80211: NL80211_CMD_SET_PMKSA failed: %d (%s)",
8873 ret, strerror(-ret));
8874 }
8875
8876 return ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -07008877}
8878
8879
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008880static int nl80211_remove_pmkid(void *priv, struct wpa_pmkid_params *params)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008881{
8882 struct i802_bss *bss = priv;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008883 int ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008884
8885 if (params->bssid)
8886 wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
8887 MAC2STR(params->bssid));
8888 else if (params->fils_cache_id && params->ssid_len) {
8889 wpa_printf(MSG_DEBUG,
8890 "nl80211: Delete PMKSA for cache id %02x%02x SSID %s",
8891 params->fils_cache_id[0], params->fils_cache_id[1],
8892 wpa_ssid_txt(params->ssid, params->ssid_len));
8893 }
8894
Roshan Pius3a1667e2018-07-03 15:17:14 -07008895 ret = nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params);
8896 if (ret < 0) {
8897 wpa_printf(MSG_DEBUG,
8898 "nl80211: NL80211_CMD_DEL_PMKSA failed: %d (%s)",
8899 ret, strerror(-ret));
8900 }
8901
8902 return ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -07008903}
8904
8905
8906static int nl80211_flush_pmkid(void *priv)
8907{
8908 struct i802_bss *bss = priv;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008909 struct nl_msg *msg;
8910
Jouni Malinen75ecf522011-06-27 15:19:46 -07008911 wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008912 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_FLUSH_PMKSA);
8913 if (!msg)
8914 return -ENOBUFS;
Hai Shalom899fcc72020-10-19 14:38:18 -07008915 return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008916}
8917
8918
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008919static void clean_survey_results(struct survey_results *survey_results)
8920{
8921 struct freq_survey *survey, *tmp;
8922
8923 if (dl_list_empty(&survey_results->survey_list))
8924 return;
8925
8926 dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
8927 struct freq_survey, list) {
8928 dl_list_del(&survey->list);
8929 os_free(survey);
8930 }
8931}
8932
8933
8934static void add_survey(struct nlattr **sinfo, u32 ifidx,
8935 struct dl_list *survey_list)
8936{
8937 struct freq_survey *survey;
8938
8939 survey = os_zalloc(sizeof(struct freq_survey));
8940 if (!survey)
8941 return;
8942
8943 survey->ifidx = ifidx;
8944 survey->freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
8945 survey->filled = 0;
8946
8947 if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
8948 survey->nf = (int8_t)
8949 nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
8950 survey->filled |= SURVEY_HAS_NF;
8951 }
8952
8953 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) {
8954 survey->channel_time =
8955 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
8956 survey->filled |= SURVEY_HAS_CHAN_TIME;
8957 }
8958
8959 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
8960 survey->channel_time_busy =
8961 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
8962 survey->filled |= SURVEY_HAS_CHAN_TIME_BUSY;
8963 }
8964
8965 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) {
8966 survey->channel_time_rx =
8967 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]);
8968 survey->filled |= SURVEY_HAS_CHAN_TIME_RX;
8969 }
8970
8971 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) {
8972 survey->channel_time_tx =
8973 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]);
8974 survey->filled |= SURVEY_HAS_CHAN_TIME_TX;
8975 }
8976
8977 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)",
8978 survey->freq,
8979 survey->nf,
8980 (unsigned long int) survey->channel_time,
8981 (unsigned long int) survey->channel_time_busy,
8982 (unsigned long int) survey->channel_time_tx,
8983 (unsigned long int) survey->channel_time_rx,
8984 survey->filled);
8985
8986 dl_list_add_tail(survey_list, &survey->list);
8987}
8988
8989
8990static int check_survey_ok(struct nlattr **sinfo, u32 surveyed_freq,
8991 unsigned int freq_filter)
8992{
8993 if (!freq_filter)
8994 return 1;
8995
8996 return freq_filter == surveyed_freq;
8997}
8998
8999
9000static int survey_handler(struct nl_msg *msg, void *arg)
9001{
9002 struct nlattr *tb[NL80211_ATTR_MAX + 1];
9003 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
9004 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
9005 struct survey_results *survey_results;
9006 u32 surveyed_freq = 0;
9007 u32 ifidx;
9008
9009 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
9010 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
9011 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
9012 };
9013
9014 survey_results = (struct survey_results *) arg;
9015
9016 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
9017 genlmsg_attrlen(gnlh, 0), NULL);
9018
Dmitry Shmidt97672262014-02-03 13:02:54 -08009019 if (!tb[NL80211_ATTR_IFINDEX])
9020 return NL_SKIP;
9021
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009022 ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
9023
9024 if (!tb[NL80211_ATTR_SURVEY_INFO])
9025 return NL_SKIP;
9026
9027 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
9028 tb[NL80211_ATTR_SURVEY_INFO],
9029 survey_policy))
9030 return NL_SKIP;
9031
9032 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) {
9033 wpa_printf(MSG_ERROR, "nl80211: Invalid survey data");
9034 return NL_SKIP;
9035 }
9036
9037 surveyed_freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
9038
9039 if (!check_survey_ok(sinfo, surveyed_freq,
9040 survey_results->freq_filter))
9041 return NL_SKIP;
9042
9043 if (survey_results->freq_filter &&
9044 survey_results->freq_filter != surveyed_freq) {
9045 wpa_printf(MSG_EXCESSIVE, "nl80211: Ignoring survey data for freq %d MHz",
9046 surveyed_freq);
9047 return NL_SKIP;
9048 }
9049
9050 add_survey(sinfo, ifidx, &survey_results->survey_list);
9051
9052 return NL_SKIP;
9053}
9054
9055
9056static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
9057{
9058 struct i802_bss *bss = priv;
9059 struct wpa_driver_nl80211_data *drv = bss->drv;
9060 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009061 int err;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009062 union wpa_event_data data;
9063 struct survey_results *survey_results;
9064
9065 os_memset(&data, 0, sizeof(data));
9066 survey_results = &data.survey_results;
9067
9068 dl_list_init(&survey_results->survey_list);
9069
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009070 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009071 if (!msg)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009072 return -ENOBUFS;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009073
9074 if (freq)
9075 data.survey_results.freq_filter = freq;
9076
9077 do {
9078 wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
9079 err = send_and_recv_msgs(drv, msg, survey_handler,
Hai Shalom899fcc72020-10-19 14:38:18 -07009080 survey_results, NULL, NULL);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009081 } while (err > 0);
9082
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009083 if (err)
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009084 wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009085 else
9086 wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009087
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009088 clean_survey_results(survey_results);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009089 return err;
9090}
9091
9092
Dmitry Shmidt807291d2015-01-27 13:40:23 -08009093static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
9094 const u8 *kck, size_t kck_len,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009095 const u8 *replay_ctr)
9096{
9097 struct i802_bss *bss = priv;
9098 struct wpa_driver_nl80211_data *drv = bss->drv;
9099 struct nlattr *replay_nested;
9100 struct nl_msg *msg;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08009101 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009102
Dmitry Shmidtff787d52015-01-12 13:01:47 -08009103 if (!drv->set_rekey_offload)
9104 return;
9105
9106 wpa_printf(MSG_DEBUG, "nl80211: Set rekey offload");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009107 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
9108 !(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
Dmitry Shmidt807291d2015-01-27 13:40:23 -08009109 nla_put(msg, NL80211_REKEY_DATA_KEK, kek_len, kek) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009110 (kck_len && nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009111 nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
9112 replay_ctr)) {
9113 nl80211_nlmsg_clear(msg);
9114 nlmsg_free(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009115 return;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009116 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009117
9118 nla_nest_end(msg, replay_nested);
9119
Hai Shalom60840252021-02-19 19:02:11 -08009120 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08009121 if (ret == -EOPNOTSUPP) {
9122 wpa_printf(MSG_DEBUG,
9123 "nl80211: Driver does not support rekey offload");
9124 drv->set_rekey_offload = 0;
9125 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009126}
9127
9128
9129static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
9130 const u8 *addr, int qos)
9131{
9132 /* send data frame to poll STA and check whether
9133 * this frame is ACKed */
9134 struct {
9135 struct ieee80211_hdr hdr;
9136 u16 qos_ctl;
9137 } STRUCT_PACKED nulldata;
9138 size_t size;
9139
9140 /* Send data frame to poll STA and check whether this frame is ACKed */
9141
9142 os_memset(&nulldata, 0, sizeof(nulldata));
9143
9144 if (qos) {
9145 nulldata.hdr.frame_control =
9146 IEEE80211_FC(WLAN_FC_TYPE_DATA,
9147 WLAN_FC_STYPE_QOS_NULL);
9148 size = sizeof(nulldata);
9149 } else {
9150 nulldata.hdr.frame_control =
9151 IEEE80211_FC(WLAN_FC_TYPE_DATA,
9152 WLAN_FC_STYPE_NULLFUNC);
9153 size = sizeof(struct ieee80211_hdr);
9154 }
9155
9156 nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
9157 os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
9158 os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
9159 os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
9160
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009161 if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -07009162 0, 0, NULL, 0, 0) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009163 wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
9164 "send poll frame");
9165}
9166
9167static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
9168 int qos)
9169{
9170 struct i802_bss *bss = priv;
9171 struct wpa_driver_nl80211_data *drv = bss->drv;
9172 struct nl_msg *msg;
Hai Shalom5f92bc92019-04-18 11:54:11 -07009173 u64 cookie;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08009174 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009175
9176 if (!drv->poll_command_supported) {
9177 nl80211_send_null_frame(bss, own_addr, addr, qos);
9178 return;
9179 }
9180
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009181 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_PROBE_CLIENT)) ||
9182 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
9183 nlmsg_free(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009184 return;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009185 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009186
Hai Shalom899fcc72020-10-19 14:38:18 -07009187 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08009188 if (ret < 0) {
9189 wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
9190 MACSTR " failed: ret=%d (%s)",
9191 MAC2STR(addr), ret, strerror(-ret));
Hai Shalom5f92bc92019-04-18 11:54:11 -07009192 } else {
9193 wpa_printf(MSG_DEBUG,
9194 "nl80211: Client probe request addr=" MACSTR
9195 " cookie=%llu", MAC2STR(addr),
9196 (long long unsigned int) cookie);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08009197 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009198}
9199
9200
9201static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
9202{
9203 struct nl_msg *msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07009204 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009205
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009206 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
9207 nla_put_u32(msg, NL80211_ATTR_PS_STATE,
9208 enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED)) {
9209 nlmsg_free(msg);
9210 return -ENOBUFS;
9211 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07009212
Hai Shalom899fcc72020-10-19 14:38:18 -07009213 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009214 if (ret < 0) {
9215 wpa_printf(MSG_DEBUG,
9216 "nl80211: Setting PS state %s failed: %d (%s)",
9217 enabled ? "enabled" : "disabled",
9218 ret, strerror(-ret));
9219 }
9220 return ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009221}
9222
9223
9224static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
9225 int ctwindow)
9226{
9227 struct i802_bss *bss = priv;
9228
9229 wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
9230 "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
9231
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08009232 if (opp_ps != -1 || ctwindow != -1) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009233#ifdef ANDROID_P2P
9234 wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08009235#else /* ANDROID_P2P */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009236 return -1; /* Not yet supported */
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08009237#endif /* ANDROID_P2P */
9238 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009239
9240 if (legacy_ps == -1)
9241 return 0;
9242 if (legacy_ps != 0 && legacy_ps != 1)
9243 return -1; /* Not yet supported */
9244
9245 return nl80211_set_power_save(bss, legacy_ps);
9246}
9247
9248
Dmitry Shmidt051af732013-10-22 13:52:46 -07009249static int nl80211_start_radar_detection(void *priv,
9250 struct hostapd_freq_params *freq)
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009251{
9252 struct i802_bss *bss = priv;
9253 struct wpa_driver_nl80211_data *drv = bss->drv;
9254 struct nl_msg *msg;
9255 int ret;
9256
Hai Shalom81f62d82019-07-22 12:10:00 -07009257 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)",
9258 freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
Dmitry Shmidt051af732013-10-22 13:52:46 -07009259 freq->bandwidth, freq->center_freq1, freq->center_freq2);
9260
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009261 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
9262 wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
9263 "detection");
9264 return -1;
9265 }
9266
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009267 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_RADAR_DETECT)) ||
9268 nl80211_put_freq_params(msg, freq) < 0) {
9269 nlmsg_free(msg);
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009270 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009271 }
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009272
Hai Shalom899fcc72020-10-19 14:38:18 -07009273 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009274 if (ret == 0)
9275 return 0;
9276 wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
9277 "%d (%s)", ret, strerror(-ret));
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009278 return -1;
9279}
9280
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009281#ifdef CONFIG_TDLS
9282
9283static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
9284 u8 dialog_token, u16 status_code,
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07009285 u32 peer_capab, int initiator, const u8 *buf,
9286 size_t len)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009287{
9288 struct i802_bss *bss = priv;
9289 struct wpa_driver_nl80211_data *drv = bss->drv;
9290 struct nl_msg *msg;
9291
9292 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
9293 return -EOPNOTSUPP;
9294
9295 if (!dst)
9296 return -EINVAL;
9297
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009298 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_MGMT)) ||
9299 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
9300 nla_put_u8(msg, NL80211_ATTR_TDLS_ACTION, action_code) ||
9301 nla_put_u8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token) ||
9302 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status_code))
9303 goto fail;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07009304 if (peer_capab) {
9305 /*
9306 * The internal enum tdls_peer_capability definition is
9307 * currently identical with the nl80211 enum
9308 * nl80211_tdls_peer_capability, so no conversion is needed
9309 * here.
9310 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009311 if (nla_put_u32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY,
9312 peer_capab))
9313 goto fail;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07009314 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009315 if ((initiator &&
9316 nla_put_flag(msg, NL80211_ATTR_TDLS_INITIATOR)) ||
9317 nla_put(msg, NL80211_ATTR_IE, len, buf))
9318 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009319
Hai Shalom899fcc72020-10-19 14:38:18 -07009320 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009321
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009322fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009323 nlmsg_free(msg);
9324 return -ENOBUFS;
9325}
9326
9327
9328static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
9329{
9330 struct i802_bss *bss = priv;
9331 struct wpa_driver_nl80211_data *drv = bss->drv;
9332 struct nl_msg *msg;
9333 enum nl80211_tdls_operation nl80211_oper;
Paul Stewart092955c2017-02-06 09:13:09 -08009334 int res;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009335
9336 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
9337 return -EOPNOTSUPP;
9338
9339 switch (oper) {
9340 case TDLS_DISCOVERY_REQ:
9341 nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
9342 break;
9343 case TDLS_SETUP:
9344 nl80211_oper = NL80211_TDLS_SETUP;
9345 break;
9346 case TDLS_TEARDOWN:
9347 nl80211_oper = NL80211_TDLS_TEARDOWN;
9348 break;
9349 case TDLS_ENABLE_LINK:
9350 nl80211_oper = NL80211_TDLS_ENABLE_LINK;
9351 break;
9352 case TDLS_DISABLE_LINK:
9353 nl80211_oper = NL80211_TDLS_DISABLE_LINK;
9354 break;
9355 case TDLS_ENABLE:
9356 return 0;
9357 case TDLS_DISABLE:
9358 return 0;
9359 default:
9360 return -EINVAL;
9361 }
9362
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009363 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_OPER)) ||
9364 nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper) ||
9365 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) {
9366 nlmsg_free(msg);
9367 return -ENOBUFS;
9368 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009369
Hai Shalom899fcc72020-10-19 14:38:18 -07009370 res = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Paul Stewart092955c2017-02-06 09:13:09 -08009371 wpa_printf(MSG_DEBUG, "nl80211: TDLS_OPER: oper=%d mac=" MACSTR
9372 " --> res=%d (%s)", nl80211_oper, MAC2STR(peer), res,
9373 strerror(-res));
9374 return res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009375}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009376
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009377
9378static int
9379nl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
9380 const struct hostapd_freq_params *params)
9381{
9382 struct i802_bss *bss = priv;
9383 struct wpa_driver_nl80211_data *drv = bss->drv;
9384 struct nl_msg *msg;
9385 int ret = -ENOBUFS;
9386
9387 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
9388 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
9389 return -EOPNOTSUPP;
9390
9391 wpa_printf(MSG_DEBUG, "nl80211: Enable TDLS channel switch " MACSTR
9392 " oper_class=%u freq=%u",
9393 MAC2STR(addr), oper_class, params->freq);
9394 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CHANNEL_SWITCH);
9395 if (!msg ||
9396 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
9397 nla_put_u8(msg, NL80211_ATTR_OPER_CLASS, oper_class) ||
9398 (ret = nl80211_put_freq_params(msg, params))) {
9399 nlmsg_free(msg);
9400 wpa_printf(MSG_DEBUG, "nl80211: Could not build TDLS chan switch");
9401 return ret;
9402 }
9403
Hai Shalom899fcc72020-10-19 14:38:18 -07009404 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009405}
9406
9407
9408static int
9409nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
9410{
9411 struct i802_bss *bss = priv;
9412 struct wpa_driver_nl80211_data *drv = bss->drv;
9413 struct nl_msg *msg;
9414
9415 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
9416 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
9417 return -EOPNOTSUPP;
9418
9419 wpa_printf(MSG_DEBUG, "nl80211: Disable TDLS channel switch " MACSTR,
9420 MAC2STR(addr));
9421 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH);
9422 if (!msg ||
9423 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
9424 nlmsg_free(msg);
9425 wpa_printf(MSG_DEBUG,
9426 "nl80211: Could not build TDLS cancel chan switch");
9427 return -ENOBUFS;
9428 }
9429
Hai Shalom899fcc72020-10-19 14:38:18 -07009430 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009431}
9432
9433#endif /* CONFIG TDLS */
9434
9435
Hai Shalomfdcde762020-04-02 11:19:20 -07009436static int driver_nl80211_set_key(void *priv,
9437 struct wpa_driver_set_key_params *params)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009438{
9439 struct i802_bss *bss = priv;
Hai Shalomfdcde762020-04-02 11:19:20 -07009440
9441 return wpa_driver_nl80211_set_key(bss, params);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009442}
9443
9444
9445static int driver_nl80211_scan2(void *priv,
9446 struct wpa_driver_scan_params *params)
9447{
9448 struct i802_bss *bss = priv;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009449#ifdef CONFIG_DRIVER_NL80211_QCA
9450 struct wpa_driver_nl80211_data *drv = bss->drv;
9451
9452 /*
9453 * Do a vendor specific scan if possible. If only_new_results is
9454 * set, do a normal scan since a kernel (cfg80211) BSS cache flush
9455 * cannot be achieved through a vendor scan. The below condition may
9456 * need to be modified if new scan flags are added in the future whose
9457 * functionality can only be achieved through a normal scan.
9458 */
9459 if (drv->scan_vendor_cmd_avail && !params->only_new_results)
9460 return wpa_driver_nl80211_vendor_scan(bss, params);
9461#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009462 return wpa_driver_nl80211_scan(bss, params);
9463}
9464
9465
9466static int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -07009467 u16 reason_code)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009468{
9469 struct i802_bss *bss = priv;
9470 return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
9471}
9472
9473
9474static int driver_nl80211_authenticate(void *priv,
9475 struct wpa_driver_auth_params *params)
9476{
9477 struct i802_bss *bss = priv;
9478 return wpa_driver_nl80211_authenticate(bss, params);
9479}
9480
9481
9482static void driver_nl80211_deinit(void *priv)
9483{
9484 struct i802_bss *bss = priv;
9485 wpa_driver_nl80211_deinit(bss);
9486}
9487
9488
9489static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
9490 const char *ifname)
9491{
9492 struct i802_bss *bss = priv;
9493 return wpa_driver_nl80211_if_remove(bss, type, ifname);
9494}
9495
9496
9497static int driver_nl80211_send_mlme(void *priv, const u8 *data,
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07009498 size_t data_len, int noack,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009499 unsigned int freq,
Hai Shalomfdcde762020-04-02 11:19:20 -07009500 const u16 *csa_offs, size_t csa_offs_len,
9501 int no_encrypt, unsigned int wait)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009502{
9503 struct i802_bss *bss = priv;
9504 return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
Hai Shalomfdcde762020-04-02 11:19:20 -07009505 freq, 0, 0, wait, csa_offs,
9506 csa_offs_len, no_encrypt);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009507}
9508
9509
9510static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
9511{
9512 struct i802_bss *bss = priv;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009513 return wpa_driver_nl80211_sta_remove(bss, addr, -1, 0);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009514}
9515
9516
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009517static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
9518 const char *ifname, int vlan_id)
9519{
9520 struct i802_bss *bss = priv;
9521 return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
9522}
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009523
9524
9525static int driver_nl80211_read_sta_data(void *priv,
9526 struct hostap_sta_driver_data *data,
9527 const u8 *addr)
9528{
9529 struct i802_bss *bss = priv;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08009530
9531 os_memset(data, 0, sizeof(*data));
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009532 return i802_read_sta_data(bss, data, addr);
9533}
9534
9535
9536static int driver_nl80211_send_action(void *priv, unsigned int freq,
9537 unsigned int wait_time,
9538 const u8 *dst, const u8 *src,
9539 const u8 *bssid,
9540 const u8 *data, size_t data_len,
9541 int no_cck)
9542{
9543 struct i802_bss *bss = priv;
9544 return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
9545 bssid, data, data_len, no_cck);
9546}
9547
9548
9549static int driver_nl80211_probe_req_report(void *priv, int report)
9550{
9551 struct i802_bss *bss = priv;
9552 return wpa_driver_nl80211_probe_req_report(bss, report);
9553}
9554
9555
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009556static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
9557 const u8 *ies, size_t ies_len)
9558{
9559 int ret;
9560 struct nl_msg *msg;
9561 struct i802_bss *bss = priv;
9562 struct wpa_driver_nl80211_data *drv = bss->drv;
9563 u16 mdid = WPA_GET_LE16(md);
9564
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009565 wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009566 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_FT_IES)) ||
9567 nla_put(msg, NL80211_ATTR_IE, ies_len, ies) ||
9568 nla_put_u16(msg, NL80211_ATTR_MDID, mdid)) {
9569 nlmsg_free(msg);
9570 return -ENOBUFS;
9571 }
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009572
Hai Shalom899fcc72020-10-19 14:38:18 -07009573 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009574 if (ret) {
9575 wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
9576 "err=%d (%s)", ret, strerror(-ret));
9577 }
9578
9579 return ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009580}
9581
9582
Hai Shalom81f62d82019-07-22 12:10:00 -07009583static int nl80211_update_dh_ie(void *priv, const u8 *peer_mac,
9584 u16 reason_code, const u8 *ie, size_t ie_len)
9585{
9586 int ret;
9587 struct nl_msg *msg;
9588 struct i802_bss *bss = priv;
9589 struct wpa_driver_nl80211_data *drv = bss->drv;
9590
9591 wpa_printf(MSG_DEBUG, "nl80211: Updating DH IE peer: " MACSTR
9592 " reason %u", MAC2STR(peer_mac), reason_code);
9593 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UPDATE_OWE_INFO)) ||
9594 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer_mac) ||
9595 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, reason_code) ||
9596 (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie))) {
9597 nlmsg_free(msg);
9598 return -ENOBUFS;
9599 }
9600
Hai Shalom899fcc72020-10-19 14:38:18 -07009601 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalom81f62d82019-07-22 12:10:00 -07009602 if (ret) {
9603 wpa_printf(MSG_DEBUG,
9604 "nl80211: update_dh_ie failed err=%d (%s)",
9605 ret, strerror(-ret));
9606 }
9607
9608 return ret;
9609}
9610
9611
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07009612static const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009613{
9614 struct i802_bss *bss = priv;
9615 struct wpa_driver_nl80211_data *drv = bss->drv;
9616
9617 if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
9618 return NULL;
9619
9620 return bss->addr;
9621}
9622
9623
Dmitry Shmidt56052862013-10-04 10:23:25 -07009624static const char * scan_state_str(enum scan_states scan_state)
9625{
9626 switch (scan_state) {
9627 case NO_SCAN:
9628 return "NO_SCAN";
9629 case SCAN_REQUESTED:
9630 return "SCAN_REQUESTED";
9631 case SCAN_STARTED:
9632 return "SCAN_STARTED";
9633 case SCAN_COMPLETED:
9634 return "SCAN_COMPLETED";
9635 case SCAN_ABORTED:
9636 return "SCAN_ABORTED";
9637 case SCHED_SCAN_STARTED:
9638 return "SCHED_SCAN_STARTED";
9639 case SCHED_SCAN_STOPPED:
9640 return "SCHED_SCAN_STOPPED";
9641 case SCHED_SCAN_RESULTS:
9642 return "SCHED_SCAN_RESULTS";
9643 }
9644
9645 return "??";
9646}
9647
9648
9649static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
9650{
9651 struct i802_bss *bss = priv;
9652 struct wpa_driver_nl80211_data *drv = bss->drv;
9653 int res;
9654 char *pos, *end;
Hai Shalom74f70d42019-02-11 14:42:39 -08009655 struct nl_msg *msg;
9656 char alpha2[3] = { 0, 0, 0 };
Dmitry Shmidt56052862013-10-04 10:23:25 -07009657
9658 pos = buf;
9659 end = buf + buflen;
9660
9661 res = os_snprintf(pos, end - pos,
9662 "ifindex=%d\n"
9663 "ifname=%s\n"
9664 "brname=%s\n"
9665 "addr=" MACSTR "\n"
9666 "freq=%d\n"
Hai Shalomc9e41a12018-07-31 14:41:42 -07009667 "%s%s%s%s%s%s",
Dmitry Shmidt56052862013-10-04 10:23:25 -07009668 bss->ifindex,
9669 bss->ifname,
9670 bss->brname,
9671 MAC2STR(bss->addr),
9672 bss->freq,
9673 bss->beacon_set ? "beacon_set=1\n" : "",
9674 bss->added_if_into_bridge ?
9675 "added_if_into_bridge=1\n" : "",
Hai Shalomc9e41a12018-07-31 14:41:42 -07009676 bss->already_in_bridge ? "already_in_bridge=1\n" : "",
Dmitry Shmidt56052862013-10-04 10:23:25 -07009677 bss->added_bridge ? "added_bridge=1\n" : "",
9678 bss->in_deinit ? "in_deinit=1\n" : "",
9679 bss->if_dynamic ? "if_dynamic=1\n" : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009680 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -07009681 return pos - buf;
9682 pos += res;
9683
9684 if (bss->wdev_id_set) {
9685 res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
9686 (unsigned long long) bss->wdev_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009687 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -07009688 return pos - buf;
9689 pos += res;
9690 }
9691
9692 res = os_snprintf(pos, end - pos,
9693 "phyname=%s\n"
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07009694 "perm_addr=" MACSTR "\n"
Dmitry Shmidt56052862013-10-04 10:23:25 -07009695 "drv_ifindex=%d\n"
9696 "operstate=%d\n"
9697 "scan_state=%s\n"
9698 "auth_bssid=" MACSTR "\n"
9699 "auth_attempt_bssid=" MACSTR "\n"
9700 "bssid=" MACSTR "\n"
9701 "prev_bssid=" MACSTR "\n"
9702 "associated=%d\n"
9703 "assoc_freq=%u\n"
9704 "monitor_sock=%d\n"
9705 "monitor_ifidx=%d\n"
9706 "monitor_refcount=%d\n"
9707 "last_mgmt_freq=%u\n"
9708 "eapol_tx_sock=%d\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009709 "%s%s%s%s%s%s%s%s%s%s%s%s%s",
Dmitry Shmidt56052862013-10-04 10:23:25 -07009710 drv->phyname,
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07009711 MAC2STR(drv->perm_addr),
Dmitry Shmidt56052862013-10-04 10:23:25 -07009712 drv->ifindex,
9713 drv->operstate,
9714 scan_state_str(drv->scan_state),
9715 MAC2STR(drv->auth_bssid),
9716 MAC2STR(drv->auth_attempt_bssid),
9717 MAC2STR(drv->bssid),
9718 MAC2STR(drv->prev_bssid),
9719 drv->associated,
9720 drv->assoc_freq,
9721 drv->monitor_sock,
9722 drv->monitor_ifidx,
9723 drv->monitor_refcount,
9724 drv->last_mgmt_freq,
9725 drv->eapol_tx_sock,
9726 drv->ignore_if_down_event ?
9727 "ignore_if_down_event=1\n" : "",
9728 drv->scan_complete_events ?
9729 "scan_complete_events=1\n" : "",
9730 drv->disabled_11b_rates ?
9731 "disabled_11b_rates=1\n" : "",
9732 drv->pending_remain_on_chan ?
9733 "pending_remain_on_chan=1\n" : "",
9734 drv->in_interface_list ? "in_interface_list=1\n" : "",
9735 drv->device_ap_sme ? "device_ap_sme=1\n" : "",
9736 drv->poll_command_supported ?
9737 "poll_command_supported=1\n" : "",
9738 drv->data_tx_status ? "data_tx_status=1\n" : "",
9739 drv->scan_for_auth ? "scan_for_auth=1\n" : "",
9740 drv->retry_auth ? "retry_auth=1\n" : "",
9741 drv->use_monitor ? "use_monitor=1\n" : "",
9742 drv->ignore_next_local_disconnect ?
9743 "ignore_next_local_disconnect=1\n" : "",
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07009744 drv->ignore_next_local_deauth ?
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009745 "ignore_next_local_deauth=1\n" : "");
9746 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -07009747 return pos - buf;
9748 pos += res;
9749
9750 if (drv->has_capability) {
9751 res = os_snprintf(pos, end - pos,
9752 "capa.key_mgmt=0x%x\n"
9753 "capa.enc=0x%x\n"
9754 "capa.auth=0x%x\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009755 "capa.flags=0x%llx\n"
9756 "capa.rrm_flags=0x%x\n"
Dmitry Shmidt56052862013-10-04 10:23:25 -07009757 "capa.max_scan_ssids=%d\n"
9758 "capa.max_sched_scan_ssids=%d\n"
9759 "capa.sched_scan_supported=%d\n"
9760 "capa.max_match_sets=%d\n"
9761 "capa.max_remain_on_chan=%u\n"
9762 "capa.max_stations=%u\n"
9763 "capa.probe_resp_offloads=0x%x\n"
9764 "capa.max_acl_mac_addrs=%u\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009765 "capa.num_multichan_concurrent=%u\n"
9766 "capa.mac_addr_rand_sched_scan_supported=%d\n"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009767 "capa.mac_addr_rand_scan_supported=%d\n"
9768 "capa.conc_capab=%u\n"
9769 "capa.max_conc_chan_2_4=%u\n"
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009770 "capa.max_conc_chan_5_0=%u\n"
9771 "capa.max_sched_scan_plans=%u\n"
9772 "capa.max_sched_scan_plan_interval=%u\n"
9773 "capa.max_sched_scan_plan_iterations=%u\n",
Dmitry Shmidt56052862013-10-04 10:23:25 -07009774 drv->capa.key_mgmt,
9775 drv->capa.enc,
9776 drv->capa.auth,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009777 (unsigned long long) drv->capa.flags,
9778 drv->capa.rrm_flags,
Dmitry Shmidt56052862013-10-04 10:23:25 -07009779 drv->capa.max_scan_ssids,
9780 drv->capa.max_sched_scan_ssids,
9781 drv->capa.sched_scan_supported,
9782 drv->capa.max_match_sets,
9783 drv->capa.max_remain_on_chan,
9784 drv->capa.max_stations,
9785 drv->capa.probe_resp_offloads,
9786 drv->capa.max_acl_mac_addrs,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009787 drv->capa.num_multichan_concurrent,
9788 drv->capa.mac_addr_rand_sched_scan_supported,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009789 drv->capa.mac_addr_rand_scan_supported,
9790 drv->capa.conc_capab,
9791 drv->capa.max_conc_chan_2_4,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009792 drv->capa.max_conc_chan_5_0,
9793 drv->capa.max_sched_scan_plans,
9794 drv->capa.max_sched_scan_plan_interval,
9795 drv->capa.max_sched_scan_plan_iterations);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009796 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -07009797 return pos - buf;
9798 pos += res;
9799 }
9800
Hai Shalom74f70d42019-02-11 14:42:39 -08009801 msg = nlmsg_alloc();
9802 if (msg &&
9803 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG) &&
9804 nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx) == 0) {
9805 if (send_and_recv_msgs(drv, msg, nl80211_get_country,
Hai Shalom899fcc72020-10-19 14:38:18 -07009806 alpha2, NULL, NULL) == 0 &&
Hai Shalom74f70d42019-02-11 14:42:39 -08009807 alpha2[0]) {
9808 res = os_snprintf(pos, end - pos, "country=%s\n",
9809 alpha2);
9810 if (os_snprintf_error(end - pos, res))
9811 return pos - buf;
9812 pos += res;
9813 }
9814 } else {
9815 nlmsg_free(msg);
9816 }
9817
Dmitry Shmidt56052862013-10-04 10:23:25 -07009818 return pos - buf;
9819}
9820
9821
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009822static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
9823{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009824 if ((settings->head &&
9825 nla_put(msg, NL80211_ATTR_BEACON_HEAD,
9826 settings->head_len, settings->head)) ||
9827 (settings->tail &&
9828 nla_put(msg, NL80211_ATTR_BEACON_TAIL,
9829 settings->tail_len, settings->tail)) ||
9830 (settings->beacon_ies &&
9831 nla_put(msg, NL80211_ATTR_IE,
9832 settings->beacon_ies_len, settings->beacon_ies)) ||
9833 (settings->proberesp_ies &&
9834 nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
9835 settings->proberesp_ies_len, settings->proberesp_ies)) ||
9836 (settings->assocresp_ies &&
9837 nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
9838 settings->assocresp_ies_len, settings->assocresp_ies)) ||
9839 (settings->probe_resp &&
9840 nla_put(msg, NL80211_ATTR_PROBE_RESP,
9841 settings->probe_resp_len, settings->probe_resp)))
9842 return -ENOBUFS;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009843
9844 return 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009845}
9846
9847
9848static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
9849{
9850 struct nl_msg *msg;
9851 struct i802_bss *bss = priv;
9852 struct wpa_driver_nl80211_data *drv = bss->drv;
9853 struct nlattr *beacon_csa;
9854 int ret = -ENOBUFS;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009855 int csa_off_len = 0;
9856 int i;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009857
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08009858 wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d width=%d cf1=%d cf2=%d)",
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009859 settings->cs_count, settings->block_tx,
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08009860 settings->freq_params.freq, settings->freq_params.bandwidth,
9861 settings->freq_params.center_freq1,
9862 settings->freq_params.center_freq2);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009863
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009864 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_AP_CSA)) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009865 wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
9866 return -EOPNOTSUPP;
9867 }
9868
Roshan Pius3a1667e2018-07-03 15:17:14 -07009869 if (drv->nlmode != NL80211_IFTYPE_AP &&
9870 drv->nlmode != NL80211_IFTYPE_P2P_GO &&
9871 drv->nlmode != NL80211_IFTYPE_MESH_POINT)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009872 return -EOPNOTSUPP;
9873
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009874 /*
9875 * Remove empty counters, assuming Probe Response and Beacon frame
9876 * counters match. This implementation assumes that there are only two
9877 * counters.
9878 */
9879 if (settings->counter_offset_beacon[0] &&
9880 !settings->counter_offset_beacon[1]) {
9881 csa_off_len = 1;
9882 } else if (settings->counter_offset_beacon[1] &&
9883 !settings->counter_offset_beacon[0]) {
9884 csa_off_len = 1;
9885 settings->counter_offset_beacon[0] =
9886 settings->counter_offset_beacon[1];
9887 settings->counter_offset_presp[0] =
9888 settings->counter_offset_presp[1];
9889 } else if (settings->counter_offset_beacon[1] &&
9890 settings->counter_offset_beacon[0]) {
9891 csa_off_len = 2;
9892 } else {
9893 wpa_printf(MSG_ERROR, "nl80211: No CSA counters provided");
9894 return -EINVAL;
9895 }
9896
9897 /* Check CSA counters validity */
9898 if (drv->capa.max_csa_counters &&
9899 csa_off_len > drv->capa.max_csa_counters) {
9900 wpa_printf(MSG_ERROR,
9901 "nl80211: Too many CSA counters provided");
9902 return -EINVAL;
9903 }
9904
9905 if (!settings->beacon_csa.tail)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009906 return -EINVAL;
9907
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009908 for (i = 0; i < csa_off_len; i++) {
9909 u16 csa_c_off_bcn = settings->counter_offset_beacon[i];
9910 u16 csa_c_off_presp = settings->counter_offset_presp[i];
9911
9912 if ((settings->beacon_csa.tail_len <= csa_c_off_bcn) ||
9913 (settings->beacon_csa.tail[csa_c_off_bcn] !=
9914 settings->cs_count))
9915 return -EINVAL;
9916
9917 if (settings->beacon_csa.probe_resp &&
9918 ((settings->beacon_csa.probe_resp_len <=
9919 csa_c_off_presp) ||
9920 (settings->beacon_csa.probe_resp[csa_c_off_presp] !=
9921 settings->cs_count)))
9922 return -EINVAL;
9923 }
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009924
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009925 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CHANNEL_SWITCH)) ||
9926 nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT,
9927 settings->cs_count) ||
9928 (ret = nl80211_put_freq_params(msg, &settings->freq_params)) ||
9929 (settings->block_tx &&
9930 nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)))
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009931 goto error;
9932
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009933 /* beacon_after params */
9934 ret = set_beacon_data(msg, &settings->beacon_after);
9935 if (ret)
9936 goto error;
9937
9938 /* beacon_csa params */
9939 beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
9940 if (!beacon_csa)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009941 goto fail;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009942
9943 ret = set_beacon_data(msg, &settings->beacon_csa);
9944 if (ret)
9945 goto error;
9946
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009947 if (nla_put(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
9948 csa_off_len * sizeof(u16),
9949 settings->counter_offset_beacon) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009950 (settings->beacon_csa.probe_resp &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009951 nla_put(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
9952 csa_off_len * sizeof(u16),
9953 settings->counter_offset_presp)))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009954 goto fail;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009955
9956 nla_nest_end(msg, beacon_csa);
Hai Shalom899fcc72020-10-19 14:38:18 -07009957 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009958 if (ret) {
9959 wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
9960 ret, strerror(-ret));
9961 }
9962 return ret;
9963
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009964fail:
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009965 ret = -ENOBUFS;
9966error:
9967 nlmsg_free(msg);
9968 wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request");
9969 return ret;
9970}
9971
9972
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009973static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr,
9974 u8 user_priority, u16 admitted_time)
9975{
9976 struct i802_bss *bss = priv;
9977 struct wpa_driver_nl80211_data *drv = bss->drv;
9978 struct nl_msg *msg;
9979 int ret;
9980
9981 wpa_printf(MSG_DEBUG,
9982 "nl80211: add_ts request: tsid=%u admitted_time=%u up=%d",
9983 tsid, admitted_time, user_priority);
9984
9985 if (!is_sta_interface(drv->nlmode))
9986 return -ENOTSUP;
9987
9988 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ADD_TX_TS);
9989 if (!msg ||
9990 nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
9991 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
9992 nla_put_u8(msg, NL80211_ATTR_USER_PRIO, user_priority) ||
9993 nla_put_u16(msg, NL80211_ATTR_ADMITTED_TIME, admitted_time)) {
9994 nlmsg_free(msg);
9995 return -ENOBUFS;
9996 }
9997
Hai Shalom899fcc72020-10-19 14:38:18 -07009998 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009999 if (ret)
10000 wpa_printf(MSG_DEBUG, "nl80211: add_ts failed err=%d (%s)",
10001 ret, strerror(-ret));
10002 return ret;
10003}
10004
10005
10006static int nl80211_del_ts(void *priv, u8 tsid, const u8 *addr)
10007{
10008 struct i802_bss *bss = priv;
10009 struct wpa_driver_nl80211_data *drv = bss->drv;
10010 struct nl_msg *msg;
10011 int ret;
10012
10013 wpa_printf(MSG_DEBUG, "nl80211: del_ts request: tsid=%u", tsid);
10014
10015 if (!is_sta_interface(drv->nlmode))
10016 return -ENOTSUP;
10017
10018 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_TX_TS)) ||
10019 nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
10020 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
10021 nlmsg_free(msg);
10022 return -ENOBUFS;
10023 }
10024
Hai Shalom899fcc72020-10-19 14:38:18 -070010025 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010026 if (ret)
10027 wpa_printf(MSG_DEBUG, "nl80211: del_ts failed err=%d (%s)",
10028 ret, strerror(-ret));
10029 return ret;
10030}
10031
10032
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010033#ifdef CONFIG_TESTING_OPTIONS
10034static int cmd_reply_handler(struct nl_msg *msg, void *arg)
10035{
10036 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
10037 struct wpabuf *buf = arg;
10038
10039 if (!buf)
10040 return NL_SKIP;
10041
10042 if ((size_t) genlmsg_attrlen(gnlh, 0) > wpabuf_tailroom(buf)) {
10043 wpa_printf(MSG_INFO, "nl80211: insufficient buffer space for reply");
10044 return NL_SKIP;
10045 }
10046
10047 wpabuf_put_data(buf, genlmsg_attrdata(gnlh, 0),
10048 genlmsg_attrlen(gnlh, 0));
10049
10050 return NL_SKIP;
10051}
10052#endif /* CONFIG_TESTING_OPTIONS */
10053
10054
10055static int vendor_reply_handler(struct nl_msg *msg, void *arg)
10056{
10057 struct nlattr *tb[NL80211_ATTR_MAX + 1];
10058 struct nlattr *nl_vendor_reply, *nl;
10059 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
10060 struct wpabuf *buf = arg;
10061 int rem;
10062
10063 if (!buf)
10064 return NL_SKIP;
10065
10066 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
10067 genlmsg_attrlen(gnlh, 0), NULL);
10068 nl_vendor_reply = tb[NL80211_ATTR_VENDOR_DATA];
10069
10070 if (!nl_vendor_reply)
10071 return NL_SKIP;
10072
10073 if ((size_t) nla_len(nl_vendor_reply) > wpabuf_tailroom(buf)) {
10074 wpa_printf(MSG_INFO, "nl80211: Vendor command: insufficient buffer space for reply");
10075 return NL_SKIP;
10076 }
10077
10078 nla_for_each_nested(nl, nl_vendor_reply, rem) {
10079 wpabuf_put_data(buf, nla_data(nl), nla_len(nl));
10080 }
10081
10082 return NL_SKIP;
10083}
10084
10085
Hai Shalom60840252021-02-19 19:02:11 -080010086static bool is_cmd_with_nested_attrs(unsigned int vendor_id,
10087 unsigned int subcmd)
10088{
10089 if (vendor_id != OUI_QCA)
10090 return true;
10091
10092 switch (subcmd) {
10093 case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
10094 case QCA_NL80211_VENDOR_SUBCMD_STATS_EXT:
10095 case QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI:
10096 case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY:
10097 case QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS:
10098 case QCA_NL80211_VENDOR_SUBCMD_NAN:
10099 return false;
10100 default:
10101 return true;
10102 }
10103}
10104
10105
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010106static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
10107 unsigned int subcmd, const u8 *data,
Hai Shalom60840252021-02-19 19:02:11 -080010108 size_t data_len, enum nested_attr nested_attr,
10109 struct wpabuf *buf)
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010110{
10111 struct i802_bss *bss = priv;
10112 struct wpa_driver_nl80211_data *drv = bss->drv;
10113 struct nl_msg *msg;
Hai Shalom60840252021-02-19 19:02:11 -080010114 int ret, nla_flag;
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010115
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010116#ifdef CONFIG_TESTING_OPTIONS
10117 if (vendor_id == 0xffffffff) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010118 msg = nlmsg_alloc();
10119 if (!msg)
10120 return -ENOMEM;
10121
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010122 nl80211_cmd(drv, msg, 0, subcmd);
10123 if (nlmsg_append(msg, (void *) data, data_len, NLMSG_ALIGNTO) <
10124 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010125 goto fail;
Hai Shalomb755a2a2020-04-23 21:49:02 -070010126 /* This test vendor_cmd can be used with nl80211 commands that
10127 * need the connect nl_sock, so use the owner-setting variant
10128 * of send_and_recv_msgs(). */
10129 ret = send_and_recv_msgs_owner(drv, msg,
10130 get_connect_handle(bss), 0,
Hai Shalom899fcc72020-10-19 14:38:18 -070010131 cmd_reply_handler, buf,
10132 NULL, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010133 if (ret)
10134 wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
10135 ret);
10136 return ret;
10137 }
10138#endif /* CONFIG_TESTING_OPTIONS */
10139
Hai Shalom60840252021-02-19 19:02:11 -080010140 if (nested_attr == NESTED_ATTR_USED)
10141 nla_flag = NLA_F_NESTED;
10142 else if (nested_attr == NESTED_ATTR_UNSPECIFIED &&
10143 is_cmd_with_nested_attrs(vendor_id, subcmd))
10144 nla_flag = NLA_F_NESTED;
10145 else
10146 nla_flag = 0;
10147
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010148 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
10149 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, vendor_id) ||
10150 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd) ||
10151 (data &&
Hai Shalom60840252021-02-19 19:02:11 -080010152 nla_put(msg, nla_flag | NL80211_ATTR_VENDOR_DATA,
10153 data_len, data)))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010154 goto fail;
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010155
Hai Shalom899fcc72020-10-19 14:38:18 -070010156 ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf,
10157 NULL, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010158 if (ret)
10159 wpa_printf(MSG_DEBUG, "nl80211: vendor command failed err=%d",
10160 ret);
10161 return ret;
10162
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010163fail:
Dmitry Shmidta38abf92014-03-06 13:38:44 -080010164 nlmsg_free(msg);
10165 return -ENOBUFS;
10166}
10167
10168
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010169static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
10170 u8 qos_map_set_len)
10171{
10172 struct i802_bss *bss = priv;
10173 struct wpa_driver_nl80211_data *drv = bss->drv;
10174 struct nl_msg *msg;
10175 int ret;
10176
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010177 wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
10178 qos_map_set, qos_map_set_len);
10179
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010180 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_QOS_MAP)) ||
10181 nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) {
10182 nlmsg_free(msg);
10183 return -ENOBUFS;
10184 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010185
Hai Shalom899fcc72020-10-19 14:38:18 -070010186 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010187 if (ret)
10188 wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
10189
10190 return ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010191}
10192
10193
Hai Shalomfdcde762020-04-02 11:19:20 -070010194static int get_wowlan_handler(struct nl_msg *msg, void *arg)
10195{
10196 struct nlattr *tb[NL80211_ATTR_MAX + 1];
10197 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
10198 int *wowlan_enabled = arg;
10199
10200 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
10201 genlmsg_attrlen(gnlh, 0), NULL);
10202
10203 *wowlan_enabled = !!tb[NL80211_ATTR_WOWLAN_TRIGGERS];
10204
10205 return NL_SKIP;
10206}
10207
10208
10209static int nl80211_get_wowlan(void *priv)
10210{
10211 struct i802_bss *bss = priv;
10212 struct wpa_driver_nl80211_data *drv = bss->drv;
10213 struct nl_msg *msg;
10214 int wowlan_enabled;
10215 int ret;
10216
10217 wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status");
10218
10219 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_WOWLAN);
10220
Hai Shalom899fcc72020-10-19 14:38:18 -070010221 ret = send_and_recv_msgs(drv, msg, get_wowlan_handler, &wowlan_enabled,
10222 NULL, NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -070010223 if (ret) {
10224 wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status failed");
10225 return 0;
10226 }
10227
10228 wpa_printf(MSG_DEBUG, "nl80211: wowlan is %s",
10229 wowlan_enabled ? "enabled" : "disabled");
10230
10231 return wowlan_enabled;
10232}
10233
10234
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010235static int nl80211_set_wowlan(void *priv,
10236 const struct wowlan_triggers *triggers)
10237{
10238 struct i802_bss *bss = priv;
10239 struct wpa_driver_nl80211_data *drv = bss->drv;
10240 struct nl_msg *msg;
10241 struct nlattr *wowlan_triggers;
10242 int ret;
10243
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010244 wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
10245
Dmitry Shmidta3dc3092015-06-23 11:21:28 -070010246 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_WOWLAN)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010247 !(wowlan_triggers = nla_nest_start(msg,
10248 NL80211_ATTR_WOWLAN_TRIGGERS)) ||
10249 (triggers->any &&
10250 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
10251 (triggers->disconnect &&
10252 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
10253 (triggers->magic_pkt &&
10254 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
10255 (triggers->gtk_rekey_failure &&
10256 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
10257 (triggers->eap_identity_req &&
10258 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
10259 (triggers->four_way_handshake &&
10260 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
10261 (triggers->rfkill_release &&
10262 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) {
10263 nlmsg_free(msg);
10264 return -ENOBUFS;
10265 }
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010266
10267 nla_nest_end(msg, wowlan_triggers);
10268
Hai Shalom899fcc72020-10-19 14:38:18 -070010269 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010270 if (ret)
10271 wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
10272
10273 return ret;
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070010274}
10275
10276
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010277#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010278static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
10279{
10280 struct i802_bss *bss = priv;
10281 struct wpa_driver_nl80211_data *drv = bss->drv;
10282 struct nl_msg *msg;
10283 struct nlattr *params;
10284
10285 wpa_printf(MSG_DEBUG, "nl80211: Roaming policy: allowed=%d", allowed);
10286
10287 if (!drv->roaming_vendor_cmd_avail) {
10288 wpa_printf(MSG_DEBUG,
10289 "nl80211: Ignore roaming policy change since driver does not provide command for setting it");
10290 return -1;
10291 }
10292
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010293 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10294 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10295 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10296 QCA_NL80211_VENDOR_SUBCMD_ROAMING) ||
10297 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10298 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
10299 allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
10300 QCA_ROAMING_NOT_ALLOWED) ||
10301 (bssid &&
10302 nla_put(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid))) {
10303 nlmsg_free(msg);
10304 return -1;
10305 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010306 nla_nest_end(msg, params);
10307
Hai Shalom899fcc72020-10-19 14:38:18 -070010308 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010309}
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010310
10311
Roshan Pius3a1667e2018-07-03 15:17:14 -070010312static int nl80211_disable_fils(void *priv, int disable)
10313{
10314 struct i802_bss *bss = priv;
10315 struct wpa_driver_nl80211_data *drv = bss->drv;
10316 struct nl_msg *msg;
10317 struct nlattr *params;
10318
10319 wpa_printf(MSG_DEBUG, "nl80211: Disable FILS=%d", disable);
10320
10321 if (!drv->set_wifi_conf_vendor_cmd_avail)
10322 return -1;
10323
10324 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10325 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10326 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10327 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION) ||
10328 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10329 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS,
10330 disable)) {
10331 nlmsg_free(msg);
10332 return -1;
10333 }
10334 nla_nest_end(msg, params);
10335
Hai Shalom899fcc72020-10-19 14:38:18 -070010336 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010337}
10338
10339
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010340/* Reserved QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID value for wpa_supplicant */
10341#define WPA_SUPPLICANT_CLIENT_ID 1
10342
Hai Shalom899fcc72020-10-19 14:38:18 -070010343static int nl80211_set_bssid_tmp_disallow(void *priv, unsigned int num_bssid,
10344 const u8 *bssid)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010345{
10346 struct i802_bss *bss = priv;
10347 struct wpa_driver_nl80211_data *drv = bss->drv;
10348 struct nl_msg *msg;
10349 struct nlattr *params, *nlbssids, *attr;
10350 unsigned int i;
10351
Hai Shalom899fcc72020-10-19 14:38:18 -070010352 wpa_printf(MSG_DEBUG,
10353 "nl80211: Set temporarily disallowed BSSIDs (num=%u)",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010354 num_bssid);
10355
10356 if (!drv->roam_vendor_cmd_avail)
10357 return -1;
10358
10359 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10360 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10361 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10362 QCA_NL80211_VENDOR_SUBCMD_ROAM) ||
10363 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10364 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
Hai Shalomc3565922019-10-28 11:58:20 -070010365 QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010366 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID,
10367 WPA_SUPPLICANT_CLIENT_ID) ||
10368 nla_put_u32(msg,
10369 QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID,
10370 num_bssid))
10371 goto fail;
10372
10373 nlbssids = nla_nest_start(
10374 msg, QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS);
10375 if (!nlbssids)
10376 goto fail;
10377
10378 for (i = 0; i < num_bssid; i++) {
10379 attr = nla_nest_start(msg, i);
10380 if (!attr)
10381 goto fail;
10382 if (nla_put(msg,
10383 QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID,
10384 ETH_ALEN, &bssid[i * ETH_ALEN]))
10385 goto fail;
10386 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%u]: " MACSTR, i,
10387 MAC2STR(&bssid[i * ETH_ALEN]));
10388 nla_nest_end(msg, attr);
10389 }
10390 nla_nest_end(msg, nlbssids);
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);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010394
10395fail:
10396 nlmsg_free(msg);
10397 return -1;
10398}
10399
Hai Shalomc3565922019-10-28 11:58:20 -070010400
10401static int nl80211_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
10402{
10403 struct i802_bss *bss = priv;
10404 struct wpa_driver_nl80211_data *drv = bss->drv;
10405 struct nl_msg *msg;
10406 struct nlattr *params;
10407
10408 if (!drv->add_sta_node_vendor_cmd_avail)
10409 return -EOPNOTSUPP;
10410
10411 wpa_printf(MSG_DEBUG, "nl80211: Add STA node");
10412
10413 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10414 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10415 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10416 QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE) ||
10417 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10418 (addr &&
10419 nla_put(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_MAC_ADDR, ETH_ALEN,
10420 addr)) ||
10421 nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO,
10422 auth_alg)) {
10423 nlmsg_free(msg);
10424 wpa_printf(MSG_ERROR,
10425 "%s: err in adding vendor_cmd and vendor_data",
10426 __func__);
10427 return -1;
10428 }
10429 nla_nest_end(msg, params);
10430
Hai Shalom899fcc72020-10-19 14:38:18 -070010431 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalomc3565922019-10-28 11:58:20 -070010432}
10433
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010434#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010435
10436
10437static int nl80211_set_mac_addr(void *priv, const u8 *addr)
10438{
10439 struct i802_bss *bss = priv;
10440 struct wpa_driver_nl80211_data *drv = bss->drv;
10441 int new_addr = addr != NULL;
Mir Ali8a8f1002020-10-06 22:41:40 +053010442#ifdef CONFIG_DRIVER_NL80211_BRCM
10443 struct nl_msg *msg;
10444 struct nlattr *params;
10445 int ret;
10446#endif /* CONFIG_DRIVER_NL80211_BRCM */
10447 wpa_printf(MSG_DEBUG, "Enter: %s", __FUNCTION__);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010448
Dmitry Shmidt849734c2016-05-27 09:59:01 -070010449 if (TEST_FAIL())
10450 return -1;
Mir Ali8a8f1002020-10-06 22:41:40 +053010451 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
10452#ifdef CONFIG_DRIVER_NL80211_BRCM
10453 if (!addr ) {
10454 addr = drv->global->p2p_perm_addr;
10455 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -070010456
Mir Ali8a8f1002020-10-06 22:41:40 +053010457 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
10458 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
10459 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10460 BRCM_VENDOR_SUBCMD_SET_MAC) ||
10461 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10462 nla_put(msg, BRCM_ATTR_DRIVER_MAC_ADDR, ETH_ALEN, addr)) {
10463 wpa_printf(MSG_ERROR, "failed to put p2p randmac");
10464 nl80211_nlmsg_clear(msg);
10465 nlmsg_free(msg);
10466 return -ENOBUFS;
10467 }
10468 nla_nest_end(msg, params);
10469
10470 ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
10471 if (ret) {
10472 wpa_printf(MSG_ERROR, "nl80211: p2p set macaddr failed: ret=%d (%s)",
10473 ret, strerror(-ret));
10474 }
10475 memcpy(bss->addr, addr, ETH_ALEN);
10476 return ret;
10477#else
10478 return -ENOTSUP;
10479#endif /* CONFIG_DRIVER_NL80211_BRCM */
10480 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010481 if (!addr)
10482 addr = drv->perm_addr;
10483
10484 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) < 0)
10485 return -1;
10486
10487 if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, addr) < 0)
10488 {
10489 wpa_printf(MSG_DEBUG,
Mir Ali8a8f1002020-10-06 22:41:40 +053010490 "nl80211: failed to set_mac_addr for %s to " MACSTR,
10491 bss->ifname, MAC2STR(addr));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010492 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
Mir Ali8a8f1002020-10-06 22:41:40 +053010493 1) < 0) {
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010494 wpa_printf(MSG_DEBUG,
Mir Ali8a8f1002020-10-06 22:41:40 +053010495 "nl80211: Could not restore interface UP after failed set_mac_addr");
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010496 }
10497 return -1;
10498 }
10499
10500 wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR,
Mir Ali8a8f1002020-10-06 22:41:40 +053010501 bss->ifname, MAC2STR(addr));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010502 drv->addr_changed = new_addr;
10503 os_memcpy(bss->addr, addr, ETH_ALEN);
10504
10505 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0)
10506 {
10507 wpa_printf(MSG_DEBUG,
Mir Ali8a8f1002020-10-06 22:41:40 +053010508 "nl80211: Could not restore interface UP after set_mac_addr");
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010509 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010510 return 0;
10511}
10512
10513
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010514#ifdef CONFIG_MESH
10515
10516static int wpa_driver_nl80211_init_mesh(void *priv)
10517{
10518 if (wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_MESH_POINT)) {
10519 wpa_printf(MSG_INFO,
10520 "nl80211: Failed to set interface into mesh mode");
10521 return -1;
10522 }
10523 return 0;
10524}
10525
10526
Dmitry Shmidtff787d52015-01-12 13:01:47 -080010527static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id,
10528 size_t mesh_id_len)
10529{
10530 if (mesh_id) {
Hai Shalom74f70d42019-02-11 14:42:39 -080010531 wpa_printf(MSG_DEBUG, " * Mesh ID (SSID)=%s",
10532 wpa_ssid_txt(mesh_id, mesh_id_len));
Dmitry Shmidtff787d52015-01-12 13:01:47 -080010533 return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
10534 }
10535
10536 return 0;
10537}
10538
10539
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070010540static int nl80211_put_mesh_config(struct nl_msg *msg,
10541 struct wpa_driver_mesh_bss_params *params)
10542{
10543 struct nlattr *container;
10544
10545 container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
10546 if (!container)
10547 return -1;
10548
10549 if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
Roshan Pius3a1667e2018-07-03 15:17:14 -070010550 nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
10551 params->auto_plinks)) ||
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070010552 ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) &&
10553 nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010554 params->max_peer_links)) ||
10555 ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD) &&
10556 nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
10557 params->rssi_threshold)))
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070010558 return -1;
10559
10560 /*
10561 * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
10562 * the timer could disconnect stations even in that case.
10563 */
10564 if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT) &&
10565 nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
10566 params->peer_link_timeout)) {
10567 wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
10568 return -1;
10569 }
10570
10571 if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE) &&
10572 nla_put_u16(msg, NL80211_MESHCONF_HT_OPMODE, params->ht_opmode)) {
10573 wpa_printf(MSG_ERROR, "nl80211: Failed to set HT_OP_MODE");
10574 return -1;
10575 }
10576
10577 nla_nest_end(msg, container);
10578
10579 return 0;
10580}
10581
10582
Dmitry Shmidt7f656022015-02-25 14:36:37 -080010583static int nl80211_join_mesh(struct i802_bss *bss,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010584 struct wpa_driver_mesh_join_params *params)
10585{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010586 struct wpa_driver_nl80211_data *drv = bss->drv;
10587 struct nl_msg *msg;
10588 struct nlattr *container;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -080010589 int ret = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010590
10591 wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
10592 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
Dmitry Shmidtff787d52015-01-12 13:01:47 -080010593 if (!msg ||
10594 nl80211_put_freq_params(msg, &params->freq) ||
10595 nl80211_put_basic_rates(msg, params->basic_rates) ||
10596 nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) ||
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070010597 nl80211_put_beacon_int(msg, params->beacon_int) ||
10598 nl80211_put_dtim_period(msg, params->dtim_period))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010599 goto fail;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010600
10601 wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags);
10602
Hai Shalom60840252021-02-19 19:02:11 -080010603 if (params->handle_dfs && nla_put_flag(msg, NL80211_ATTR_HANDLE_DFS))
10604 goto fail;
10605
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010606 container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
10607 if (!container)
10608 goto fail;
10609
10610 if (params->ies) {
10611 wpa_hexdump(MSG_DEBUG, " * IEs", params->ies, params->ie_len);
10612 if (nla_put(msg, NL80211_MESH_SETUP_IE, params->ie_len,
10613 params->ies))
10614 goto fail;
10615 }
10616 /* WPA_DRIVER_MESH_FLAG_OPEN_AUTH is treated as default by nl80211 */
10617 if (params->flags & WPA_DRIVER_MESH_FLAG_SAE_AUTH) {
10618 if (nla_put_u8(msg, NL80211_MESH_SETUP_AUTH_PROTOCOL, 0x1) ||
10619 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AUTH))
10620 goto fail;
10621 }
10622 if ((params->flags & WPA_DRIVER_MESH_FLAG_AMPE) &&
10623 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AMPE))
10624 goto fail;
10625 if ((params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) &&
10626 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_MPM))
10627 goto fail;
10628 nla_nest_end(msg, container);
10629
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070010630 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
10631 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT;
10632 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS;
10633 if (nl80211_put_mesh_config(msg, &params->conf) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010634 goto fail;
10635
Hai Shalomb755a2a2020-04-23 21:49:02 -070010636 ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1,
Hai Shalom899fcc72020-10-19 14:38:18 -070010637 NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010638 msg = NULL;
10639 if (ret) {
10640 wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
10641 ret, strerror(-ret));
10642 goto fail;
10643 }
10644 ret = 0;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070010645 drv->assoc_freq = bss->freq = params->freq.freq;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010646 wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
10647
10648fail:
10649 nlmsg_free(msg);
10650 return ret;
10651}
10652
10653
Dmitry Shmidt7f656022015-02-25 14:36:37 -080010654static int
10655wpa_driver_nl80211_join_mesh(void *priv,
10656 struct wpa_driver_mesh_join_params *params)
10657{
10658 struct i802_bss *bss = priv;
10659 int ret, timeout;
10660
10661 timeout = params->conf.peer_link_timeout;
10662
10663 /* Disable kernel inactivity timer */
10664 if (params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM)
10665 params->conf.peer_link_timeout = 0;
10666
10667 ret = nl80211_join_mesh(bss, params);
10668 if (ret == -EINVAL && params->conf.peer_link_timeout == 0) {
10669 wpa_printf(MSG_DEBUG,
10670 "nl80211: Mesh join retry for peer_link_timeout");
10671 /*
10672 * Old kernel does not support setting
10673 * NL80211_MESHCONF_PLINK_TIMEOUT to zero, so set 60 seconds
10674 * into future from peer_link_timeout.
10675 */
10676 params->conf.peer_link_timeout = timeout + 60;
10677 ret = nl80211_join_mesh(priv, params);
10678 }
10679
10680 params->conf.peer_link_timeout = timeout;
10681 return ret;
10682}
10683
10684
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010685static int wpa_driver_nl80211_leave_mesh(void *priv)
10686{
10687 struct i802_bss *bss = priv;
10688 struct wpa_driver_nl80211_data *drv = bss->drv;
10689 struct nl_msg *msg;
10690 int ret;
10691
10692 wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
10693 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
Hai Shalomb755a2a2020-04-23 21:49:02 -070010694 ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 0,
Hai Shalom899fcc72020-10-19 14:38:18 -070010695 NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010696 if (ret) {
10697 wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
10698 ret, strerror(-ret));
10699 } else {
10700 wpa_printf(MSG_DEBUG,
10701 "nl80211: mesh leave request send successfully");
10702 }
10703
10704 if (wpa_driver_nl80211_set_mode(drv->first_bss,
10705 NL80211_IFTYPE_STATION)) {
10706 wpa_printf(MSG_INFO,
10707 "nl80211: Failed to set interface into station mode");
10708 }
10709 return ret;
10710}
10711
Hai Shalom81f62d82019-07-22 12:10:00 -070010712
10713static int nl80211_probe_mesh_link(void *priv, const u8 *addr, const u8 *eth,
10714 size_t len)
10715{
10716 struct i802_bss *bss = priv;
10717 struct wpa_driver_nl80211_data *drv = bss->drv;
10718 struct nl_msg *msg;
10719 int ret;
10720
10721 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_PROBE_MESH_LINK);
10722 if (!msg ||
10723 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
10724 nla_put(msg, NL80211_ATTR_FRAME, len, eth)) {
10725 nlmsg_free(msg);
10726 return -ENOBUFS;
10727 }
10728
Hai Shalom899fcc72020-10-19 14:38:18 -070010729 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalom81f62d82019-07-22 12:10:00 -070010730 if (ret) {
10731 wpa_printf(MSG_DEBUG, "nl80211: mesh link probe to " MACSTR
10732 " failed: ret=%d (%s)",
10733 MAC2STR(addr), ret, strerror(-ret));
10734 } else {
10735 wpa_printf(MSG_DEBUG, "nl80211: Mesh link to " MACSTR
10736 " probed successfully", MAC2STR(addr));
10737 }
10738
10739 return ret;
10740}
10741
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010742#endif /* CONFIG_MESH */
10743
10744
10745static int wpa_driver_br_add_ip_neigh(void *priv, u8 version,
10746 const u8 *ipaddr, int prefixlen,
10747 const u8 *addr)
10748{
10749#ifdef CONFIG_LIBNL3_ROUTE
10750 struct i802_bss *bss = priv;
10751 struct wpa_driver_nl80211_data *drv = bss->drv;
10752 struct rtnl_neigh *rn;
10753 struct nl_addr *nl_ipaddr = NULL;
10754 struct nl_addr *nl_lladdr = NULL;
10755 int family, addrsize;
10756 int res;
10757
10758 if (!ipaddr || prefixlen == 0 || !addr)
10759 return -EINVAL;
10760
10761 if (bss->br_ifindex == 0) {
10762 wpa_printf(MSG_DEBUG,
10763 "nl80211: bridge must be set before adding an ip neigh to it");
10764 return -1;
10765 }
10766
10767 if (!drv->rtnl_sk) {
10768 wpa_printf(MSG_DEBUG,
10769 "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
10770 return -1;
10771 }
10772
10773 if (version == 4) {
10774 family = AF_INET;
10775 addrsize = 4;
10776 } else if (version == 6) {
10777 family = AF_INET6;
10778 addrsize = 16;
10779 } else {
10780 return -EINVAL;
10781 }
10782
10783 rn = rtnl_neigh_alloc();
10784 if (rn == NULL)
10785 return -ENOMEM;
10786
10787 /* set the destination ip address for neigh */
10788 nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
10789 if (nl_ipaddr == NULL) {
10790 wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
10791 res = -ENOMEM;
10792 goto errout;
10793 }
10794 nl_addr_set_prefixlen(nl_ipaddr, prefixlen);
10795 res = rtnl_neigh_set_dst(rn, nl_ipaddr);
10796 if (res) {
10797 wpa_printf(MSG_DEBUG,
10798 "nl80211: neigh set destination addr failed");
10799 goto errout;
10800 }
10801
10802 /* set the corresponding lladdr for neigh */
10803 nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN);
10804 if (nl_lladdr == NULL) {
10805 wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed");
10806 res = -ENOMEM;
10807 goto errout;
10808 }
10809 rtnl_neigh_set_lladdr(rn, nl_lladdr);
10810
10811 rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
10812 rtnl_neigh_set_state(rn, NUD_PERMANENT);
10813
10814 res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE);
10815 if (res) {
10816 wpa_printf(MSG_DEBUG,
10817 "nl80211: Adding bridge ip neigh failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070010818 nl_geterror(res));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010819 }
10820errout:
10821 if (nl_lladdr)
10822 nl_addr_put(nl_lladdr);
10823 if (nl_ipaddr)
10824 nl_addr_put(nl_ipaddr);
10825 if (rn)
10826 rtnl_neigh_put(rn);
10827 return res;
10828#else /* CONFIG_LIBNL3_ROUTE */
10829 return -1;
10830#endif /* CONFIG_LIBNL3_ROUTE */
10831}
10832
10833
10834static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version,
10835 const u8 *ipaddr)
10836{
10837#ifdef CONFIG_LIBNL3_ROUTE
10838 struct i802_bss *bss = priv;
10839 struct wpa_driver_nl80211_data *drv = bss->drv;
10840 struct rtnl_neigh *rn;
10841 struct nl_addr *nl_ipaddr;
10842 int family, addrsize;
10843 int res;
10844
10845 if (!ipaddr)
10846 return -EINVAL;
10847
10848 if (version == 4) {
10849 family = AF_INET;
10850 addrsize = 4;
10851 } else if (version == 6) {
10852 family = AF_INET6;
10853 addrsize = 16;
10854 } else {
10855 return -EINVAL;
10856 }
10857
10858 if (bss->br_ifindex == 0) {
10859 wpa_printf(MSG_DEBUG,
10860 "nl80211: bridge must be set to delete an ip neigh");
10861 return -1;
10862 }
10863
10864 if (!drv->rtnl_sk) {
10865 wpa_printf(MSG_DEBUG,
10866 "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
10867 return -1;
10868 }
10869
10870 rn = rtnl_neigh_alloc();
10871 if (rn == NULL)
10872 return -ENOMEM;
10873
10874 /* set the destination ip address for neigh */
10875 nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
10876 if (nl_ipaddr == NULL) {
10877 wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
10878 res = -ENOMEM;
10879 goto errout;
10880 }
10881 res = rtnl_neigh_set_dst(rn, nl_ipaddr);
10882 if (res) {
10883 wpa_printf(MSG_DEBUG,
10884 "nl80211: neigh set destination addr failed");
10885 goto errout;
10886 }
10887
10888 rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
10889
10890 res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
10891 if (res) {
10892 wpa_printf(MSG_DEBUG,
10893 "nl80211: Deleting bridge ip neigh failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070010894 nl_geterror(res));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010895 }
10896errout:
10897 if (nl_ipaddr)
10898 nl_addr_put(nl_ipaddr);
10899 if (rn)
10900 rtnl_neigh_put(rn);
10901 return res;
10902#else /* CONFIG_LIBNL3_ROUTE */
10903 return -1;
10904#endif /* CONFIG_LIBNL3_ROUTE */
10905}
10906
10907
10908static int linux_write_system_file(const char *path, unsigned int val)
10909{
10910 char buf[50];
10911 int fd, len;
10912
10913 len = os_snprintf(buf, sizeof(buf), "%u\n", val);
10914 if (os_snprintf_error(sizeof(buf), len))
10915 return -1;
10916
10917 fd = open(path, O_WRONLY);
10918 if (fd < 0)
10919 return -1;
10920
10921 if (write(fd, buf, len) < 0) {
10922 wpa_printf(MSG_DEBUG,
10923 "nl80211: Failed to write Linux system file: %s with the value of %d",
10924 path, val);
10925 close(fd);
10926 return -1;
10927 }
10928 close(fd);
10929
10930 return 0;
10931}
10932
10933
10934static const char * drv_br_port_attr_str(enum drv_br_port_attr attr)
10935{
10936 switch (attr) {
10937 case DRV_BR_PORT_ATTR_PROXYARP:
Dmitry Shmidt4dd28dc2015-03-10 11:21:43 -070010938 return "proxyarp_wifi";
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010939 case DRV_BR_PORT_ATTR_HAIRPIN_MODE:
10940 return "hairpin_mode";
10941 }
10942
10943 return NULL;
10944}
10945
10946
10947static int wpa_driver_br_port_set_attr(void *priv, enum drv_br_port_attr attr,
10948 unsigned int val)
10949{
10950 struct i802_bss *bss = priv;
10951 char path[128];
10952 const char *attr_txt;
10953
10954 attr_txt = drv_br_port_attr_str(attr);
10955 if (attr_txt == NULL)
10956 return -EINVAL;
10957
10958 os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/%s",
10959 bss->ifname, attr_txt);
10960
10961 if (linux_write_system_file(path, val))
10962 return -1;
10963
10964 return 0;
10965}
10966
10967
10968static const char * drv_br_net_param_str(enum drv_br_net_param param)
10969{
10970 switch (param) {
10971 case DRV_BR_NET_PARAM_GARP_ACCEPT:
10972 return "arp_accept";
Dmitry Shmidt83474442015-04-15 13:47:09 -070010973 default:
10974 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010975 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010976}
10977
10978
10979static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
10980 unsigned int val)
10981{
10982 struct i802_bss *bss = priv;
10983 char path[128];
10984 const char *param_txt;
10985 int ip_version = 4;
10986
Dmitry Shmidt83474442015-04-15 13:47:09 -070010987 if (param == DRV_BR_MULTICAST_SNOOPING) {
10988 os_snprintf(path, sizeof(path),
10989 "/sys/devices/virtual/net/%s/bridge/multicast_snooping",
10990 bss->brname);
10991 goto set_val;
10992 }
10993
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010994 param_txt = drv_br_net_param_str(param);
10995 if (param_txt == NULL)
10996 return -EINVAL;
10997
10998 switch (param) {
10999 case DRV_BR_NET_PARAM_GARP_ACCEPT:
11000 ip_version = 4;
11001 break;
11002 default:
11003 return -EINVAL;
11004 }
11005
11006 os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
11007 ip_version, bss->brname, param_txt);
11008
Dmitry Shmidt83474442015-04-15 13:47:09 -070011009set_val:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011010 if (linux_write_system_file(path, val))
11011 return -1;
11012
11013 return 0;
11014}
11015
11016
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011017#ifdef CONFIG_DRIVER_NL80211_QCA
11018
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011019static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
11020{
11021 switch (hw_mode) {
11022 case HOSTAPD_MODE_IEEE80211B:
11023 return QCA_ACS_MODE_IEEE80211B;
11024 case HOSTAPD_MODE_IEEE80211G:
11025 return QCA_ACS_MODE_IEEE80211G;
11026 case HOSTAPD_MODE_IEEE80211A:
11027 return QCA_ACS_MODE_IEEE80211A;
11028 case HOSTAPD_MODE_IEEE80211AD:
11029 return QCA_ACS_MODE_IEEE80211AD;
Dmitry Shmidtb1e52102015-05-29 12:36:29 -070011030 case HOSTAPD_MODE_IEEE80211ANY:
11031 return QCA_ACS_MODE_IEEE80211ANY;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011032 default:
11033 return -1;
11034 }
11035}
11036
11037
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080011038static int add_acs_ch_list(struct nl_msg *msg, const int *freq_list)
11039{
11040 int num_channels = 0, num_freqs;
11041 u8 *ch_list;
11042 enum hostapd_hw_mode hw_mode;
11043 int ret = 0;
11044 int i;
11045
11046 if (!freq_list)
11047 return 0;
11048
11049 num_freqs = int_array_len(freq_list);
11050 ch_list = os_malloc(sizeof(u8) * num_freqs);
11051 if (!ch_list)
11052 return -1;
11053
11054 for (i = 0; i < num_freqs; i++) {
11055 const int freq = freq_list[i];
11056
11057 if (freq == 0)
11058 break;
11059 /* Send 2.4 GHz and 5 GHz channels with
11060 * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST to maintain backwards
11061 * compatibility.
11062 */
11063 if (!(freq >= 2412 && freq <= 2484) &&
11064 !(freq >= 5180 && freq <= 5900))
11065 continue;
11066 hw_mode = ieee80211_freq_to_chan(freq, &ch_list[num_channels]);
11067 if (hw_mode != NUM_HOSTAPD_MODES)
11068 num_channels++;
11069 }
11070
11071 if (num_channels)
11072 ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
11073 num_channels, ch_list);
11074
11075 os_free(ch_list);
11076 return ret;
11077}
11078
11079
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011080static int add_acs_freq_list(struct nl_msg *msg, const int *freq_list)
11081{
11082 int i, len, ret;
11083 u32 *freqs;
11084
11085 if (!freq_list)
11086 return 0;
11087 len = int_array_len(freq_list);
11088 freqs = os_malloc(sizeof(u32) * len);
11089 if (!freqs)
11090 return -1;
11091 for (i = 0; i < len; i++)
11092 freqs[i] = freq_list[i];
11093 ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
11094 sizeof(u32) * len, freqs);
11095 os_free(freqs);
11096 return ret;
11097}
11098
11099
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011100static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
11101{
11102 struct i802_bss *bss = priv;
11103 struct wpa_driver_nl80211_data *drv = bss->drv;
11104 struct nl_msg *msg;
11105 struct nlattr *data;
11106 int ret;
11107 int mode;
11108
11109 mode = hw_mode_to_qca_acs(params->hw_mode);
11110 if (mode < 0)
11111 return -1;
11112
11113 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11114 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11115 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11116 QCA_NL80211_VENDOR_SUBCMD_DO_ACS) ||
11117 !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
11118 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, mode) ||
11119 (params->ht_enabled &&
11120 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
11121 (params->ht40_enabled &&
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070011122 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) ||
11123 (params->vht_enabled &&
11124 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
11125 nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
11126 params->ch_width) ||
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080011127 add_acs_ch_list(msg, params->freq_list) ||
Hai Shalomfdcde762020-04-02 11:19:20 -070011128 add_acs_freq_list(msg, params->freq_list) ||
11129 (params->edmg_enabled &&
11130 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011131 nlmsg_free(msg);
11132 return -ENOBUFS;
11133 }
11134 nla_nest_end(msg, data);
11135
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070011136 wpa_printf(MSG_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -070011137 "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d EDMG: %d",
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070011138 params->hw_mode, params->ht_enabled, params->ht40_enabled,
Hai Shalomfdcde762020-04-02 11:19:20 -070011139 params->vht_enabled, params->ch_width, params->edmg_enabled);
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070011140
Hai Shalom899fcc72020-10-19 14:38:18 -070011141 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011142 if (ret) {
11143 wpa_printf(MSG_DEBUG,
11144 "nl80211: Failed to invoke driver ACS function: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070011145 strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011146 }
11147 return ret;
11148}
11149
11150
Hai Shalom60840252021-02-19 19:02:11 -080011151static int nl80211_set_band(void *priv, u32 band_mask)
Ravi Joshie6ccb162015-07-16 17:45:41 -070011152{
11153 struct i802_bss *bss = priv;
11154 struct wpa_driver_nl80211_data *drv = bss->drv;
11155 struct nl_msg *msg;
11156 struct nlattr *data;
11157 int ret;
Hai Shalom60840252021-02-19 19:02:11 -080011158 enum qca_set_band qca_band_value;
11159 u32 qca_band_mask = QCA_SETBAND_AUTO;
Ravi Joshie6ccb162015-07-16 17:45:41 -070011160
Hai Shalom60840252021-02-19 19:02:11 -080011161 if (!drv->setband_vendor_cmd_avail ||
11162 (band_mask > (WPA_SETBAND_2G | WPA_SETBAND_5G | WPA_SETBAND_6G)))
Ravi Joshie6ccb162015-07-16 17:45:41 -070011163 return -1;
11164
Hai Shalom60840252021-02-19 19:02:11 -080011165 if (band_mask & WPA_SETBAND_5G)
11166 qca_band_mask |= QCA_SETBAND_5G;
11167 if (band_mask & WPA_SETBAND_2G)
11168 qca_band_mask |= QCA_SETBAND_2G;
11169 if (band_mask & WPA_SETBAND_6G)
11170 qca_band_mask |= QCA_SETBAND_6G;
11171
11172 /*
11173 * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE is a legacy interface hence make
11174 * it suite to its values (AUTO/5G/2G) for backwards compatibility.
11175 */
11176 qca_band_value = ((qca_band_mask & QCA_SETBAND_5G) &&
11177 (qca_band_mask & QCA_SETBAND_2G)) ?
11178 QCA_SETBAND_AUTO :
11179 qca_band_mask & ~QCA_SETBAND_6G;
11180
11181 wpa_printf(MSG_DEBUG,
11182 "nl80211: QCA_BAND_MASK = 0x%x, QCA_BAND_VALUE = %d",
11183 qca_band_mask, qca_band_value);
Ravi Joshie6ccb162015-07-16 17:45:41 -070011184
11185 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11186 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11187 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11188 QCA_NL80211_VENDOR_SUBCMD_SETBAND) ||
11189 !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
Hai Shalom60840252021-02-19 19:02:11 -080011190 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE,
11191 qca_band_value) ||
11192 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_MASK,
11193 qca_band_mask)) {
Ravi Joshie6ccb162015-07-16 17:45:41 -070011194 nlmsg_free(msg);
11195 return -ENOBUFS;
11196 }
11197 nla_nest_end(msg, data);
11198
Hai Shalom899fcc72020-10-19 14:38:18 -070011199 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Ravi Joshie6ccb162015-07-16 17:45:41 -070011200 if (ret) {
11201 wpa_printf(MSG_DEBUG,
11202 "nl80211: Driver setband function failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070011203 strerror(-ret));
Ravi Joshie6ccb162015-07-16 17:45:41 -070011204 }
11205 return ret;
11206}
11207
11208
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011209struct nl80211_pcl {
11210 unsigned int num;
11211 unsigned int *freq_list;
11212};
11213
11214static int preferred_freq_info_handler(struct nl_msg *msg, void *arg)
11215{
11216 struct nlattr *tb[NL80211_ATTR_MAX + 1];
11217 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
11218 struct nl80211_pcl *param = arg;
11219 struct nlattr *nl_vend, *attr;
11220 enum qca_iface_type iface_type;
11221 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
11222 unsigned int num, max_num;
11223 u32 *freqs;
11224
11225 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
11226 genlmsg_attrlen(gnlh, 0), NULL);
11227
11228 nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
11229 if (!nl_vend)
11230 return NL_SKIP;
11231
11232 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
11233 nla_data(nl_vend), nla_len(nl_vend), NULL);
11234
11235 attr = tb_vendor[
11236 QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE];
11237 if (!attr) {
11238 wpa_printf(MSG_ERROR, "nl80211: iface_type couldn't be found");
11239 param->num = 0;
11240 return NL_SKIP;
11241 }
11242
11243 iface_type = (enum qca_iface_type) nla_get_u32(attr);
11244 wpa_printf(MSG_DEBUG, "nl80211: Driver returned iface_type=%d",
11245 iface_type);
11246
11247 attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST];
11248 if (!attr) {
11249 wpa_printf(MSG_ERROR,
11250 "nl80211: preferred_freq_list couldn't be found");
11251 param->num = 0;
11252 return NL_SKIP;
11253 }
11254
11255 /*
11256 * param->num has the maximum number of entries for which there
11257 * is room in the freq_list provided by the caller.
11258 */
11259 freqs = nla_data(attr);
11260 max_num = nla_len(attr) / sizeof(u32);
11261 if (max_num > param->num)
11262 max_num = param->num;
11263 for (num = 0; num < max_num; num++)
11264 param->freq_list[num] = freqs[num];
11265 param->num = num;
11266
11267 return NL_SKIP;
11268}
11269
11270
11271static int nl80211_get_pref_freq_list(void *priv,
11272 enum wpa_driver_if_type if_type,
11273 unsigned int *num,
11274 unsigned int *freq_list)
11275{
11276 struct i802_bss *bss = priv;
11277 struct wpa_driver_nl80211_data *drv = bss->drv;
11278 struct nl_msg *msg;
11279 int ret;
11280 unsigned int i;
11281 struct nlattr *params;
11282 struct nl80211_pcl param;
11283 enum qca_iface_type iface_type;
11284
11285 if (!drv->get_pref_freq_list)
11286 return -1;
11287
11288 switch (if_type) {
11289 case WPA_IF_STATION:
11290 iface_type = QCA_IFACE_TYPE_STA;
11291 break;
11292 case WPA_IF_AP_BSS:
11293 iface_type = QCA_IFACE_TYPE_AP;
11294 break;
11295 case WPA_IF_P2P_GO:
11296 iface_type = QCA_IFACE_TYPE_P2P_GO;
11297 break;
11298 case WPA_IF_P2P_CLIENT:
11299 iface_type = QCA_IFACE_TYPE_P2P_CLIENT;
11300 break;
11301 case WPA_IF_IBSS:
11302 iface_type = QCA_IFACE_TYPE_IBSS;
11303 break;
11304 case WPA_IF_TDLS:
11305 iface_type = QCA_IFACE_TYPE_TDLS;
11306 break;
11307 default:
11308 return -1;
11309 }
11310
11311 param.num = *num;
11312 param.freq_list = freq_list;
11313
11314 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11315 nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) ||
11316 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11317 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11318 QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST) ||
11319 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
11320 nla_put_u32(msg,
11321 QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE,
11322 iface_type)) {
11323 wpa_printf(MSG_ERROR,
11324 "%s: err in adding vendor_cmd and vendor_data",
11325 __func__);
11326 nlmsg_free(msg);
11327 return -1;
11328 }
11329 nla_nest_end(msg, params);
11330
11331 os_memset(freq_list, 0, *num * sizeof(freq_list[0]));
Hai Shalom899fcc72020-10-19 14:38:18 -070011332 ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, &param,
11333 NULL, NULL);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011334 if (ret) {
11335 wpa_printf(MSG_ERROR,
11336 "%s: err in send_and_recv_msgs", __func__);
11337 return ret;
11338 }
11339
11340 *num = param.num;
11341
11342 for (i = 0; i < *num; i++) {
11343 wpa_printf(MSG_DEBUG, "nl80211: preferred_channel_list[%d]=%d",
11344 i, freq_list[i]);
11345 }
11346
11347 return 0;
11348}
11349
11350
11351static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq)
11352{
11353 struct i802_bss *bss = priv;
11354 struct wpa_driver_nl80211_data *drv = bss->drv;
11355 struct nl_msg *msg;
11356 int ret;
11357 struct nlattr *params;
11358
11359 if (!drv->set_prob_oper_freq)
11360 return -1;
11361
11362 wpa_printf(MSG_DEBUG,
11363 "nl80211: Set P2P probable operating freq %u for ifindex %d",
11364 freq, bss->ifindex);
11365
11366 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11367 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11368 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11369 QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL) ||
11370 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
11371 nla_put_u32(msg,
11372 QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE,
11373 QCA_IFACE_TYPE_P2P_CLIENT) ||
11374 nla_put_u32(msg,
11375 QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ,
11376 freq)) {
11377 wpa_printf(MSG_ERROR,
11378 "%s: err in adding vendor_cmd and vendor_data",
11379 __func__);
11380 nlmsg_free(msg);
11381 return -1;
11382 }
11383 nla_nest_end(msg, params);
11384
Hai Shalom899fcc72020-10-19 14:38:18 -070011385 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011386 msg = NULL;
11387 if (ret) {
11388 wpa_printf(MSG_ERROR, "%s: err in send_and_recv_msgs",
11389 __func__);
11390 return ret;
11391 }
11392 nlmsg_free(msg);
11393 return 0;
11394}
11395
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070011396
11397static int nl80211_p2p_lo_start(void *priv, unsigned int freq,
11398 unsigned int period, unsigned int interval,
11399 unsigned int count, const u8 *device_types,
11400 size_t dev_types_len,
11401 const u8 *ies, size_t ies_len)
11402{
11403 struct i802_bss *bss = priv;
11404 struct wpa_driver_nl80211_data *drv = bss->drv;
11405 struct nl_msg *msg;
11406 struct nlattr *container;
11407 int ret;
11408
11409 wpa_printf(MSG_DEBUG,
11410 "nl80211: Start P2P Listen offload: freq=%u, period=%u, interval=%u, count=%u",
11411 freq, period, interval, count);
11412
11413 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
11414 return -1;
11415
11416 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11417 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11418 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11419 QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START))
11420 goto fail;
11421
11422 container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
11423 if (!container)
11424 goto fail;
11425
11426 if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL,
11427 freq) ||
11428 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD,
11429 period) ||
11430 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL,
11431 interval) ||
11432 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT,
11433 count) ||
11434 nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES,
11435 dev_types_len, device_types) ||
11436 nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE,
11437 ies_len, ies))
11438 goto fail;
11439
11440 nla_nest_end(msg, container);
Hai Shalom899fcc72020-10-19 14:38:18 -070011441 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070011442 msg = NULL;
11443 if (ret) {
11444 wpa_printf(MSG_DEBUG,
11445 "nl80211: Failed to send P2P Listen offload vendor command");
11446 goto fail;
11447 }
11448
11449 return 0;
11450
11451fail:
11452 nlmsg_free(msg);
11453 return -1;
11454}
11455
11456
11457static int nl80211_p2p_lo_stop(void *priv)
11458{
11459 struct i802_bss *bss = priv;
11460 struct wpa_driver_nl80211_data *drv = bss->drv;
11461 struct nl_msg *msg;
11462
11463 wpa_printf(MSG_DEBUG, "nl80211: Stop P2P Listen offload");
11464
11465 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
11466 return -1;
11467
11468 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11469 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11470 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11471 QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP)) {
11472 nlmsg_free(msg);
11473 return -1;
11474 }
11475
Hai Shalom899fcc72020-10-19 14:38:18 -070011476 return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070011477}
11478
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080011479
11480static int nl80211_set_tdls_mode(void *priv, int tdls_external_control)
11481{
11482 struct i802_bss *bss = priv;
11483 struct wpa_driver_nl80211_data *drv = bss->drv;
11484 struct nl_msg *msg;
11485 struct nlattr *params;
11486 int ret;
11487 u32 tdls_mode;
11488
11489 wpa_printf(MSG_DEBUG,
11490 "nl80211: Set TDKS mode: tdls_external_control=%d",
11491 tdls_external_control);
11492
11493 if (tdls_external_control == 1)
11494 tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT |
11495 QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL;
11496 else
11497 tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT;
11498
11499 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11500 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11501 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11502 QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS))
11503 goto fail;
11504
11505 params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
11506 if (!params)
11507 goto fail;
11508
11509 if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE,
11510 tdls_mode))
11511 goto fail;
11512
11513 nla_nest_end(msg, params);
11514
Hai Shalom899fcc72020-10-19 14:38:18 -070011515 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080011516 msg = NULL;
11517 if (ret) {
11518 wpa_printf(MSG_ERROR,
11519 "nl80211: Set TDLS mode failed: ret=%d (%s)",
11520 ret, strerror(-ret));
11521 goto fail;
11522 }
11523 return 0;
11524fail:
11525 nlmsg_free(msg);
11526 return -1;
11527}
11528
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011529
11530#ifdef CONFIG_MBO
11531
11532static enum mbo_transition_reject_reason
11533nl80211_mbo_reject_reason_mapping(enum qca_wlan_btm_candidate_status status)
11534{
11535 switch (status) {
11536 case QCA_STATUS_REJECT_EXCESSIVE_FRAME_LOSS_EXPECTED:
11537 return MBO_TRANSITION_REJECT_REASON_FRAME_LOSS;
11538 case QCA_STATUS_REJECT_EXCESSIVE_DELAY_EXPECTED:
11539 return MBO_TRANSITION_REJECT_REASON_DELAY;
11540 case QCA_STATUS_REJECT_INSUFFICIENT_QOS_CAPACITY:
11541 return MBO_TRANSITION_REJECT_REASON_QOS_CAPACITY;
11542 case QCA_STATUS_REJECT_LOW_RSSI:
11543 return MBO_TRANSITION_REJECT_REASON_RSSI;
11544 case QCA_STATUS_REJECT_HIGH_INTERFERENCE:
11545 return MBO_TRANSITION_REJECT_REASON_INTERFERENCE;
11546 case QCA_STATUS_REJECT_UNKNOWN:
11547 default:
11548 return MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
11549 }
11550}
11551
11552
11553static void nl80211_parse_btm_candidate_info(struct candidate_list *candidate,
11554 struct nlattr *tb[], int num)
11555{
11556 enum qca_wlan_btm_candidate_status status;
11557 char buf[50];
11558
11559 os_memcpy(candidate->bssid,
11560 nla_data(tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]),
11561 ETH_ALEN);
11562
11563 status = nla_get_u32(
11564 tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS]);
11565 candidate->is_accept = status == QCA_STATUS_ACCEPT;
11566 candidate->reject_reason = nl80211_mbo_reject_reason_mapping(status);
11567
11568 if (candidate->is_accept)
11569 os_snprintf(buf, sizeof(buf), "Accepted");
11570 else
11571 os_snprintf(buf, sizeof(buf),
11572 "Rejected, Reject_reason: %d",
11573 candidate->reject_reason);
11574 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%d]: " MACSTR " %s",
11575 num, MAC2STR(candidate->bssid), buf);
11576}
11577
11578
11579static int
11580nl80211_get_bss_transition_status_handler(struct nl_msg *msg, void *arg)
11581{
11582 struct wpa_bss_candidate_info *info = arg;
11583 struct candidate_list *candidate = info->candidates;
11584 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
11585 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
11586 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1];
11587 static struct nla_policy policy[
11588 QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1] = {
11589 [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] = {
11590 .minlen = ETH_ALEN
11591 },
11592 [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS] = {
11593 .type = NLA_U32,
11594 },
11595 };
11596 struct nlattr *attr;
11597 int rem;
11598 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
11599 u8 num;
11600
11601 num = info->num; /* number of candidates sent to driver */
11602 info->num = 0;
11603 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
11604 genlmsg_attrlen(gnlh, 0), NULL);
11605
11606 if (!tb_msg[NL80211_ATTR_VENDOR_DATA] ||
11607 nla_parse_nested(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
11608 tb_msg[NL80211_ATTR_VENDOR_DATA], NULL) ||
11609 !tb_vendor[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO])
11610 return NL_SKIP;
11611
11612 wpa_printf(MSG_DEBUG,
11613 "nl80211: WNM Candidate list received from driver");
11614 nla_for_each_nested(attr,
11615 tb_vendor[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO],
11616 rem) {
11617 if (info->num >= num ||
11618 nla_parse_nested(
11619 tb, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX,
11620 attr, policy) ||
11621 !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] ||
11622 !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS])
11623 break;
11624
11625 nl80211_parse_btm_candidate_info(candidate, tb, info->num);
11626
11627 candidate++;
11628 info->num++;
11629 }
11630
11631 return NL_SKIP;
11632}
11633
11634
11635static struct wpa_bss_candidate_info *
11636nl80211_get_bss_transition_status(void *priv, struct wpa_bss_trans_info *params)
11637{
11638 struct i802_bss *bss = priv;
11639 struct wpa_driver_nl80211_data *drv = bss->drv;
11640 struct nl_msg *msg;
11641 struct nlattr *attr, *attr1, *attr2;
11642 struct wpa_bss_candidate_info *info;
11643 u8 i;
11644 int ret;
11645 u8 *pos;
11646
11647 if (!drv->fetch_bss_trans_status)
11648 return NULL;
11649
11650 info = os_zalloc(sizeof(*info));
11651 if (!info)
11652 return NULL;
11653 /* Allocate memory for number of candidates sent to driver */
11654 info->candidates = os_calloc(params->n_candidates,
11655 sizeof(*info->candidates));
11656 if (!info->candidates) {
11657 os_free(info);
11658 return NULL;
11659 }
11660
11661 /* Copy the number of candidates being sent to driver. This is used in
11662 * nl80211_get_bss_transition_status_handler() to limit the number of
11663 * candidates that can be populated in info->candidates and will be
11664 * later overwritten with the actual number of candidates received from
11665 * the driver.
11666 */
11667 info->num = params->n_candidates;
11668
11669 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11670 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11671 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11672 QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS))
11673 goto fail;
11674
11675 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
11676 if (!attr)
11677 goto fail;
11678
11679 if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON,
11680 params->mbo_transition_reason))
11681 goto fail;
11682
11683 attr1 = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO);
11684 if (!attr1)
11685 goto fail;
11686
11687 wpa_printf(MSG_DEBUG,
11688 "nl80211: WNM Candidate list info sending to driver: mbo_transition_reason: %d n_candidates: %d",
11689 params->mbo_transition_reason, params->n_candidates);
11690 pos = params->bssid;
11691 for (i = 0; i < params->n_candidates; i++) {
11692 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%d]: " MACSTR, i,
11693 MAC2STR(pos));
11694 attr2 = nla_nest_start(msg, i);
11695 if (!attr2 ||
11696 nla_put(msg, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID,
11697 ETH_ALEN, pos))
11698 goto fail;
11699 pos += ETH_ALEN;
11700 nla_nest_end(msg, attr2);
11701 }
11702
11703 nla_nest_end(msg, attr1);
11704 nla_nest_end(msg, attr);
11705
11706 ret = send_and_recv_msgs(drv, msg,
11707 nl80211_get_bss_transition_status_handler,
Hai Shalom899fcc72020-10-19 14:38:18 -070011708 info, NULL, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011709 msg = NULL;
11710 if (ret) {
11711 wpa_printf(MSG_ERROR,
11712 "nl80211: WNM Get BSS transition status failed: ret=%d (%s)",
11713 ret, strerror(-ret));
11714 goto fail;
11715 }
11716 return info;
11717
11718fail:
11719 nlmsg_free(msg);
11720 os_free(info->candidates);
11721 os_free(info);
11722 return NULL;
11723}
11724
11725
11726/**
11727 * nl80211_ignore_assoc_disallow - Configure driver to ignore assoc_disallow
11728 * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
11729 * @ignore_assoc_disallow: 0 to not ignore, 1 to ignore
11730 * Returns: 0 on success, -1 on failure
11731 */
11732static int nl80211_ignore_assoc_disallow(void *priv, int ignore_disallow)
11733{
11734 struct i802_bss *bss = priv;
11735 struct wpa_driver_nl80211_data *drv = bss->drv;
11736 struct nl_msg *msg;
11737 struct nlattr *attr;
11738 int ret = -1;
11739
11740 if (!drv->set_wifi_conf_vendor_cmd_avail)
11741 return -1;
11742
11743 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11744 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11745 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11746 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION))
11747 goto fail;
11748
11749 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
11750 if (!attr)
11751 goto fail;
11752
11753 wpa_printf(MSG_DEBUG, "nl80211: Set ignore_assoc_disallow %d",
11754 ignore_disallow);
11755 if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED,
11756 ignore_disallow))
11757 goto fail;
11758
11759 nla_nest_end(msg, attr);
11760
Hai Shalom899fcc72020-10-19 14:38:18 -070011761 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011762 msg = NULL;
11763 if (ret) {
11764 wpa_printf(MSG_ERROR,
11765 "nl80211: Set ignore_assoc_disallow failed: ret=%d (%s)",
11766 ret, strerror(-ret));
11767 goto fail;
11768 }
11769
11770fail:
11771 nlmsg_free(msg);
11772 return ret;
11773}
11774
11775#endif /* CONFIG_MBO */
11776
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011777#endif /* CONFIG_DRIVER_NL80211_QCA */
11778
11779
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011780static int nl80211_write_to_file(const char *name, unsigned int val)
11781{
11782 int fd, len;
11783 char tmp[128];
Hai Shalomc3565922019-10-28 11:58:20 -070011784 int ret = 0;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011785
11786 fd = open(name, O_RDWR);
11787 if (fd < 0) {
Hai Shalomc3565922019-10-28 11:58:20 -070011788 int level;
11789 /*
11790 * Flags may not exist on older kernels, or while we're tearing
11791 * down a disappearing device.
11792 */
11793 if (errno == ENOENT) {
11794 ret = 0;
11795 level = MSG_DEBUG;
11796 } else {
11797 ret = -1;
11798 level = MSG_ERROR;
11799 }
11800 wpa_printf(level, "nl80211: Failed to open %s: %s",
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011801 name, strerror(errno));
Hai Shalomc3565922019-10-28 11:58:20 -070011802 return ret;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011803 }
11804
11805 len = os_snprintf(tmp, sizeof(tmp), "%u\n", val);
11806 len = write(fd, tmp, len);
Hai Shalomc3565922019-10-28 11:58:20 -070011807 if (len < 0) {
11808 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011809 wpa_printf(MSG_ERROR, "nl80211: Failed to write to %s: %s",
11810 name, strerror(errno));
Hai Shalomc3565922019-10-28 11:58:20 -070011811 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011812 close(fd);
11813
Hai Shalomc3565922019-10-28 11:58:20 -070011814 return ret;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011815}
11816
11817
11818static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags)
11819{
11820 struct i802_bss *bss = priv;
11821 char path[128];
11822 int ret;
11823
Hai Shalom60840252021-02-19 19:02:11 -080011824 /* P2P-Device has no netdev that can (or should) be configured here */
11825 if (nl80211_get_ifmode(bss) == NL80211_IFTYPE_P2P_DEVICE)
11826 return 0;
11827
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011828 wpa_printf(MSG_DEBUG, "nl80211: Data frame filter flags=0x%x",
11829 filter_flags);
11830
11831 /* Configure filtering of unicast frame encrypted using GTK */
11832 ret = os_snprintf(path, sizeof(path),
11833 "/proc/sys/net/ipv4/conf/%s/drop_unicast_in_l2_multicast",
11834 bss->ifname);
11835 if (os_snprintf_error(sizeof(path), ret))
11836 return -1;
11837
11838 ret = nl80211_write_to_file(path,
11839 !!(filter_flags &
11840 WPA_DATA_FRAME_FILTER_FLAG_GTK));
11841 if (ret) {
11842 wpa_printf(MSG_ERROR,
11843 "nl80211: Failed to set IPv4 unicast in multicast filter");
11844 return ret;
11845 }
11846
11847 os_snprintf(path, sizeof(path),
11848 "/proc/sys/net/ipv6/conf/%s/drop_unicast_in_l2_multicast",
11849 bss->ifname);
11850 ret = nl80211_write_to_file(path,
11851 !!(filter_flags &
11852 WPA_DATA_FRAME_FILTER_FLAG_GTK));
11853
11854 if (ret) {
11855 wpa_printf(MSG_ERROR,
11856 "nl80211: Failed to set IPv6 unicast in multicast filter");
11857 return ret;
11858 }
11859
11860 /* Configure filtering of unicast frame encrypted using GTK */
11861 os_snprintf(path, sizeof(path),
11862 "/proc/sys/net/ipv4/conf/%s/drop_gratuitous_arp",
11863 bss->ifname);
11864 ret = nl80211_write_to_file(path,
11865 !!(filter_flags &
11866 WPA_DATA_FRAME_FILTER_FLAG_ARP));
11867 if (ret) {
11868 wpa_printf(MSG_ERROR,
11869 "nl80211: Failed set gratuitous ARP filter");
11870 return ret;
11871 }
11872
11873 /* Configure filtering of IPv6 NA frames */
11874 os_snprintf(path, sizeof(path),
11875 "/proc/sys/net/ipv6/conf/%s/drop_unsolicited_na",
11876 bss->ifname);
11877 ret = nl80211_write_to_file(path,
11878 !!(filter_flags &
11879 WPA_DATA_FRAME_FILTER_FLAG_NA));
11880 if (ret) {
11881 wpa_printf(MSG_ERROR,
11882 "nl80211: Failed to set unsolicited NA filter");
11883 return ret;
11884 }
11885
11886 return 0;
11887}
11888
11889
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070011890static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type,
11891 const u8 **ext_capa, const u8 **ext_capa_mask,
11892 unsigned int *ext_capa_len)
11893{
11894 struct i802_bss *bss = priv;
11895 struct wpa_driver_nl80211_data *drv = bss->drv;
11896 enum nl80211_iftype nlmode;
11897 unsigned int i;
11898
11899 if (!ext_capa || !ext_capa_mask || !ext_capa_len)
11900 return -1;
11901
11902 nlmode = wpa_driver_nl80211_if_type(type);
11903
11904 /* By default, use the per-radio values */
11905 *ext_capa = drv->extended_capa;
11906 *ext_capa_mask = drv->extended_capa_mask;
11907 *ext_capa_len = drv->extended_capa_len;
11908
11909 /* Replace the default value if a per-interface type value exists */
11910 for (i = 0; i < drv->num_iface_ext_capa; i++) {
11911 if (nlmode == drv->iface_ext_capa[i].iftype) {
11912 *ext_capa = drv->iface_ext_capa[i].ext_capa;
11913 *ext_capa_mask = drv->iface_ext_capa[i].ext_capa_mask;
11914 *ext_capa_len = drv->iface_ext_capa[i].ext_capa_len;
11915 break;
11916 }
11917 }
11918
11919 return 0;
11920}
11921
11922
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011923static int nl80211_update_connection_params(
11924 void *priv, struct wpa_driver_associate_params *params,
11925 enum wpa_drv_update_connect_params_mask mask)
11926{
11927 struct i802_bss *bss = priv;
11928 struct wpa_driver_nl80211_data *drv = bss->drv;
11929 struct nl_msg *msg;
11930 int ret = -1;
11931 enum nl80211_auth_type type;
11932
Hai Shalomc3565922019-10-28 11:58:20 -070011933 /* Update Connection Params is intended for drivers that implement
11934 * internal SME and expect these updated connection params from
11935 * wpa_supplicant. Do not send this request for the drivers using
11936 * SME from wpa_supplicant.
11937 */
11938 if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
11939 return 0;
11940
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011941 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_CONNECT_PARAMS);
11942 if (!msg)
11943 goto fail;
11944
11945 wpa_printf(MSG_DEBUG, "nl80211: Update connection params (ifindex=%d)",
11946 drv->ifindex);
11947
11948 if ((mask & WPA_DRV_UPDATE_ASSOC_IES) && params->wpa_ie) {
11949 if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
11950 params->wpa_ie))
11951 goto fail;
11952 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie,
11953 params->wpa_ie_len);
11954 }
11955
11956 if (mask & WPA_DRV_UPDATE_AUTH_TYPE) {
11957 type = get_nl_auth_type(params->auth_alg);
11958 if (type == NL80211_AUTHTYPE_MAX ||
11959 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
11960 goto fail;
11961 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
11962 }
11963
11964 if ((mask & WPA_DRV_UPDATE_FILS_ERP_INFO) &&
11965 nl80211_put_fils_connect_params(drv, params, msg))
11966 goto fail;
11967
Hai Shalom899fcc72020-10-19 14:38:18 -070011968 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011969 msg = NULL;
11970 if (ret)
11971 wpa_dbg(drv->ctx, MSG_DEBUG,
11972 "nl80211: Update connect params command failed: ret=%d (%s)",
11973 ret, strerror(-ret));
11974
11975fail:
11976 nlmsg_free(msg);
11977 return ret;
11978}
11979
11980
Roshan Pius3a1667e2018-07-03 15:17:14 -070011981static int nl80211_send_external_auth_status(void *priv,
11982 struct external_auth *params)
11983{
11984 struct i802_bss *bss = priv;
11985 struct wpa_driver_nl80211_data *drv = bss->drv;
11986 struct nl_msg *msg = NULL;
11987 int ret = -1;
11988
Hai Shalom5f92bc92019-04-18 11:54:11 -070011989 /* External auth command/status is intended for drivers that implement
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080011990 * internal SME but want to offload authentication processing (e.g.,
11991 * SAE) to hostapd/wpa_supplicant. Do not send the status to drivers
Hai Shalom5f92bc92019-04-18 11:54:11 -070011992 * which do not support AP SME or use wpa_supplicant/hostapd SME.
11993 */
Hai Shalom81f62d82019-07-22 12:10:00 -070011994 if ((is_ap_interface(drv->nlmode) && !bss->drv->device_ap_sme) ||
Hai Shalom5f92bc92019-04-18 11:54:11 -070011995 (drv->capa.flags & WPA_DRIVER_FLAGS_SME))
11996 return -1;
11997
Roshan Pius3a1667e2018-07-03 15:17:14 -070011998 wpa_dbg(drv->ctx, MSG_DEBUG,
11999 "nl80211: External auth status: %u", params->status);
12000
12001 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_EXTERNAL_AUTH);
12002 if (!msg ||
12003 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, params->status) ||
Hai Shalom5f92bc92019-04-18 11:54:11 -070012004 (params->ssid && params->ssid_len &&
12005 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
12006 (params->pmkid &&
12007 nla_put(msg, NL80211_ATTR_PMKID, PMKID_LEN, params->pmkid)) ||
12008 (params->bssid &&
12009 nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid)))
Roshan Pius3a1667e2018-07-03 15:17:14 -070012010 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -070012011 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -070012012 msg = NULL;
12013 if (ret) {
12014 wpa_printf(MSG_DEBUG,
12015 "nl80211: External Auth status update failed: ret=%d (%s)",
12016 ret, strerror(-ret));
12017 goto fail;
12018 }
12019fail:
12020 nlmsg_free(msg);
12021 return ret;
12022}
12023
12024
Hai Shalom74f70d42019-02-11 14:42:39 -080012025static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname,
12026 int val)
12027{
12028 struct i802_bss *bss = priv;
12029 struct wpa_driver_nl80211_data *drv = bss->drv;
12030 struct nl_msg *msg;
12031 int ret = -ENOBUFS;
12032
12033 wpa_printf(MSG_DEBUG, "nl80211: %s 4addr mode (bridge_ifname: %s)",
12034 val ? "Enable" : "Disable", bridge_ifname);
12035
12036 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
12037 if (!msg || nla_put_u8(msg, NL80211_ATTR_4ADDR, val))
12038 goto fail;
12039
12040 if (bridge_ifname[0] && bss->added_if_into_bridge && !val) {
12041 if (linux_br_del_if(drv->global->ioctl_sock,
12042 bridge_ifname, bss->ifname)) {
12043 wpa_printf(MSG_ERROR,
12044 "nl80211: Failed to remove interface %s from bridge %s",
12045 bss->ifname, bridge_ifname);
12046 return -1;
12047 }
12048 bss->added_if_into_bridge = 0;
12049 }
12050
Hai Shalom899fcc72020-10-19 14:38:18 -070012051 ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
Hai Shalom74f70d42019-02-11 14:42:39 -080012052 msg = NULL;
Hai Shalom60840252021-02-19 19:02:11 -080012053 if (ret && val && nl80211_get_4addr(bss) == 1) {
12054 wpa_printf(MSG_DEBUG,
12055 "nl80211: 4addr mode was already enabled");
12056 ret = 0;
12057 }
Hai Shalom74f70d42019-02-11 14:42:39 -080012058 if (!ret) {
12059 if (bridge_ifname[0] && val &&
12060 i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0)
12061 return -1;
12062 return 0;
12063 }
12064
12065fail:
12066 nlmsg_free(msg);
12067 wpa_printf(MSG_ERROR, "nl80211: Failed to enable/disable 4addr");
12068
12069 return ret;
12070}
12071
12072
Hai Shalome21d4e82020-04-29 16:34:06 -070012073#ifdef CONFIG_DPP
12074static int nl80211_dpp_listen(void *priv, bool enable)
12075{
12076 struct i802_bss *bss = priv;
12077 struct wpa_driver_nl80211_data *drv = bss->drv;
12078 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
12079 struct nl_sock *handle;
12080
12081 if (!drv->multicast_registrations || !bss->nl_mgmt)
12082 return 0; /* cannot do more than hope broadcast RX works */
12083
12084 wpa_printf(MSG_DEBUG,
12085 "nl80211: Update DPP Public Action frame registration (%s multicast RX)",
12086 enable ? "enable" : "disable");
12087 handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID);
12088 return nl80211_register_frame(bss, handle, type,
12089 (u8 *) "\x04\x09\x50\x6f\x9a\x1a", 6,
12090 enable);
12091}
12092#endif /* CONFIG_DPP */
12093
12094
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012095const struct wpa_driver_ops wpa_driver_nl80211_ops = {
12096 .name = "nl80211",
12097 .desc = "Linux nl80211/cfg80211",
12098 .get_bssid = wpa_driver_nl80211_get_bssid,
12099 .get_ssid = wpa_driver_nl80211_get_ssid,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012100 .set_key = driver_nl80211_set_key,
12101 .scan2 = driver_nl80211_scan2,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012102 .sched_scan = wpa_driver_nl80211_sched_scan,
12103 .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012104 .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080012105 .abort_scan = wpa_driver_nl80211_abort_scan,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012106 .deauthenticate = driver_nl80211_deauthenticate,
12107 .authenticate = driver_nl80211_authenticate,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012108 .associate = wpa_driver_nl80211_associate,
12109 .global_init = nl80211_global_init,
12110 .global_deinit = nl80211_global_deinit,
12111 .init2 = wpa_driver_nl80211_init,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012112 .deinit = driver_nl80211_deinit,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012113 .get_capa = wpa_driver_nl80211_get_capa,
12114 .set_operstate = wpa_driver_nl80211_set_operstate,
12115 .set_supp_port = wpa_driver_nl80211_set_supp_port,
12116 .set_country = wpa_driver_nl80211_set_country,
Dmitry Shmidtcce06662013-11-04 18:44:24 -080012117 .get_country = wpa_driver_nl80211_get_country,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012118 .set_ap = wpa_driver_nl80211_set_ap,
Dmitry Shmidt8bae4132013-06-06 11:25:10 -070012119 .set_acl = wpa_driver_nl80211_set_acl,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012120 .if_add = wpa_driver_nl80211_if_add,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012121 .if_remove = driver_nl80211_if_remove,
12122 .send_mlme = driver_nl80211_send_mlme,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012123 .get_hw_feature_data = nl80211_get_hw_feature_data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012124 .sta_add = wpa_driver_nl80211_sta_add,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012125 .sta_remove = driver_nl80211_sta_remove,
Hai Shalomfdcde762020-04-02 11:19:20 -070012126 .tx_control_port = nl80211_tx_control_port,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012127 .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
12128 .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
Hai Shalom81f62d82019-07-22 12:10:00 -070012129 .sta_set_airtime_weight = driver_nl80211_sta_set_airtime_weight,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012130 .hapd_init = i802_init,
12131 .hapd_deinit = i802_deinit,
Jouni Malinen75ecf522011-06-27 15:19:46 -070012132 .set_wds_sta = i802_set_wds_sta,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012133 .get_seqnum = i802_get_seqnum,
12134 .flush = i802_flush,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012135 .get_inact_sec = i802_get_inact_sec,
12136 .sta_clear_stats = i802_sta_clear_stats,
12137 .set_rts = i802_set_rts,
12138 .set_frag = i802_set_frag,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012139 .set_tx_queue_params = i802_set_tx_queue_params,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012140 .set_sta_vlan = driver_nl80211_set_sta_vlan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012141 .sta_deauth = i802_sta_deauth,
12142 .sta_disassoc = i802_sta_disassoc,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012143 .read_sta_data = driver_nl80211_read_sta_data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012144 .set_freq = i802_set_freq,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012145 .send_action = driver_nl80211_send_action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012146 .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
12147 .remain_on_channel = wpa_driver_nl80211_remain_on_channel,
12148 .cancel_remain_on_channel =
12149 wpa_driver_nl80211_cancel_remain_on_channel,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080012150 .probe_req_report = driver_nl80211_probe_req_report,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012151 .deinit_ap = wpa_driver_nl80211_deinit_ap,
Dmitry Shmidt04949592012-07-19 12:16:46 -070012152 .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012153 .resume = wpa_driver_nl80211_resume,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012154 .signal_monitor = nl80211_signal_monitor,
12155 .signal_poll = nl80211_signal_poll,
Hai Shalom74f70d42019-02-11 14:42:39 -080012156 .channel_info = nl80211_channel_info,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012157 .set_param = nl80211_set_param,
12158 .get_radio_name = nl80211_get_radio_name,
Jouni Malinen75ecf522011-06-27 15:19:46 -070012159 .add_pmkid = nl80211_add_pmkid,
12160 .remove_pmkid = nl80211_remove_pmkid,
12161 .flush_pmkid = nl80211_flush_pmkid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012162 .set_rekey_info = nl80211_set_rekey_info,
12163 .poll_client = nl80211_poll_client,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012164 .set_p2p_powersave = nl80211_set_p2p_powersave,
Dmitry Shmidtea69e842013-05-13 14:52:28 -070012165 .start_dfs_cac = nl80211_start_radar_detection,
12166 .stop_ap = wpa_driver_nl80211_stop_ap,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012167#ifdef CONFIG_TDLS
12168 .send_tdls_mgmt = nl80211_send_tdls_mgmt,
12169 .tdls_oper = nl80211_tdls_oper,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012170 .tdls_enable_channel_switch = nl80211_tdls_enable_channel_switch,
12171 .tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012172#endif /* CONFIG_TDLS */
Dmitry Shmidt700a1372013-03-15 14:14:44 -070012173 .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
Hai Shalom81f62d82019-07-22 12:10:00 -070012174 .update_dh_ie = nl80211_update_dh_ie,
Dmitry Shmidt34af3062013-07-11 10:46:32 -070012175 .get_mac_addr = wpa_driver_nl80211_get_macaddr,
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070012176 .get_survey = wpa_driver_nl80211_get_survey,
Dmitry Shmidt56052862013-10-04 10:23:25 -070012177 .status = wpa_driver_nl80211_status,
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080012178 .switch_channel = nl80211_switch_channel,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012179#ifdef ANDROID_P2P
Dmitry Shmidt6e933c12011-09-27 12:29:26 -070012180 .set_noa = wpa_driver_set_p2p_noa,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080012181 .get_noa = wpa_driver_get_p2p_noa,
Dmitry Shmidt6e933c12011-09-27 12:29:26 -070012182 .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
Dmitry Shmidt292b0c32013-11-22 12:54:42 -080012183#endif /* ANDROID_P2P */
Dmitry Shmidt738a26e2011-07-07 14:22:14 -070012184#ifdef ANDROID
Dmitry Shmidt41712582015-06-29 11:02:15 -070012185#ifndef ANDROID_LIB_STUB
Dmitry Shmidt738a26e2011-07-07 14:22:14 -070012186 .driver_cmd = wpa_driver_nl80211_driver_cmd,
Dmitry Shmidt41712582015-06-29 11:02:15 -070012187#endif /* !ANDROID_LIB_STUB */
Dmitry Shmidt292b0c32013-11-22 12:54:42 -080012188#endif /* ANDROID */
Dmitry Shmidta38abf92014-03-06 13:38:44 -080012189 .vendor_cmd = nl80211_vendor_cmd,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080012190 .set_qos_map = nl80211_set_qos_map,
Hai Shalomfdcde762020-04-02 11:19:20 -070012191 .get_wowlan = nl80211_get_wowlan,
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070012192 .set_wowlan = nl80211_set_wowlan,
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070012193 .set_mac_addr = nl80211_set_mac_addr,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012194#ifdef CONFIG_MESH
12195 .init_mesh = wpa_driver_nl80211_init_mesh,
12196 .join_mesh = wpa_driver_nl80211_join_mesh,
12197 .leave_mesh = wpa_driver_nl80211_leave_mesh,
Hai Shalom81f62d82019-07-22 12:10:00 -070012198 .probe_mesh_link = nl80211_probe_mesh_link,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012199#endif /* CONFIG_MESH */
12200 .br_add_ip_neigh = wpa_driver_br_add_ip_neigh,
12201 .br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh,
12202 .br_port_set_attr = wpa_driver_br_port_set_attr,
12203 .br_set_net_param = wpa_driver_br_set_net_param,
12204 .add_tx_ts = nl80211_add_ts,
12205 .del_tx_ts = nl80211_del_ts,
Dmitry Shmidte4663042016-04-04 10:07:49 -070012206 .get_ifindex = nl80211_get_ifindex,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012207#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070012208 .roaming = nl80211_roaming,
Roshan Pius3a1667e2018-07-03 15:17:14 -070012209 .disable_fils = nl80211_disable_fils,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012210 .do_acs = wpa_driver_do_acs,
Ravi Joshie6ccb162015-07-16 17:45:41 -070012211 .set_band = nl80211_set_band,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012212 .get_pref_freq_list = nl80211_get_pref_freq_list,
12213 .set_prob_oper_freq = nl80211_set_prob_oper_freq,
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070012214 .p2p_lo_start = nl80211_p2p_lo_start,
12215 .p2p_lo_stop = nl80211_p2p_lo_stop,
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -070012216 .set_default_scan_ies = nl80211_set_default_scan_ies,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080012217 .set_tdls_mode = nl80211_set_tdls_mode,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012218#ifdef CONFIG_MBO
12219 .get_bss_transition_status = nl80211_get_bss_transition_status,
12220 .ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
12221#endif /* CONFIG_MBO */
Hai Shalom899fcc72020-10-19 14:38:18 -070012222 .set_bssid_tmp_disallow = nl80211_set_bssid_tmp_disallow,
Hai Shalomc3565922019-10-28 11:58:20 -070012223 .add_sta_node = nl80211_add_sta_node,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012224#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt849734c2016-05-27 09:59:01 -070012225 .configure_data_frame_filters = nl80211_configure_data_frame_filters,
Ajay Davanagerib921bb82020-09-16 12:49:08 +053012226#if defined(CONFIG_DRIVER_NL80211_BRCM)
12227 .do_acs = wpa_driver_do_broadcom_acs,
12228#endif /* CONFIG_DRIVER_NL80211_BRCM */
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070012229 .get_ext_capab = nl80211_get_ext_capab,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012230 .update_connect_params = nl80211_update_connection_params,
Roshan Pius3a1667e2018-07-03 15:17:14 -070012231 .send_external_auth_status = nl80211_send_external_auth_status,
Hai Shalom74f70d42019-02-11 14:42:39 -080012232 .set_4addr_mode = nl80211_set_4addr_mode,
Hai Shalome21d4e82020-04-29 16:34:06 -070012233#ifdef CONFIG_DPP
12234 .dpp_listen = nl80211_dpp_listen,
12235#endif /* CONFIG_DPP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070012236};