blob: 5a760ff8127854543ae44ac3dcb367d041005164 [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
283static int finish_handler(struct nl_msg *msg, void *arg)
284{
285 int *ret = arg;
286 *ret = 0;
287 return NL_SKIP;
288}
289
290static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
291 void *arg)
292{
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800293 struct nlmsghdr *nlh = (struct nlmsghdr *) err - 1;
294 int len = nlh->nlmsg_len;
295 struct nlattr *attrs;
296 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700297 int *ret = arg;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800298 int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh);
299
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700300 *ret = err->error;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800301
302 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
303 return NL_SKIP;
304
305 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
306 ack_len += err->msg.nlmsg_len - sizeof(*nlh);
307
308 if (len <= ack_len)
309 return NL_STOP;
310
311 attrs = (void *) ((unsigned char *) nlh + ack_len);
312 len -= ack_len;
313
314 nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, len, NULL);
315 if (tb[NLMSGERR_ATTR_MSG]) {
316 len = strnlen((char *) nla_data(tb[NLMSGERR_ATTR_MSG]),
317 nla_len(tb[NLMSGERR_ATTR_MSG]));
318 wpa_printf(MSG_ERROR, "nl80211: kernel reports: %*s",
319 len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG]));
320 }
321
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700322 return NL_SKIP;
323}
324
325
326static int no_seq_check(struct nl_msg *msg, void *arg)
327{
328 return NL_OK;
329}
330
331
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800332static void nl80211_nlmsg_clear(struct nl_msg *msg)
333{
334 /*
335 * Clear nlmsg data, e.g., to make sure key material is not left in
336 * heap memory for unnecessarily long time.
337 */
338 if (msg) {
339 struct nlmsghdr *hdr = nlmsg_hdr(msg);
340 void *data = nlmsg_data(hdr);
341 /*
342 * This would use nlmsg_datalen() or the older nlmsg_len() if
343 * only libnl were to maintain a stable API.. Neither will work
344 * with all released versions, so just calculate the length
345 * here.
346 */
347 int len = hdr->nlmsg_len - NLMSG_HDRLEN;
348
349 os_memset(data, 0, len);
350 }
351}
352
353
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800354static int send_and_recv(struct nl80211_global *global,
Hai Shalomfdcde762020-04-02 11:19:20 -0700355 struct nl_sock *nl_handle, struct nl_msg *msg,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700356 int (*valid_handler)(struct nl_msg *, void *),
357 void *valid_data)
358{
359 struct nl_cb *cb;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800360 int err = -ENOMEM, opt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700361
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800362 if (!msg)
363 return -ENOMEM;
364
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800365 cb = nl_cb_clone(global->nl_cb);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700366 if (!cb)
367 goto out;
368
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800369 /* try to set NETLINK_EXT_ACK to 1, ignoring errors */
370 opt = 1;
371 setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
372 NETLINK_EXT_ACK, &opt, sizeof(opt));
373
Hai Shalom74f70d42019-02-11 14:42:39 -0800374 /* try to set NETLINK_CAP_ACK to 1, ignoring errors */
375 opt = 1;
376 setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
377 NETLINK_CAP_ACK, &opt, sizeof(opt));
378
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700379 err = nl_send_auto_complete(nl_handle, msg);
Hai Shalomfdcde762020-04-02 11:19:20 -0700380 if (err < 0) {
381 wpa_printf(MSG_INFO,
382 "nl80211: nl_send_auto_complete() failed: %s",
383 nl_geterror(err));
384 /* Need to convert libnl error code to an errno value. For now,
385 * just hardcode this to EBADF; the real error reason is shown
386 * in that error print above. */
387 err = -EBADF;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700388 goto out;
Hai Shalomfdcde762020-04-02 11:19:20 -0700389 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700390
391 err = 1;
392
393 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
394 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
395 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
396
397 if (valid_handler)
398 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
399 valid_handler, valid_data);
400
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700401 while (err > 0) {
402 int res = nl_recvmsgs(nl_handle, cb);
Hai Shalomfdcde762020-04-02 11:19:20 -0700403
404 if (res == -NLE_DUMP_INTR) {
405 /* Most likely one of the nl80211 dump routines hit a
406 * case where internal results changed while the dump
407 * was being sent. The most common known case for this
408 * is scan results fetching while associated were every
409 * received Beacon frame from the AP may end up
410 * incrementing bss_generation. This
411 * NL80211_CMD_GET_SCAN case tries again in the caller;
412 * other cases (of which there are no known common ones)
413 * will stop and return an error. */
414 wpa_printf(MSG_DEBUG, "nl80211: %s; convert to -EAGAIN",
415 nl_geterror(res));
416 err = -EAGAIN;
417 } else if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700418 wpa_printf(MSG_INFO,
Hai Shalomfdcde762020-04-02 11:19:20 -0700419 "nl80211: %s->nl_recvmsgs failed: %d (%s)",
420 __func__, res, nl_geterror(res));
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700421 }
422 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700423 out:
424 nl_cb_put(cb);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800425 if (!valid_handler && valid_data == (void *) -1)
426 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700427 nlmsg_free(msg);
428 return err;
429}
430
431
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800432int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
433 struct nl_msg *msg,
434 int (*valid_handler)(struct nl_msg *, void *),
435 void *valid_data)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700436{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800437 return send_and_recv(drv->global, drv->global->nl, msg,
438 valid_handler, valid_data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700439}
440
441
Hai Shalomb755a2a2020-04-23 21:49:02 -0700442/* Use this method to mark that it is necessary to own the connection/interface
443 * for this operation.
444 * handle may be set to NULL, to get the same behavior as send_and_recv_msgs().
445 * set_owner can be used to mark this socket for receiving control port frames.
446 */
447static int send_and_recv_msgs_owner(struct wpa_driver_nl80211_data *drv,
448 struct nl_msg *msg,
449 struct nl_sock *handle, int set_owner,
450 int (*valid_handler)(struct nl_msg *,
451 void *),
452 void *valid_data)
453{
454 /* Control port over nl80211 needs the flags and attributes below.
455 *
456 * The Linux kernel has initial checks for them (in nl80211.c) like:
457 * validate_pae_over_nl80211(...)
458 * or final checks like:
459 * dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid
460 *
461 * Final operations (e.g., disassociate) don't need to set these
462 * attributes, but they have to be performed on the socket, which has
463 * the connection owner property set in the kernel.
464 */
465 if ((drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) &&
466 handle && set_owner &&
467 (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) ||
468 nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER) ||
469 nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
470 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_PREAUTH)))
471 return -1;
472
473 return send_and_recv(drv->global, handle ? handle : drv->global->nl,
474 msg, valid_handler, valid_data);
475}
476
477
478struct nl_sock * get_connect_handle(struct i802_bss *bss)
479{
480 if ((bss->drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) ||
481 bss->use_nl_connect)
482 return bss->nl_connect;
483
484 return NULL;
485}
486
487
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700488struct family_data {
489 const char *group;
490 int id;
491};
492
493
494static int family_handler(struct nl_msg *msg, void *arg)
495{
496 struct family_data *res = arg;
497 struct nlattr *tb[CTRL_ATTR_MAX + 1];
498 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
499 struct nlattr *mcgrp;
500 int i;
501
502 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
503 genlmsg_attrlen(gnlh, 0), NULL);
504 if (!tb[CTRL_ATTR_MCAST_GROUPS])
505 return NL_SKIP;
506
507 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
508 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
509 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
510 nla_len(mcgrp), NULL);
511 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
512 !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
513 os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
514 res->group,
515 nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
516 continue;
517 res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
518 break;
519 };
520
521 return NL_SKIP;
522}
523
524
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800525static int nl_get_multicast_id(struct nl80211_global *global,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700526 const char *family, const char *group)
527{
528 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800529 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700530 struct family_data res = { group, -ENOENT };
531
532 msg = nlmsg_alloc();
533 if (!msg)
534 return -ENOMEM;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800535 if (!genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
536 0, 0, CTRL_CMD_GETFAMILY, 0) ||
537 nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family)) {
538 nlmsg_free(msg);
539 return -1;
540 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700541
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800542 ret = send_and_recv(global, global->nl, msg, family_handler, &res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700543 if (ret == 0)
544 ret = res.id;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700545 return ret;
546}
547
548
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800549void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
550 struct nl_msg *msg, int flags, uint8_t cmd)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800551{
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700552 if (TEST_FAIL())
553 return NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800554 return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
555 0, flags, cmd, 0);
556}
557
558
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800559static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
560{
561 if (bss->wdev_id_set)
562 return nla_put_u64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
563 return nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
564}
565
566
567struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd)
568{
569 struct nl_msg *msg;
570
571 msg = nlmsg_alloc();
572 if (!msg)
573 return NULL;
574
575 if (!nl80211_cmd(bss->drv, msg, flags, cmd) ||
576 nl80211_set_iface_id(msg, bss) < 0) {
577 nlmsg_free(msg);
578 return NULL;
579 }
580
581 return msg;
582}
583
584
585static struct nl_msg *
586nl80211_ifindex_msg(struct wpa_driver_nl80211_data *drv, int ifindex,
587 int flags, uint8_t cmd)
588{
589 struct nl_msg *msg;
590
591 msg = nlmsg_alloc();
592 if (!msg)
593 return NULL;
594
595 if (!nl80211_cmd(drv, msg, flags, cmd) ||
596 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
597 nlmsg_free(msg);
598 return NULL;
599 }
600
601 return msg;
602}
603
604
605struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
606 uint8_t cmd)
607{
608 return nl80211_ifindex_msg(drv, drv->ifindex, flags, cmd);
609}
610
611
612struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd)
613{
614 return nl80211_ifindex_msg(bss->drv, bss->ifindex, flags, cmd);
615}
616
617
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800618struct wiphy_idx_data {
619 int wiphy_idx;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700620 enum nl80211_iftype nlmode;
621 u8 *macaddr;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800622};
623
624
625static int netdev_info_handler(struct nl_msg *msg, void *arg)
626{
627 struct nlattr *tb[NL80211_ATTR_MAX + 1];
628 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
629 struct wiphy_idx_data *info = arg;
630
631 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
632 genlmsg_attrlen(gnlh, 0), NULL);
633
634 if (tb[NL80211_ATTR_WIPHY])
635 info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
636
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700637 if (tb[NL80211_ATTR_IFTYPE])
638 info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]);
639
640 if (tb[NL80211_ATTR_MAC] && info->macaddr)
641 os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
642 ETH_ALEN);
643
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800644 return NL_SKIP;
645}
646
647
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800648int nl80211_get_wiphy_index(struct i802_bss *bss)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800649{
650 struct nl_msg *msg;
651 struct wiphy_idx_data data = {
652 .wiphy_idx = -1,
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700653 .macaddr = NULL,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800654 };
655
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800656 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
657 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800658
659 if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
660 return data.wiphy_idx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800661 return -1;
662}
663
664
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700665static enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
666{
667 struct nl_msg *msg;
668 struct wiphy_idx_data data = {
669 .nlmode = NL80211_IFTYPE_UNSPECIFIED,
670 .macaddr = NULL,
671 };
672
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800673 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
674 return NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700675
676 if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
677 return data.nlmode;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700678 return NL80211_IFTYPE_UNSPECIFIED;
679}
680
681
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700682static int nl80211_get_macaddr(struct i802_bss *bss)
683{
684 struct nl_msg *msg;
685 struct wiphy_idx_data data = {
686 .macaddr = bss->addr,
687 };
688
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800689 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
690 return -1;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700691
692 return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data);
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700693}
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700694
695
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800696static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
697 struct nl80211_wiphy_data *w)
698{
699 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800700 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800701
702 msg = nlmsg_alloc();
703 if (!msg)
704 return -1;
705
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800706 if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS) ||
707 nla_put_u32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx)) {
708 nlmsg_free(msg);
709 return -1;
710 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800711
712 ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800713 if (ret) {
714 wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
715 "failed: ret=%d (%s)",
716 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800717 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800718 return ret;
719}
720
721
722static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
723{
724 struct nl80211_wiphy_data *w = eloop_ctx;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700725 int res;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800726
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800727 wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800728
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700729 res = nl_recvmsgs(handle, w->nl_cb);
Dmitry Shmidt71757432014-06-02 13:50:35 -0700730 if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700731 wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
732 __func__, res);
733 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800734}
735
736
737static int process_beacon_event(struct nl_msg *msg, void *arg)
738{
739 struct nl80211_wiphy_data *w = arg;
740 struct wpa_driver_nl80211_data *drv;
741 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
742 struct nlattr *tb[NL80211_ATTR_MAX + 1];
743 union wpa_event_data event;
744
745 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
746 genlmsg_attrlen(gnlh, 0), NULL);
747
748 if (gnlh->cmd != NL80211_CMD_FRAME) {
749 wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
750 gnlh->cmd);
751 return NL_SKIP;
752 }
753
754 if (!tb[NL80211_ATTR_FRAME])
755 return NL_SKIP;
756
757 dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
758 wiphy_list) {
759 os_memset(&event, 0, sizeof(event));
760 event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
761 event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
762 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
763 }
764
765 return NL_SKIP;
766}
767
768
769static struct nl80211_wiphy_data *
770nl80211_get_wiphy_data_ap(struct i802_bss *bss)
771{
772 static DEFINE_DL_LIST(nl80211_wiphys);
773 struct nl80211_wiphy_data *w;
774 int wiphy_idx, found = 0;
775 struct i802_bss *tmp_bss;
Paul Stewart092955c2017-02-06 09:13:09 -0800776 u8 channel;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800777
778 if (bss->wiphy_data != NULL)
779 return bss->wiphy_data;
780
781 wiphy_idx = nl80211_get_wiphy_index(bss);
782
783 dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
784 if (w->wiphy_idx == wiphy_idx)
785 goto add;
786 }
787
788 /* alloc new one */
789 w = os_zalloc(sizeof(*w));
790 if (w == NULL)
791 return NULL;
792 w->wiphy_idx = wiphy_idx;
793 dl_list_init(&w->bsss);
794 dl_list_init(&w->drvs);
795
Paul Stewart092955c2017-02-06 09:13:09 -0800796 /* Beacon frames not supported in IEEE 802.11ad */
797 if (ieee80211_freq_to_chan(bss->freq, &channel) !=
798 HOSTAPD_MODE_IEEE80211AD) {
799 w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
800 if (!w->nl_cb) {
801 os_free(w);
802 return NULL;
803 }
804 nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
805 no_seq_check, NULL);
806 nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
807 process_beacon_event, w);
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000808
Paul Stewart092955c2017-02-06 09:13:09 -0800809 w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
810 "wiphy beacons");
811 if (w->nl_beacons == NULL) {
812 os_free(w);
813 return NULL;
814 }
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000815
Paul Stewart092955c2017-02-06 09:13:09 -0800816 if (nl80211_register_beacons(bss->drv, w)) {
817 nl_destroy_handles(&w->nl_beacons);
818 os_free(w);
819 return NULL;
820 }
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000821
Paul Stewart092955c2017-02-06 09:13:09 -0800822 nl80211_register_eloop_read(&w->nl_beacons,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700823 nl80211_recv_beacons, w, 0);
Paul Stewart092955c2017-02-06 09:13:09 -0800824 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800825
826 dl_list_add(&nl80211_wiphys, &w->list);
827
828add:
829 /* drv entry for this bss already there? */
830 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
831 if (tmp_bss->drv == bss->drv) {
832 found = 1;
833 break;
834 }
835 }
836 /* if not add it */
837 if (!found)
838 dl_list_add(&w->drvs, &bss->drv->wiphy_list);
839
840 dl_list_add(&w->bsss, &bss->wiphy_list);
841 bss->wiphy_data = w;
842 return w;
843}
844
845
846static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
847{
848 struct nl80211_wiphy_data *w = bss->wiphy_data;
849 struct i802_bss *tmp_bss;
850 int found = 0;
851
852 if (w == NULL)
853 return;
854 bss->wiphy_data = NULL;
855 dl_list_del(&bss->wiphy_list);
856
857 /* still any for this drv present? */
858 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
859 if (tmp_bss->drv == bss->drv) {
860 found = 1;
861 break;
862 }
863 }
864 /* if not remove it */
865 if (!found)
866 dl_list_del(&bss->drv->wiphy_list);
867
868 if (!dl_list_empty(&w->bsss))
869 return;
870
Paul Stewart092955c2017-02-06 09:13:09 -0800871 if (w->nl_beacons)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700872 nl80211_destroy_eloop_handle(&w->nl_beacons, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800873
874 nl_cb_put(w->nl_cb);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800875 dl_list_del(&w->list);
876 os_free(w);
877}
878
879
Dmitry Shmidte4663042016-04-04 10:07:49 -0700880static unsigned int nl80211_get_ifindex(void *priv)
881{
882 struct i802_bss *bss = priv;
883 struct wpa_driver_nl80211_data *drv = bss->drv;
884
885 return drv->ifindex;
886}
887
888
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700889static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
890{
891 struct i802_bss *bss = priv;
892 struct wpa_driver_nl80211_data *drv = bss->drv;
893 if (!drv->associated)
894 return -1;
895 os_memcpy(bssid, drv->bssid, ETH_ALEN);
896 return 0;
897}
898
899
900static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
901{
902 struct i802_bss *bss = priv;
903 struct wpa_driver_nl80211_data *drv = bss->drv;
904 if (!drv->associated)
905 return -1;
906 os_memcpy(ssid, drv->ssid, drv->ssid_len);
907 return drv->ssid_len;
908}
909
910
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800911static void wpa_driver_nl80211_event_newlink(
Dmitry Shmidte4663042016-04-04 10:07:49 -0700912 struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
913 int ifindex, const char *ifname)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700914{
915 union wpa_event_data event;
916
Dmitry Shmidte4663042016-04-04 10:07:49 -0700917 if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800918 if (if_nametoindex(drv->first_bss->ifname) == 0) {
919 wpa_printf(MSG_DEBUG, "nl80211: Interface %s does not exist - ignore RTM_NEWLINK",
920 drv->first_bss->ifname);
921 return;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700922 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800923 if (!drv->if_removed)
924 return;
925 wpa_printf(MSG_DEBUG, "nl80211: Mark if_removed=0 for %s based on RTM_NEWLINK event",
926 drv->first_bss->ifname);
927 drv->if_removed = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700928 }
929
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800930 os_memset(&event, 0, sizeof(event));
Dmitry Shmidte4663042016-04-04 10:07:49 -0700931 event.interface_status.ifindex = ifindex;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800932 os_strlcpy(event.interface_status.ifname, ifname,
933 sizeof(event.interface_status.ifname));
934 event.interface_status.ievent = EVENT_INTERFACE_ADDED;
Dmitry Shmidte4663042016-04-04 10:07:49 -0700935 if (drv)
936 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
937 else
938 wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
939 &event);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800940}
941
942
943static void wpa_driver_nl80211_event_dellink(
Dmitry Shmidte4663042016-04-04 10:07:49 -0700944 struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
945 int ifindex, const char *ifname)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800946{
947 union wpa_event_data event;
948
Dmitry Shmidte4663042016-04-04 10:07:49 -0700949 if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800950 if (drv->if_removed) {
951 wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s",
952 ifname);
953 return;
954 }
955 wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed - mark if_removed=1",
956 ifname);
957 drv->if_removed = 1;
958 } else {
959 wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed",
960 ifname);
961 }
962
963 os_memset(&event, 0, sizeof(event));
Dmitry Shmidte4663042016-04-04 10:07:49 -0700964 event.interface_status.ifindex = ifindex;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800965 os_strlcpy(event.interface_status.ifname, ifname,
966 sizeof(event.interface_status.ifname));
967 event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
Dmitry Shmidte4663042016-04-04 10:07:49 -0700968 if (drv)
969 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
970 else
971 wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
972 &event);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700973}
974
975
976static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
977 u8 *buf, size_t len)
978{
979 int attrlen, rta_len;
980 struct rtattr *attr;
981
982 attrlen = len;
983 attr = (struct rtattr *) buf;
984
985 rta_len = RTA_ALIGN(sizeof(struct rtattr));
986 while (RTA_OK(attr, attrlen)) {
987 if (attr->rta_type == IFLA_IFNAME) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -0800988 if (os_strcmp(((char *) attr) + rta_len,
989 drv->first_bss->ifname) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700990 return 1;
991 else
992 break;
993 }
994 attr = RTA_NEXT(attr, attrlen);
995 }
996
997 return 0;
998}
999
1000
1001static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
1002 int ifindex, u8 *buf, size_t len)
1003{
1004 if (drv->ifindex == ifindex)
1005 return 1;
1006
1007 if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001008 nl80211_check_global(drv->global);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001009 wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
1010 "interface");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001011 if (wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL) < 0)
1012 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001013 return 1;
1014 }
1015
1016 return 0;
1017}
1018
1019
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001020static struct wpa_driver_nl80211_data *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001021nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len,
1022 int *init_failed)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001023{
1024 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001025 int res;
1026
1027 if (init_failed)
1028 *init_failed = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001029 dl_list_for_each(drv, &global->interfaces,
1030 struct wpa_driver_nl80211_data, list) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001031 res = wpa_driver_nl80211_own_ifindex(drv, idx, buf, len);
1032 if (res < 0) {
1033 wpa_printf(MSG_DEBUG,
1034 "nl80211: Found matching own interface, but failed to complete reinitialization");
1035 if (init_failed)
1036 *init_failed = 1;
1037 return drv;
1038 }
1039 if (res > 0 || have_ifidx(drv, idx, IFIDX_ANY))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001040 return drv;
1041 }
1042 return NULL;
1043}
1044
1045
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001046static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001047 int ifindex, int notify)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001048{
1049 struct i802_bss *bss;
1050 u8 addr[ETH_ALEN];
1051
1052 bss = get_bss_ifindex(drv, ifindex);
1053 if (bss &&
1054 linux_get_ifhwaddr(drv->global->ioctl_sock,
1055 bss->ifname, addr) < 0) {
1056 wpa_printf(MSG_DEBUG,
1057 "nl80211: %s: failed to re-read MAC address",
1058 bss->ifname);
1059 } else if (bss && os_memcmp(addr, bss->addr, ETH_ALEN) != 0) {
1060 wpa_printf(MSG_DEBUG,
1061 "nl80211: Own MAC address on ifindex %d (%s) changed from "
1062 MACSTR " to " MACSTR,
1063 ifindex, bss->ifname,
1064 MAC2STR(bss->addr), MAC2STR(addr));
1065 os_memcpy(bss->addr, addr, ETH_ALEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001066 if (notify)
1067 wpa_supplicant_event(drv->ctx,
1068 EVENT_INTERFACE_MAC_CHANGED, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001069 }
1070}
1071
1072
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001073static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
1074 struct ifinfomsg *ifi,
1075 u8 *buf, size_t len)
1076{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001077 struct nl80211_global *global = ctx;
1078 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001079 int attrlen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001080 struct rtattr *attr;
1081 u32 brid = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001082 char namebuf[IFNAMSIZ];
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001083 char ifname[IFNAMSIZ + 1];
1084 char extra[100], *pos, *end;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001085 int init_failed;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001086
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001087 extra[0] = '\0';
1088 pos = extra;
1089 end = pos + sizeof(extra);
1090 ifname[0] = '\0';
1091
1092 attrlen = len;
1093 attr = (struct rtattr *) buf;
1094 while (RTA_OK(attr, attrlen)) {
1095 switch (attr->rta_type) {
1096 case IFLA_IFNAME:
Hai Shalomfdcde762020-04-02 11:19:20 -07001097 if (RTA_PAYLOAD(attr) > IFNAMSIZ)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001098 break;
1099 os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
1100 ifname[RTA_PAYLOAD(attr)] = '\0';
1101 break;
1102 case IFLA_MASTER:
1103 brid = nla_get_u32((struct nlattr *) attr);
1104 pos += os_snprintf(pos, end - pos, " master=%u", brid);
1105 break;
1106 case IFLA_WIRELESS:
1107 pos += os_snprintf(pos, end - pos, " wext");
1108 break;
1109 case IFLA_OPERSTATE:
1110 pos += os_snprintf(pos, end - pos, " operstate=%u",
1111 nla_get_u32((struct nlattr *) attr));
1112 break;
1113 case IFLA_LINKMODE:
1114 pos += os_snprintf(pos, end - pos, " linkmode=%u",
1115 nla_get_u32((struct nlattr *) attr));
1116 break;
1117 }
1118 attr = RTA_NEXT(attr, attrlen);
1119 }
1120 extra[sizeof(extra) - 1] = '\0';
1121
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001122 wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
1123 ifi->ifi_index, ifname, extra, ifi->ifi_family,
1124 ifi->ifi_flags,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001125 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
1126 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
1127 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
1128 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
1129
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001130 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, &init_failed);
Dmitry Shmidte4663042016-04-04 10:07:49 -07001131 if (!drv)
1132 goto event_newlink;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001133 if (init_failed)
1134 return; /* do not update interface state */
Dmitry Shmidte4663042016-04-04 10:07:49 -07001135
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001136 if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001137 namebuf[0] = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001138 if (if_indextoname(ifi->ifi_index, namebuf) &&
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001139 linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001140 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
1141 "event since interface %s is up", namebuf);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001142 drv->ignore_if_down_event = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001143 /* Re-read MAC address as it may have changed */
1144 nl80211_refresh_mac(drv, ifi->ifi_index, 1);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001145 return;
1146 }
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001147 wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
1148 namebuf, ifname);
1149 if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
1150 wpa_printf(MSG_DEBUG,
1151 "nl80211: Not the main interface (%s) - do not indicate interface down",
1152 drv->first_bss->ifname);
1153 } else if (drv->ignore_if_down_event) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001154 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
1155 "event generated by mode change");
1156 drv->ignore_if_down_event = 0;
1157 } else {
1158 drv->if_disabled = 1;
1159 wpa_supplicant_event(drv->ctx,
1160 EVENT_INTERFACE_DISABLED, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08001161
1162 /*
1163 * Try to get drv again, since it may be removed as
1164 * part of the EVENT_INTERFACE_DISABLED handling for
1165 * dynamic interfaces
1166 */
1167 drv = nl80211_find_drv(global, ifi->ifi_index,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001168 buf, len, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08001169 if (!drv)
1170 return;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001171 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001172 }
1173
1174 if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
Hai Shalomc9e41a12018-07-31 14:41:42 -07001175 namebuf[0] = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001176 if (if_indextoname(ifi->ifi_index, namebuf) &&
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001177 linux_iface_up(drv->global->ioctl_sock, namebuf) == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001178 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1179 "event since interface %s is down",
1180 namebuf);
Hai Shalomc9e41a12018-07-31 14:41:42 -07001181 return;
1182 }
1183 wpa_printf(MSG_DEBUG, "nl80211: Interface up (%s/%s)",
1184 namebuf, ifname);
1185 if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
1186 wpa_printf(MSG_DEBUG,
1187 "nl80211: Not the main interface (%s) - do not indicate interface up",
1188 drv->first_bss->ifname);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001189 } else if (if_nametoindex(drv->first_bss->ifname) == 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001190 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1191 "event since interface %s does not exist",
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001192 drv->first_bss->ifname);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001193 } else if (drv->if_removed) {
1194 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1195 "event since interface %s is marked "
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001196 "removed", drv->first_bss->ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001197 } else {
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07001198 /* Re-read MAC address as it may have changed */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001199 nl80211_refresh_mac(drv, ifi->ifi_index, 0);
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07001200
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001201 drv->if_disabled = 0;
1202 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
1203 NULL);
1204 }
Sunil Ravi90775442020-09-24 11:53:19 -07001205 } else if (ifi->ifi_flags & IFF_UP) {
1206 /* Re-read MAC address as it may have changed */
1207 nl80211_refresh_mac(drv, ifi->ifi_index, 1);
1208 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001209 }
1210
1211 /*
1212 * Some drivers send the association event before the operup event--in
1213 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
1214 * fails. This will hit us when wpa_supplicant does not need to do
1215 * IEEE 802.1X authentication
1216 */
1217 if (drv->operstate == 1 &&
1218 (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001219 !(ifi->ifi_flags & IFF_RUNNING)) {
1220 wpa_printf(MSG_DEBUG, "nl80211: Set IF_OPER_UP again based on ifi_flags and expected operstate");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001221 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001222 -1, IF_OPER_UP);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001223 }
1224
Dmitry Shmidte4663042016-04-04 10:07:49 -07001225event_newlink:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001226 if (ifname[0])
Dmitry Shmidte4663042016-04-04 10:07:49 -07001227 wpa_driver_nl80211_event_newlink(global, drv, ifi->ifi_index,
1228 ifname);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001229
Dmitry Shmidte4663042016-04-04 10:07:49 -07001230 if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001231 struct i802_bss *bss;
1232
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001233 /* device has been added to bridge */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001234 if (!if_indextoname(brid, namebuf)) {
1235 wpa_printf(MSG_DEBUG,
1236 "nl80211: Could not find bridge ifname for ifindex %u",
1237 brid);
1238 return;
1239 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001240 wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
1241 brid, namebuf);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001242 add_ifidx(drv, brid, ifi->ifi_index);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001243
1244 for (bss = drv->first_bss; bss; bss = bss->next) {
1245 if (os_strcmp(ifname, bss->ifname) == 0) {
1246 os_strlcpy(bss->brname, namebuf, IFNAMSIZ);
1247 break;
1248 }
1249 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001250 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001251}
1252
1253
1254static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
1255 struct ifinfomsg *ifi,
1256 u8 *buf, size_t len)
1257{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001258 struct nl80211_global *global = ctx;
1259 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001260 int attrlen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001261 struct rtattr *attr;
1262 u32 brid = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001263 char ifname[IFNAMSIZ + 1];
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001264 char extra[100], *pos, *end;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001265
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001266 extra[0] = '\0';
1267 pos = extra;
1268 end = pos + sizeof(extra);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001269 ifname[0] = '\0';
1270
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001271 attrlen = len;
1272 attr = (struct rtattr *) buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001273 while (RTA_OK(attr, attrlen)) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001274 switch (attr->rta_type) {
1275 case IFLA_IFNAME:
Hai Shalomfdcde762020-04-02 11:19:20 -07001276 if (RTA_PAYLOAD(attr) > IFNAMSIZ)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001277 break;
1278 os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
1279 ifname[RTA_PAYLOAD(attr)] = '\0';
1280 break;
1281 case IFLA_MASTER:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001282 brid = nla_get_u32((struct nlattr *) attr);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001283 pos += os_snprintf(pos, end - pos, " master=%u", brid);
1284 break;
1285 case IFLA_OPERSTATE:
1286 pos += os_snprintf(pos, end - pos, " operstate=%u",
1287 nla_get_u32((struct nlattr *) attr));
1288 break;
1289 case IFLA_LINKMODE:
1290 pos += os_snprintf(pos, end - pos, " linkmode=%u",
1291 nla_get_u32((struct nlattr *) attr));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001292 break;
1293 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001294 attr = RTA_NEXT(attr, attrlen);
1295 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001296 extra[sizeof(extra) - 1] = '\0';
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001297
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001298 wpa_printf(MSG_DEBUG, "RTM_DELLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
1299 ifi->ifi_index, ifname, extra, ifi->ifi_family,
1300 ifi->ifi_flags,
1301 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
1302 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
1303 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
1304 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
1305
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001306 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001307
Dmitry Shmidte4663042016-04-04 10:07:49 -07001308 if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001309 /* device has been removed from bridge */
1310 char namebuf[IFNAMSIZ];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001311
1312 if (!if_indextoname(brid, namebuf)) {
1313 wpa_printf(MSG_DEBUG,
1314 "nl80211: Could not find bridge ifname for ifindex %u",
1315 brid);
1316 } else {
1317 wpa_printf(MSG_DEBUG,
1318 "nl80211: Remove ifindex %u for bridge %s",
1319 brid, namebuf);
1320 }
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001321 del_ifidx(drv, brid, ifi->ifi_index);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001322 }
Dmitry Shmidte4663042016-04-04 10:07:49 -07001323
1324 if (ifi->ifi_family != AF_BRIDGE || !brid)
1325 wpa_driver_nl80211_event_dellink(global, drv, ifi->ifi_index,
1326 ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001327}
1328
1329
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001330struct nl80211_get_assoc_freq_arg {
1331 struct wpa_driver_nl80211_data *drv;
1332 unsigned int assoc_freq;
1333 unsigned int ibss_freq;
1334 u8 assoc_bssid[ETH_ALEN];
1335 u8 assoc_ssid[SSID_MAX_LEN];
1336 u8 assoc_ssid_len;
1337};
1338
1339static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg)
1340{
1341 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1342 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1343 struct nlattr *bss[NL80211_BSS_MAX + 1];
1344 static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
1345 [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
1346 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
1347 [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
1348 [NL80211_BSS_STATUS] = { .type = NLA_U32 },
1349 };
1350 struct nl80211_get_assoc_freq_arg *ctx = arg;
1351 enum nl80211_bss_status status;
1352
1353 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1354 genlmsg_attrlen(gnlh, 0), NULL);
1355 if (!tb[NL80211_ATTR_BSS] ||
1356 nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
1357 bss_policy) ||
1358 !bss[NL80211_BSS_STATUS])
1359 return NL_SKIP;
1360
1361 status = nla_get_u32(bss[NL80211_BSS_STATUS]);
1362 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1363 bss[NL80211_BSS_FREQUENCY]) {
1364 ctx->assoc_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
1365 wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
1366 ctx->assoc_freq);
1367 }
1368 if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
1369 bss[NL80211_BSS_FREQUENCY]) {
1370 ctx->ibss_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
1371 wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
1372 ctx->ibss_freq);
1373 }
1374 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1375 bss[NL80211_BSS_BSSID]) {
1376 os_memcpy(ctx->assoc_bssid,
1377 nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
1378 wpa_printf(MSG_DEBUG, "nl80211: Associated with "
1379 MACSTR, MAC2STR(ctx->assoc_bssid));
1380 }
1381
1382 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1383 bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
1384 const u8 *ie, *ssid;
1385 size_t ie_len;
1386
1387 ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1388 ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1389 ssid = get_ie(ie, ie_len, WLAN_EID_SSID);
1390 if (ssid && ssid[1] > 0 && ssid[1] <= SSID_MAX_LEN) {
1391 ctx->assoc_ssid_len = ssid[1];
1392 os_memcpy(ctx->assoc_ssid, ssid + 2, ssid[1]);
1393 }
1394 }
1395
1396 return NL_SKIP;
1397}
1398
1399
1400int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid)
Jouni Malinen87fd2792011-05-16 18:35:42 +03001401{
1402 struct nl_msg *msg;
1403 int ret;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001404 struct nl80211_get_assoc_freq_arg arg;
Hai Shalomfdcde762020-04-02 11:19:20 -07001405 int count = 0;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001406
Hai Shalomfdcde762020-04-02 11:19:20 -07001407try_again:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001408 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
Jouni Malinen87fd2792011-05-16 18:35:42 +03001409 os_memset(&arg, 0, sizeof(arg));
Jouni Malinen87fd2792011-05-16 18:35:42 +03001410 arg.drv = drv;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001411 ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
1412 &arg);
Hai Shalomfdcde762020-04-02 11:19:20 -07001413 if (ret == -EAGAIN) {
1414 count++;
1415 if (count >= 10) {
1416 wpa_printf(MSG_INFO,
1417 "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid");
1418 } else {
1419 wpa_printf(MSG_DEBUG,
1420 "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid - try again");
1421 goto try_again;
1422 }
1423 }
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001424 if (ret == 0) {
1425 os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len);
1426 return arg.assoc_ssid_len;
1427 }
1428 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d (%s)",
1429 ret, strerror(-ret));
1430 return ret;
1431}
1432
1433
1434unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
1435{
1436 struct nl_msg *msg;
1437 int ret;
1438 struct nl80211_get_assoc_freq_arg arg;
Hai Shalomfdcde762020-04-02 11:19:20 -07001439 int count = 0;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001440
Hai Shalomfdcde762020-04-02 11:19:20 -07001441try_again:
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001442 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
1443 os_memset(&arg, 0, sizeof(arg));
1444 arg.drv = drv;
1445 ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
1446 &arg);
Hai Shalomfdcde762020-04-02 11:19:20 -07001447 if (ret == -EAGAIN) {
1448 count++;
1449 if (count >= 10) {
1450 wpa_printf(MSG_INFO,
1451 "nl80211: Failed to receive consistent scan result dump for get_assoc_freq");
1452 } else {
1453 wpa_printf(MSG_DEBUG,
1454 "nl80211: Failed to receive consistent scan result dump for get_assoc_freq - try again");
1455 goto try_again;
1456 }
1457 }
Jouni Malinen87fd2792011-05-16 18:35:42 +03001458 if (ret == 0) {
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07001459 unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
1460 arg.ibss_freq : arg.assoc_freq;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001461 wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07001462 "associated BSS from scan results: %u MHz", freq);
1463 if (freq)
1464 drv->assoc_freq = freq;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001465 return drv->assoc_freq;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001466 }
1467 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
1468 "(%s)", ret, strerror(-ret));
Jouni Malinen87fd2792011-05-16 18:35:42 +03001469 return drv->assoc_freq;
1470}
1471
1472
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001473static int get_link_signal(struct nl_msg *msg, void *arg)
1474{
1475 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1476 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1477 struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
1478 static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
1479 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
Dmitry Shmidt34af3062013-07-11 10:46:32 -07001480 [NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07001481 [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001482 };
1483 struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
1484 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
1485 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
1486 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
1487 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
1488 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
1489 };
1490 struct wpa_signal_info *sig_change = arg;
1491
1492 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1493 genlmsg_attrlen(gnlh, 0), NULL);
1494 if (!tb[NL80211_ATTR_STA_INFO] ||
1495 nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
1496 tb[NL80211_ATTR_STA_INFO], policy))
1497 return NL_SKIP;
1498 if (!sinfo[NL80211_STA_INFO_SIGNAL])
1499 return NL_SKIP;
1500
1501 sig_change->current_signal =
1502 (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
1503
Dmitry Shmidt34af3062013-07-11 10:46:32 -07001504 if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
1505 sig_change->avg_signal =
1506 (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
1507 else
1508 sig_change->avg_signal = 0;
1509
Dmitry Shmidtf73259c2015-03-17 11:00:54 -07001510 if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG])
1511 sig_change->avg_beacon_signal =
1512 (s8)
1513 nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
1514 else
1515 sig_change->avg_beacon_signal = 0;
1516
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001517 if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
1518 if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
1519 sinfo[NL80211_STA_INFO_TX_BITRATE],
1520 rate_policy)) {
1521 sig_change->current_txrate = 0;
1522 } else {
1523 if (rinfo[NL80211_RATE_INFO_BITRATE]) {
1524 sig_change->current_txrate =
1525 nla_get_u16(rinfo[
1526 NL80211_RATE_INFO_BITRATE]) * 100;
1527 }
1528 }
1529 }
1530
1531 return NL_SKIP;
1532}
1533
1534
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001535int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
1536 struct wpa_signal_info *sig)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001537{
1538 struct nl_msg *msg;
1539
Hai Shalom74f70d42019-02-11 14:42:39 -08001540 sig->current_signal = -WPA_INVALID_NOISE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001541 sig->current_txrate = 0;
1542
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001543 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
1544 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid)) {
1545 nlmsg_free(msg);
1546 return -ENOBUFS;
1547 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001548
1549 return send_and_recv_msgs(drv, msg, get_link_signal, sig);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001550}
1551
1552
1553static int get_link_noise(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_SURVEY_INFO_MAX + 1];
1558 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
1559 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
1560 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
1561 };
1562 struct wpa_signal_info *sig_change = arg;
1563
1564 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1565 genlmsg_attrlen(gnlh, 0), NULL);
1566
1567 if (!tb[NL80211_ATTR_SURVEY_INFO]) {
1568 wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
1569 return NL_SKIP;
1570 }
1571
1572 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
1573 tb[NL80211_ATTR_SURVEY_INFO],
1574 survey_policy)) {
1575 wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested "
1576 "attributes!");
1577 return NL_SKIP;
1578 }
1579
1580 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
1581 return NL_SKIP;
1582
1583 if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
1584 sig_change->frequency)
1585 return NL_SKIP;
1586
1587 if (!sinfo[NL80211_SURVEY_INFO_NOISE])
1588 return NL_SKIP;
1589
1590 sig_change->current_noise =
1591 (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
1592
1593 return NL_SKIP;
1594}
1595
1596
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001597int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
1598 struct wpa_signal_info *sig_change)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001599{
1600 struct nl_msg *msg;
1601
Hai Shalom74f70d42019-02-11 14:42:39 -08001602 sig_change->current_noise = WPA_INVALID_NOISE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001603 sig_change->frequency = drv->assoc_freq;
1604
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001605 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001606 return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001607}
1608
1609
Hai Shalom74f70d42019-02-11 14:42:39 -08001610static int get_channel_info(struct nl_msg *msg, void *arg)
1611{
1612 struct nlattr *tb[NL80211_ATTR_MAX + 1] = { 0 };
1613 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1614 struct wpa_channel_info *chan_info = arg;
1615
1616 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1617 genlmsg_attrlen(gnlh, 0), NULL);
1618
1619 os_memset(chan_info, 0, sizeof(struct wpa_channel_info));
1620 chan_info->chanwidth = CHAN_WIDTH_UNKNOWN;
1621
1622 if (tb[NL80211_ATTR_WIPHY_FREQ])
1623 chan_info->frequency =
1624 nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
1625 if (tb[NL80211_ATTR_CHANNEL_WIDTH])
1626 chan_info->chanwidth = convert2width(
1627 nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
1628 if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
1629 enum nl80211_channel_type ct =
1630 nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
1631
1632 switch (ct) {
1633 case NL80211_CHAN_HT40MINUS:
1634 chan_info->sec_channel = -1;
1635 break;
1636 case NL80211_CHAN_HT40PLUS:
1637 chan_info->sec_channel = 1;
1638 break;
1639 default:
1640 chan_info->sec_channel = 0;
1641 break;
1642 }
1643 }
1644 if (tb[NL80211_ATTR_CENTER_FREQ1])
1645 chan_info->center_frq1 =
1646 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
1647 if (tb[NL80211_ATTR_CENTER_FREQ2])
1648 chan_info->center_frq2 =
1649 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
1650
1651 if (chan_info->center_frq2) {
1652 u8 seg1_idx = 0;
1653
1654 if (ieee80211_freq_to_chan(chan_info->center_frq2, &seg1_idx) !=
1655 NUM_HOSTAPD_MODES)
1656 chan_info->seg1_idx = seg1_idx;
1657 }
1658
1659 return NL_SKIP;
1660}
1661
1662
1663static int nl80211_channel_info(void *priv, struct wpa_channel_info *ci)
1664{
1665 struct i802_bss *bss = priv;
1666 struct wpa_driver_nl80211_data *drv = bss->drv;
1667 struct nl_msg *msg;
1668
1669 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
1670 return send_and_recv_msgs(drv, msg, get_channel_info, ci);
1671}
1672
1673
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001674static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
1675 void *handle)
1676{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001677 struct nl_cb *cb = eloop_ctx;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001678 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001679
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07001680 wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001681
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001682 res = nl_recvmsgs(handle, cb);
Dmitry Shmidt71757432014-06-02 13:50:35 -07001683 if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001684 wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
1685 __func__, res);
1686 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001687}
1688
1689
1690/**
1691 * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
1692 * @priv: driver_nl80211 private data
1693 * @alpha2_arg: country to which to switch to
1694 * Returns: 0 on success, -1 on failure
1695 *
1696 * This asks nl80211 to set the regulatory domain for given
1697 * country ISO / IEC alpha2.
1698 */
1699static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
1700{
1701 struct i802_bss *bss = priv;
1702 struct wpa_driver_nl80211_data *drv = bss->drv;
1703 char alpha2[3];
1704 struct nl_msg *msg;
1705
1706 msg = nlmsg_alloc();
1707 if (!msg)
1708 return -ENOMEM;
1709
1710 alpha2[0] = alpha2_arg[0];
1711 alpha2[1] = alpha2_arg[1];
1712 alpha2[2] = '\0';
1713
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001714 if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG) ||
1715 nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, alpha2)) {
1716 nlmsg_free(msg);
1717 return -EINVAL;
1718 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001719 if (send_and_recv_msgs(drv, msg, NULL, NULL))
1720 return -EINVAL;
1721 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001722}
1723
1724
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001725static int nl80211_get_country(struct nl_msg *msg, void *arg)
1726{
1727 char *alpha2 = arg;
1728 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
1729 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1730
1731 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1732 genlmsg_attrlen(gnlh, 0), NULL);
1733 if (!tb_msg[NL80211_ATTR_REG_ALPHA2]) {
1734 wpa_printf(MSG_DEBUG, "nl80211: No country information available");
1735 return NL_SKIP;
1736 }
1737 os_strlcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3);
1738 return NL_SKIP;
1739}
1740
1741
1742static int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
1743{
1744 struct i802_bss *bss = priv;
1745 struct wpa_driver_nl80211_data *drv = bss->drv;
1746 struct nl_msg *msg;
1747 int ret;
1748
1749 msg = nlmsg_alloc();
1750 if (!msg)
1751 return -ENOMEM;
1752
1753 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
1754 alpha2[0] = '\0';
1755 ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2);
1756 if (!alpha2[0])
1757 ret = -1;
1758
1759 return ret;
1760}
1761
1762
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001763static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001764{
1765 int ret;
1766
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001767 global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
1768 if (global->nl_cb == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001769 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
1770 "callbacks");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001771 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001772 }
1773
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001774 global->nl = nl_create_handle(global->nl_cb, "nl");
1775 if (global->nl == NULL)
1776 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001777
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001778 global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
1779 if (global->nl80211_id < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001780 wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
1781 "found");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001782 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001783 }
1784
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001785 global->nl_event = nl_create_handle(global->nl_cb, "event");
1786 if (global->nl_event == NULL)
1787 goto err;
1788
1789 ret = nl_get_multicast_id(global, "nl80211", "scan");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001790 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001791 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001792 if (ret < 0) {
1793 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
1794 "membership for scan events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001795 ret, nl_geterror(ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001796 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001797 }
1798
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001799 ret = nl_get_multicast_id(global, "nl80211", "mlme");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001800 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001801 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001802 if (ret < 0) {
1803 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
1804 "membership for mlme events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001805 ret, nl_geterror(ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001806 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001807 }
1808
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001809 ret = nl_get_multicast_id(global, "nl80211", "regulatory");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001810 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001811 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001812 if (ret < 0) {
1813 wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
1814 "membership for regulatory events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001815 ret, nl_geterror(ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001816 /* Continue without regulatory events */
1817 }
1818
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001819 ret = nl_get_multicast_id(global, "nl80211", "vendor");
1820 if (ret >= 0)
1821 ret = nl_socket_add_membership(global->nl_event, ret);
1822 if (ret < 0) {
1823 wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
1824 "membership for vendor events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001825 ret, nl_geterror(ret));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001826 /* Continue without vendor events */
1827 }
1828
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001829 nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
1830 no_seq_check, NULL);
1831 nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
1832 process_global_event, global);
1833
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001834 nl80211_register_eloop_read(&global->nl_event,
1835 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001836 global->nl_cb, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001837
1838 return 0;
1839
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001840err:
1841 nl_destroy_handles(&global->nl_event);
1842 nl_destroy_handles(&global->nl);
1843 nl_cb_put(global->nl_cb);
1844 global->nl_cb = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001845 return -1;
1846}
1847
1848
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001849static void nl80211_check_global(struct nl80211_global *global)
1850{
Hai Shalomfdcde762020-04-02 11:19:20 -07001851 struct nl_sock *handle;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001852 const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL };
1853 int ret;
1854 unsigned int i;
1855
1856 /*
1857 * Try to re-add memberships to handle case of cfg80211 getting reloaded
1858 * and all registration having been cleared.
1859 */
1860 handle = (void *) (((intptr_t) global->nl_event) ^
1861 ELOOP_SOCKET_INVALID);
1862
1863 for (i = 0; groups[i]; i++) {
1864 ret = nl_get_multicast_id(global, "nl80211", groups[i]);
1865 if (ret >= 0)
1866 ret = nl_socket_add_membership(handle, ret);
1867 if (ret < 0) {
1868 wpa_printf(MSG_INFO,
1869 "nl80211: Could not re-add multicast membership for %s events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001870 groups[i], ret, nl_geterror(ret));
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001871 }
1872 }
1873}
1874
1875
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001876static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
1877{
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08001878 struct wpa_driver_nl80211_data *drv = ctx;
1879
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001880 wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08001881
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001882 /*
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08001883 * rtnetlink ifdown handler will report interfaces other than the P2P
1884 * Device interface as disabled.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001885 */
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08001886 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
1887 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001888}
1889
1890
1891static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
1892{
1893 struct wpa_driver_nl80211_data *drv = ctx;
1894 wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001895 if (i802_set_iface_flags(drv->first_bss, 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001896 wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
1897 "after rfkill unblock");
1898 return;
1899 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001900
1901 if (is_p2p_net_interface(drv->nlmode))
1902 nl80211_disable_11b_rates(drv, drv->ifindex, 1);
1903
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08001904 /*
1905 * rtnetlink ifup handler will report interfaces other than the P2P
1906 * Device interface as enabled.
1907 */
1908 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
1909 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001910}
1911
1912
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001913static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
1914 void *eloop_ctx,
1915 void *handle)
1916{
1917 struct wpa_driver_nl80211_data *drv = eloop_ctx;
1918 u8 data[2048];
1919 struct msghdr msg;
1920 struct iovec entry;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001921 u8 control[512];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001922 struct cmsghdr *cmsg;
1923 int res, found_ee = 0, found_wifi = 0, acked = 0;
1924 union wpa_event_data event;
1925
1926 memset(&msg, 0, sizeof(msg));
1927 msg.msg_iov = &entry;
1928 msg.msg_iovlen = 1;
1929 entry.iov_base = data;
1930 entry.iov_len = sizeof(data);
1931 msg.msg_control = &control;
1932 msg.msg_controllen = sizeof(control);
1933
1934 res = recvmsg(sock, &msg, MSG_ERRQUEUE);
1935 /* if error or not fitting 802.3 header, return */
1936 if (res < 14)
1937 return;
1938
1939 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
1940 {
1941 if (cmsg->cmsg_level == SOL_SOCKET &&
1942 cmsg->cmsg_type == SCM_WIFI_STATUS) {
1943 int *ack;
1944
1945 found_wifi = 1;
1946 ack = (void *)CMSG_DATA(cmsg);
1947 acked = *ack;
1948 }
1949
1950 if (cmsg->cmsg_level == SOL_PACKET &&
1951 cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
1952 struct sock_extended_err *err =
1953 (struct sock_extended_err *)CMSG_DATA(cmsg);
1954
1955 if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
1956 found_ee = 1;
1957 }
1958 }
1959
1960 if (!found_ee || !found_wifi)
1961 return;
1962
1963 memset(&event, 0, sizeof(event));
1964 event.eapol_tx_status.dst = data;
1965 event.eapol_tx_status.data = data + 14;
1966 event.eapol_tx_status.data_len = res - 14;
1967 event.eapol_tx_status.ack = acked;
1968 wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
1969}
1970
1971
Hai Shalomb755a2a2020-04-23 21:49:02 -07001972static int nl80211_init_connect_handle(struct i802_bss *bss)
1973{
1974 if (bss->nl_connect) {
1975 wpa_printf(MSG_DEBUG,
1976 "nl80211: Connect handle already created (nl_connect=%p)",
1977 bss->nl_connect);
1978 return -1;
1979 }
1980
1981 bss->nl_connect = nl_create_handle(bss->nl_cb, "connect");
1982 if (!bss->nl_connect)
1983 return -1;
1984 nl80211_register_eloop_read(&bss->nl_connect,
1985 wpa_driver_nl80211_event_receive,
1986 bss->nl_cb, 1);
1987 return 0;
1988}
1989
1990
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001991static int nl80211_init_bss(struct i802_bss *bss)
1992{
1993 bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
1994 if (!bss->nl_cb)
1995 return -1;
1996
1997 nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
1998 no_seq_check, NULL);
1999 nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
2000 process_bss_event, bss);
2001
Hai Shalomb755a2a2020-04-23 21:49:02 -07002002 nl80211_init_connect_handle(bss);
2003
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002004 return 0;
2005}
2006
2007
2008static void nl80211_destroy_bss(struct i802_bss *bss)
2009{
2010 nl_cb_put(bss->nl_cb);
2011 bss->nl_cb = NULL;
Hai Shalomb755a2a2020-04-23 21:49:02 -07002012
2013 if (bss->nl_connect)
2014 nl80211_destroy_eloop_handle(&bss->nl_connect, 1);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002015}
2016
2017
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002018static void
2019wpa_driver_nl80211_drv_init_rfkill(struct wpa_driver_nl80211_data *drv)
2020{
2021 struct rfkill_config *rcfg;
2022
2023 if (drv->rfkill)
2024 return;
2025
2026 rcfg = os_zalloc(sizeof(*rcfg));
2027 if (!rcfg)
2028 return;
2029
2030 rcfg->ctx = drv;
2031
2032 /* rfkill uses netdev sysfs for initialization. However, P2P Device is
2033 * not associated with a netdev, so use the name of some other interface
2034 * sharing the same wiphy as the P2P Device interface.
2035 *
2036 * Note: This is valid, as a P2P Device interface is always dynamically
2037 * created and is created only once another wpa_s interface was added.
2038 */
2039 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
2040 struct nl80211_global *global = drv->global;
2041 struct wpa_driver_nl80211_data *tmp1;
2042
2043 dl_list_for_each(tmp1, &global->interfaces,
2044 struct wpa_driver_nl80211_data, list) {
2045 if (drv == tmp1 || drv->wiphy_idx != tmp1->wiphy_idx ||
2046 !tmp1->rfkill)
2047 continue;
2048
2049 wpa_printf(MSG_DEBUG,
2050 "nl80211: Use (%s) to initialize P2P Device rfkill",
2051 tmp1->first_bss->ifname);
2052 os_strlcpy(rcfg->ifname, tmp1->first_bss->ifname,
2053 sizeof(rcfg->ifname));
2054 break;
2055 }
2056 } else {
2057 os_strlcpy(rcfg->ifname, drv->first_bss->ifname,
2058 sizeof(rcfg->ifname));
2059 }
2060
2061 rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
2062 rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
2063 drv->rfkill = rfkill_init(rcfg);
2064 if (!drv->rfkill) {
2065 wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
2066 os_free(rcfg);
2067 }
2068}
2069
2070
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002071static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
2072 void *global_priv, int hostapd,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002073 const u8 *set_addr,
2074 const char *driver_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002075{
2076 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002077 struct i802_bss *bss;
2078
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002079 if (global_priv == NULL)
2080 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002081 drv = os_zalloc(sizeof(*drv));
2082 if (drv == NULL)
2083 return NULL;
2084 drv->global = global_priv;
2085 drv->ctx = ctx;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002086 drv->hostapd = !!hostapd;
2087 drv->eapol_sock = -1;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002088
2089 /*
2090 * There is no driver capability flag for this, so assume it is
2091 * supported and disable this on first attempt to use if the driver
2092 * rejects the command due to missing support.
2093 */
2094 drv->set_rekey_offload = 1;
2095
Hai Shalom81f62d82019-07-22 12:10:00 -07002096 drv->num_if_indices = ARRAY_SIZE(drv->default_if_indices);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002097 drv->if_indices = drv->default_if_indices;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002098
2099 drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
2100 if (!drv->first_bss) {
2101 os_free(drv);
2102 return NULL;
2103 }
2104 bss = drv->first_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002105 bss->drv = drv;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002106 bss->ctx = ctx;
2107
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002108 os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
2109 drv->monitor_ifidx = -1;
2110 drv->monitor_sock = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002111 drv->eapol_tx_sock = -1;
2112 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002113
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002114 if (nl80211_init_bss(bss))
2115 goto failed;
2116
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002117 if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002118 goto failed;
2119
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002120 drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
2121 if (drv->eapol_tx_sock < 0)
2122 goto failed;
2123
2124 if (drv->data_tx_status) {
2125 int enabled = 1;
2126
2127 if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
2128 &enabled, sizeof(enabled)) < 0) {
2129 wpa_printf(MSG_DEBUG,
2130 "nl80211: wifi status sockopt failed\n");
2131 drv->data_tx_status = 0;
2132 if (!drv->use_monitor)
2133 drv->capa.flags &=
2134 ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
2135 } else {
2136 eloop_register_read_sock(drv->eapol_tx_sock,
2137 wpa_driver_nl80211_handle_eapol_tx_status,
2138 drv, NULL);
2139 }
2140 }
2141
2142 if (drv->global) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002143 nl80211_check_global(drv->global);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002144 dl_list_add(&drv->global->interfaces, &drv->list);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002145 drv->in_interface_list = 1;
2146 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002147
2148 return bss;
2149
2150failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002151 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002152 return NULL;
2153}
2154
2155
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002156/**
2157 * wpa_driver_nl80211_init - Initialize nl80211 driver interface
2158 * @ctx: context to be used when calling wpa_supplicant functions,
2159 * e.g., wpa_supplicant_event()
2160 * @ifname: interface name, e.g., wlan0
2161 * @global_priv: private driver global data from global_init()
2162 * Returns: Pointer to private data, %NULL on failure
2163 */
2164static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
2165 void *global_priv)
2166{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002167 return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL,
2168 NULL);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002169}
2170
2171
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002172static int nl80211_register_frame(struct i802_bss *bss,
Hai Shalomfdcde762020-04-02 11:19:20 -07002173 struct nl_sock *nl_handle,
Hai Shalome21d4e82020-04-29 16:34:06 -07002174 u16 type, const u8 *match, size_t match_len,
2175 bool multicast)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002176{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002177 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002178 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002179 int ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002180 char buf[30];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002181
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002182 buf[0] = '\0';
2183 wpa_snprintf_hex(buf, sizeof(buf), match, match_len);
Hai Shalome21d4e82020-04-29 16:34:06 -07002184 wpa_printf(MSG_DEBUG,
2185 "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s multicast=%d",
2186 type, fc2str(type), nl_handle, buf, multicast);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002187
Hai Shalomfdcde762020-04-02 11:19:20 -07002188 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_FRAME)) ||
Hai Shalome21d4e82020-04-29 16:34:06 -07002189 (multicast && nla_put_flag(msg, NL80211_ATTR_RECEIVE_MULTICAST)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002190 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type) ||
2191 nla_put(msg, NL80211_ATTR_FRAME_MATCH, match_len, match)) {
2192 nlmsg_free(msg);
2193 return -1;
2194 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002195
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002196 ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002197 if (ret) {
2198 wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
2199 "failed (type=%u): ret=%d (%s)",
2200 type, ret, strerror(-ret));
2201 wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
2202 match, match_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002203 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002204 return ret;
2205}
2206
2207
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002208static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
2209{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002210 if (bss->nl_mgmt) {
2211 wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
2212 "already on! (nl_mgmt=%p)", bss->nl_mgmt);
2213 return -1;
2214 }
2215
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002216 bss->nl_mgmt = nl_create_handle(bss->nl_cb, "mgmt");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002217 if (bss->nl_mgmt == NULL)
2218 return -1;
2219
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002220 return 0;
2221}
2222
2223
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002224static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss)
2225{
2226 nl80211_register_eloop_read(&bss->nl_mgmt,
2227 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002228 bss->nl_cb, 0);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002229}
2230
2231
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002232static int nl80211_register_action_frame(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002233 const u8 *match, size_t match_len)
2234{
2235 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002236 return nl80211_register_frame(bss, bss->nl_mgmt,
Hai Shalome21d4e82020-04-29 16:34:06 -07002237 type, match, match_len, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002238}
2239
2240
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002241static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002242{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002243 struct wpa_driver_nl80211_data *drv = bss->drv;
Hai Shalomfdcde762020-04-02 11:19:20 -07002244 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002245 int ret = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002246
2247 if (nl80211_alloc_mgmt_handle(bss))
2248 return -1;
2249 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
2250 "handle %p", bss->nl_mgmt);
2251
Hai Shalomfdcde762020-04-02 11:19:20 -07002252 if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002253 /* register for any AUTH message */
Hai Shalome21d4e82020-04-29 16:34:06 -07002254 nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0, false);
Hai Shalomfdcde762020-04-02 11:19:20 -07002255 } else if ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
2256 !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
2257 /* register for SAE Authentication frames */
2258 nl80211_register_frame(bss, bss->nl_mgmt, type,
Hai Shalome21d4e82020-04-29 16:34:06 -07002259 (u8 *) "\x03\x00", 2, false);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002260 }
2261
Dmitry Shmidt051af732013-10-22 13:52:46 -07002262#ifdef CONFIG_INTERWORKING
2263 /* QoS Map Configure */
2264 if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002265 ret = -1;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002266#endif /* CONFIG_INTERWORKING */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002267#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002268 /* GAS Initial Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002269 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002270 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002271 /* GAS Initial Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002272 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002273 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002274 /* GAS Comeback Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002275 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002276 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002277 /* GAS Comeback Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002278 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002279 ret = -1;
Dmitry Shmidt18463232014-01-24 12:29:41 -08002280 /* Protected GAS Initial Request */
2281 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0a", 2) < 0)
2282 ret = -1;
2283 /* Protected GAS Initial Response */
2284 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0b", 2) < 0)
2285 ret = -1;
2286 /* Protected GAS Comeback Request */
2287 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0c", 2) < 0)
2288 ret = -1;
2289 /* Protected GAS Comeback Response */
2290 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0d", 2) < 0)
2291 ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002292#endif /* CONFIG_P2P || CONFIG_INTERWORKING || CONFIG_DPP */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002293#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002294 /* P2P Public Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002295 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002296 (u8 *) "\x04\x09\x50\x6f\x9a\x09",
2297 6) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002298 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002299 /* P2P Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002300 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002301 (u8 *) "\x7f\x50\x6f\x9a\x09",
2302 5) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002303 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002304#endif /* CONFIG_P2P */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002305#ifdef CONFIG_DPP
2306 /* DPP Public Action */
2307 if (nl80211_register_action_frame(bss,
2308 (u8 *) "\x04\x09\x50\x6f\x9a\x1a",
2309 6) < 0)
2310 ret = -1;
2311#endif /* CONFIG_DPP */
Hai Shalom74f70d42019-02-11 14:42:39 -08002312#ifdef CONFIG_OCV
2313 /* SA Query Request */
2314 if (nl80211_register_action_frame(bss, (u8 *) "\x08\x00", 2) < 0)
2315 ret = -1;
2316#endif /* CONFIG_OCV */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002317 /* SA Query Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002318 if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002319 ret = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002320#ifdef CONFIG_TDLS
2321 if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
2322 /* TDLS Discovery Response */
2323 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
2324 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002325 ret = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002326 }
2327#endif /* CONFIG_TDLS */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002328#ifdef CONFIG_FST
2329 /* FST Action frames */
2330 if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
2331 ret = -1;
2332#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002333
2334 /* FT Action frames */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002335 if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002336 ret = -1;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002337 else if (!drv->has_driver_key_mgmt) {
2338 int i;
2339
2340 /* Update supported AKMs only if the driver doesn't advertize
2341 * any AKM capabilities. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002342 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
2343 WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
2344
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002345 /* Update per interface supported AKMs */
2346 for (i = 0; i < WPA_IF_MAX; i++)
2347 drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt;
2348 }
2349
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002350 /* WNM - BSS Transition Management Request */
2351 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002352 ret = -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002353 /* WNM-Sleep Mode Response */
2354 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002355 ret = -1;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08002356#ifdef CONFIG_WNM
2357 /* WNM - Collocated Interference Request */
2358 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x0b", 2) < 0)
2359 ret = -1;
2360#endif /* CONFIG_WNM */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002361
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002362#ifdef CONFIG_HS20
2363 /* WNM-Notification */
2364 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x1a", 2) < 0)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002365 ret = -1;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002366#endif /* CONFIG_HS20 */
2367
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002368 /* WMM-AC ADDTS Response */
2369 if (nl80211_register_action_frame(bss, (u8 *) "\x11\x01", 2) < 0)
2370 ret = -1;
2371
2372 /* WMM-AC DELTS */
2373 if (nl80211_register_action_frame(bss, (u8 *) "\x11\x02", 2) < 0)
2374 ret = -1;
2375
2376 /* Radio Measurement - Neighbor Report Response */
2377 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
2378 ret = -1;
2379
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002380 /* Radio Measurement - Radio Measurement Request */
2381 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x00", 2) < 0)
2382 ret = -1;
2383
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002384 /* Radio Measurement - Link Measurement Request */
2385 if ((drv->capa.rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) &&
2386 (nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
2387 ret = -1;
2388
2389 nl80211_mgmt_handle_register_eloop(bss);
2390
2391 return ret;
2392}
2393
2394
2395static int nl80211_mgmt_subscribe_mesh(struct i802_bss *bss)
2396{
2397 int ret = 0;
2398
2399 if (nl80211_alloc_mgmt_handle(bss))
2400 return -1;
2401
2402 wpa_printf(MSG_DEBUG,
2403 "nl80211: Subscribe to mgmt frames with mesh handle %p",
2404 bss->nl_mgmt);
2405
2406 /* Auth frames for mesh SAE */
2407 if (nl80211_register_frame(bss, bss->nl_mgmt,
2408 (WLAN_FC_TYPE_MGMT << 2) |
2409 (WLAN_FC_STYPE_AUTH << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07002410 NULL, 0, false) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002411 ret = -1;
2412
2413 /* Mesh peering open */
2414 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x01", 2) < 0)
2415 ret = -1;
2416 /* Mesh peering confirm */
2417 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x02", 2) < 0)
2418 ret = -1;
2419 /* Mesh peering close */
2420 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x03", 2) < 0)
2421 ret = -1;
2422
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002423 nl80211_mgmt_handle_register_eloop(bss);
2424
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002425 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002426}
2427
2428
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002429static int nl80211_register_spurious_class3(struct i802_bss *bss)
2430{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002431 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002432 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002433
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002434 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
2435 ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002436 if (ret) {
2437 wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
2438 "failed: ret=%d (%s)",
2439 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002440 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002441 return ret;
2442}
2443
2444
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002445static int nl80211_action_subscribe_ap(struct i802_bss *bss)
2446{
2447 int ret = 0;
2448
2449 /* Public Action frames */
2450 if (nl80211_register_action_frame(bss, (u8 *) "\x04", 1) < 0)
2451 ret = -1;
2452 /* RRM Measurement Report */
2453 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x01", 2) < 0)
2454 ret = -1;
Paul Stewart092955c2017-02-06 09:13:09 -08002455 /* RRM Link Measurement Report */
2456 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x03", 2) < 0)
2457 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002458 /* RRM Neighbor Report Request */
2459 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x04", 2) < 0)
2460 ret = -1;
2461 /* FT Action frames */
2462 if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
2463 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002464 /* SA Query */
2465 if (nl80211_register_action_frame(bss, (u8 *) "\x08", 1) < 0)
2466 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002467 /* Protected Dual of Public Action */
2468 if (nl80211_register_action_frame(bss, (u8 *) "\x09", 1) < 0)
2469 ret = -1;
2470 /* WNM */
2471 if (nl80211_register_action_frame(bss, (u8 *) "\x0a", 1) < 0)
2472 ret = -1;
2473 /* WMM */
2474 if (nl80211_register_action_frame(bss, (u8 *) "\x11", 1) < 0)
2475 ret = -1;
2476#ifdef CONFIG_FST
2477 /* FST Action frames */
2478 if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
2479 ret = -1;
2480#endif /* CONFIG_FST */
2481 /* Vendor-specific */
2482 if (nl80211_register_action_frame(bss, (u8 *) "\x7f", 1) < 0)
2483 ret = -1;
2484
2485 return ret;
2486}
2487
2488
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002489static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
2490{
2491 static const int stypes[] = {
2492 WLAN_FC_STYPE_AUTH,
2493 WLAN_FC_STYPE_ASSOC_REQ,
2494 WLAN_FC_STYPE_REASSOC_REQ,
2495 WLAN_FC_STYPE_DISASSOC,
2496 WLAN_FC_STYPE_DEAUTH,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002497 WLAN_FC_STYPE_PROBE_REQ,
2498/* Beacon doesn't work as mac80211 doesn't currently allow
2499 * it, but it wouldn't really be the right thing anyway as
2500 * it isn't per interface ... maybe just dump the scan
2501 * results periodically for OLBC?
2502 */
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002503 /* WLAN_FC_STYPE_BEACON, */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002504 };
2505 unsigned int i;
2506
2507 if (nl80211_alloc_mgmt_handle(bss))
2508 return -1;
2509 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
2510 "handle %p", bss->nl_mgmt);
2511
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002512 for (i = 0; i < ARRAY_SIZE(stypes); i++) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002513 if (nl80211_register_frame(bss, bss->nl_mgmt,
2514 (WLAN_FC_TYPE_MGMT << 2) |
2515 (stypes[i] << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07002516 NULL, 0, false) < 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002517 goto out_err;
2518 }
2519 }
2520
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002521 if (nl80211_action_subscribe_ap(bss))
2522 goto out_err;
2523
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002524 if (nl80211_register_spurious_class3(bss))
2525 goto out_err;
2526
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002527 nl80211_mgmt_handle_register_eloop(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002528 return 0;
2529
2530out_err:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002531 nl_destroy_handles(&bss->nl_mgmt);
2532 return -1;
2533}
2534
2535
2536static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
2537{
2538 if (nl80211_alloc_mgmt_handle(bss))
2539 return -1;
2540 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
2541 "handle %p (device SME)", bss->nl_mgmt);
2542
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002543 if (nl80211_action_subscribe_ap(bss))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002544 goto out_err;
2545
Hai Shalom5f92bc92019-04-18 11:54:11 -07002546 if (bss->drv->device_ap_sme) {
2547 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
2548
2549 /* Register for all Authentication frames */
Hai Shalome21d4e82020-04-29 16:34:06 -07002550 if (nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0,
2551 false) < 0)
Hai Shalom5f92bc92019-04-18 11:54:11 -07002552 wpa_printf(MSG_DEBUG,
2553 "nl80211: Failed to subscribe to handle Authentication frames - SAE offload may not work");
2554 }
2555
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002556 nl80211_mgmt_handle_register_eloop(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002557 return 0;
2558
2559out_err:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002560 nl_destroy_handles(&bss->nl_mgmt);
2561 return -1;
2562}
2563
2564
2565static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
2566{
2567 if (bss->nl_mgmt == NULL)
2568 return;
2569 wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
2570 "(%s)", bss->nl_mgmt, reason);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002571 nl80211_destroy_eloop_handle(&bss->nl_mgmt, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002572
2573 nl80211_put_wiphy_data_ap(bss);
2574}
2575
2576
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002577static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
2578{
2579 wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
2580}
2581
2582
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002583static void nl80211_del_p2pdev(struct i802_bss *bss)
2584{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002585 struct nl_msg *msg;
2586 int ret;
2587
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002588 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
2589 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002590
2591 wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
2592 bss->ifname, (long long unsigned int) bss->wdev_id,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002593 strerror(-ret));
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002594}
2595
2596
2597static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
2598{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002599 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002600 int ret;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002601
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002602 msg = nl80211_cmd_msg(bss, 0, start ? NL80211_CMD_START_P2P_DEVICE :
2603 NL80211_CMD_STOP_P2P_DEVICE);
2604 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002605
2606 wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
2607 start ? "Start" : "Stop",
2608 bss->ifname, (long long unsigned int) bss->wdev_id,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002609 strerror(-ret));
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002610 return ret;
2611}
2612
2613
2614static int i802_set_iface_flags(struct i802_bss *bss, int up)
2615{
2616 enum nl80211_iftype nlmode;
2617
2618 nlmode = nl80211_get_ifmode(bss);
2619 if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
2620 return linux_set_iface_flags(bss->drv->global->ioctl_sock,
2621 bss->ifname, up);
2622 }
2623
2624 /* P2P Device has start/stop which is equivalent */
2625 return nl80211_set_p2pdev(bss, up);
2626}
2627
2628
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002629#ifdef CONFIG_TESTING_OPTIONS
2630static int qca_vendor_test_cmd_handler(struct nl_msg *msg, void *arg)
2631{
2632 /* struct wpa_driver_nl80211_data *drv = arg; */
2633 struct nlattr *tb[NL80211_ATTR_MAX + 1];
2634 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2635
2636
2637 wpa_printf(MSG_DEBUG,
2638 "nl80211: QCA vendor test command response received");
2639
2640 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2641 genlmsg_attrlen(gnlh, 0), NULL);
2642 if (!tb[NL80211_ATTR_VENDOR_DATA]) {
2643 wpa_printf(MSG_DEBUG, "nl80211: No vendor data attribute");
2644 return NL_SKIP;
2645 }
2646
2647 wpa_hexdump(MSG_DEBUG,
2648 "nl80211: Received QCA vendor test command response",
2649 nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
2650 nla_len(tb[NL80211_ATTR_VENDOR_DATA]));
2651
2652 return NL_SKIP;
2653}
2654#endif /* CONFIG_TESTING_OPTIONS */
2655
2656
2657static void qca_vendor_test(struct wpa_driver_nl80211_data *drv)
2658{
2659#ifdef CONFIG_TESTING_OPTIONS
2660 struct nl_msg *msg;
2661 struct nlattr *params;
2662 int ret;
2663
2664 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
2665 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
2666 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
2667 QCA_NL80211_VENDOR_SUBCMD_TEST) ||
2668 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
2669 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TEST, 123)) {
2670 nlmsg_free(msg);
2671 return;
2672 }
2673 nla_nest_end(msg, params);
2674
2675 ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv);
2676 wpa_printf(MSG_DEBUG,
2677 "nl80211: QCA vendor test command returned %d (%s)",
2678 ret, strerror(-ret));
2679#endif /* CONFIG_TESTING_OPTIONS */
2680}
2681
2682
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002683static int
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002684wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002685 const u8 *set_addr, int first,
2686 const char *driver_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002687{
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002688 struct i802_bss *bss = drv->first_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002689 int send_rfkill_event = 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002690 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002691
2692 drv->ifindex = if_nametoindex(bss->ifname);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002693 bss->ifindex = drv->ifindex;
2694 bss->wdev_id = drv->global->if_add_wdevid;
2695 bss->wdev_id_set = drv->global->if_add_wdevid_set;
2696
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002697 bss->if_dynamic = drv->ifindex == drv->global->if_add_ifindex;
2698 bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002699 drv->global->if_add_wdevid_set = 0;
2700
Dmitry Shmidt03658832014-08-13 11:03:49 -07002701 if (!bss->if_dynamic && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
2702 bss->static_ap = 1;
2703
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08002704 if (first &&
2705 nl80211_get_ifmode(bss) != NL80211_IFTYPE_P2P_DEVICE &&
2706 linux_iface_up(drv->global->ioctl_sock, bss->ifname) > 0)
2707 drv->start_iface_up = 1;
2708
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002709 if (wpa_driver_nl80211_capa(drv))
2710 return -1;
2711
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002712 if (driver_params && nl80211_set_param(bss, driver_params) < 0)
2713 return -1;
2714
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002715 wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
2716 bss->ifname, drv->phyname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002717
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002718 if (set_addr &&
2719 (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) ||
2720 linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
2721 set_addr)))
2722 return -1;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002723
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002724 if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
2725 drv->start_mode_ap = 1;
2726
Dmitry Shmidt03658832014-08-13 11:03:49 -07002727 if (drv->hostapd || bss->static_ap)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002728 nlmode = NL80211_IFTYPE_AP;
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07002729 else if (bss->if_dynamic ||
2730 nl80211_get_ifmode(bss) == NL80211_IFTYPE_MESH_POINT)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002731 nlmode = nl80211_get_ifmode(bss);
2732 else
2733 nlmode = NL80211_IFTYPE_STATION;
2734
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002735 if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002736 wpa_printf(MSG_ERROR, "nl80211: Could not configure driver mode");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002737 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002738 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002739
Dmitry Shmidt98660862014-03-11 17:26:21 -07002740 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002741 nl80211_get_macaddr(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002742
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002743 wpa_driver_nl80211_drv_init_rfkill(drv);
2744
Dmitry Shmidt98660862014-03-11 17:26:21 -07002745 if (!rfkill_is_blocked(drv->rfkill)) {
2746 int ret = i802_set_iface_flags(bss, 1);
2747 if (ret) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002748 wpa_printf(MSG_ERROR, "nl80211: Could not set "
2749 "interface '%s' UP", bss->ifname);
Dmitry Shmidt98660862014-03-11 17:26:21 -07002750 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002751 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002752
2753 if (is_p2p_net_interface(nlmode))
2754 nl80211_disable_11b_rates(bss->drv,
2755 bss->drv->ifindex, 1);
2756
Dmitry Shmidt98660862014-03-11 17:26:21 -07002757 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
2758 return ret;
2759 } else {
2760 wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
2761 "interface '%s' due to rfkill", bss->ifname);
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002762 if (nlmode != NL80211_IFTYPE_P2P_DEVICE)
2763 drv->if_disabled = 1;
2764
Dmitry Shmidt98660862014-03-11 17:26:21 -07002765 send_rfkill_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002766 }
2767
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002768 if (!drv->hostapd && nlmode != NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002769 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
2770 1, IF_OPER_DORMANT);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002771
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002772 if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
2773 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
2774 bss->addr))
2775 return -1;
2776 os_memcpy(drv->perm_addr, bss->addr, ETH_ALEN);
2777 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002778
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002779 if (send_rfkill_event) {
2780 eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
2781 drv, drv->ctx);
2782 }
2783
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002784 if (drv->vendor_cmd_test_avail)
2785 qca_vendor_test(drv);
2786
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002787 return 0;
2788}
2789
2790
Paul Stewart092955c2017-02-06 09:13:09 -08002791static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002792{
2793 struct nl_msg *msg;
Paul Stewart092955c2017-02-06 09:13:09 -08002794 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002795
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002796 wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
2797 drv->ifindex);
Paul Stewart092955c2017-02-06 09:13:09 -08002798 nl80211_put_wiphy_data_ap(bss);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002799 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002800 return send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002801}
2802
2803
2804/**
2805 * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08002806 * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002807 *
2808 * Shut down driver interface and processing of driver events. Free
2809 * private data buffer if one was allocated in wpa_driver_nl80211_init().
2810 */
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08002811static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002812{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002813 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07002814 unsigned int i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002815
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002816 wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
2817 bss->ifname, drv->disabled_11b_rates);
2818
Dmitry Shmidt04949592012-07-19 12:16:46 -07002819 bss->in_deinit = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002820 if (drv->data_tx_status)
2821 eloop_unregister_read_sock(drv->eapol_tx_sock);
2822 if (drv->eapol_tx_sock >= 0)
2823 close(drv->eapol_tx_sock);
2824
2825 if (bss->nl_preq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002826 wpa_driver_nl80211_probe_req_report(bss, 0);
2827 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002828 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
2829 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002830 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
2831 "interface %s from bridge %s: %s",
2832 bss->ifname, bss->brname, strerror(errno));
2833 }
Hai Shalomc9e41a12018-07-31 14:41:42 -07002834
2835 if (drv->rtnl_sk)
Hai Shalomfdcde762020-04-02 11:19:20 -07002836 nl_socket_free(drv->rtnl_sk);
Hai Shalomc9e41a12018-07-31 14:41:42 -07002837
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002838 if (bss->added_bridge) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002839 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
2840 0) < 0)
2841 wpa_printf(MSG_INFO,
2842 "nl80211: Could not set bridge %s down",
2843 bss->brname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002844 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002845 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
2846 "bridge %s: %s",
2847 bss->brname, strerror(errno));
2848 }
2849
2850 nl80211_remove_monitor_interface(drv);
2851
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002852 if (is_ap_interface(drv->nlmode))
Paul Stewart092955c2017-02-06 09:13:09 -08002853 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002854
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002855 if (drv->eapol_sock >= 0) {
2856 eloop_unregister_read_sock(drv->eapol_sock);
2857 close(drv->eapol_sock);
2858 }
2859
2860 if (drv->if_indices != drv->default_if_indices)
2861 os_free(drv->if_indices);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002862
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002863 if (drv->disabled_11b_rates)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002864 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
2865
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002866 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
2867 IF_OPER_UP);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07002868 eloop_cancel_timeout(wpa_driver_nl80211_send_rfkill, drv, drv->ctx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002869 rfkill_deinit(drv->rfkill);
2870
2871 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
2872
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002873 if (!drv->start_iface_up)
2874 (void) i802_set_iface_flags(bss, 0);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002875
2876 if (drv->addr_changed) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002877 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
2878 0) < 0) {
2879 wpa_printf(MSG_DEBUG,
2880 "nl80211: Could not set interface down to restore permanent MAC address");
2881 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002882 if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
2883 drv->perm_addr) < 0) {
2884 wpa_printf(MSG_DEBUG,
2885 "nl80211: Could not restore permanent MAC address");
2886 }
2887 }
2888
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002889 if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002890 if (!drv->hostapd || !drv->start_mode_ap)
2891 wpa_driver_nl80211_set_mode(bss,
2892 NL80211_IFTYPE_STATION);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002893 nl80211_mgmt_unsubscribe(bss, "deinit");
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002894 } else {
2895 nl80211_mgmt_unsubscribe(bss, "deinit");
2896 nl80211_del_p2pdev(bss);
2897 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002898
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002899 nl80211_destroy_bss(drv->first_bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002900
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002901 os_free(drv->filter_ssids);
2902
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002903 os_free(drv->auth_ie);
2904
2905 if (drv->in_interface_list)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002906 dl_list_del(&drv->list);
2907
Dmitry Shmidt444d5672013-04-01 13:08:44 -07002908 os_free(drv->extended_capa);
2909 os_free(drv->extended_capa_mask);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07002910 for (i = 0; i < drv->num_iface_ext_capa; i++) {
2911 os_free(drv->iface_ext_capa[i].ext_capa);
2912 os_free(drv->iface_ext_capa[i].ext_capa_mask);
2913 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002914 os_free(drv->first_bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002915 os_free(drv);
2916}
2917
2918
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002919static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len)
2920{
2921 switch (alg) {
2922 case WPA_ALG_WEP:
2923 if (key_len == 5)
Paul Stewart092955c2017-02-06 09:13:09 -08002924 return RSN_CIPHER_SUITE_WEP40;
2925 return RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002926 case WPA_ALG_TKIP:
Paul Stewart092955c2017-02-06 09:13:09 -08002927 return RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002928 case WPA_ALG_CCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08002929 return RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002930 case WPA_ALG_GCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08002931 return RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002932 case WPA_ALG_CCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08002933 return RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002934 case WPA_ALG_GCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08002935 return RSN_CIPHER_SUITE_GCMP_256;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002936 case WPA_ALG_BIP_CMAC_128:
Paul Stewart092955c2017-02-06 09:13:09 -08002937 return RSN_CIPHER_SUITE_AES_128_CMAC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002938 case WPA_ALG_BIP_GMAC_128:
Paul Stewart092955c2017-02-06 09:13:09 -08002939 return RSN_CIPHER_SUITE_BIP_GMAC_128;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002940 case WPA_ALG_BIP_GMAC_256:
Paul Stewart092955c2017-02-06 09:13:09 -08002941 return RSN_CIPHER_SUITE_BIP_GMAC_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002942 case WPA_ALG_BIP_CMAC_256:
Paul Stewart092955c2017-02-06 09:13:09 -08002943 return RSN_CIPHER_SUITE_BIP_CMAC_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002944 case WPA_ALG_SMS4:
Paul Stewart092955c2017-02-06 09:13:09 -08002945 return RSN_CIPHER_SUITE_SMS4;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002946 case WPA_ALG_KRK:
Paul Stewart092955c2017-02-06 09:13:09 -08002947 return RSN_CIPHER_SUITE_KRK;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002948 case WPA_ALG_NONE:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002949 wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d",
2950 alg);
2951 return 0;
2952 }
2953
2954 wpa_printf(MSG_ERROR, "nl80211: Unsupported encryption algorithm %d",
2955 alg);
2956 return 0;
2957}
2958
2959
2960static u32 wpa_cipher_to_cipher_suite(unsigned int cipher)
2961{
2962 switch (cipher) {
2963 case WPA_CIPHER_CCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08002964 return RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002965 case WPA_CIPHER_GCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08002966 return RSN_CIPHER_SUITE_GCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002967 case WPA_CIPHER_CCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08002968 return RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002969 case WPA_CIPHER_GCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08002970 return RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002971 case WPA_CIPHER_TKIP:
Paul Stewart092955c2017-02-06 09:13:09 -08002972 return RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002973 case WPA_CIPHER_WEP104:
Paul Stewart092955c2017-02-06 09:13:09 -08002974 return RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002975 case WPA_CIPHER_WEP40:
Paul Stewart092955c2017-02-06 09:13:09 -08002976 return RSN_CIPHER_SUITE_WEP40;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002977 case WPA_CIPHER_GTK_NOT_USED:
Paul Stewart092955c2017-02-06 09:13:09 -08002978 return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002979 }
2980
2981 return 0;
2982}
2983
2984
2985static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[],
2986 int max_suites)
2987{
2988 int num_suites = 0;
2989
2990 if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP_256)
Paul Stewart092955c2017-02-06 09:13:09 -08002991 suites[num_suites++] = RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002992 if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP_256)
Paul Stewart092955c2017-02-06 09:13:09 -08002993 suites[num_suites++] = RSN_CIPHER_SUITE_GCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002994 if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP)
Paul Stewart092955c2017-02-06 09:13:09 -08002995 suites[num_suites++] = RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002996 if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP)
Paul Stewart092955c2017-02-06 09:13:09 -08002997 suites[num_suites++] = RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002998 if (num_suites < max_suites && ciphers & WPA_CIPHER_TKIP)
Paul Stewart092955c2017-02-06 09:13:09 -08002999 suites[num_suites++] = RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003000 if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP104)
Paul Stewart092955c2017-02-06 09:13:09 -08003001 suites[num_suites++] = RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003002 if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP40)
Paul Stewart092955c2017-02-06 09:13:09 -08003003 suites[num_suites++] = RSN_CIPHER_SUITE_WEP40;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003004
3005 return num_suites;
3006}
3007
3008
Hai Shalomfdcde762020-04-02 11:19:20 -07003009static int wpa_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
3010 int max_suites)
3011{
3012 int num_suites = 0;
3013
3014#define __AKM(a, b) \
3015 if (num_suites < max_suites && \
3016 (key_mgmt_suites & (WPA_KEY_MGMT_ ## a))) \
3017 suites[num_suites++] = (RSN_AUTH_KEY_MGMT_ ## b)
3018 __AKM(IEEE8021X, UNSPEC_802_1X);
3019 __AKM(PSK, PSK_OVER_802_1X);
3020 __AKM(FT_IEEE8021X, FT_802_1X);
3021 __AKM(FT_PSK, FT_PSK);
3022 __AKM(IEEE8021X_SHA256, 802_1X_SHA256);
3023 __AKM(PSK_SHA256, PSK_SHA256);
3024 __AKM(SAE, SAE);
3025 __AKM(FT_SAE, FT_SAE);
3026 __AKM(CCKM, CCKM);
3027 __AKM(OSEN, OSEN);
3028 __AKM(IEEE8021X_SUITE_B, 802_1X_SUITE_B);
3029 __AKM(IEEE8021X_SUITE_B_192, 802_1X_SUITE_B_192);
3030 __AKM(FILS_SHA256, FILS_SHA256);
3031 __AKM(FILS_SHA384, FILS_SHA384);
3032 __AKM(FT_FILS_SHA256, FT_FILS_SHA256);
3033 __AKM(FT_FILS_SHA384, FT_FILS_SHA384);
3034 __AKM(OWE, OWE);
3035 __AKM(DPP, DPP);
3036 __AKM(FT_IEEE8021X_SHA384, FT_802_1X_SHA384);
3037#undef __AKM
3038
3039 return num_suites;
3040}
3041
Ajay Davanagerib921bb82020-09-16 12:49:08 +05303042#ifdef CONFIG_DRIVER_NL80211_BRCM
3043static int wpa_driver_do_broadcom_acs(void *priv, struct drv_acs_params
3044 *params)
3045{
3046 struct i802_bss *bss = priv;
3047 struct wpa_driver_nl80211_data *drv = bss->drv;
3048 struct nl_msg *msg;
3049 struct nlattr *data;
3050 int freq_list_len;
3051 int ret = 0;
3052 do {
3053 freq_list_len =
3054 int_array_len(params->freq_list);
3055 wpa_printf(MSG_DEBUG, "%s: freq_list_len=%d",
3056 __FUNCTION__, freq_list_len);
3057 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
3058 if (!msg) {
3059 wpa_printf(MSG_ERROR, "%s: *errof, no memory for msg", __FUNCTION__);
3060 return ret;
3061 }
3062 if ((nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM))) {
3063 wpa_printf(MSG_ERROR, "%s: *errof, NL80211_ATTR_VENDOR_ID",
3064 __FUNCTION__);
3065 nlmsg_free(msg);
3066 return ret;
3067 }
3068
3069 if ((nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, BRCM_VENDOR_SCMD_ACS))) {
3070 wpa_printf(MSG_ERROR, "%s: *errof, NL80211_ATTR_VENDOR_SUBCMD",
3071 __FUNCTION__);
3072 nlmsg_free(msg);
3073 return ret;
3074 }
3075 if (!(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA))) {
3076 wpa_printf(MSG_ERROR, "%s: *errof, NL80211_ATTR_VENDOR_DATA", __FUNCTION__);
3077 nlmsg_free(msg);
3078 return ret;
3079 }
3080 if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HW_MODE, params->hw_mode))) {
3081 wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_HW_MODE",
3082 __FUNCTION__);
3083 nlmsg_free(msg);
3084 return ret;
3085 }
3086 if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT_ENABLED, params->ht_enabled))) {
3087 wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_HT_ENABLED",
3088 __FUNCTION__);
3089 nlmsg_free(msg);
3090 return ret;
3091 }
3092 if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED, params->ht40_enabled))) {
3093 wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED",
3094 __FUNCTION__);
3095 nlmsg_free(msg);
3096 return ret;
3097 }
3098 if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED, params->vht_enabled))) {
3099 wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED",
3100 __FUNCTION__);
3101 nlmsg_free(msg);
3102 return ret;
3103 }
3104 if ((nla_put_u16(msg, BRCM_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width))) {
3105 wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_CHWIDTH",
3106 __FUNCTION__);
3107 nlmsg_free(msg);
3108 return ret;
3109 }
3110 wpa_printf(MSG_DEBUG, "%s: ht40=%d, ch_width=%d\n",
3111 __FUNCTION__, params->ht40_enabled, params->ch_width);
3112 if ((freq_list_len > 0) && (nla_put(msg, BRCM_VENDOR_ATTR_ACS_FREQ_LIST,
3113 sizeof(int) * freq_list_len, params->freq_list))) {
3114 wpa_printf(MSG_ERROR, "%s: *error, BRCM_VENDOR_ATTR_ACS_FREQ_LIST,"
3115 "list_len=%d\n", __FUNCTION__, freq_list_len);
3116 nlmsg_free(msg);
3117 return ret;
3118 }
3119 nla_nest_end(msg, data);
3120 wpa_printf(MSG_DEBUG, "nl80211: ACS Params: HW_MODE: %d HT: %d HT40:"
3121 " %d VHT: %d BW: %d\n",
3122 params->hw_mode, params->ht_enabled, params->ht40_enabled,
3123 params->vht_enabled, params->ch_width);
3124 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
3125 if (ret) {
3126 wpa_printf(MSG_ERROR, "nl80211: Failed to invoke vendor"
3127 " driver ACS function: %s\n",
3128 strerror(errno));
3129 }
3130 } while (0);
3131 return ret;
3132}
3133#endif /* CONFIG_DRIVER_NL80211_BRCM */
Hai Shalomfdcde762020-04-02 11:19:20 -07003134
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003135#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003136static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
3137 const u8 *key, size_t key_len)
3138{
3139 struct nl_msg *msg;
3140 int ret;
3141
3142 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
3143 return 0;
3144
3145 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
3146 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
3147 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
3148 QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY) ||
3149 nla_put(msg, NL80211_ATTR_VENDOR_DATA, key_len, key)) {
3150 nl80211_nlmsg_clear(msg);
3151 nlmsg_free(msg);
3152 return -1;
3153 }
3154 ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
3155 if (ret) {
3156 wpa_printf(MSG_DEBUG,
3157 "nl80211: Key management set key failed: ret=%d (%s)",
3158 ret, strerror(-ret));
3159 }
3160
3161 return ret;
3162}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003163#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003164
3165
Roshan Pius3a1667e2018-07-03 15:17:14 -07003166static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
3167 const u8 *key, size_t key_len,
3168 const u8 *addr)
3169{
3170 struct nl_msg *msg = NULL;
3171 int ret;
3172
3173 /*
3174 * If the authenticator address is not set, assume it is
3175 * the current BSSID.
3176 */
3177 if (!addr && drv->associated)
3178 addr = drv->bssid;
3179 else if (!addr)
3180 return -1;
3181
3182 wpa_printf(MSG_DEBUG, "nl80211: Set PMK to the driver for " MACSTR,
3183 MAC2STR(addr));
3184 wpa_hexdump_key(MSG_DEBUG, "nl80211: PMK", key, key_len);
3185 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_PMK);
3186 if (!msg ||
3187 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
3188 nla_put(msg, NL80211_ATTR_PMK, key_len, key)) {
3189 nl80211_nlmsg_clear(msg);
3190 nlmsg_free(msg);
3191 return -ENOBUFS;
3192 }
3193
3194 ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
3195 if (ret) {
3196 wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)",
3197 ret, strerror(-ret));
3198 }
3199
3200 return ret;
3201}
3202
3203
Hai Shalomfdcde762020-04-02 11:19:20 -07003204static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
3205 struct wpa_driver_set_key_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003206{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003207 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003208 int ifindex;
Hai Shalomc3565922019-10-28 11:58:20 -07003209 struct nl_msg *msg;
3210 struct nl_msg *key_msg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003211 int ret;
Hai Shalomfdcde762020-04-02 11:19:20 -07003212 int skip_set_key = 1;
3213 const char *ifname = params->ifname;
3214 enum wpa_alg alg = params->alg;
3215 const u8 *addr = params->addr;
3216 int key_idx = params->key_idx;
3217 int set_tx = params->set_tx;
3218 const u8 *seq = params->seq;
3219 size_t seq_len = params->seq_len;
3220 const u8 *key = params->key;
3221 size_t key_len = params->key_len;
3222 int vlan_id = params->vlan_id;
3223 enum key_flag key_flag = params->key_flag;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003224
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003225 /* Ignore for P2P Device */
3226 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
3227 return 0;
3228
3229 ifindex = if_nametoindex(ifname);
3230 wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
Hai Shalomfdcde762020-04-02 11:19:20 -07003231 "set_tx=%d seq_len=%lu key_len=%lu key_flag=0x%x",
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003232 __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
Hai Shalomfdcde762020-04-02 11:19:20 -07003233 (unsigned long) seq_len, (unsigned long) key_len, key_flag);
3234
3235 if (check_key_flag(key_flag)) {
3236 wpa_printf(MSG_DEBUG, "%s: invalid key_flag", __func__);
3237 return -EINVAL;
Dmitry Shmidtd5c075b2013-08-05 14:36:10 -07003238 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003239
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003240#ifdef CONFIG_DRIVER_NL80211_QCA
Hai Shalomfdcde762020-04-02 11:19:20 -07003241 if ((key_flag & KEY_FLAG_PMK) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003242 (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
3243 wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
3244 __func__);
3245 ret = issue_key_mgmt_set_key(drv, key, key_len);
3246 return ret;
3247 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003248#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003249
Hai Shalomfdcde762020-04-02 11:19:20 -07003250 if (key_flag & KEY_FLAG_PMK) {
3251 if (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)
3252 return nl80211_set_pmk(drv, key, key_len, addr);
3253 /* The driver does not have any offload mechanism for PMK, so
3254 * there is no need to configure this key. */
3255 return 0;
3256 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003257
Hai Shalomfdcde762020-04-02 11:19:20 -07003258 ret = -ENOBUFS;
Hai Shalomc3565922019-10-28 11:58:20 -07003259 key_msg = nlmsg_alloc();
3260 if (!key_msg)
Hai Shalomfdcde762020-04-02 11:19:20 -07003261 return ret;
Hai Shalomc3565922019-10-28 11:58:20 -07003262
Hai Shalomfdcde762020-04-02 11:19:20 -07003263 if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3264 KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
3265 wpa_printf(MSG_DEBUG,
3266 "nl80211: SET_KEY (pairwise RX/TX modify)");
3267 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
3268 if (!msg)
3269 goto fail2;
3270 } else if (alg == WPA_ALG_NONE && (key_flag & KEY_FLAG_RX_TX)) {
3271 wpa_printf(MSG_DEBUG, "%s: invalid key_flag to delete key",
3272 __func__);
3273 ret = -EINVAL;
3274 goto fail2;
3275 } else if (alg == WPA_ALG_NONE) {
3276 wpa_printf(MSG_DEBUG, "nl80211: DEL_KEY");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003277 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
3278 if (!msg)
Hai Shalomc3565922019-10-28 11:58:20 -07003279 goto fail2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003280 } else {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003281 u32 suite;
3282
3283 suite = wpa_alg_to_cipher_suite(alg, key_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07003284 if (!suite) {
3285 ret = -EINVAL;
Hai Shalomc3565922019-10-28 11:58:20 -07003286 goto fail2;
Hai Shalomfdcde762020-04-02 11:19:20 -07003287 }
3288 wpa_printf(MSG_DEBUG, "nl80211: NEW_KEY");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003289 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
Hai Shalomc3565922019-10-28 11:58:20 -07003290 if (!msg)
3291 goto fail2;
3292 if (nla_put(key_msg, NL80211_KEY_DATA, key_len, key) ||
3293 nla_put_u32(key_msg, NL80211_KEY_CIPHER, suite))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003294 goto fail;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003295 wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003296
Hai Shalomfdcde762020-04-02 11:19:20 -07003297 if (seq && seq_len) {
3298 if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq))
3299 goto fail;
3300 wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ",
3301 seq, seq_len);
3302 }
Dmitry Shmidt98660862014-03-11 17:26:21 -07003303 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003304
3305 if (addr && !is_broadcast_ether_addr(addr)) {
3306 wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003307 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
3308 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003309
Hai Shalomfdcde762020-04-02 11:19:20 -07003310 if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3311 KEY_FLAG_PAIRWISE_RX ||
3312 (key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3313 KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
3314 if (nla_put_u8(key_msg, NL80211_KEY_MODE,
3315 key_flag == KEY_FLAG_PAIRWISE_RX ?
3316 NL80211_KEY_NO_TX : NL80211_KEY_SET_TX))
3317 goto fail;
3318 } else if ((key_flag & KEY_FLAG_GROUP_MASK) ==
3319 KEY_FLAG_GROUP_RX) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003320 wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
Hai Shalomc3565922019-10-28 11:58:20 -07003321 if (nla_put_u32(key_msg, NL80211_KEY_TYPE,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003322 NL80211_KEYTYPE_GROUP))
3323 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003324 } else if (!(key_flag & KEY_FLAG_PAIRWISE)) {
3325 wpa_printf(MSG_DEBUG,
3326 " key_flag missing PAIRWISE when setting a pairwise key");
3327 ret = -EINVAL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003328 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003329 } else if (alg == WPA_ALG_WEP &&
3330 (key_flag & KEY_FLAG_RX_TX) == KEY_FLAG_RX_TX) {
3331 wpa_printf(MSG_DEBUG, " unicast WEP key");
3332 skip_set_key = 0;
3333 } else {
3334 wpa_printf(MSG_DEBUG, " pairwise key");
3335 }
3336 } else if ((key_flag & KEY_FLAG_PAIRWISE) ||
3337 !(key_flag & KEY_FLAG_GROUP)) {
3338 wpa_printf(MSG_DEBUG,
3339 " invalid key_flag for a broadcast key");
3340 ret = -EINVAL;
3341 goto fail;
3342 } else {
3343 wpa_printf(MSG_DEBUG, " broadcast key");
3344 if (key_flag & KEY_FLAG_DEFAULT)
3345 skip_set_key = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003346 }
Hai Shalomc3565922019-10-28 11:58:20 -07003347 if (nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
3348 nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003349 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003350 nl80211_nlmsg_clear(key_msg);
3351 nlmsg_free(key_msg);
3352 key_msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003353
Hai Shalomfdcde762020-04-02 11:19:20 -07003354 if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
3355 wpa_printf(MSG_DEBUG, "nl80211: VLAN ID %d", vlan_id);
3356 if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
3357 goto fail;
3358 }
3359
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003360 ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003361 if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
3362 ret = 0;
3363 if (ret)
Hai Shalomfdcde762020-04-02 11:19:20 -07003364 wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003365 ret, strerror(-ret));
3366
3367 /*
Hai Shalomfdcde762020-04-02 11:19:20 -07003368 * If we failed or don't need to set the key as default (below),
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003369 * we're done here.
3370 */
Hai Shalomfdcde762020-04-02 11:19:20 -07003371 if (ret || skip_set_key)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003372 return ret;
Hai Shalomfdcde762020-04-02 11:19:20 -07003373 wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_SET_KEY - default key");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003374
Hai Shalomfdcde762020-04-02 11:19:20 -07003375 ret = -ENOBUFS;
Hai Shalomc3565922019-10-28 11:58:20 -07003376 key_msg = nlmsg_alloc();
3377 if (!key_msg)
Hai Shalomfdcde762020-04-02 11:19:20 -07003378 return ret;
Hai Shalomc3565922019-10-28 11:58:20 -07003379
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003380 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
Hai Shalomc3565922019-10-28 11:58:20 -07003381 if (!msg)
3382 goto fail2;
3383 if (!key_msg ||
3384 nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003385 nla_put_flag(key_msg, wpa_alg_bip(alg) ?
Hai Shalomfdcde762020-04-02 11:19:20 -07003386 (key_idx == 6 || key_idx == 7 ?
3387 NL80211_KEY_DEFAULT_BEACON :
3388 NL80211_KEY_DEFAULT_MGMT) :
3389 NL80211_KEY_DEFAULT))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003390 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003391 if (addr && is_broadcast_ether_addr(addr)) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003392 struct nlattr *types;
3393
Hai Shalomc3565922019-10-28 11:58:20 -07003394 types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003395 if (!types ||
Hai Shalomc3565922019-10-28 11:58:20 -07003396 nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003397 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003398 nla_nest_end(key_msg, types);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003399 } else if (addr) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003400 struct nlattr *types;
3401
Hai Shalomc3565922019-10-28 11:58:20 -07003402 types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003403 if (!types ||
Hai Shalomc3565922019-10-28 11:58:20 -07003404 nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003405 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003406 nla_nest_end(key_msg, types);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003407 }
3408
Hai Shalomc3565922019-10-28 11:58:20 -07003409 if (nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
3410 goto fail;
3411 nl80211_nlmsg_clear(key_msg);
3412 nlmsg_free(key_msg);
3413 key_msg = NULL;
3414
Hai Shalomfdcde762020-04-02 11:19:20 -07003415 if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
3416 wpa_printf(MSG_DEBUG, "nl80211: set_key default - VLAN ID %d",
3417 vlan_id);
3418 if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
3419 goto fail;
3420 }
3421
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003422 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003423 if (ret)
Hai Shalomfdcde762020-04-02 11:19:20 -07003424 wpa_printf(MSG_DEBUG,
3425 "nl80211: set_key default failed; err=%d %s",
3426 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003427 return ret;
3428
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003429fail:
3430 nl80211_nlmsg_clear(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003431 nlmsg_free(msg);
Hai Shalomc3565922019-10-28 11:58:20 -07003432fail2:
3433 nl80211_nlmsg_clear(key_msg);
3434 nlmsg_free(key_msg);
Hai Shalomfdcde762020-04-02 11:19:20 -07003435 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003436}
3437
3438
3439static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
3440 int key_idx, int defkey,
3441 const u8 *seq, size_t seq_len,
3442 const u8 *key, size_t key_len)
3443{
3444 struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003445 u32 suite;
3446
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003447 if (!key_attr)
3448 return -1;
3449
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003450 suite = wpa_alg_to_cipher_suite(alg, key_len);
3451 if (!suite)
3452 return -1;
3453
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003454 if (defkey && wpa_alg_bip(alg)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003455 if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT))
3456 return -1;
3457 } else if (defkey) {
3458 if (nla_put_flag(msg, NL80211_KEY_DEFAULT))
3459 return -1;
3460 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003461
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003462 if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) ||
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003463 nla_put_u32(msg, NL80211_KEY_CIPHER, suite) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003464 (seq && seq_len &&
3465 nla_put(msg, NL80211_KEY_SEQ, seq_len, seq)) ||
3466 nla_put(msg, NL80211_KEY_DATA, key_len, key))
3467 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003468
3469 nla_nest_end(msg, key_attr);
3470
3471 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003472}
3473
3474
3475static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
3476 struct nl_msg *msg)
3477{
3478 int i, privacy = 0;
3479 struct nlattr *nl_keys, *nl_key;
3480
3481 for (i = 0; i < 4; i++) {
3482 if (!params->wep_key[i])
3483 continue;
3484 privacy = 1;
3485 break;
3486 }
3487 if (params->wps == WPS_MODE_PRIVACY)
3488 privacy = 1;
3489 if (params->pairwise_suite &&
3490 params->pairwise_suite != WPA_CIPHER_NONE)
3491 privacy = 1;
3492
3493 if (!privacy)
3494 return 0;
3495
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003496 if (nla_put_flag(msg, NL80211_ATTR_PRIVACY))
3497 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003498
3499 nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
3500 if (!nl_keys)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003501 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003502
3503 for (i = 0; i < 4; i++) {
3504 if (!params->wep_key[i])
3505 continue;
3506
3507 nl_key = nla_nest_start(msg, i);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003508 if (!nl_key ||
3509 nla_put(msg, NL80211_KEY_DATA, params->wep_key_len[i],
3510 params->wep_key[i]) ||
3511 nla_put_u32(msg, NL80211_KEY_CIPHER,
3512 params->wep_key_len[i] == 5 ?
Paul Stewart092955c2017-02-06 09:13:09 -08003513 RSN_CIPHER_SUITE_WEP40 :
3514 RSN_CIPHER_SUITE_WEP104) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003515 nla_put_u8(msg, NL80211_KEY_IDX, i) ||
3516 (i == params->wep_tx_keyidx &&
3517 nla_put_flag(msg, NL80211_KEY_DEFAULT)))
3518 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003519
3520 nla_nest_end(msg, nl_key);
3521 }
3522 nla_nest_end(msg, nl_keys);
3523
3524 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003525}
3526
3527
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003528int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
3529 const u8 *addr, int cmd, u16 reason_code,
Hai Shalom74f70d42019-02-11 14:42:39 -08003530 int local_state_change,
Hai Shalomfdcde762020-04-02 11:19:20 -07003531 struct nl_sock *nl_connect)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003532{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003533 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003534 struct nl_msg *msg;
3535
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003536 if (!(msg = nl80211_drv_msg(drv, 0, cmd)) ||
3537 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code) ||
3538 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
3539 (local_state_change &&
3540 nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))) {
3541 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003542 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003543 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003544
Hai Shalom74f70d42019-02-11 14:42:39 -08003545 if (nl_connect)
3546 ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL);
3547 else
3548 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003549 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003550 wpa_dbg(drv->ctx, MSG_DEBUG,
3551 "nl80211: MLME command failed: reason=%u ret=%d (%s)",
3552 reason_code, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003553 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003554 return ret;
3555}
3556
3557
3558static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
Hai Shalom81f62d82019-07-22 12:10:00 -07003559 u16 reason_code,
Hai Shalomfdcde762020-04-02 11:19:20 -07003560 struct nl_sock *nl_connect)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003561{
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003562 int ret;
Hai Shalomce48b4a2018-09-05 11:41:35 -07003563 int drv_associated = drv->associated;
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003564
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003565 wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003566 nl80211_mark_disconnected(drv);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003567 /* Disconnect command doesn't need BSSID - it uses cached value */
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003568 ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
Hai Shalom74f70d42019-02-11 14:42:39 -08003569 reason_code, 0, nl_connect);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003570 /*
3571 * For locally generated disconnect, supplicant already generates a
3572 * DEAUTH event, so ignore the event from NL80211.
3573 */
Hai Shalomce48b4a2018-09-05 11:41:35 -07003574 drv->ignore_next_local_disconnect = drv_associated && (ret == 0);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003575
3576 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003577}
3578
3579
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003580static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
Hai Shalom81f62d82019-07-22 12:10:00 -07003581 const u8 *addr, u16 reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003582{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003583 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003584 int ret;
Hai Shalomce48b4a2018-09-05 11:41:35 -07003585 int drv_associated = drv->associated;
Dmitry Shmidt413dde72014-04-11 10:23:22 -07003586
3587 if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
3588 nl80211_mark_disconnected(drv);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003589 return nl80211_leave_ibss(drv, 1);
Dmitry Shmidt413dde72014-04-11 10:23:22 -07003590 }
Hai Shalom74f70d42019-02-11 14:42:39 -08003591 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
Hai Shalom74f70d42019-02-11 14:42:39 -08003592 return wpa_driver_nl80211_disconnect(drv, reason_code,
Hai Shalomb755a2a2020-04-23 21:49:02 -07003593 get_connect_handle(bss));
Hai Shalom74f70d42019-02-11 14:42:39 -08003594 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003595 wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
3596 __func__, MAC2STR(addr), reason_code);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003597 nl80211_mark_disconnected(drv);
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003598 ret = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
Hai Shalomb755a2a2020-04-23 21:49:02 -07003599 reason_code, 0, get_connect_handle(bss));
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003600 /*
3601 * For locally generated deauthenticate, supplicant already generates a
3602 * DEAUTH event, so ignore the event from NL80211.
3603 */
Hai Shalomce48b4a2018-09-05 11:41:35 -07003604 drv->ignore_next_local_deauth = drv_associated && (ret == 0);
3605
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003606 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003607}
3608
3609
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003610static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
3611 struct wpa_driver_auth_params *params)
3612{
3613 int i;
3614
3615 drv->auth_freq = params->freq;
3616 drv->auth_alg = params->auth_alg;
3617 drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
3618 drv->auth_local_state_change = params->local_state_change;
3619 drv->auth_p2p = params->p2p;
3620
3621 if (params->bssid)
3622 os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
3623 else
3624 os_memset(drv->auth_bssid_, 0, ETH_ALEN);
3625
3626 if (params->ssid) {
3627 os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
3628 drv->auth_ssid_len = params->ssid_len;
3629 } else
3630 drv->auth_ssid_len = 0;
3631
3632
3633 os_free(drv->auth_ie);
3634 drv->auth_ie = NULL;
3635 drv->auth_ie_len = 0;
3636 if (params->ie) {
3637 drv->auth_ie = os_malloc(params->ie_len);
3638 if (drv->auth_ie) {
3639 os_memcpy(drv->auth_ie, params->ie, params->ie_len);
3640 drv->auth_ie_len = params->ie_len;
3641 }
3642 }
3643
3644 for (i = 0; i < 4; i++) {
3645 if (params->wep_key[i] && params->wep_key_len[i] &&
3646 params->wep_key_len[i] <= 16) {
3647 os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
3648 params->wep_key_len[i]);
3649 drv->auth_wep_key_len[i] = params->wep_key_len[i];
3650 } else
3651 drv->auth_wep_key_len[i] = 0;
3652 }
3653}
3654
3655
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003656static void nl80211_unmask_11b_rates(struct i802_bss *bss)
3657{
3658 struct wpa_driver_nl80211_data *drv = bss->drv;
3659
3660 if (is_p2p_net_interface(drv->nlmode) || !drv->disabled_11b_rates)
3661 return;
3662
3663 /*
3664 * Looks like we failed to unmask 11b rates previously. This could
3665 * happen, e.g., if the interface was down at the point in time when a
3666 * P2P group was terminated.
3667 */
3668 wpa_printf(MSG_DEBUG,
3669 "nl80211: Interface %s mode is for non-P2P, but 11b rates were disabled - re-enable them",
3670 bss->ifname);
3671 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
3672}
3673
3674
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003675static enum nl80211_auth_type get_nl_auth_type(int wpa_auth_alg)
3676{
3677 if (wpa_auth_alg & WPA_AUTH_ALG_OPEN)
3678 return NL80211_AUTHTYPE_OPEN_SYSTEM;
3679 if (wpa_auth_alg & WPA_AUTH_ALG_SHARED)
3680 return NL80211_AUTHTYPE_SHARED_KEY;
3681 if (wpa_auth_alg & WPA_AUTH_ALG_LEAP)
3682 return NL80211_AUTHTYPE_NETWORK_EAP;
3683 if (wpa_auth_alg & WPA_AUTH_ALG_FT)
3684 return NL80211_AUTHTYPE_FT;
3685 if (wpa_auth_alg & WPA_AUTH_ALG_SAE)
3686 return NL80211_AUTHTYPE_SAE;
3687 if (wpa_auth_alg & WPA_AUTH_ALG_FILS)
3688 return NL80211_AUTHTYPE_FILS_SK;
3689 if (wpa_auth_alg & WPA_AUTH_ALG_FILS_SK_PFS)
3690 return NL80211_AUTHTYPE_FILS_SK_PFS;
3691
3692 return NL80211_AUTHTYPE_MAX;
3693}
3694
3695
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003696static int wpa_driver_nl80211_authenticate(
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003697 struct i802_bss *bss, struct wpa_driver_auth_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003698{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003699 struct wpa_driver_nl80211_data *drv = bss->drv;
3700 int ret = -1, i;
3701 struct nl_msg *msg;
3702 enum nl80211_auth_type type;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003703 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003704 int count = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003705 int is_retry;
Hai Shalomfdcde762020-04-02 11:19:20 -07003706 struct wpa_driver_set_key_params p;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003707
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003708 nl80211_unmask_11b_rates(bss);
3709
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003710 is_retry = drv->retry_auth;
3711 drv->retry_auth = 0;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003712 drv->ignore_deauth_event = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003713
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003714 nl80211_mark_disconnected(drv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003715 os_memset(drv->auth_bssid, 0, ETH_ALEN);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003716 if (params->bssid)
3717 os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
3718 else
3719 os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003720 /* FIX: IBSS mode */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003721 nlmode = params->p2p ?
3722 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
3723 if (drv->nlmode != nlmode &&
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003724 wpa_driver_nl80211_set_mode(bss, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003725 return -1;
3726
3727retry:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003728 wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
3729 drv->ifindex);
3730
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003731 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_AUTHENTICATE);
3732 if (!msg)
3733 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003734
Hai Shalomfdcde762020-04-02 11:19:20 -07003735 os_memset(&p, 0, sizeof(p));
3736 p.ifname = bss->ifname;
3737 p.alg = WPA_ALG_WEP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003738 for (i = 0; i < 4; i++) {
3739 if (!params->wep_key[i])
3740 continue;
Hai Shalomfdcde762020-04-02 11:19:20 -07003741 p.key_idx = i;
3742 p.set_tx = i == params->wep_tx_keyidx;
3743 p.key = params->wep_key[i];
3744 p.key_len = params->wep_key_len[i];
3745 p.key_flag = i == params->wep_tx_keyidx ?
3746 KEY_FLAG_GROUP_RX_TX_DEFAULT :
3747 KEY_FLAG_GROUP_RX_TX;
3748 wpa_driver_nl80211_set_key(bss, &p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003749 if (params->wep_tx_keyidx != i)
3750 continue;
3751 if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003752 params->wep_key[i], params->wep_key_len[i]))
3753 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003754 }
3755
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003756 if (params->bssid) {
3757 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
3758 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003759 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
3760 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003761 }
3762 if (params->freq) {
3763 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003764 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
3765 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003766 }
3767 if (params->ssid) {
Hai Shalom74f70d42019-02-11 14:42:39 -08003768 wpa_printf(MSG_DEBUG, " * SSID=%s",
3769 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003770 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
3771 params->ssid))
3772 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003773 }
3774 wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003775 if (params->ie &&
3776 nla_put(msg, NL80211_ATTR_IE, params->ie_len, params->ie))
3777 goto fail;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003778 if (params->auth_data) {
3779 wpa_hexdump(MSG_DEBUG, " * auth_data", params->auth_data,
3780 params->auth_data_len);
3781 if (nla_put(msg, NL80211_ATTR_SAE_DATA, params->auth_data_len,
3782 params->auth_data))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003783 goto fail;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003784 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003785 type = get_nl_auth_type(params->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003786 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003787 if (type == NL80211_AUTHTYPE_MAX ||
3788 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003789 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003790 if (params->local_state_change) {
3791 wpa_printf(MSG_DEBUG, " * Local state change only");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003792 if (nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))
3793 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003794 }
3795
3796 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
3797 msg = NULL;
3798 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003799 wpa_dbg(drv->ctx, MSG_DEBUG,
Roshan Pius3a1667e2018-07-03 15:17:14 -07003800 "nl80211: MLME command failed (auth): count=%d ret=%d (%s)",
3801 count, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003802 count++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003803 if ((ret == -EALREADY || ret == -EEXIST) && count == 1 &&
3804 params->bssid && !params->local_state_change) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003805 /*
3806 * mac80211 does not currently accept new
3807 * authentication if we are already authenticated. As a
3808 * workaround, force deauthentication and try again.
3809 */
3810 wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
3811 "after forced deauthentication");
Dmitry Shmidt98660862014-03-11 17:26:21 -07003812 drv->ignore_deauth_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003813 wpa_driver_nl80211_deauthenticate(
3814 bss, params->bssid,
3815 WLAN_REASON_PREV_AUTH_NOT_VALID);
3816 nlmsg_free(msg);
3817 goto retry;
3818 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003819
3820 if (ret == -ENOENT && params->freq && !is_retry) {
3821 /*
3822 * cfg80211 has likely expired the BSS entry even
3823 * though it was previously available in our internal
3824 * BSS table. To recover quickly, start a single
3825 * channel scan on the specified channel.
3826 */
3827 struct wpa_driver_scan_params scan;
3828 int freqs[2];
3829
3830 os_memset(&scan, 0, sizeof(scan));
3831 scan.num_ssids = 1;
3832 if (params->ssid) {
3833 scan.ssids[0].ssid = params->ssid;
3834 scan.ssids[0].ssid_len = params->ssid_len;
3835 }
3836 freqs[0] = params->freq;
3837 freqs[1] = 0;
3838 scan.freqs = freqs;
3839 wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
3840 "channel scan to refresh cfg80211 BSS "
3841 "entry");
3842 ret = wpa_driver_nl80211_scan(bss, &scan);
3843 if (ret == 0) {
3844 nl80211_copy_auth_params(drv, params);
3845 drv->scan_for_auth = 1;
3846 }
3847 } else if (is_retry) {
3848 /*
3849 * Need to indicate this with an event since the return
3850 * value from the retry is not delivered to core code.
3851 */
3852 union wpa_event_data event;
3853 wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
3854 "failed");
3855 os_memset(&event, 0, sizeof(event));
3856 os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
3857 ETH_ALEN);
3858 wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
3859 &event);
3860 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003861 } else {
3862 wpa_printf(MSG_DEBUG,
3863 "nl80211: Authentication request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003864 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003865
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003866fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003867 nlmsg_free(msg);
3868 return ret;
3869}
3870
3871
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003872int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003873{
3874 struct wpa_driver_auth_params params;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003875 struct i802_bss *bss = drv->first_bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003876 int i;
3877
3878 wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
3879
3880 os_memset(&params, 0, sizeof(params));
3881 params.freq = drv->auth_freq;
3882 params.auth_alg = drv->auth_alg;
3883 params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
3884 params.local_state_change = drv->auth_local_state_change;
3885 params.p2p = drv->auth_p2p;
3886
3887 if (!is_zero_ether_addr(drv->auth_bssid_))
3888 params.bssid = drv->auth_bssid_;
3889
3890 if (drv->auth_ssid_len) {
3891 params.ssid = drv->auth_ssid;
3892 params.ssid_len = drv->auth_ssid_len;
3893 }
3894
3895 params.ie = drv->auth_ie;
3896 params.ie_len = drv->auth_ie_len;
3897
3898 for (i = 0; i < 4; i++) {
3899 if (drv->auth_wep_key_len[i]) {
3900 params.wep_key[i] = drv->auth_wep_key[i];
3901 params.wep_key_len[i] = drv->auth_wep_key_len[i];
3902 }
3903 }
3904
3905 drv->retry_auth = 1;
3906 return wpa_driver_nl80211_authenticate(bss, &params);
3907}
3908
3909
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003910static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
3911 size_t data_len, int noack,
3912 unsigned int freq, int no_cck,
3913 int offchanok,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003914 unsigned int wait_time,
3915 const u16 *csa_offs,
Hai Shalomfdcde762020-04-02 11:19:20 -07003916 size_t csa_offs_len, int no_encrypt)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003917{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003918 struct wpa_driver_nl80211_data *drv = bss->drv;
3919 struct ieee80211_mgmt *mgmt;
Hai Shalomfdcde762020-04-02 11:19:20 -07003920 int encrypt = !no_encrypt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003921 u16 fc;
Hai Shalomfdcde762020-04-02 11:19:20 -07003922 int use_cookie = 1;
3923 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003924
3925 mgmt = (struct ieee80211_mgmt *) data;
3926 fc = le_to_host16(mgmt->frame_control);
Hai Shalomfdcde762020-04-02 11:19:20 -07003927 wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR
3928 " 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 -07003929 MAC2STR(mgmt->da), noack, freq, no_cck, offchanok, wait_time,
Hai Shalomfdcde762020-04-02 11:19:20 -07003930 no_encrypt, fc, fc2str(fc), drv->nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003931
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003932 if ((is_sta_interface(drv->nlmode) ||
3933 drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003934 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
3935 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
3936 /*
3937 * The use of last_mgmt_freq is a bit of a hack,
3938 * but it works due to the single-threaded nature
3939 * of wpa_supplicant.
3940 */
Dmitry Shmidt56052862013-10-04 10:23:25 -07003941 if (freq == 0) {
3942 wpa_printf(MSG_DEBUG, "nl80211: Use last_mgmt_freq=%d",
3943 drv->last_mgmt_freq);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003944 freq = drv->last_mgmt_freq;
Dmitry Shmidt56052862013-10-04 10:23:25 -07003945 }
Hai Shalomfdcde762020-04-02 11:19:20 -07003946 wait_time = 0;
3947 use_cookie = 0;
3948 no_cck = 1;
3949 offchanok = 1;
3950 goto send_frame_cmd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003951 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003952
3953 if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
Dmitry Shmidt56052862013-10-04 10:23:25 -07003954 if (freq == 0) {
3955 wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d",
3956 bss->freq);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003957 freq = bss->freq;
Dmitry Shmidt56052862013-10-04 10:23:25 -07003958 }
Hai Shalomfdcde762020-04-02 11:19:20 -07003959 if ((int) freq == bss->freq)
3960 wait_time = 0;
3961 goto send_frame_cmd;
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07003962 }
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07003963
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003964 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
3965 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
3966 /*
3967 * Only one of the authentication frame types is encrypted.
3968 * In order for static WEP encryption to work properly (i.e.,
3969 * to not encrypt the frame), we need to tell mac80211 about
3970 * the frames that must not be encrypted.
3971 */
3972 u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
3973 u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
3974 if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
3975 encrypt = 0;
3976 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003977
Hai Shalomfdcde762020-04-02 11:19:20 -07003978 if (freq == 0 && drv->nlmode == NL80211_IFTYPE_STATION &&
3979 (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
3980 !(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
3981 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
3982 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
3983 freq = nl80211_get_assoc_freq(drv);
3984 wpa_printf(MSG_DEBUG,
3985 "nl80211: send_mlme - Use assoc_freq=%u for external auth",
3986 freq);
3987 }
3988
3989 if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
3990 freq = nl80211_get_assoc_freq(drv);
3991 wpa_printf(MSG_DEBUG,
3992 "nl80211: send_mlme - Use assoc_freq=%u for IBSS",
3993 freq);
3994 }
3995 if (freq == 0) {
3996 wpa_printf(MSG_DEBUG, "nl80211: send_mlme - Use bss->freq=%u",
3997 bss->freq);
3998 freq = bss->freq;
3999 }
4000
4001 if (drv->use_monitor) {
4002 wpa_printf(MSG_DEBUG,
4003 "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
4004 freq, bss->freq);
4005 return nl80211_send_monitor(drv, data, data_len, encrypt,
4006 noack);
4007 }
4008
4009 if (noack || WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
4010 WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
4011 use_cookie = 0;
4012send_frame_cmd:
4013#ifdef CONFIG_TESTING_OPTIONS
4014 if (no_encrypt && !encrypt && !drv->use_monitor) {
4015 wpa_printf(MSG_DEBUG,
4016 "nl80211: Request to send an unencrypted frame - use a monitor interface for this");
4017 if (nl80211_create_monitor_interface(drv) < 0)
4018 return -1;
4019 res = nl80211_send_monitor(drv, data, data_len, encrypt,
4020 noack);
4021 nl80211_remove_monitor_interface(drv);
4022 return res;
4023 }
4024#endif /* CONFIG_TESTING_OPTIONS */
4025
4026 wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame_cmd");
4027 res = nl80211_send_frame_cmd(bss, freq, wait_time, data, data_len,
4028 use_cookie, no_cck, noack, offchanok,
4029 csa_offs, csa_offs_len);
4030
4031 return res;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004032}
4033
4034
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004035static int nl80211_put_basic_rates(struct nl_msg *msg, const int *basic_rates)
4036{
4037 u8 rates[NL80211_MAX_SUPP_RATES];
4038 u8 rates_len = 0;
4039 int i;
4040
4041 if (!basic_rates)
4042 return 0;
4043
4044 for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
4045 rates[rates_len++] = basic_rates[i] / 5;
4046
4047 return nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
4048}
4049
4050
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004051static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
4052 int slot, int ht_opmode, int ap_isolate,
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004053 const int *basic_rates)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004054{
4055 struct wpa_driver_nl80211_data *drv = bss->drv;
4056 struct nl_msg *msg;
4057
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004058 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_BSS)) ||
4059 (cts >= 0 &&
4060 nla_put_u8(msg, NL80211_ATTR_BSS_CTS_PROT, cts)) ||
4061 (preamble >= 0 &&
4062 nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble)) ||
4063 (slot >= 0 &&
4064 nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot)) ||
4065 (ht_opmode >= 0 &&
4066 nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) ||
4067 (ap_isolate >= 0 &&
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004068 nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)) ||
4069 nl80211_put_basic_rates(msg, basic_rates)) {
4070 nlmsg_free(msg);
4071 return -ENOBUFS;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004072 }
4073
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004074 return send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004075}
4076
4077
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004078static int wpa_driver_nl80211_set_acl(void *priv,
4079 struct hostapd_acl_params *params)
4080{
4081 struct i802_bss *bss = priv;
4082 struct wpa_driver_nl80211_data *drv = bss->drv;
4083 struct nl_msg *msg;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004084 struct nl_msg *acl;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004085 unsigned int i;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004086 int ret;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004087
4088 if (!(drv->capa.max_acl_mac_addrs))
4089 return -ENOTSUP;
4090
4091 if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
4092 return -ENOTSUP;
4093
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004094 wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
4095 params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
4096
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004097 acl = nlmsg_alloc();
4098 if (!acl)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004099 return -ENOMEM;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004100 for (i = 0; i < params->num_mac_acl; i++) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004101 if (nla_put(acl, i + 1, ETH_ALEN, params->mac_acl[i].addr)) {
4102 nlmsg_free(acl);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004103 return -ENOMEM;
4104 }
4105 }
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004106
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004107 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MAC_ACL)) ||
4108 nla_put_u32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
4109 NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
4110 NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED) ||
4111 nla_put_nested(msg, NL80211_ATTR_MAC_ADDRS, acl)) {
4112 nlmsg_free(msg);
4113 nlmsg_free(acl);
4114 return -ENOMEM;
4115 }
4116 nlmsg_free(acl);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004117
4118 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004119 if (ret) {
4120 wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
4121 ret, strerror(-ret));
4122 }
4123
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004124 return ret;
4125}
4126
4127
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004128static int nl80211_put_beacon_int(struct nl_msg *msg, int beacon_int)
4129{
4130 if (beacon_int > 0) {
4131 wpa_printf(MSG_DEBUG, " * beacon_int=%d", beacon_int);
4132 return nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
4133 beacon_int);
4134 }
4135
4136 return 0;
4137}
4138
4139
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004140static int nl80211_put_dtim_period(struct nl_msg *msg, int dtim_period)
4141{
4142 if (dtim_period > 0) {
4143 wpa_printf(MSG_DEBUG, " * dtim_period=%d", dtim_period);
4144 return nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
4145 }
4146
4147 return 0;
4148}
4149
4150
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004151#ifdef CONFIG_MESH
4152static int nl80211_set_mesh_config(void *priv,
4153 struct wpa_driver_mesh_bss_params *params)
4154{
4155 struct i802_bss *bss = priv;
4156 struct wpa_driver_nl80211_data *drv = bss->drv;
4157 struct nl_msg *msg;
4158 int ret;
4159
4160 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MESH_CONFIG);
4161 if (!msg)
4162 return -1;
4163
4164 ret = nl80211_put_mesh_config(msg, params);
4165 if (ret < 0) {
4166 nlmsg_free(msg);
4167 return ret;
4168 }
4169
4170 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4171 if (ret) {
4172 wpa_printf(MSG_ERROR,
4173 "nl80211: Mesh config set failed: %d (%s)",
4174 ret, strerror(-ret));
4175 return ret;
4176 }
4177 return 0;
4178}
4179#endif /* CONFIG_MESH */
4180
4181
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004182static int nl80211_put_beacon_rate(struct nl_msg *msg, const u64 flags,
4183 struct wpa_driver_ap_params *params)
4184{
4185 struct nlattr *bands, *band;
4186 struct nl80211_txrate_vht vht_rate;
4187
4188 if (!params->freq ||
4189 (params->beacon_rate == 0 &&
4190 params->rate_type == BEACON_RATE_LEGACY))
4191 return 0;
4192
4193 bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
4194 if (!bands)
4195 return -1;
4196
4197 switch (params->freq->mode) {
4198 case HOSTAPD_MODE_IEEE80211B:
4199 case HOSTAPD_MODE_IEEE80211G:
4200 band = nla_nest_start(msg, NL80211_BAND_2GHZ);
4201 break;
4202 case HOSTAPD_MODE_IEEE80211A:
4203 band = nla_nest_start(msg, NL80211_BAND_5GHZ);
4204 break;
4205 case HOSTAPD_MODE_IEEE80211AD:
4206 band = nla_nest_start(msg, NL80211_BAND_60GHZ);
4207 break;
4208 default:
4209 return 0;
4210 }
4211
4212 if (!band)
4213 return -1;
4214
4215 os_memset(&vht_rate, 0, sizeof(vht_rate));
4216
4217 switch (params->rate_type) {
4218 case BEACON_RATE_LEGACY:
4219 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY)) {
4220 wpa_printf(MSG_INFO,
4221 "nl80211: Driver does not support setting Beacon frame rate (legacy)");
4222 return -1;
4223 }
4224
4225 if (nla_put_u8(msg, NL80211_TXRATE_LEGACY,
4226 (u8) params->beacon_rate / 5) ||
4227 nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
4228 (params->freq->vht_enabled &&
4229 nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4230 &vht_rate)))
4231 return -1;
4232
4233 wpa_printf(MSG_DEBUG, " * beacon_rate = legacy:%u (* 100 kbps)",
4234 params->beacon_rate);
4235 break;
4236 case BEACON_RATE_HT:
4237 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_HT)) {
4238 wpa_printf(MSG_INFO,
4239 "nl80211: Driver does not support setting Beacon frame rate (HT)");
4240 return -1;
4241 }
4242 if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
4243 nla_put_u8(msg, NL80211_TXRATE_HT, params->beacon_rate) ||
4244 (params->freq->vht_enabled &&
4245 nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4246 &vht_rate)))
4247 return -1;
4248 wpa_printf(MSG_DEBUG, " * beacon_rate = HT-MCS %u",
4249 params->beacon_rate);
4250 break;
4251 case BEACON_RATE_VHT:
4252 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_VHT)) {
4253 wpa_printf(MSG_INFO,
4254 "nl80211: Driver does not support setting Beacon frame rate (VHT)");
4255 return -1;
4256 }
4257 vht_rate.mcs[0] = BIT(params->beacon_rate);
4258 if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL))
4259 return -1;
4260 if (nla_put(msg, NL80211_TXRATE_HT, 0, NULL))
4261 return -1;
4262 if (nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4263 &vht_rate))
4264 return -1;
4265 wpa_printf(MSG_DEBUG, " * beacon_rate = VHT-MCS %u",
4266 params->beacon_rate);
4267 break;
4268 }
4269
4270 nla_nest_end(msg, band);
4271 nla_nest_end(msg, bands);
4272
4273 return 0;
4274}
4275
4276
4277static int nl80211_set_multicast_to_unicast(struct i802_bss *bss,
4278 int multicast_to_unicast)
4279{
4280 struct wpa_driver_nl80211_data *drv = bss->drv;
4281 struct nl_msg *msg;
4282 int ret;
4283
4284 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_MULTICAST_TO_UNICAST);
4285 if (!msg ||
4286 (multicast_to_unicast &&
4287 nla_put_flag(msg, NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED))) {
4288 wpa_printf(MSG_ERROR,
4289 "nl80211: Failed to build NL80211_CMD_SET_MULTICAST_TO_UNICAST msg for %s",
4290 bss->ifname);
4291 nlmsg_free(msg);
4292 return -ENOBUFS;
4293 }
4294
4295 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4296
4297 switch (ret) {
4298 case 0:
4299 wpa_printf(MSG_DEBUG,
4300 "nl80211: multicast to unicast %s on interface %s",
4301 multicast_to_unicast ? "enabled" : "disabled",
4302 bss->ifname);
4303 break;
4304 case -EOPNOTSUPP:
4305 if (!multicast_to_unicast)
4306 break;
4307 wpa_printf(MSG_INFO,
4308 "nl80211: multicast to unicast not supported on interface %s",
4309 bss->ifname);
4310 break;
4311 default:
4312 wpa_printf(MSG_ERROR,
4313 "nl80211: %s multicast to unicast failed with %d (%s) on interface %s",
4314 multicast_to_unicast ? "enabling" : "disabling",
4315 ret, strerror(-ret), bss->ifname);
4316 break;
4317 }
4318
4319 return ret;
4320}
4321
4322
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004323static int wpa_driver_nl80211_set_ap(void *priv,
4324 struct wpa_driver_ap_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004325{
4326 struct i802_bss *bss = priv;
4327 struct wpa_driver_nl80211_data *drv = bss->drv;
4328 struct nl_msg *msg;
4329 u8 cmd = NL80211_CMD_NEW_BEACON;
Hai Shalom74f70d42019-02-11 14:42:39 -08004330 int ret = -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004331 int beacon_set;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004332 int num_suites;
Hai Shalomfdcde762020-04-02 11:19:20 -07004333 u32 suites[20], suite;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004334 u32 ver;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004335#ifdef CONFIG_MESH
4336 struct wpa_driver_mesh_bss_params mesh_params;
4337#endif /* CONFIG_MESH */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004338
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004339 beacon_set = params->reenable ? 0 : bss->beacon_set;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004340
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004341 wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
4342 beacon_set);
4343 if (beacon_set)
4344 cmd = NL80211_CMD_SET_BEACON;
Paul Stewart092955c2017-02-06 09:13:09 -08004345 else if (!drv->device_ap_sme && !drv->use_monitor &&
4346 !nl80211_get_wiphy_data_ap(bss))
4347 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004348
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004349 wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
4350 params->head, params->head_len);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004351 wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
4352 params->tail, params->tail_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004353 wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004354 wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004355 wpa_printf(MSG_DEBUG, "nl80211: beacon_rate=%u", params->beacon_rate);
4356 wpa_printf(MSG_DEBUG, "nl80211: rate_type=%d", params->rate_type);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004357 wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
Hai Shalom74f70d42019-02-11 14:42:39 -08004358 wpa_printf(MSG_DEBUG, "nl80211: ssid=%s",
4359 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004360 if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
4361 nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
4362 params->head) ||
4363 nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
4364 params->tail) ||
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004365 nl80211_put_beacon_int(msg, params->beacon_int) ||
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004366 nl80211_put_beacon_rate(msg, drv->capa.flags, params) ||
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004367 nl80211_put_dtim_period(msg, params->dtim_period) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004368 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
4369 goto fail;
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004370 if (params->proberesp && params->proberesp_len) {
4371 wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
4372 params->proberesp, params->proberesp_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004373 if (nla_put(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
4374 params->proberesp))
4375 goto fail;
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004376 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004377 switch (params->hide_ssid) {
4378 case NO_SSID_HIDING:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004379 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004380 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
4381 NL80211_HIDDEN_SSID_NOT_IN_USE))
4382 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004383 break;
4384 case HIDDEN_SSID_ZERO_LEN:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004385 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004386 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
4387 NL80211_HIDDEN_SSID_ZERO_LEN))
4388 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004389 break;
4390 case HIDDEN_SSID_ZERO_CONTENTS:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004391 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004392 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
4393 NL80211_HIDDEN_SSID_ZERO_CONTENTS))
4394 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004395 break;
4396 }
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004397 wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004398 if (params->privacy &&
4399 nla_put_flag(msg, NL80211_ATTR_PRIVACY))
4400 goto fail;
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004401 wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004402 if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
4403 (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
4404 /* Leave out the attribute */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004405 } else if (params->auth_algs & WPA_AUTH_ALG_SHARED) {
4406 if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
4407 NL80211_AUTHTYPE_SHARED_KEY))
4408 goto fail;
4409 } else {
4410 if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
4411 NL80211_AUTHTYPE_OPEN_SYSTEM))
4412 goto fail;
4413 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004414
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004415 wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004416 ver = 0;
4417 if (params->wpa_version & WPA_PROTO_WPA)
4418 ver |= NL80211_WPA_VERSION_1;
4419 if (params->wpa_version & WPA_PROTO_RSN)
4420 ver |= NL80211_WPA_VERSION_2;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004421 if (ver &&
4422 nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
4423 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004424
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004425 wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
4426 params->key_mgmt_suites);
Hai Shalomfdcde762020-04-02 11:19:20 -07004427 num_suites = wpa_key_mgmt_to_suites(params->key_mgmt_suites,
4428 suites, ARRAY_SIZE(suites));
4429 if (num_suites > NL80211_MAX_NR_AKM_SUITES)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004430 wpa_printf(MSG_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07004431 "nl80211: Not enough room for all AKM suites (num_suites=%d > NL80211_MAX_NR_AKM_SUITES)",
4432 num_suites);
4433 else if (num_suites &&
4434 nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
4435 suites))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004436 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004437
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004438 if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004439 (!params->pairwise_ciphers ||
4440 params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
4441 (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
4442 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004443 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004444
Hai Shalom81f62d82019-07-22 12:10:00 -07004445 if (drv->device_ap_sme &&
4446 (params->key_mgmt_suites & WPA_KEY_MGMT_SAE) &&
4447 nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
4448 goto fail;
Hai Shalom5f92bc92019-04-18 11:54:11 -07004449
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004450 wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
4451 params->pairwise_ciphers);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004452 num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers,
4453 suites, ARRAY_SIZE(suites));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004454 if (num_suites &&
4455 nla_put(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
4456 num_suites * sizeof(u32), suites))
4457 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004458
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004459 wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
4460 params->group_cipher);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004461 suite = wpa_cipher_to_cipher_suite(params->group_cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004462 if (suite &&
4463 nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
4464 goto fail;
4465
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004466 if (params->beacon_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004467 wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
4468 params->beacon_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004469 if (nla_put(msg, NL80211_ATTR_IE,
4470 wpabuf_len(params->beacon_ies),
4471 wpabuf_head(params->beacon_ies)))
4472 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004473 }
4474 if (params->proberesp_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004475 wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
4476 params->proberesp_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004477 if (nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
4478 wpabuf_len(params->proberesp_ies),
4479 wpabuf_head(params->proberesp_ies)))
4480 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004481 }
4482 if (params->assocresp_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004483 wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
4484 params->assocresp_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004485 if (nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
4486 wpabuf_len(params->assocresp_ies),
4487 wpabuf_head(params->assocresp_ies)))
4488 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004489 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004490
Dmitry Shmidt04949592012-07-19 12:16:46 -07004491 if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07004492 wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
4493 params->ap_max_inactivity);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004494 if (nla_put_u16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
4495 params->ap_max_inactivity))
4496 goto fail;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004497 }
4498
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004499#ifdef CONFIG_P2P
4500 if (params->p2p_go_ctwindow > 0) {
4501 if (drv->p2p_go_ctwindow_supported) {
4502 wpa_printf(MSG_DEBUG, "nl80211: P2P GO ctwindow=%d",
4503 params->p2p_go_ctwindow);
4504 if (nla_put_u8(msg, NL80211_ATTR_P2P_CTWINDOW,
4505 params->p2p_go_ctwindow))
4506 goto fail;
4507 } else {
4508 wpa_printf(MSG_INFO,
4509 "nl80211: Driver does not support CTWindow configuration - ignore this parameter");
4510 }
4511 }
4512#endif /* CONFIG_P2P */
4513
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004514 if (params->pbss) {
4515 wpa_printf(MSG_DEBUG, "nl80211: PBSS");
4516 if (nla_put_flag(msg, NL80211_ATTR_PBSS))
4517 goto fail;
4518 }
4519
Hai Shalom74f70d42019-02-11 14:42:39 -08004520 if (params->ftm_responder) {
4521 struct nlattr *ftm;
4522
4523 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_FTM_RESPONDER)) {
4524 ret = -ENOTSUP;
4525 goto fail;
4526 }
4527
4528 ftm = nla_nest_start(msg, NL80211_ATTR_FTM_RESPONDER);
4529 if (!ftm ||
4530 nla_put_flag(msg, NL80211_FTM_RESP_ATTR_ENABLED) ||
4531 (params->lci &&
4532 nla_put(msg, NL80211_FTM_RESP_ATTR_LCI,
4533 wpabuf_len(params->lci),
4534 wpabuf_head(params->lci))) ||
4535 (params->civic &&
4536 nla_put(msg, NL80211_FTM_RESP_ATTR_CIVICLOC,
4537 wpabuf_len(params->civic),
4538 wpabuf_head(params->civic))))
4539 goto fail;
4540 nla_nest_end(msg, ftm);
4541 }
4542
Hai Shalomc3565922019-10-28 11:58:20 -07004543#ifdef CONFIG_IEEE80211AX
4544 if (params->he_spr) {
4545 struct nlattr *spr;
4546
4547 spr = nla_nest_start(msg, NL80211_ATTR_HE_OBSS_PD);
4548 wpa_printf(MSG_DEBUG, "nl80211: he_spr=%d", params->he_spr);
4549
Hai Shalomfdcde762020-04-02 11:19:20 -07004550 if (!spr ||
4551 nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
Hai Shalomc3565922019-10-28 11:58:20 -07004552 params->he_spr_srg_obss_pd_min_offset) ||
4553 nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
4554 params->he_spr_srg_obss_pd_max_offset))
4555 goto fail;
4556
4557 nla_nest_end(msg, spr);
4558 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004559
4560 if (params->freq && params->freq->he_enabled) {
4561 struct nlattr *bss_color;
4562
4563 bss_color = nla_nest_start(msg, NL80211_ATTR_HE_BSS_COLOR);
4564 if (!bss_color ||
4565 (params->he_bss_color_disabled &&
4566 nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_DISABLED)) ||
4567 (params->he_bss_color_partial &&
4568 nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_PARTIAL)) ||
4569 nla_put_u8(msg, NL80211_HE_BSS_COLOR_ATTR_COLOR,
4570 params->he_bss_color))
4571 goto fail;
4572 nla_nest_end(msg, bss_color);
4573 }
4574
4575 if (params->twt_responder) {
4576 wpa_printf(MSG_DEBUG, "nl80211: twt_responder=%d",
4577 params->twt_responder);
4578 if (nla_put_flag(msg, NL80211_ATTR_TWT_RESPONDER))
4579 goto fail;
4580 }
Hai Shalomc3565922019-10-28 11:58:20 -07004581#endif /* CONFIG_IEEE80211AX */
4582
Hai Shalomb755a2a2020-04-23 21:49:02 -07004583 ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1,
4584 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004585 if (ret) {
4586 wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
4587 ret, strerror(-ret));
4588 } else {
4589 bss->beacon_set = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004590 nl80211_set_bss(bss, params->cts_protect, params->preamble,
4591 params->short_slot_time, params->ht_opmode,
4592 params->isolate, params->basic_rates);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004593 nl80211_set_multicast_to_unicast(bss,
4594 params->multicast_to_unicast);
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004595 if (beacon_set && params->freq &&
4596 params->freq->bandwidth != bss->bandwidth) {
4597 wpa_printf(MSG_DEBUG,
4598 "nl80211: Update BSS %s bandwidth: %d -> %d",
4599 bss->ifname, bss->bandwidth,
4600 params->freq->bandwidth);
4601 ret = nl80211_set_channel(bss, params->freq, 1);
4602 if (ret) {
4603 wpa_printf(MSG_DEBUG,
4604 "nl80211: Frequency set failed: %d (%s)",
4605 ret, strerror(-ret));
4606 } else {
4607 wpa_printf(MSG_DEBUG,
4608 "nl80211: Frequency set succeeded for ht2040 coex");
4609 bss->bandwidth = params->freq->bandwidth;
4610 }
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004611 } else if (!beacon_set && params->freq) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004612 /*
4613 * cfg80211 updates the driver on frequence change in AP
4614 * mode only at the point when beaconing is started, so
4615 * set the initial value here.
4616 */
4617 bss->bandwidth = params->freq->bandwidth;
4618 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004619 }
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004620
4621#ifdef CONFIG_MESH
4622 if (is_mesh_interface(drv->nlmode) && params->ht_opmode != -1) {
4623 os_memset(&mesh_params, 0, sizeof(mesh_params));
4624 mesh_params.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
4625 mesh_params.ht_opmode = params->ht_opmode;
4626 ret = nl80211_set_mesh_config(priv, &mesh_params);
4627 if (ret < 0)
4628 return ret;
4629 }
4630#endif /* CONFIG_MESH */
4631
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004632 return ret;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004633fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004634 nlmsg_free(msg);
Hai Shalom74f70d42019-02-11 14:42:39 -08004635 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004636}
4637
4638
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08004639static int nl80211_put_freq_params(struct nl_msg *msg,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004640 const struct hostapd_freq_params *freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004641{
Hai Shalomc3565922019-10-28 11:58:20 -07004642 enum hostapd_hw_mode hw_mode;
4643 int is_24ghz;
4644 u8 channel;
4645
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004646 wpa_printf(MSG_DEBUG, " * freq=%d", freq->freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004647 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
4648 return -ENOBUFS;
4649
Hai Shalom81f62d82019-07-22 12:10:00 -07004650 wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004651 wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
4652 wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
4653
Hai Shalomc3565922019-10-28 11:58:20 -07004654 hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
4655 is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
4656 hw_mode == HOSTAPD_MODE_IEEE80211B;
4657
4658 if (freq->vht_enabled || (freq->he_enabled && !is_24ghz)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004659 enum nl80211_chan_width cw;
4660
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004661 wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004662 switch (freq->bandwidth) {
4663 case 20:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004664 cw = NL80211_CHAN_WIDTH_20;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004665 break;
4666 case 40:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004667 cw = NL80211_CHAN_WIDTH_40;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004668 break;
4669 case 80:
4670 if (freq->center_freq2)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004671 cw = NL80211_CHAN_WIDTH_80P80;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004672 else
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004673 cw = NL80211_CHAN_WIDTH_80;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004674 break;
4675 case 160:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004676 cw = NL80211_CHAN_WIDTH_160;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004677 break;
4678 default:
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08004679 return -EINVAL;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004680 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004681
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004682 wpa_printf(MSG_DEBUG, " * channel_width=%d", cw);
4683 wpa_printf(MSG_DEBUG, " * center_freq1=%d",
4684 freq->center_freq1);
4685 wpa_printf(MSG_DEBUG, " * center_freq2=%d",
4686 freq->center_freq2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004687 if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) ||
4688 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1,
4689 freq->center_freq1) ||
4690 (freq->center_freq2 &&
4691 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2,
4692 freq->center_freq2)))
4693 return -ENOBUFS;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004694 } else if (freq->ht_enabled) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004695 enum nl80211_channel_type ct;
4696
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004697 wpa_printf(MSG_DEBUG, " * sec_channel_offset=%d",
4698 freq->sec_channel_offset);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004699 switch (freq->sec_channel_offset) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004700 case -1:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004701 ct = NL80211_CHAN_HT40MINUS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004702 break;
4703 case 1:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004704 ct = NL80211_CHAN_HT40PLUS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004705 break;
4706 default:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004707 ct = NL80211_CHAN_HT20;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004708 break;
4709 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004710
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004711 wpa_printf(MSG_DEBUG, " * channel_type=%d", ct);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004712 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
4713 return -ENOBUFS;
Hai Shalomc3565922019-10-28 11:58:20 -07004714 } else if (freq->edmg.channels && freq->edmg.bw_config) {
4715 wpa_printf(MSG_DEBUG,
4716 " * EDMG configuration: channels=0x%x bw_config=%d",
4717 freq->edmg.channels, freq->edmg.bw_config);
4718 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
4719 freq->edmg.channels) ||
4720 nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
4721 freq->edmg.bw_config))
4722 return -1;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004723 } else {
4724 wpa_printf(MSG_DEBUG, " * channel_type=%d",
4725 NL80211_CHAN_NO_HT);
4726 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
4727 NL80211_CHAN_NO_HT))
4728 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004729 }
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08004730 return 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08004731}
4732
4733
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07004734static int nl80211_set_channel(struct i802_bss *bss,
4735 struct hostapd_freq_params *freq, int set_chan)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08004736{
4737 struct wpa_driver_nl80211_data *drv = bss->drv;
4738 struct nl_msg *msg;
4739 int ret;
4740
4741 wpa_printf(MSG_DEBUG,
Hai Shalom81f62d82019-07-22 12:10:00 -07004742 "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
4743 freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08004744 freq->bandwidth, freq->center_freq1, freq->center_freq2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004745
4746 msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
4747 NL80211_CMD_SET_WIPHY);
4748 if (!msg || nl80211_put_freq_params(msg, freq) < 0) {
4749 nlmsg_free(msg);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08004750 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004751 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004752
4753 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004754 if (ret == 0) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004755 bss->freq = freq->freq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004756 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004757 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004758 wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004759 "%d (%s)", freq->freq, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004760 return -1;
4761}
4762
4763
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004764static u32 sta_flags_nl80211(int flags)
4765{
4766 u32 f = 0;
4767
4768 if (flags & WPA_STA_AUTHORIZED)
4769 f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
4770 if (flags & WPA_STA_WMM)
4771 f |= BIT(NL80211_STA_FLAG_WME);
4772 if (flags & WPA_STA_SHORT_PREAMBLE)
4773 f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
4774 if (flags & WPA_STA_MFP)
4775 f |= BIT(NL80211_STA_FLAG_MFP);
4776 if (flags & WPA_STA_TDLS_PEER)
4777 f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004778 if (flags & WPA_STA_AUTHENTICATED)
4779 f |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004780 if (flags & WPA_STA_ASSOCIATED)
4781 f |= BIT(NL80211_STA_FLAG_ASSOCIATED);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004782
4783 return f;
4784}
4785
4786
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004787#ifdef CONFIG_MESH
4788static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
4789{
4790 switch (state) {
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004791 case PLINK_IDLE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004792 return NL80211_PLINK_LISTEN;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004793 case PLINK_OPN_SNT:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004794 return NL80211_PLINK_OPN_SNT;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004795 case PLINK_OPN_RCVD:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004796 return NL80211_PLINK_OPN_RCVD;
4797 case PLINK_CNF_RCVD:
4798 return NL80211_PLINK_CNF_RCVD;
4799 case PLINK_ESTAB:
4800 return NL80211_PLINK_ESTAB;
4801 case PLINK_HOLDING:
4802 return NL80211_PLINK_HOLDING;
4803 case PLINK_BLOCKED:
4804 return NL80211_PLINK_BLOCKED;
4805 default:
4806 wpa_printf(MSG_ERROR, "nl80211: Invalid mesh plink state %d",
4807 state);
4808 }
4809 return -1;
4810}
4811#endif /* CONFIG_MESH */
4812
4813
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004814static int wpa_driver_nl80211_sta_add(void *priv,
4815 struct hostapd_sta_add_params *params)
4816{
4817 struct i802_bss *bss = priv;
4818 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07004819 struct nl_msg *msg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004820 struct nl80211_sta_flag_update upd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004821 int ret = -ENOBUFS;
4822
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004823 if ((params->flags & WPA_STA_TDLS_PEER) &&
4824 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
4825 return -EOPNOTSUPP;
4826
Dmitry Shmidtf8623282013-02-20 14:34:59 -08004827 wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
4828 params->set ? "Set" : "Add", MAC2STR(params->addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004829 msg = nl80211_bss_msg(bss, 0, params->set ? NL80211_CMD_SET_STATION :
4830 NL80211_CMD_NEW_STATION);
4831 if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
4832 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004833
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004834 /*
4835 * Set the below properties only in one of the following cases:
4836 * 1. New station is added, already associated.
4837 * 2. Set WPA_STA_TDLS_PEER station.
4838 * 3. Set an already added unassociated station, if driver supports
4839 * full AP client state. (Set these properties after station became
4840 * associated will be rejected by the driver).
4841 */
4842 if (!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
4843 (params->set && FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags) &&
4844 (params->flags & WPA_STA_ASSOCIATED))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004845 wpa_hexdump(MSG_DEBUG, " * supported rates",
4846 params->supp_rates, params->supp_rates_len);
4847 wpa_printf(MSG_DEBUG, " * capability=0x%x",
4848 params->capability);
4849 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_RATES,
4850 params->supp_rates_len, params->supp_rates) ||
4851 nla_put_u16(msg, NL80211_ATTR_STA_CAPABILITY,
4852 params->capability))
4853 goto fail;
4854
4855 if (params->ht_capabilities) {
4856 wpa_hexdump(MSG_DEBUG, " * ht_capabilities",
4857 (u8 *) params->ht_capabilities,
4858 sizeof(*params->ht_capabilities));
4859 if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY,
4860 sizeof(*params->ht_capabilities),
4861 params->ht_capabilities))
4862 goto fail;
4863 }
4864
4865 if (params->vht_capabilities) {
4866 wpa_hexdump(MSG_DEBUG, " * vht_capabilities",
4867 (u8 *) params->vht_capabilities,
4868 sizeof(*params->vht_capabilities));
4869 if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY,
4870 sizeof(*params->vht_capabilities),
4871 params->vht_capabilities))
4872 goto fail;
4873 }
4874
Hai Shalom81f62d82019-07-22 12:10:00 -07004875 if (params->he_capab) {
4876 wpa_hexdump(MSG_DEBUG, " * he_capab",
4877 params->he_capab, params->he_capab_len);
4878 if (nla_put(msg, NL80211_ATTR_HE_CAPABILITY,
4879 params->he_capab_len, params->he_capab))
4880 goto fail;
4881 }
4882
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004883 if (params->ext_capab) {
4884 wpa_hexdump(MSG_DEBUG, " * ext_capab",
4885 params->ext_capab, params->ext_capab_len);
4886 if (nla_put(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
4887 params->ext_capab_len, params->ext_capab))
4888 goto fail;
4889 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004890
4891 if (is_ap_interface(drv->nlmode) &&
4892 nla_put_u8(msg, NL80211_ATTR_STA_SUPPORT_P2P_PS,
4893 params->support_p2p_ps ?
4894 NL80211_P2P_PS_SUPPORTED :
4895 NL80211_P2P_PS_UNSUPPORTED))
4896 goto fail;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004897 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004898 if (!params->set) {
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07004899 if (params->aid) {
4900 wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004901 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid))
4902 goto fail;
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07004903 } else {
4904 /*
4905 * cfg80211 validates that AID is non-zero, so we have
4906 * to make this a non-zero value for the TDLS case where
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004907 * a dummy STA entry is used for now and for a station
4908 * that is still not associated.
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07004909 */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004910 wpa_printf(MSG_DEBUG, " * aid=1 (%s workaround)",
4911 (params->flags & WPA_STA_TDLS_PEER) ?
4912 "TDLS" : "UNASSOC_STA");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004913 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, 1))
4914 goto fail;
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07004915 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08004916 wpa_printf(MSG_DEBUG, " * listen_interval=%u",
4917 params->listen_interval);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004918 if (nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
4919 params->listen_interval))
4920 goto fail;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004921 } else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
4922 wpa_printf(MSG_DEBUG, " * peer_aid=%u", params->aid);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004923 if (nla_put_u16(msg, NL80211_ATTR_PEER_AID, params->aid))
4924 goto fail;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004925 } else if (FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags) &&
4926 (params->flags & WPA_STA_ASSOCIATED)) {
4927 wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
4928 wpa_printf(MSG_DEBUG, " * listen_interval=%u",
4929 params->listen_interval);
4930 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid) ||
4931 nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
4932 params->listen_interval))
4933 goto fail;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004934 }
4935
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08004936 if (params->vht_opmode_enabled) {
4937 wpa_printf(MSG_DEBUG, " * opmode=%u", params->vht_opmode);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004938 if (nla_put_u8(msg, NL80211_ATTR_OPMODE_NOTIF,
4939 params->vht_opmode))
4940 goto fail;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08004941 }
4942
Dmitry Shmidt344abd32014-01-14 13:17:00 -08004943 if (params->supp_channels) {
4944 wpa_hexdump(MSG_DEBUG, " * supported channels",
4945 params->supp_channels, params->supp_channels_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004946 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
4947 params->supp_channels_len, params->supp_channels))
4948 goto fail;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08004949 }
4950
4951 if (params->supp_oper_classes) {
4952 wpa_hexdump(MSG_DEBUG, " * supported operating classes",
4953 params->supp_oper_classes,
4954 params->supp_oper_classes_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004955 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
4956 params->supp_oper_classes_len,
4957 params->supp_oper_classes))
4958 goto fail;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08004959 }
4960
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004961 os_memset(&upd, 0, sizeof(upd));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004962 upd.set = sta_flags_nl80211(params->flags);
4963 upd.mask = upd.set | sta_flags_nl80211(params->flags_mask);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08004964
4965 /*
4966 * If the driver doesn't support full AP client state, ignore ASSOC/AUTH
4967 * flags, as nl80211 driver moves a new station, by default, into
4968 * associated state.
4969 *
4970 * On the other hand, if the driver supports that feature and the
4971 * station is added in unauthenticated state, set the
4972 * authenticated/associated bits in the mask to prevent moving this
4973 * station to associated state before it is actually associated.
4974 *
4975 * This is irrelevant for mesh mode where the station is added to the
4976 * driver as authenticated already, and ASSOCIATED isn't part of the
4977 * nl80211 API.
4978 */
4979 if (!is_mesh_interface(drv->nlmode)) {
4980 if (!FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) {
4981 wpa_printf(MSG_DEBUG,
4982 "nl80211: Ignore ASSOC/AUTH flags since driver doesn't support full AP client state");
4983 upd.mask &= ~(BIT(NL80211_STA_FLAG_ASSOCIATED) |
4984 BIT(NL80211_STA_FLAG_AUTHENTICATED));
4985 } else if (!params->set &&
4986 !(params->flags & WPA_STA_TDLS_PEER)) {
4987 if (!(params->flags & WPA_STA_AUTHENTICATED))
4988 upd.mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
4989 if (!(params->flags & WPA_STA_ASSOCIATED))
4990 upd.mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
4991 }
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004992#ifdef CONFIG_MESH
4993 } else {
4994 if (params->plink_state == PLINK_ESTAB && params->peer_aid) {
4995 ret = nla_put_u16(msg, NL80211_ATTR_MESH_PEER_AID,
4996 params->peer_aid);
4997 if (ret)
4998 goto fail;
4999 }
5000#endif /* CONFIG_MESH */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005001 }
5002
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005003 wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x",
5004 upd.set, upd.mask);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005005 if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
5006 goto fail;
5007
5008#ifdef CONFIG_MESH
5009 if (params->plink_state &&
5010 nla_put_u8(msg, NL80211_ATTR_STA_PLINK_STATE,
5011 sta_plink_state_nl80211(params->plink_state)))
5012 goto fail;
5013#endif /* CONFIG_MESH */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005014
Hai Shalomc3565922019-10-28 11:58:20 -07005015 if ((!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
5016 FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) &&
5017 (params->flags & WPA_STA_WMM)) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005018 struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
5019
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005020 wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005021 if (!wme ||
5022 nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
5023 params->qosinfo & WMM_QOSINFO_STA_AC_MASK) ||
5024 nla_put_u8(msg, NL80211_STA_WME_MAX_SP,
5025 (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
5026 WMM_QOSINFO_STA_SP_MASK))
5027 goto fail;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005028 nla_nest_end(msg, wme);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005029 }
5030
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005031 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005032 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005033 if (ret)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005034 wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
5035 "result: %d (%s)", params->set ? "SET" : "NEW", ret,
5036 strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005037 if (ret == -EEXIST)
5038 ret = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005039fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005040 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005041 return ret;
5042}
5043
5044
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005045static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr)
5046{
5047#ifdef CONFIG_LIBNL3_ROUTE
5048 struct wpa_driver_nl80211_data *drv = bss->drv;
5049 struct rtnl_neigh *rn;
5050 struct nl_addr *nl_addr;
5051 int err;
5052
5053 rn = rtnl_neigh_alloc();
5054 if (!rn)
5055 return;
5056
5057 rtnl_neigh_set_family(rn, AF_BRIDGE);
5058 rtnl_neigh_set_ifindex(rn, bss->ifindex);
5059 nl_addr = nl_addr_build(AF_BRIDGE, (void *) addr, ETH_ALEN);
5060 if (!nl_addr) {
5061 rtnl_neigh_put(rn);
5062 return;
5063 }
5064 rtnl_neigh_set_lladdr(rn, nl_addr);
5065
5066 err = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
5067 if (err < 0) {
5068 wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for "
5069 MACSTR " ifindex=%d failed: %s", MAC2STR(addr),
5070 bss->ifindex, nl_geterror(err));
5071 } else {
5072 wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry for "
5073 MACSTR, MAC2STR(addr));
5074 }
5075
5076 nl_addr_put(nl_addr);
5077 rtnl_neigh_put(rn);
5078#endif /* CONFIG_LIBNL3_ROUTE */
5079}
5080
5081
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005082static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
5083 int deauth, u16 reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005084{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005085 struct wpa_driver_nl80211_data *drv = bss->drv;
5086 struct nl_msg *msg;
5087 int ret;
5088
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005089 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION)) ||
5090 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
5091 (deauth == 0 &&
5092 nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
5093 WLAN_FC_STYPE_DISASSOC)) ||
5094 (deauth == 1 &&
5095 nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
5096 WLAN_FC_STYPE_DEAUTH)) ||
5097 (reason_code &&
5098 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code))) {
5099 nlmsg_free(msg);
5100 return -ENOBUFS;
5101 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005102
5103 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07005104 wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
5105 " --> %d (%s)",
5106 bss->ifname, MAC2STR(addr), ret, strerror(-ret));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005107
5108 if (drv->rtnl_sk)
5109 rtnl_neigh_delete_fdb_entry(bss, addr);
5110
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005111 if (ret == -ENOENT)
5112 return 0;
5113 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005114}
5115
5116
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005117void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005118{
5119 struct nl_msg *msg;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005120 struct wpa_driver_nl80211_data *drv2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005121
5122 wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
5123
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005124 /* stop listening for EAPOL on this interface */
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005125 dl_list_for_each(drv2, &drv->global->interfaces,
5126 struct wpa_driver_nl80211_data, list)
Dmitry Shmidt9c175262016-03-03 10:20:07 -08005127 {
5128 del_ifidx(drv2, ifidx, IFIDX_ANY);
5129 /* Remove all bridges learned for this iface */
5130 del_ifidx(drv2, IFIDX_ANY, ifidx);
5131 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005132
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005133 msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005134 if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
5135 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005136 wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
5137}
5138
5139
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07005140const char * nl80211_iftype_str(enum nl80211_iftype mode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005141{
5142 switch (mode) {
5143 case NL80211_IFTYPE_ADHOC:
5144 return "ADHOC";
5145 case NL80211_IFTYPE_STATION:
5146 return "STATION";
5147 case NL80211_IFTYPE_AP:
5148 return "AP";
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07005149 case NL80211_IFTYPE_AP_VLAN:
5150 return "AP_VLAN";
5151 case NL80211_IFTYPE_WDS:
5152 return "WDS";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005153 case NL80211_IFTYPE_MONITOR:
5154 return "MONITOR";
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07005155 case NL80211_IFTYPE_MESH_POINT:
5156 return "MESH_POINT";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005157 case NL80211_IFTYPE_P2P_CLIENT:
5158 return "P2P_CLIENT";
5159 case NL80211_IFTYPE_P2P_GO:
5160 return "P2P_GO";
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005161 case NL80211_IFTYPE_P2P_DEVICE:
5162 return "P2P_DEVICE";
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005163 case NL80211_IFTYPE_OCB:
5164 return "OCB";
5165 case NL80211_IFTYPE_NAN:
5166 return "NAN";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005167 default:
5168 return "unknown";
5169 }
5170}
5171
5172
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005173static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
5174 const char *ifname,
5175 enum nl80211_iftype iftype,
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005176 const u8 *addr, int wds,
5177 int (*handler)(struct nl_msg *, void *),
5178 void *arg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005179{
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005180 struct nl_msg *msg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005181 int ifidx;
5182 int ret = -ENOBUFS;
5183
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005184 wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
5185 iftype, nl80211_iftype_str(iftype));
5186
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005187 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_NEW_INTERFACE);
5188 if (!msg ||
5189 nla_put_string(msg, NL80211_ATTR_IFNAME, ifname) ||
5190 nla_put_u32(msg, NL80211_ATTR_IFTYPE, iftype))
5191 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005192
5193 if (iftype == NL80211_IFTYPE_MONITOR) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005194 struct nlattr *flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005195
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005196 flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005197 if (!flags ||
5198 nla_put_flag(msg, NL80211_MNTR_FLAG_COOK_FRAMES))
5199 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005200
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005201 nla_nest_end(msg, flags);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005202 } else if (wds) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005203 if (nla_put_u8(msg, NL80211_ATTR_4ADDR, wds))
5204 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005205 }
5206
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07005207 /*
5208 * Tell cfg80211 that the interface belongs to the socket that created
5209 * it, and the interface should be deleted when the socket is closed.
5210 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005211 if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
5212 goto fail;
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07005213
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005214 ret = send_and_recv_msgs(drv, msg, handler, arg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005215 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005216 if (ret) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005217 fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005218 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005219 wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
5220 ifname, ret, strerror(-ret));
5221 return ret;
5222 }
5223
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005224 if (iftype == NL80211_IFTYPE_P2P_DEVICE)
5225 return 0;
5226
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005227 ifidx = if_nametoindex(ifname);
5228 wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
5229 ifname, ifidx);
5230
5231 if (ifidx <= 0)
5232 return -1;
5233
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005234 /*
5235 * Some virtual interfaces need to process EAPOL packets and events on
5236 * the parent interface. This is used mainly with hostapd.
5237 */
5238 if (drv->hostapd ||
5239 iftype == NL80211_IFTYPE_AP_VLAN ||
5240 iftype == NL80211_IFTYPE_WDS ||
5241 iftype == NL80211_IFTYPE_MONITOR) {
5242 /* start listening for EAPOL on this interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08005243 add_ifidx(drv, ifidx, IFIDX_ANY);
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07005244 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005245
5246 if (addr && iftype != NL80211_IFTYPE_MONITOR &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005247 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005248 nl80211_remove_iface(drv, ifidx);
5249 return -1;
5250 }
5251
5252 return ifidx;
5253}
5254
5255
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005256int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
5257 const char *ifname, enum nl80211_iftype iftype,
5258 const u8 *addr, int wds,
5259 int (*handler)(struct nl_msg *, void *),
5260 void *arg, int use_existing)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005261{
5262 int ret;
5263
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005264 ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
5265 arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005266
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005267 /* if error occurred and interface exists already */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005268 if (ret == -ENFILE && if_nametoindex(ifname)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005269 if (use_existing) {
5270 wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s",
5271 ifname);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07005272 if (addr && iftype != NL80211_IFTYPE_MONITOR &&
5273 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
5274 addr) < 0 &&
5275 (linux_set_iface_flags(drv->global->ioctl_sock,
5276 ifname, 0) < 0 ||
5277 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
5278 addr) < 0 ||
5279 linux_set_iface_flags(drv->global->ioctl_sock,
5280 ifname, 1) < 0))
5281 return -1;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005282 return -ENFILE;
5283 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005284 wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
5285
5286 /* Try to remove the interface that was already there. */
5287 nl80211_remove_iface(drv, if_nametoindex(ifname));
5288
5289 /* Try to create the interface again */
5290 ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
Dmitry Shmidt34af3062013-07-11 10:46:32 -07005291 wds, handler, arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005292 }
5293
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005294 if (ret >= 0 && is_p2p_net_interface(iftype)) {
5295 wpa_printf(MSG_DEBUG,
5296 "nl80211: Interface %s created for P2P - disable 11b rates",
5297 ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005298 nl80211_disable_11b_rates(drv, ret, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005299 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005300
5301 return ret;
5302}
5303
5304
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005305static int nl80211_setup_ap(struct i802_bss *bss)
5306{
5307 struct wpa_driver_nl80211_data *drv = bss->drv;
5308
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005309 wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d use_monitor=%d",
5310 bss->ifname, drv->device_ap_sme, drv->use_monitor);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005311
5312 /*
5313 * Disable Probe Request reporting unless we need it in this way for
5314 * devices that include the AP SME, in the other case (unless using
5315 * monitor iface) we'll get it through the nl_mgmt socket instead.
5316 */
5317 if (!drv->device_ap_sme)
5318 wpa_driver_nl80211_probe_req_report(bss, 0);
5319
5320 if (!drv->device_ap_sme && !drv->use_monitor)
5321 if (nl80211_mgmt_subscribe_ap(bss))
5322 return -1;
5323
5324 if (drv->device_ap_sme && !drv->use_monitor)
5325 if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005326 wpa_printf(MSG_DEBUG,
5327 "nl80211: Failed to subscribe for mgmt frames from SME driver - trying to run without it");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005328
5329 if (!drv->device_ap_sme && drv->use_monitor &&
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07005330 nl80211_create_monitor_interface(drv) &&
5331 !drv->device_ap_sme)
Dmitry Shmidt04949592012-07-19 12:16:46 -07005332 return -1;
5333
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005334 if (drv->device_ap_sme &&
5335 wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
5336 wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
5337 "Probe Request frame reporting in AP mode");
5338 /* Try to survive without this */
5339 }
5340
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005341 return 0;
5342}
5343
5344
5345static void nl80211_teardown_ap(struct i802_bss *bss)
5346{
5347 struct wpa_driver_nl80211_data *drv = bss->drv;
5348
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005349 wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d use_monitor=%d",
5350 bss->ifname, drv->device_ap_sme, drv->use_monitor);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005351 if (drv->device_ap_sme) {
5352 wpa_driver_nl80211_probe_req_report(bss, 0);
5353 if (!drv->use_monitor)
5354 nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
5355 } else if (drv->use_monitor)
5356 nl80211_remove_monitor_interface(drv);
5357 else
5358 nl80211_mgmt_unsubscribe(bss, "AP teardown");
5359
Paul Stewart092955c2017-02-06 09:13:09 -08005360 nl80211_put_wiphy_data_ap(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005361 bss->beacon_set = 0;
5362}
5363
5364
Hai Shalomfdcde762020-04-02 11:19:20 -07005365static int nl80211_tx_control_port(void *priv, const u8 *dest,
5366 u16 proto, const u8 *buf, size_t len,
5367 int no_encrypt)
5368{
5369 struct i802_bss *bss = priv;
5370 struct nl_msg *msg;
5371 int ret;
5372
5373 wpa_printf(MSG_DEBUG,
5374 "nl80211: Send over control port dest=" MACSTR
5375 " proto=0x%04x len=%u no_encrypt=%d",
5376 MAC2STR(dest), proto, (unsigned int) len, no_encrypt);
5377
5378 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CONTROL_PORT_FRAME);
5379 if (!msg ||
5380 nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
5381 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dest) ||
5382 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
5383 (no_encrypt &&
5384 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) {
5385 nlmsg_free(msg);
5386 return -ENOBUFS;
5387 }
5388
5389 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
5390 if (ret)
5391 wpa_printf(MSG_DEBUG,
5392 "nl80211: tx_control_port failed: ret=%d (%s)",
5393 ret, strerror(-ret));
5394
5395 return ret;
5396}
5397
5398
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005399static int nl80211_send_eapol_data(struct i802_bss *bss,
5400 const u8 *addr, const u8 *data,
5401 size_t data_len)
5402{
5403 struct sockaddr_ll ll;
5404 int ret;
5405
5406 if (bss->drv->eapol_tx_sock < 0) {
5407 wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
5408 return -1;
5409 }
5410
5411 os_memset(&ll, 0, sizeof(ll));
5412 ll.sll_family = AF_PACKET;
5413 ll.sll_ifindex = bss->ifindex;
5414 ll.sll_protocol = htons(ETH_P_PAE);
5415 ll.sll_halen = ETH_ALEN;
5416 os_memcpy(ll.sll_addr, addr, ETH_ALEN);
5417 ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
5418 (struct sockaddr *) &ll, sizeof(ll));
5419 if (ret < 0)
5420 wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
5421 strerror(errno));
5422
5423 return ret;
5424}
5425
5426
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005427static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
5428
5429static int wpa_driver_nl80211_hapd_send_eapol(
5430 void *priv, const u8 *addr, const u8 *data,
5431 size_t data_len, int encrypt, const u8 *own_addr, u32 flags)
5432{
5433 struct i802_bss *bss = priv;
5434 struct wpa_driver_nl80211_data *drv = bss->drv;
5435 struct ieee80211_hdr *hdr;
5436 size_t len;
5437 u8 *pos;
5438 int res;
5439 int qos = flags & WPA_STA_WMM;
Dmitry Shmidt641185e2013-11-06 15:17:13 -08005440
Hai Shalomb755a2a2020-04-23 21:49:02 -07005441 /* For now, disable EAPOL TX over control port in AP mode by default
5442 * since it does not provide TX status notifications. */
5443 if (drv->control_port_ap &&
5444 (drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT))
Hai Shalomfdcde762020-04-02 11:19:20 -07005445 return nl80211_tx_control_port(bss, addr, ETH_P_EAPOL,
5446 data, data_len, !encrypt);
5447
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005448 if (drv->device_ap_sme || !drv->use_monitor)
5449 return nl80211_send_eapol_data(bss, addr, data, data_len);
5450
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005451 len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
5452 data_len;
5453 hdr = os_zalloc(len);
5454 if (hdr == NULL) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07005455 wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)",
5456 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005457 return -1;
5458 }
5459
5460 hdr->frame_control =
5461 IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
5462 hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
5463 if (encrypt)
5464 hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
5465 if (qos) {
5466 hdr->frame_control |=
5467 host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
5468 }
5469
5470 memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
5471 memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
5472 memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
5473 pos = (u8 *) (hdr + 1);
5474
5475 if (qos) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07005476 /* Set highest priority in QoS header */
5477 pos[0] = 7;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005478 pos[1] = 0;
5479 pos += 2;
5480 }
5481
5482 memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
5483 pos += sizeof(rfc1042_header);
5484 WPA_PUT_BE16(pos, ETH_P_PAE);
5485 pos += 2;
5486 memcpy(pos, data, data_len);
5487
Hai Shalomfdcde762020-04-02 11:19:20 -07005488 res = nl80211_send_monitor(drv, hdr, len, encrypt, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005489 if (res < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005490 wpa_printf(MSG_ERROR,
5491 "hapd_send_eapol - packet len: %lu - failed",
5492 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005493 }
5494 os_free(hdr);
5495
5496 return res;
5497}
5498
5499
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005500static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005501 unsigned int total_flags,
5502 unsigned int flags_or,
5503 unsigned int flags_and)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005504{
5505 struct i802_bss *bss = priv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005506 struct nl_msg *msg;
5507 struct nlattr *flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005508 struct nl80211_sta_flag_update upd;
5509
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005510 wpa_printf(MSG_DEBUG, "nl80211: Set STA flags - ifname=%s addr=" MACSTR
5511 " total_flags=0x%x flags_or=0x%x flags_and=0x%x authorized=%d",
5512 bss->ifname, MAC2STR(addr), total_flags, flags_or, flags_and,
5513 !!(total_flags & WPA_STA_AUTHORIZED));
5514
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005515 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
5516 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
5517 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005518
5519 /*
5520 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
5521 * can be removed eventually.
5522 */
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005523 flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005524 if (!flags ||
5525 ((total_flags & WPA_STA_AUTHORIZED) &&
5526 nla_put_flag(msg, NL80211_STA_FLAG_AUTHORIZED)) ||
5527 ((total_flags & WPA_STA_WMM) &&
5528 nla_put_flag(msg, NL80211_STA_FLAG_WME)) ||
5529 ((total_flags & WPA_STA_SHORT_PREAMBLE) &&
5530 nla_put_flag(msg, NL80211_STA_FLAG_SHORT_PREAMBLE)) ||
5531 ((total_flags & WPA_STA_MFP) &&
5532 nla_put_flag(msg, NL80211_STA_FLAG_MFP)) ||
5533 ((total_flags & WPA_STA_TDLS_PEER) &&
5534 nla_put_flag(msg, NL80211_STA_FLAG_TDLS_PEER)))
5535 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005536
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005537 nla_nest_end(msg, flags);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005538
5539 os_memset(&upd, 0, sizeof(upd));
5540 upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
5541 upd.set = sta_flags_nl80211(flags_or);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005542 if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
5543 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005544
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005545 return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
5546fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005547 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005548 return -ENOBUFS;
5549}
5550
5551
Hai Shalom81f62d82019-07-22 12:10:00 -07005552static int driver_nl80211_sta_set_airtime_weight(void *priv, const u8 *addr,
5553 unsigned int weight)
5554{
5555 struct i802_bss *bss = priv;
5556 struct nl_msg *msg;
5557
5558 wpa_printf(MSG_DEBUG,
5559 "nl80211: Set STA airtime weight - ifname=%s addr=" MACSTR
5560 " weight=%u", bss->ifname, MAC2STR(addr), weight);
5561
5562 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
5563 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
5564 nla_put_u16(msg, NL80211_ATTR_AIRTIME_WEIGHT, weight))
5565 goto fail;
5566
5567 return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
5568fail:
5569 nlmsg_free(msg);
5570 return -ENOBUFS;
5571}
5572
5573
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005574static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
5575 struct wpa_driver_associate_params *params)
5576{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005577 enum nl80211_iftype nlmode, old_mode;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005578
5579 if (params->p2p) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005580 wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
5581 "group (GO)");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005582 nlmode = NL80211_IFTYPE_P2P_GO;
5583 } else
5584 nlmode = NL80211_IFTYPE_AP;
5585
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005586 old_mode = drv->nlmode;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005587 if (wpa_driver_nl80211_set_mode(drv->first_bss, nlmode)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005588 nl80211_remove_monitor_interface(drv);
5589 return -1;
5590 }
5591
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08005592 if (params->freq.freq &&
5593 nl80211_set_channel(drv->first_bss, &params->freq, 0)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005594 if (old_mode != nlmode)
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005595 wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005596 nl80211_remove_monitor_interface(drv);
5597 return -1;
5598 }
5599
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005600 return 0;
5601}
5602
5603
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005604static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
5605 int reset_mode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005606{
5607 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005608 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005609
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005610 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
Hai Shalomb755a2a2020-04-23 21:49:02 -07005611 ret = send_and_recv_msgs_owner(drv, msg,
5612 get_connect_handle(drv->first_bss), 1,
5613 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005614 if (ret) {
5615 wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
5616 "(%s)", ret, strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005617 } else {
5618 wpa_printf(MSG_DEBUG,
5619 "nl80211: Leave IBSS request sent successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005620 }
5621
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005622 if (reset_mode &&
5623 wpa_driver_nl80211_set_mode(drv->first_bss,
Dmitry Shmidt56052862013-10-04 10:23:25 -07005624 NL80211_IFTYPE_STATION)) {
5625 wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
5626 "station mode");
5627 }
5628
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005629 return ret;
5630}
5631
5632
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005633static int nl80211_ht_vht_overrides(struct nl_msg *msg,
5634 struct wpa_driver_associate_params *params)
5635{
5636 if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
5637 return -1;
5638
5639 if (params->htcaps && params->htcaps_mask) {
5640 int sz = sizeof(struct ieee80211_ht_capabilities);
5641 wpa_hexdump(MSG_DEBUG, " * htcaps", params->htcaps, sz);
5642 wpa_hexdump(MSG_DEBUG, " * htcaps_mask",
5643 params->htcaps_mask, sz);
5644 if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
5645 params->htcaps) ||
5646 nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
5647 params->htcaps_mask))
5648 return -1;
5649 }
5650
5651#ifdef CONFIG_VHT_OVERRIDES
5652 if (params->disable_vht) {
5653 wpa_printf(MSG_DEBUG, " * VHT disabled");
5654 if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
5655 return -1;
5656 }
5657
5658 if (params->vhtcaps && params->vhtcaps_mask) {
5659 int sz = sizeof(struct ieee80211_vht_capabilities);
5660 wpa_hexdump(MSG_DEBUG, " * vhtcaps", params->vhtcaps, sz);
5661 wpa_hexdump(MSG_DEBUG, " * vhtcaps_mask",
5662 params->vhtcaps_mask, sz);
5663 if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
5664 params->vhtcaps) ||
5665 nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
5666 params->vhtcaps_mask))
5667 return -1;
5668 }
5669#endif /* CONFIG_VHT_OVERRIDES */
5670
5671 return 0;
5672}
5673
5674
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005675static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
5676 struct wpa_driver_associate_params *params)
5677{
5678 struct nl_msg *msg;
5679 int ret = -1;
5680 int count = 0;
5681
5682 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
5683
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07005684 if (wpa_driver_nl80211_set_mode_ibss(drv->first_bss, &params->freq)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005685 wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
5686 "IBSS mode");
5687 return -1;
5688 }
5689
5690retry:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005691 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_IBSS)) ||
5692 params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
5693 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005694
Hai Shalom74f70d42019-02-11 14:42:39 -08005695 wpa_printf(MSG_DEBUG, " * SSID=%s",
5696 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005697 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
5698 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005699 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
5700 drv->ssid_len = params->ssid_len;
5701
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005702 if (nl80211_put_freq_params(msg, &params->freq) < 0 ||
5703 nl80211_put_beacon_int(msg, params->beacon_int))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005704 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005705
5706 ret = nl80211_set_conn_keys(params, msg);
5707 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005708 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005709
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005710 if (params->bssid && params->fixed_bssid) {
5711 wpa_printf(MSG_DEBUG, " * BSSID=" MACSTR,
5712 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005713 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
5714 goto fail;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005715 }
5716
Dmitry Shmidt7f656022015-02-25 14:36:37 -08005717 if (params->fixed_freq) {
5718 wpa_printf(MSG_DEBUG, " * fixed_freq");
5719 if (nla_put_flag(msg, NL80211_ATTR_FREQ_FIXED))
5720 goto fail;
5721 }
5722
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005723 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
5724 params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
5725 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
5726 params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005727 wpa_printf(MSG_DEBUG, " * control port");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005728 if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
5729 goto fail;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005730 }
5731
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005732 if (params->wpa_ie) {
5733 wpa_hexdump(MSG_DEBUG,
5734 " * Extra IEs for Beacon/Probe Response frames",
5735 params->wpa_ie, params->wpa_ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005736 if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
5737 params->wpa_ie))
5738 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005739 }
5740
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08005741 ret = nl80211_ht_vht_overrides(msg, params);
5742 if (ret < 0)
5743 goto fail;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08005744
Hai Shalomb755a2a2020-04-23 21:49:02 -07005745 ret = send_and_recv_msgs_owner(drv, msg,
5746 get_connect_handle(drv->first_bss), 1,
5747 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005748 msg = NULL;
5749 if (ret) {
5750 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
5751 ret, strerror(-ret));
5752 count++;
5753 if (ret == -EALREADY && count == 1) {
5754 wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
5755 "forced leave");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005756 nl80211_leave_ibss(drv, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005757 nlmsg_free(msg);
5758 goto retry;
5759 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005760 } else {
5761 wpa_printf(MSG_DEBUG,
5762 "nl80211: Join IBSS request sent successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005763 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005764
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005765fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005766 nlmsg_free(msg);
5767 return ret;
5768}
5769
5770
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005771static int nl80211_put_fils_connect_params(struct wpa_driver_nl80211_data *drv,
5772 struct wpa_driver_associate_params *params,
5773 struct nl_msg *msg)
5774{
5775 if (params->fils_erp_username_len) {
5776 wpa_hexdump_ascii(MSG_DEBUG, " * FILS ERP EMSKname/username",
5777 params->fils_erp_username,
5778 params->fils_erp_username_len);
5779 if (nla_put(msg, NL80211_ATTR_FILS_ERP_USERNAME,
5780 params->fils_erp_username_len,
5781 params->fils_erp_username))
5782 return -1;
5783 }
5784
5785 if (params->fils_erp_realm_len) {
5786 wpa_hexdump_ascii(MSG_DEBUG, " * FILS ERP Realm",
5787 params->fils_erp_realm,
5788 params->fils_erp_realm_len);
5789 if (nla_put(msg, NL80211_ATTR_FILS_ERP_REALM,
5790 params->fils_erp_realm_len, params->fils_erp_realm))
5791 return -1;
5792 }
5793
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005794 if (params->fils_erp_rrk_len) {
Vinita S. Maloo3a5b4412020-05-19 17:43:22 +05305795 wpa_printf(MSG_DEBUG, " * FILS ERP next seq %u",
5796 params->fils_erp_next_seq_num);
5797 if (nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
5798 params->fils_erp_next_seq_num))
5799 return -1;
5800
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005801 wpa_printf(MSG_DEBUG, " * FILS ERP rRK (len=%lu)",
5802 (unsigned long) params->fils_erp_rrk_len);
5803 if (nla_put(msg, NL80211_ATTR_FILS_ERP_RRK,
5804 params->fils_erp_rrk_len, params->fils_erp_rrk))
5805 return -1;
5806 }
5807
5808 return 0;
5809}
5810
5811
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005812static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
5813 struct wpa_driver_associate_params *params,
5814 struct nl_msg *msg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005815{
Paul Stewart092955c2017-02-06 09:13:09 -08005816 if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
5817 return -1;
5818
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005819 if (params->bssid) {
5820 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
5821 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005822 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
5823 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005824 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005825
Dmitry Shmidt96be6222014-02-13 10:16:51 -08005826 if (params->bssid_hint) {
5827 wpa_printf(MSG_DEBUG, " * bssid_hint=" MACSTR,
5828 MAC2STR(params->bssid_hint));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005829 if (nla_put(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
5830 params->bssid_hint))
5831 return -1;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08005832 }
5833
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07005834 if (params->freq.freq) {
5835 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq.freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005836 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
5837 params->freq.freq))
5838 return -1;
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07005839 drv->assoc_freq = params->freq.freq;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07005840 } else
5841 drv->assoc_freq = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005842
Dmitry Shmidt96be6222014-02-13 10:16:51 -08005843 if (params->freq_hint) {
5844 wpa_printf(MSG_DEBUG, " * freq_hint=%d", params->freq_hint);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005845 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_HINT,
5846 params->freq_hint))
5847 return -1;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08005848 }
5849
Hai Shalomc3565922019-10-28 11:58:20 -07005850 if (params->freq.edmg.channels && params->freq.edmg.bw_config) {
5851 wpa_printf(MSG_DEBUG,
5852 " * EDMG configuration: channels=0x%x bw_config=%d",
5853 params->freq.edmg.channels,
5854 params->freq.edmg.bw_config);
5855 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
5856 params->freq.edmg.channels) ||
5857 nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
5858 params->freq.edmg.bw_config))
5859 return -1;
5860 }
5861
Dmitry Shmidt04949592012-07-19 12:16:46 -07005862 if (params->bg_scan_period >= 0) {
5863 wpa_printf(MSG_DEBUG, " * bg scan period=%d",
5864 params->bg_scan_period);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005865 if (nla_put_u16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
5866 params->bg_scan_period))
5867 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005868 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005869
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005870 if (params->ssid) {
Hai Shalom74f70d42019-02-11 14:42:39 -08005871 wpa_printf(MSG_DEBUG, " * SSID=%s",
5872 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005873 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
5874 params->ssid))
5875 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005876 if (params->ssid_len > sizeof(drv->ssid))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005877 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005878 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
5879 drv->ssid_len = params->ssid_len;
5880 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005881
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005882 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005883 if (params->wpa_ie &&
5884 nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie))
5885 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005886
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005887 if (params->wpa_proto) {
5888 enum nl80211_wpa_versions ver = 0;
5889
5890 if (params->wpa_proto & WPA_PROTO_WPA)
5891 ver |= NL80211_WPA_VERSION_1;
5892 if (params->wpa_proto & WPA_PROTO_RSN)
5893 ver |= NL80211_WPA_VERSION_2;
5894
5895 wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005896 if (nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
5897 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005898 }
5899
5900 if (params->pairwise_suite != WPA_CIPHER_NONE) {
5901 u32 cipher = wpa_cipher_to_cipher_suite(params->pairwise_suite);
5902 wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005903 if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
5904 cipher))
5905 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005906 }
5907
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08005908 if (params->group_suite == WPA_CIPHER_GTK_NOT_USED &&
5909 !(drv->capa.enc & WPA_DRIVER_CAPA_ENC_GTK_NOT_USED)) {
5910 /*
5911 * This is likely to work even though many drivers do not
5912 * advertise support for operations without GTK.
5913 */
5914 wpa_printf(MSG_DEBUG, " * skip group cipher configuration for GTK_NOT_USED due to missing driver support advertisement");
5915 } else if (params->group_suite != WPA_CIPHER_NONE) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005916 u32 cipher = wpa_cipher_to_cipher_suite(params->group_suite);
5917 wpa_printf(MSG_DEBUG, " * group=0x%x", cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005918 if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher))
5919 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005920 }
5921
5922 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
5923 params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
5924 params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X ||
5925 params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
Dmitry Shmidt15907092014-03-25 10:42:57 -07005926 params->key_mgmt_suite == WPA_KEY_MGMT_CCKM ||
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07005927 params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
5928 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005929 params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
Hai Shalom021b0b52019-04-10 11:17:58 -07005930 params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
5931 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE ||
Dmitry Shmidt807291d2015-01-27 13:40:23 -08005932 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005933 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ||
Hai Shalom021b0b52019-04-10 11:17:58 -07005934 params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005935 params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA256 ||
5936 params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA384 ||
5937 params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA256 ||
Roshan Pius3a1667e2018-07-03 15:17:14 -07005938 params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384 ||
5939 params->key_mgmt_suite == WPA_KEY_MGMT_OWE ||
5940 params->key_mgmt_suite == WPA_KEY_MGMT_DPP) {
Paul Stewart092955c2017-02-06 09:13:09 -08005941 int mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005942
5943 switch (params->key_mgmt_suite) {
5944 case WPA_KEY_MGMT_CCKM:
Paul Stewart092955c2017-02-06 09:13:09 -08005945 mgmt = RSN_AUTH_KEY_MGMT_CCKM;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005946 break;
5947 case WPA_KEY_MGMT_IEEE8021X:
Paul Stewart092955c2017-02-06 09:13:09 -08005948 mgmt = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005949 break;
5950 case WPA_KEY_MGMT_FT_IEEE8021X:
Paul Stewart092955c2017-02-06 09:13:09 -08005951 mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005952 break;
5953 case WPA_KEY_MGMT_FT_PSK:
Paul Stewart092955c2017-02-06 09:13:09 -08005954 mgmt = RSN_AUTH_KEY_MGMT_FT_PSK;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005955 break;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07005956 case WPA_KEY_MGMT_IEEE8021X_SHA256:
Paul Stewart092955c2017-02-06 09:13:09 -08005957 mgmt = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07005958 break;
5959 case WPA_KEY_MGMT_PSK_SHA256:
Paul Stewart092955c2017-02-06 09:13:09 -08005960 mgmt = RSN_AUTH_KEY_MGMT_PSK_SHA256;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07005961 break;
Dmitry Shmidt15907092014-03-25 10:42:57 -07005962 case WPA_KEY_MGMT_OSEN:
Paul Stewart092955c2017-02-06 09:13:09 -08005963 mgmt = RSN_AUTH_KEY_MGMT_OSEN;
Dmitry Shmidt15907092014-03-25 10:42:57 -07005964 break;
Hai Shalom021b0b52019-04-10 11:17:58 -07005965 case WPA_KEY_MGMT_SAE:
5966 mgmt = RSN_AUTH_KEY_MGMT_SAE;
5967 break;
5968 case WPA_KEY_MGMT_FT_SAE:
5969 mgmt = RSN_AUTH_KEY_MGMT_FT_SAE;
5970 break;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005971 case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
Paul Stewart092955c2017-02-06 09:13:09 -08005972 mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005973 break;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08005974 case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
Paul Stewart092955c2017-02-06 09:13:09 -08005975 mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08005976 break;
Hai Shalom021b0b52019-04-10 11:17:58 -07005977 case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
5978 mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
5979 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005980 case WPA_KEY_MGMT_FILS_SHA256:
5981 mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA256;
5982 break;
5983 case WPA_KEY_MGMT_FILS_SHA384:
5984 mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA384;
5985 break;
5986 case WPA_KEY_MGMT_FT_FILS_SHA256:
5987 mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
5988 break;
5989 case WPA_KEY_MGMT_FT_FILS_SHA384:
5990 mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
5991 break;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005992 case WPA_KEY_MGMT_OWE:
5993 mgmt = RSN_AUTH_KEY_MGMT_OWE;
5994 break;
5995 case WPA_KEY_MGMT_DPP:
5996 mgmt = RSN_AUTH_KEY_MGMT_DPP;
5997 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005998 case WPA_KEY_MGMT_PSK:
5999 default:
Paul Stewart092955c2017-02-06 09:13:09 -08006000 mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006001 break;
6002 }
Dmitry Shmidt15907092014-03-25 10:42:57 -07006003 wpa_printf(MSG_DEBUG, " * akm=0x%x", mgmt);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006004 if (nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, mgmt))
6005 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006006 }
6007
Hai Shalomc3565922019-10-28 11:58:20 -07006008 if (params->req_handshake_offload &&
Hai Shalom74f70d42019-02-11 14:42:39 -08006009 (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) {
6010 wpa_printf(MSG_DEBUG, " * WANT_1X_4WAY_HS");
6011 if (nla_put_flag(msg, NL80211_ATTR_WANT_1X_4WAY_HS))
6012 return -1;
6013 }
6014
Roshan Pius3a1667e2018-07-03 15:17:14 -07006015 /* Add PSK in case of 4-way handshake offload */
6016 if (params->psk &&
Hai Shalom74f70d42019-02-11 14:42:39 -08006017 (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006018 wpa_hexdump_key(MSG_DEBUG, " * PSK", params->psk, 32);
6019 if (nla_put(msg, NL80211_ATTR_PMK, 32, params->psk))
6020 return -1;
6021 }
6022
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006023 if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
6024 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006025
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07006026 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
6027 (params->pairwise_suite == WPA_CIPHER_NONE ||
6028 params->pairwise_suite == WPA_CIPHER_WEP104 ||
6029 params->pairwise_suite == WPA_CIPHER_WEP40) &&
6030 (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
6031 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
6032 return -1;
6033
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006034 if (params->rrm_used) {
6035 u32 drv_rrm_flags = drv->capa.rrm_flags;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006036 if ((!((drv_rrm_flags &
6037 WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) &&
6038 (drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) &&
6039 !(drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006040 nla_put_flag(msg, NL80211_ATTR_USE_RRM))
6041 return -1;
6042 }
6043
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006044 if (nl80211_ht_vht_overrides(msg, params) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006045 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006046
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006047 if (params->p2p)
6048 wpa_printf(MSG_DEBUG, " * P2P group");
6049
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006050 if (params->pbss) {
6051 wpa_printf(MSG_DEBUG, " * PBSS");
6052 if (nla_put_flag(msg, NL80211_ATTR_PBSS))
6053 return -1;
6054 }
6055
Dmitry Shmidte4663042016-04-04 10:07:49 -07006056 drv->connect_reassoc = 0;
6057 if (params->prev_bssid) {
6058 wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR,
6059 MAC2STR(params->prev_bssid));
6060 if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
6061 params->prev_bssid))
6062 return -1;
6063 drv->connect_reassoc = 1;
6064 }
6065
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006066 if ((params->auth_alg & WPA_AUTH_ALG_FILS) &&
6067 nl80211_put_fils_connect_params(drv, params, msg) != 0)
6068 return -1;
6069
Hai Shalomc3565922019-10-28 11:58:20 -07006070 if ((params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
6071 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) &&
Roshan Pius3a1667e2018-07-03 15:17:14 -07006072 (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
6073 nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
6074 return -1;
6075
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006076 return 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006077}
6078
6079
6080static int wpa_driver_nl80211_try_connect(
6081 struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006082 struct wpa_driver_associate_params *params,
Hai Shalomfdcde762020-04-02 11:19:20 -07006083 struct nl_sock *nl_connect)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006084{
6085 struct nl_msg *msg;
6086 enum nl80211_auth_type type;
6087 int ret;
6088 int algs;
6089
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006090#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006091 if (params->req_key_mgmt_offload && params->psk &&
6092 (params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
6093 params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
6094 params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
6095 wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK");
6096 ret = issue_key_mgmt_set_key(drv, params->psk, 32);
6097 if (ret)
6098 return ret;
6099 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006100#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006101
6102 wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
6103 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_CONNECT);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006104 if (!msg)
6105 return -1;
6106
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006107 ret = nl80211_connect_common(drv, params, msg);
6108 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006109 goto fail;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006110
Roshan Pius3a1667e2018-07-03 15:17:14 -07006111 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
6112 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
6113 goto fail;
6114
6115 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_OPTIONAL &&
6116 (drv->capa.flags & WPA_DRIVER_FLAGS_MFP_OPTIONAL) &&
6117 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_OPTIONAL))
6118 goto fail;
6119
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006120 algs = 0;
6121 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
6122 algs++;
6123 if (params->auth_alg & WPA_AUTH_ALG_SHARED)
6124 algs++;
6125 if (params->auth_alg & WPA_AUTH_ALG_LEAP)
6126 algs++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006127 if (params->auth_alg & WPA_AUTH_ALG_FILS)
6128 algs++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006129 if (params->auth_alg & WPA_AUTH_ALG_FT)
6130 algs++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006131 if (algs > 1) {
6132 wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic "
6133 "selection");
6134 goto skip_auth_type;
6135 }
6136
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006137 type = get_nl_auth_type(params->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006138 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006139 if (type == NL80211_AUTHTYPE_MAX ||
6140 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006141 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006142
6143skip_auth_type:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006144 ret = nl80211_set_conn_keys(params, msg);
6145 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006146 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006147
Hai Shalomb755a2a2020-04-23 21:49:02 -07006148 ret = send_and_recv_msgs_owner(drv, msg, nl_connect, 1, NULL,
6149 (void *) -1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006150 msg = NULL;
6151 if (ret) {
6152 wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
6153 "(%s)", ret, strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006154 } else {
6155 wpa_printf(MSG_DEBUG,
6156 "nl80211: Connect request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006157 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006158
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006159fail:
Hai Shalom74f70d42019-02-11 14:42:39 -08006160 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006161 nlmsg_free(msg);
6162 return ret;
6163
6164}
6165
6166
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006167static int wpa_driver_nl80211_connect(
6168 struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07006169 struct wpa_driver_associate_params *params,
Hai Shalomfdcde762020-04-02 11:19:20 -07006170 struct nl_sock *nl_connect)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006171{
Jithu Jancea7c60b42014-12-03 18:54:40 +05306172 int ret;
6173
6174 /* Store the connection attempted bssid for future use */
6175 if (params->bssid)
6176 os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
6177 else
6178 os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
6179
Roshan Pius3a1667e2018-07-03 15:17:14 -07006180 ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006181 if (ret == -EALREADY) {
6182 /*
6183 * cfg80211 does not currently accept new connections if
6184 * we are already connected. As a workaround, force
6185 * disconnection and try again.
6186 */
6187 wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
6188 "disconnecting before reassociation "
6189 "attempt");
6190 if (wpa_driver_nl80211_disconnect(
Hai Shalom74f70d42019-02-11 14:42:39 -08006191 drv, WLAN_REASON_PREV_AUTH_NOT_VALID, nl_connect))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006192 return -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07006193 ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006194 }
6195 return ret;
6196}
6197
6198
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006199static int wpa_driver_nl80211_associate(
6200 void *priv, struct wpa_driver_associate_params *params)
6201{
6202 struct i802_bss *bss = priv;
6203 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006204 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006205 struct nl_msg *msg;
6206
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006207 nl80211_unmask_11b_rates(bss);
6208
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006209 if (params->mode == IEEE80211_MODE_AP)
6210 return wpa_driver_nl80211_ap(drv, params);
6211
6212 if (params->mode == IEEE80211_MODE_IBSS)
6213 return wpa_driver_nl80211_ibss(drv, params);
6214
6215 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006216 enum nl80211_iftype nlmode = params->p2p ?
6217 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
6218
6219 if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006220 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07006221 if (params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
Hai Shalomb755a2a2020-04-23 21:49:02 -07006222 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE)
Hai Shalom74f70d42019-02-11 14:42:39 -08006223 bss->use_nl_connect = 1;
Hai Shalomb755a2a2020-04-23 21:49:02 -07006224 else
Hai Shalom74f70d42019-02-11 14:42:39 -08006225 bss->use_nl_connect = 0;
Hai Shalom74f70d42019-02-11 14:42:39 -08006226
Hai Shalomb755a2a2020-04-23 21:49:02 -07006227 return wpa_driver_nl80211_connect(drv, params,
6228 get_connect_handle(bss));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006229 }
6230
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07006231 nl80211_mark_disconnected(drv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006232
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006233 wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
6234 drv->ifindex);
6235 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ASSOCIATE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006236 if (!msg)
6237 return -1;
6238
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006239 ret = nl80211_connect_common(drv, params, msg);
6240 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006241 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006242
Roshan Pius3a1667e2018-07-03 15:17:14 -07006243 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
6244 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
6245 goto fail;
6246
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006247 if (params->fils_kek) {
6248 wpa_printf(MSG_DEBUG, " * FILS KEK (len=%u)",
6249 (unsigned int) params->fils_kek_len);
6250 if (nla_put(msg, NL80211_ATTR_FILS_KEK, params->fils_kek_len,
6251 params->fils_kek))
6252 goto fail;
6253 }
6254 if (params->fils_nonces) {
6255 wpa_hexdump(MSG_DEBUG, " * FILS nonces (for AAD)",
6256 params->fils_nonces,
6257 params->fils_nonces_len);
6258 if (nla_put(msg, NL80211_ATTR_FILS_NONCES,
6259 params->fils_nonces_len, params->fils_nonces))
6260 goto fail;
6261 }
6262
Hai Shalomb755a2a2020-04-23 21:49:02 -07006263 ret = send_and_recv_msgs_owner(drv, msg,
6264 get_connect_handle(drv->first_bss), 1,
6265 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006266 msg = NULL;
6267 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006268 wpa_dbg(drv->ctx, MSG_DEBUG,
6269 "nl80211: MLME command failed (assoc): ret=%d (%s)",
6270 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006271 nl80211_dump_scan(drv);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006272 } else {
6273 wpa_printf(MSG_DEBUG,
6274 "nl80211: Association request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006275 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006276
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006277fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006278 nlmsg_free(msg);
6279 return ret;
6280}
6281
6282
6283static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006284 int ifindex, enum nl80211_iftype mode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006285{
6286 struct nl_msg *msg;
6287 int ret = -ENOBUFS;
6288
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006289 wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
6290 ifindex, mode, nl80211_iftype_str(mode));
6291
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006292 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
6293 if (!msg || nla_put_u32(msg, NL80211_ATTR_IFTYPE, mode))
6294 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006295
6296 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006297 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006298 if (!ret)
6299 return 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006300fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006301 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006302 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
6303 " %d (%s)", ifindex, mode, ret, strerror(-ret));
6304 return ret;
6305}
6306
6307
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006308static int wpa_driver_nl80211_set_mode_impl(
6309 struct i802_bss *bss,
6310 enum nl80211_iftype nlmode,
6311 struct hostapd_freq_params *desired_freq_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006312{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006313 struct wpa_driver_nl80211_data *drv = bss->drv;
6314 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006315 int i;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006316 int was_ap = is_ap_interface(drv->nlmode);
6317 int res;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006318 int mode_switch_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006319
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07006320 if (TEST_FAIL())
6321 return -1;
6322
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006323 mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
6324 if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))
6325 mode_switch_res = 0;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006326
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006327 if (mode_switch_res == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006328 drv->nlmode = nlmode;
6329 ret = 0;
6330 goto done;
6331 }
6332
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006333 if (mode_switch_res == -ENODEV)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006334 return -1;
6335
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006336 if (nlmode == drv->nlmode) {
6337 wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
6338 "requested mode - ignore error");
6339 ret = 0;
6340 goto done; /* Already in the requested mode */
6341 }
6342
6343 /* mac80211 doesn't allow mode changes while the device is up, so
6344 * take the device down, try to set the mode again, and bring the
6345 * device back up.
6346 */
6347 wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
6348 "interface down");
6349 for (i = 0; i < 10; i++) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006350 res = i802_set_iface_flags(bss, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006351 if (res == -EACCES || res == -ENODEV)
6352 break;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006353 if (res != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006354 wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
6355 "interface down");
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006356 os_sleep(0, 100000);
6357 continue;
6358 }
6359
6360 /*
6361 * Setting the mode will fail for some drivers if the phy is
6362 * on a frequency that the mode is disallowed in.
6363 */
6364 if (desired_freq_params) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006365 res = nl80211_set_channel(bss, desired_freq_params, 0);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006366 if (res) {
6367 wpa_printf(MSG_DEBUG,
6368 "nl80211: Failed to set frequency on interface");
6369 }
6370 }
6371
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006372 if (i == 0 && was_ap && !is_ap_interface(nlmode) &&
6373 bss->brname[0] &&
6374 (bss->added_if_into_bridge || bss->already_in_bridge)) {
6375 wpa_printf(MSG_DEBUG,
6376 "nl80211: Remove AP interface %s temporarily from the bridge %s to allow its mode to be set to STATION",
6377 bss->ifname, bss->brname);
6378 if (linux_br_del_if(drv->global->ioctl_sock,
6379 bss->brname, bss->ifname) < 0)
6380 wpa_printf(MSG_INFO,
6381 "nl80211: Failed to remove interface %s from bridge %s: %s",
6382 bss->ifname, bss->brname,
6383 strerror(errno));
6384 }
6385
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006386 /* Try to set the mode again while the interface is down */
6387 mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
6388 if (mode_switch_res == -EBUSY) {
6389 wpa_printf(MSG_DEBUG,
6390 "nl80211: Delaying mode set while interface going down");
6391 os_sleep(0, 100000);
6392 continue;
6393 }
6394 ret = mode_switch_res;
6395 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006396 }
6397
6398 if (!ret) {
6399 wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
6400 "interface is down");
6401 drv->nlmode = nlmode;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006402 drv->ignore_if_down_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006403 }
6404
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006405 /* Bring the interface back up */
6406 res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
6407 if (res != 0) {
6408 wpa_printf(MSG_DEBUG,
6409 "nl80211: Failed to set interface up after switching mode");
6410 ret = -1;
6411 }
6412
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006413done:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006414 if (ret) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006415 wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
6416 "from %d failed", nlmode, drv->nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006417 return ret;
6418 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006419
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006420 if (is_p2p_net_interface(nlmode)) {
6421 wpa_printf(MSG_DEBUG,
6422 "nl80211: Interface %s mode change to P2P - disable 11b rates",
6423 bss->ifname);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006424 nl80211_disable_11b_rates(drv, drv->ifindex, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006425 } else if (drv->disabled_11b_rates) {
6426 wpa_printf(MSG_DEBUG,
6427 "nl80211: Interface %s mode changed to non-P2P - re-enable 11b rates",
6428 bss->ifname);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006429 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006430 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006431
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006432 if (is_ap_interface(nlmode)) {
6433 nl80211_mgmt_unsubscribe(bss, "start AP");
6434 /* Setup additional AP mode functionality if needed */
6435 if (nl80211_setup_ap(bss))
6436 return -1;
6437 } else if (was_ap) {
6438 /* Remove additional AP mode functionality */
6439 nl80211_teardown_ap(bss);
6440 } else {
6441 nl80211_mgmt_unsubscribe(bss, "mode change");
6442 }
6443
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006444 if (is_mesh_interface(nlmode) &&
6445 nl80211_mgmt_subscribe_mesh(bss))
6446 return -1;
6447
Dmitry Shmidt04949592012-07-19 12:16:46 -07006448 if (!bss->in_deinit && !is_ap_interface(nlmode) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006449 !is_mesh_interface(nlmode) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006450 nl80211_mgmt_subscribe_non_ap(bss) < 0)
6451 wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
6452 "frame processing - ignore for now");
6453
6454 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006455}
6456
6457
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006458void nl80211_restore_ap_mode(struct i802_bss *bss)
6459{
6460 struct wpa_driver_nl80211_data *drv = bss->drv;
6461 int was_ap = is_ap_interface(drv->nlmode);
6462
6463 wpa_driver_nl80211_set_mode(bss, drv->ap_scan_as_station);
6464 if (!was_ap && is_ap_interface(drv->ap_scan_as_station) &&
6465 bss->brname[0] &&
6466 (bss->added_if_into_bridge || bss->already_in_bridge)) {
6467 wpa_printf(MSG_DEBUG,
6468 "nl80211: Add AP interface %s back into the bridge %s",
6469 bss->ifname, bss->brname);
6470 if (linux_br_add_if(drv->global->ioctl_sock, bss->brname,
6471 bss->ifname) < 0) {
6472 wpa_printf(MSG_WARNING,
6473 "nl80211: Failed to add interface %s into bridge %s: %s",
6474 bss->ifname, bss->brname, strerror(errno));
6475 }
6476 }
6477 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
6478}
6479
6480
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006481int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
6482 enum nl80211_iftype nlmode)
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006483{
6484 return wpa_driver_nl80211_set_mode_impl(bss, nlmode, NULL);
6485}
6486
6487
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006488static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
6489 struct hostapd_freq_params *freq)
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006490{
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006491 return wpa_driver_nl80211_set_mode_impl(bss, NL80211_IFTYPE_ADHOC,
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006492 freq);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07006493}
6494
6495
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006496static int wpa_driver_nl80211_get_capa(void *priv,
6497 struct wpa_driver_capa *capa)
6498{
6499 struct i802_bss *bss = priv;
6500 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07006501
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006502 if (!drv->has_capability)
6503 return -1;
6504 os_memcpy(capa, &drv->capa, sizeof(*capa));
Dmitry Shmidt444d5672013-04-01 13:08:44 -07006505 if (drv->extended_capa && drv->extended_capa_mask) {
6506 capa->extended_capa = drv->extended_capa;
6507 capa->extended_capa_mask = drv->extended_capa_mask;
6508 capa->extended_capa_len = drv->extended_capa_len;
6509 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006510
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006511 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006512}
6513
6514
6515static int wpa_driver_nl80211_set_operstate(void *priv, int state)
6516{
6517 struct i802_bss *bss = priv;
6518 struct wpa_driver_nl80211_data *drv = bss->drv;
6519
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006520 wpa_printf(MSG_DEBUG, "nl80211: Set %s operstate %d->%d (%s)",
6521 bss->ifname, drv->operstate, state,
6522 state ? "UP" : "DORMANT");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006523 drv->operstate = state;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006524 return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006525 state ? IF_OPER_UP : IF_OPER_DORMANT);
6526}
6527
6528
6529static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
6530{
6531 struct i802_bss *bss = priv;
6532 struct wpa_driver_nl80211_data *drv = bss->drv;
6533 struct nl_msg *msg;
6534 struct nl80211_sta_flag_update upd;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006535 int ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006536
6537 if (!drv->associated && is_zero_ether_addr(drv->bssid) && !authorized) {
6538 wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated");
6539 return 0;
6540 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006541
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07006542 wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
6543 MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
6544
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006545 os_memset(&upd, 0, sizeof(upd));
6546 upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
6547 if (authorized)
6548 upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006549
6550 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
6551 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid) ||
6552 nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd)) {
6553 nlmsg_free(msg);
6554 return -ENOBUFS;
6555 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006556
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006557 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006558 if (!ret)
6559 return 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006560 wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)",
6561 ret, strerror(-ret));
6562 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006563}
6564
6565
Jouni Malinen75ecf522011-06-27 15:19:46 -07006566/* Set kernel driver on given frequency (MHz) */
6567static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006568{
Jouni Malinen75ecf522011-06-27 15:19:46 -07006569 struct i802_bss *bss = priv;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07006570 return nl80211_set_channel(bss, freq, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006571}
6572
6573
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006574static inline int min_int(int a, int b)
6575{
6576 if (a < b)
6577 return a;
6578 return b;
6579}
6580
6581
6582static int get_key_handler(struct nl_msg *msg, void *arg)
6583{
6584 struct nlattr *tb[NL80211_ATTR_MAX + 1];
6585 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
6586
6587 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
6588 genlmsg_attrlen(gnlh, 0), NULL);
6589
6590 /*
6591 * TODO: validate the key index and mac address!
6592 * Otherwise, there's a race condition as soon as
6593 * the kernel starts sending key notifications.
6594 */
6595
6596 if (tb[NL80211_ATTR_KEY_SEQ])
6597 memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
6598 min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
Hai Shalom021b0b52019-04-10 11:17:58 -07006599 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006600 return NL_SKIP;
6601}
6602
6603
6604static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
6605 int idx, u8 *seq)
6606{
6607 struct i802_bss *bss = priv;
6608 struct wpa_driver_nl80211_data *drv = bss->drv;
6609 struct nl_msg *msg;
6610
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006611 msg = nl80211_ifindex_msg(drv, if_nametoindex(iface), 0,
6612 NL80211_CMD_GET_KEY);
6613 if (!msg ||
6614 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
6615 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, idx)) {
6616 nlmsg_free(msg);
6617 return -ENOBUFS;
6618 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006619
6620 memset(seq, 0, 6);
6621
6622 return send_and_recv_msgs(drv, msg, get_key_handler, seq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006623}
6624
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006625
6626static int i802_set_rts(void *priv, int rts)
6627{
6628 struct i802_bss *bss = priv;
6629 struct wpa_driver_nl80211_data *drv = bss->drv;
6630 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006631 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006632 u32 val;
6633
Hai Shalom021b0b52019-04-10 11:17:58 -07006634 if (rts >= 2347 || rts == -1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006635 val = (u32) -1;
6636 else
6637 val = rts;
6638
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006639 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
6640 nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val)) {
6641 nlmsg_free(msg);
6642 return -ENOBUFS;
6643 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006644
6645 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
6646 if (!ret)
6647 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006648 wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
6649 "%d (%s)", rts, ret, strerror(-ret));
6650 return ret;
6651}
6652
6653
6654static int i802_set_frag(void *priv, int frag)
6655{
6656 struct i802_bss *bss = priv;
6657 struct wpa_driver_nl80211_data *drv = bss->drv;
6658 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006659 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006660 u32 val;
6661
Hai Shalom021b0b52019-04-10 11:17:58 -07006662 if (frag >= 2346 || frag == -1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006663 val = (u32) -1;
6664 else
6665 val = frag;
6666
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006667 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
6668 nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val)) {
6669 nlmsg_free(msg);
6670 return -ENOBUFS;
6671 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006672
6673 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
6674 if (!ret)
6675 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006676 wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
6677 "%d: %d (%s)", frag, ret, strerror(-ret));
6678 return ret;
6679}
6680
6681
6682static int i802_flush(void *priv)
6683{
6684 struct i802_bss *bss = priv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006685 struct nl_msg *msg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006686 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006687
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07006688 wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
6689 bss->ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006690
6691 /*
6692 * XXX: FIX! this needs to flush all VLANs too
6693 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006694 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
6695 res = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006696 if (res) {
6697 wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
6698 "(%s)", res, strerror(-res));
6699 }
6700 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006701}
6702
6703
Hai Shalom81f62d82019-07-22 12:10:00 -07006704static void get_sta_tid_stats(struct hostap_sta_driver_data *data,
6705 struct nlattr *attr)
6706{
6707 struct nlattr *tid_stats[NL80211_TID_STATS_MAX + 1], *tidattr;
6708 struct nlattr *txq_stats[NL80211_TXQ_STATS_MAX + 1];
6709 static struct nla_policy txq_stats_policy[NL80211_TXQ_STATS_MAX + 1] = {
6710 [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 },
6711 [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 },
6712 };
6713 int rem;
6714
6715 nla_for_each_nested(tidattr, attr, rem) {
6716 if (nla_parse_nested(tid_stats, NL80211_TID_STATS_MAX,
6717 tidattr, NULL) != 0 ||
6718 !tid_stats[NL80211_TID_STATS_TXQ_STATS] ||
6719 nla_parse_nested(txq_stats, NL80211_TXQ_STATS_MAX,
6720 tid_stats[NL80211_TID_STATS_TXQ_STATS],
6721 txq_stats_policy) != 0)
6722 continue;
6723 /* sum the backlogs over all TIDs for station */
6724 if (txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES])
6725 data->backlog_bytes += nla_get_u32(
6726 txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES]);
6727 if (txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS])
6728 data->backlog_bytes += nla_get_u32(
6729 txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS]);
6730 }
6731}
6732
6733
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006734static int get_sta_handler(struct nl_msg *msg, void *arg)
6735{
6736 struct nlattr *tb[NL80211_ATTR_MAX + 1];
6737 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
6738 struct hostap_sta_driver_data *data = arg;
6739 struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
6740 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
6741 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
6742 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
6743 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
6744 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
6745 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03006746 [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006747 [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
6748 [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006749 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
Roshan Pius3a1667e2018-07-03 15:17:14 -07006750 [NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 },
Hai Shalom81f62d82019-07-22 12:10:00 -07006751 [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 },
6752 [NL80211_STA_INFO_TX_DURATION] = { .type = NLA_U64 },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006753 };
6754 struct nlattr *rate[NL80211_RATE_INFO_MAX + 1];
6755 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
6756 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
6757 [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 },
6758 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
6759 [NL80211_RATE_INFO_VHT_MCS] = { .type = NLA_U8 },
6760 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
6761 [NL80211_RATE_INFO_VHT_NSS] = { .type = NLA_U8 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006762 };
6763
6764 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
6765 genlmsg_attrlen(gnlh, 0), NULL);
6766
6767 /*
6768 * TODO: validate the interface and mac address!
6769 * Otherwise, there's a race condition as soon as
6770 * the kernel starts sending station notifications.
6771 */
6772
6773 if (!tb[NL80211_ATTR_STA_INFO]) {
6774 wpa_printf(MSG_DEBUG, "sta stats missing!");
6775 return NL_SKIP;
6776 }
6777 if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
6778 tb[NL80211_ATTR_STA_INFO],
6779 stats_policy)) {
6780 wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
6781 return NL_SKIP;
6782 }
6783
6784 if (stats[NL80211_STA_INFO_INACTIVE_TIME])
6785 data->inactive_msec =
6786 nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006787 /* For backwards compatibility, fetch the 32-bit counters first. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006788 if (stats[NL80211_STA_INFO_RX_BYTES])
6789 data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
6790 if (stats[NL80211_STA_INFO_TX_BYTES])
6791 data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006792 if (stats[NL80211_STA_INFO_RX_BYTES64] &&
6793 stats[NL80211_STA_INFO_TX_BYTES64]) {
6794 /*
6795 * The driver supports 64-bit counters, so use them to override
6796 * the 32-bit values.
6797 */
6798 data->rx_bytes =
6799 nla_get_u64(stats[NL80211_STA_INFO_RX_BYTES64]);
6800 data->tx_bytes =
6801 nla_get_u64(stats[NL80211_STA_INFO_TX_BYTES64]);
6802 data->bytes_64bit = 1;
6803 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006804 if (stats[NL80211_STA_INFO_RX_PACKETS])
6805 data->rx_packets =
6806 nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
6807 if (stats[NL80211_STA_INFO_TX_PACKETS])
6808 data->tx_packets =
6809 nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
Hai Shalom81f62d82019-07-22 12:10:00 -07006810 if (stats[NL80211_STA_INFO_RX_DURATION])
6811 data->rx_airtime =
6812 nla_get_u64(stats[NL80211_STA_INFO_RX_DURATION]);
6813 if (stats[NL80211_STA_INFO_TX_DURATION])
6814 data->tx_airtime =
6815 nla_get_u64(stats[NL80211_STA_INFO_TX_DURATION]);
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03006816 if (stats[NL80211_STA_INFO_TX_FAILED])
6817 data->tx_retry_failed =
6818 nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006819 if (stats[NL80211_STA_INFO_SIGNAL])
6820 data->signal = nla_get_u8(stats[NL80211_STA_INFO_SIGNAL]);
Roshan Pius3a1667e2018-07-03 15:17:14 -07006821 if (stats[NL80211_STA_INFO_ACK_SIGNAL]) {
6822 data->last_ack_rssi =
6823 nla_get_u8(stats[NL80211_STA_INFO_ACK_SIGNAL]);
6824 data->flags |= STA_DRV_DATA_LAST_ACK_RSSI;
6825 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006826
6827 if (stats[NL80211_STA_INFO_TX_BITRATE] &&
6828 nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
6829 stats[NL80211_STA_INFO_TX_BITRATE],
6830 rate_policy) == 0) {
6831 if (rate[NL80211_RATE_INFO_BITRATE32])
6832 data->current_tx_rate =
6833 nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
6834 else if (rate[NL80211_RATE_INFO_BITRATE])
6835 data->current_tx_rate =
6836 nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
6837
6838 if (rate[NL80211_RATE_INFO_MCS]) {
6839 data->tx_mcs = nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
6840 data->flags |= STA_DRV_DATA_TX_MCS;
6841 }
6842 if (rate[NL80211_RATE_INFO_VHT_MCS]) {
6843 data->tx_vhtmcs =
6844 nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
6845 data->flags |= STA_DRV_DATA_TX_VHT_MCS;
6846 }
6847 if (rate[NL80211_RATE_INFO_SHORT_GI])
6848 data->flags |= STA_DRV_DATA_TX_SHORT_GI;
6849 if (rate[NL80211_RATE_INFO_VHT_NSS]) {
6850 data->tx_vht_nss =
6851 nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
6852 data->flags |= STA_DRV_DATA_TX_VHT_NSS;
6853 }
6854 }
6855
6856 if (stats[NL80211_STA_INFO_RX_BITRATE] &&
6857 nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
6858 stats[NL80211_STA_INFO_RX_BITRATE],
6859 rate_policy) == 0) {
6860 if (rate[NL80211_RATE_INFO_BITRATE32])
6861 data->current_rx_rate =
6862 nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
6863 else if (rate[NL80211_RATE_INFO_BITRATE])
6864 data->current_rx_rate =
6865 nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
6866
6867 if (rate[NL80211_RATE_INFO_MCS]) {
6868 data->rx_mcs =
6869 nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
6870 data->flags |= STA_DRV_DATA_RX_MCS;
6871 }
6872 if (rate[NL80211_RATE_INFO_VHT_MCS]) {
6873 data->rx_vhtmcs =
6874 nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
6875 data->flags |= STA_DRV_DATA_RX_VHT_MCS;
6876 }
6877 if (rate[NL80211_RATE_INFO_SHORT_GI])
6878 data->flags |= STA_DRV_DATA_RX_SHORT_GI;
6879 if (rate[NL80211_RATE_INFO_VHT_NSS]) {
6880 data->rx_vht_nss =
6881 nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
6882 data->flags |= STA_DRV_DATA_RX_VHT_NSS;
6883 }
6884 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006885
Hai Shalom81f62d82019-07-22 12:10:00 -07006886 if (stats[NL80211_STA_INFO_TID_STATS])
6887 get_sta_tid_stats(data, stats[NL80211_STA_INFO_TID_STATS]);
6888
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006889 return NL_SKIP;
6890}
6891
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08006892static int i802_read_sta_data(struct i802_bss *bss,
6893 struct hostap_sta_driver_data *data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006894 const u8 *addr)
6895{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006896 struct nl_msg *msg;
6897
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006898 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_STATION)) ||
6899 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
6900 nlmsg_free(msg);
6901 return -ENOBUFS;
6902 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006903
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006904 return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006905}
6906
6907
6908static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
6909 int cw_min, int cw_max, int burst_time)
6910{
6911 struct i802_bss *bss = priv;
6912 struct wpa_driver_nl80211_data *drv = bss->drv;
6913 struct nl_msg *msg;
6914 struct nlattr *txq, *params;
Hai Shalom74f70d42019-02-11 14:42:39 -08006915 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006916
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006917 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006918 if (!msg)
6919 return -1;
6920
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006921 txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
6922 if (!txq)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006923 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006924
6925 /* We are only sending parameters for a single TXQ at a time */
6926 params = nla_nest_start(msg, 1);
6927 if (!params)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006928 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006929
6930 switch (queue) {
6931 case 0:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006932 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO))
6933 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006934 break;
6935 case 1:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006936 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI))
6937 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006938 break;
6939 case 2:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006940 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE))
6941 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006942 break;
6943 case 3:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006944 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK))
6945 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006946 break;
6947 }
6948 /* Burst time is configured in units of 0.1 msec and TXOP parameter in
6949 * 32 usec, so need to convert the value here. */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006950 if (nla_put_u16(msg, NL80211_TXQ_ATTR_TXOP,
6951 (burst_time * 100 + 16) / 32) ||
6952 nla_put_u16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min) ||
6953 nla_put_u16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max) ||
6954 nla_put_u8(msg, NL80211_TXQ_ATTR_AIFS, aifs))
6955 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006956
6957 nla_nest_end(msg, params);
6958
6959 nla_nest_end(msg, txq);
6960
Hai Shalom74f70d42019-02-11 14:42:39 -08006961 res = send_and_recv_msgs(drv, msg, NULL, NULL);
6962 wpa_printf(MSG_DEBUG,
6963 "nl80211: TX queue param set: queue=%d aifs=%d cw_min=%d cw_max=%d burst_time=%d --> res=%d",
6964 queue, aifs, cw_min, cw_max, burst_time, res);
6965 if (res == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006966 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006967 msg = NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006968fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006969 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006970 return -1;
6971}
6972
6973
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08006974static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006975 const char *ifname, int vlan_id)
6976{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006977 struct wpa_driver_nl80211_data *drv = bss->drv;
6978 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006979 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006980
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006981 wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
6982 ", ifname=%s[%d], vlan_id=%d)",
6983 bss->ifname, if_nametoindex(bss->ifname),
6984 MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006985 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
6986 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07006987 ((drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) &&
6988 nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006989 nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
6990 nlmsg_free(msg);
6991 return -ENOBUFS;
6992 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006993
6994 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
6995 if (ret < 0) {
6996 wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
6997 MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
6998 MAC2STR(addr), ifname, vlan_id, ret,
6999 strerror(-ret));
7000 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007001 return ret;
7002}
7003
7004
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007005static int i802_get_inact_sec(void *priv, const u8 *addr)
7006{
7007 struct hostap_sta_driver_data data;
7008 int ret;
7009
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08007010 os_memset(&data, 0, sizeof(data));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007011 data.inactive_msec = (unsigned long) -1;
7012 ret = i802_read_sta_data(priv, &data, addr);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007013 if (ret == -ENOENT)
7014 return -ENOENT;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007015 if (ret || data.inactive_msec == (unsigned long) -1)
7016 return -1;
7017 return data.inactive_msec / 1000;
7018}
7019
7020
7021static int i802_sta_clear_stats(void *priv, const u8 *addr)
7022{
7023#if 0
7024 /* TODO */
7025#endif
7026 return 0;
7027}
7028
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007029
7030static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -07007031 u16 reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007032{
7033 struct i802_bss *bss = priv;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007034 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007035 struct ieee80211_mgmt mgmt;
Dmitry Shmidt29333592017-01-09 12:27:11 -08007036 u8 channel;
7037
7038 if (ieee80211_freq_to_chan(bss->freq, &channel) ==
7039 HOSTAPD_MODE_IEEE80211AD) {
7040 /* Deauthentication is not used in DMG/IEEE 802.11ad;
7041 * disassociate the STA instead. */
7042 return i802_sta_disassoc(priv, own_addr, addr, reason);
7043 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007044
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007045 if (is_mesh_interface(drv->nlmode))
7046 return -1;
7047
Dmitry Shmidt04949592012-07-19 12:16:46 -07007048 if (drv->device_ap_sme)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007049 return wpa_driver_nl80211_sta_remove(bss, addr, 1, reason);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007050
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007051 memset(&mgmt, 0, sizeof(mgmt));
7052 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
7053 WLAN_FC_STYPE_DEAUTH);
7054 memcpy(mgmt.da, addr, ETH_ALEN);
7055 memcpy(mgmt.sa, own_addr, ETH_ALEN);
7056 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
7057 mgmt.u.deauth.reason_code = host_to_le16(reason);
7058 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
7059 IEEE80211_HDRLEN +
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007060 sizeof(mgmt.u.deauth), 0, 0, 0, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -07007061 0, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007062}
7063
7064
7065static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -07007066 u16 reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007067{
7068 struct i802_bss *bss = priv;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007069 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007070 struct ieee80211_mgmt mgmt;
7071
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007072 if (is_mesh_interface(drv->nlmode))
7073 return -1;
7074
Dmitry Shmidt04949592012-07-19 12:16:46 -07007075 if (drv->device_ap_sme)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007076 return wpa_driver_nl80211_sta_remove(bss, addr, 0, reason);
Dmitry Shmidt04949592012-07-19 12:16:46 -07007077
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007078 memset(&mgmt, 0, sizeof(mgmt));
7079 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
7080 WLAN_FC_STYPE_DISASSOC);
7081 memcpy(mgmt.da, addr, ETH_ALEN);
7082 memcpy(mgmt.sa, own_addr, ETH_ALEN);
7083 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
7084 mgmt.u.disassoc.reason_code = host_to_le16(reason);
7085 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
7086 IEEE80211_HDRLEN +
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007087 sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -07007088 0, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007089}
7090
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007091
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007092static void dump_ifidx(struct wpa_driver_nl80211_data *drv)
7093{
7094 char buf[200], *pos, *end;
7095 int i, res;
7096
7097 pos = buf;
7098 end = pos + sizeof(buf);
7099
7100 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007101 if (!drv->if_indices[i].ifindex)
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007102 continue;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007103 res = os_snprintf(pos, end - pos, " %d(%d)",
Hai Shalom81f62d82019-07-22 12:10:00 -07007104 drv->if_indices[i].ifindex,
7105 drv->if_indices[i].reason);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007106 if (os_snprintf_error(end - pos, res))
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007107 break;
7108 pos += res;
7109 }
7110 *pos = '\0';
7111
7112 wpa_printf(MSG_DEBUG, "nl80211: if_indices[%d]:%s",
7113 drv->num_if_indices, buf);
7114}
7115
7116
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007117static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
7118 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007119{
7120 int i;
Hai Shalom81f62d82019-07-22 12:10:00 -07007121 struct drv_nl80211_if_info *old;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007122
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007123 wpa_printf(MSG_DEBUG,
7124 "nl80211: Add own interface ifindex %d (ifidx_reason %d)",
7125 ifidx, ifidx_reason);
7126 if (have_ifidx(drv, ifidx, ifidx_reason)) {
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007127 wpa_printf(MSG_DEBUG, "nl80211: ifindex %d already in the list",
7128 ifidx);
7129 return;
7130 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07007131 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007132 if (drv->if_indices[i].ifindex == 0) {
7133 drv->if_indices[i].ifindex = ifidx;
7134 drv->if_indices[i].reason = ifidx_reason;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007135 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007136 return;
7137 }
7138 }
7139
7140 if (drv->if_indices != drv->default_if_indices)
7141 old = drv->if_indices;
7142 else
7143 old = NULL;
7144
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007145 drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
Hai Shalom81f62d82019-07-22 12:10:00 -07007146 sizeof(*old));
Jouni Malinen75ecf522011-06-27 15:19:46 -07007147 if (!drv->if_indices) {
7148 if (!old)
7149 drv->if_indices = drv->default_if_indices;
7150 else
7151 drv->if_indices = old;
7152 wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
7153 "interfaces");
7154 wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
7155 return;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007156 }
7157 if (!old)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007158 os_memcpy(drv->if_indices, drv->default_if_indices,
7159 sizeof(drv->default_if_indices));
Hai Shalom81f62d82019-07-22 12:10:00 -07007160 drv->if_indices[drv->num_if_indices].ifindex = ifidx;
7161 drv->if_indices[drv->num_if_indices].reason = ifidx_reason;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007162 drv->num_if_indices++;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007163 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007164}
7165
7166
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007167static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
7168 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007169{
7170 int i;
7171
7172 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007173 if ((drv->if_indices[i].ifindex == ifidx ||
7174 ifidx == IFIDX_ANY) &&
7175 (drv->if_indices[i].reason == ifidx_reason ||
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007176 ifidx_reason == IFIDX_ANY)) {
Hai Shalom81f62d82019-07-22 12:10:00 -07007177 drv->if_indices[i].ifindex = 0;
7178 drv->if_indices[i].reason = 0;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007179 break;
7180 }
7181 }
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007182 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007183}
7184
7185
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007186static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
7187 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007188{
7189 int i;
7190
7191 for (i = 0; i < drv->num_if_indices; i++)
Hai Shalom81f62d82019-07-22 12:10:00 -07007192 if (drv->if_indices[i].ifindex == ifidx &&
7193 (drv->if_indices[i].reason == ifidx_reason ||
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007194 ifidx_reason == IFIDX_ANY))
Jouni Malinen75ecf522011-06-27 15:19:46 -07007195 return 1;
7196
7197 return 0;
7198}
7199
7200
7201static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07007202 const char *bridge_ifname, char *ifname_wds)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007203{
7204 struct i802_bss *bss = priv;
7205 struct wpa_driver_nl80211_data *drv = bss->drv;
7206 char name[IFNAMSIZ + 1];
Roshan Pius3a1667e2018-07-03 15:17:14 -07007207 union wpa_event_data event;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08007208 int ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007209
Hai Shalom39ba6fc2019-01-22 12:40:38 -08007210 ret = os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
7211 if (ret >= (int) sizeof(name))
7212 wpa_printf(MSG_WARNING,
7213 "nl80211: WDS interface name was truncated");
7214 else if (ret < 0)
7215 return ret;
7216
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07007217 if (ifname_wds)
7218 os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
7219
Jouni Malinen75ecf522011-06-27 15:19:46 -07007220 wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
7221 " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
7222 if (val) {
7223 if (!if_nametoindex(name)) {
7224 if (nl80211_create_iface(drv, name,
7225 NL80211_IFTYPE_AP_VLAN,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007226 bss->addr, 1, NULL, NULL, 0) <
7227 0)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007228 return -1;
7229 if (bridge_ifname &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007230 linux_br_add_if(drv->global->ioctl_sock,
7231 bridge_ifname, name) < 0)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007232 return -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007233
7234 os_memset(&event, 0, sizeof(event));
7235 event.wds_sta_interface.sta_addr = addr;
7236 event.wds_sta_interface.ifname = name;
7237 event.wds_sta_interface.istatus = INTERFACE_ADDED;
Hai Shalomce48b4a2018-09-05 11:41:35 -07007238 wpa_supplicant_event(bss->ctx,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007239 EVENT_WDS_STA_INTERFACE_STATUS,
7240 &event);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007241 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007242 if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
7243 wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
7244 "interface %s up", name);
7245 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07007246 return i802_set_sta_vlan(priv, addr, name, 0);
7247 } else {
Hai Shalom74f70d42019-02-11 14:42:39 -08007248 if (bridge_ifname &&
7249 linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
7250 name) < 0)
7251 wpa_printf(MSG_INFO,
7252 "nl80211: Failed to remove interface %s from bridge %s: %s",
7253 name, bridge_ifname, strerror(errno));
Dmitry Shmidtaa532512012-09-24 10:35:31 -07007254
Jouni Malinen75ecf522011-06-27 15:19:46 -07007255 i802_set_sta_vlan(priv, addr, bss->ifname, 0);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007256 nl80211_remove_iface(drv, if_nametoindex(name));
Roshan Pius3a1667e2018-07-03 15:17:14 -07007257 os_memset(&event, 0, sizeof(event));
7258 event.wds_sta_interface.sta_addr = addr;
7259 event.wds_sta_interface.ifname = name;
7260 event.wds_sta_interface.istatus = INTERFACE_REMOVED;
Hai Shalomce48b4a2018-09-05 11:41:35 -07007261 wpa_supplicant_event(bss->ctx, EVENT_WDS_STA_INTERFACE_STATUS,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007262 &event);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08007263 return 0;
Jouni Malinen75ecf522011-06-27 15:19:46 -07007264 }
7265}
7266
7267
7268static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
7269{
7270 struct wpa_driver_nl80211_data *drv = eloop_ctx;
7271 struct sockaddr_ll lladdr;
7272 unsigned char buf[3000];
7273 int len;
7274 socklen_t fromlen = sizeof(lladdr);
7275
7276 len = recvfrom(sock, buf, sizeof(buf), 0,
7277 (struct sockaddr *)&lladdr, &fromlen);
7278 if (len < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007279 wpa_printf(MSG_ERROR, "nl80211: EAPOL recv failed: %s",
7280 strerror(errno));
Jouni Malinen75ecf522011-06-27 15:19:46 -07007281 return;
7282 }
7283
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007284 if (have_ifidx(drv, lladdr.sll_ifindex, IFIDX_ANY))
Jouni Malinen75ecf522011-06-27 15:19:46 -07007285 drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
7286}
7287
7288
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007289static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
7290 struct i802_bss *bss,
7291 const char *brname, const char *ifname)
7292{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007293 int br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007294 char in_br[IFNAMSIZ];
7295
7296 os_strlcpy(bss->brname, brname, IFNAMSIZ);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007297 br_ifindex = if_nametoindex(brname);
7298 if (br_ifindex == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007299 /*
7300 * Bridge was configured, but the bridge device does
7301 * not exist. Try to add it now.
7302 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007303 if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007304 wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
7305 "bridge interface %s: %s",
7306 brname, strerror(errno));
7307 return -1;
7308 }
7309 bss->added_bridge = 1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007310 br_ifindex = if_nametoindex(brname);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007311 add_ifidx(drv, br_ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007312 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007313 bss->br_ifindex = br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007314
7315 if (linux_br_get(in_br, ifname) == 0) {
Hai Shalomc9e41a12018-07-31 14:41:42 -07007316 if (os_strcmp(in_br, brname) == 0) {
7317 bss->already_in_bridge = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007318 return 0; /* already in the bridge */
Hai Shalomc9e41a12018-07-31 14:41:42 -07007319 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007320
7321 wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
7322 "bridge %s", ifname, in_br);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007323 if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
7324 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007325 wpa_printf(MSG_ERROR, "nl80211: Failed to "
7326 "remove interface %s from bridge "
7327 "%s: %s",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007328 ifname, in_br, strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007329 return -1;
7330 }
7331 }
7332
7333 wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
7334 ifname, brname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007335 if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08007336 wpa_printf(MSG_WARNING,
7337 "nl80211: Failed to add interface %s into bridge %s: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007338 ifname, brname, strerror(errno));
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08007339 /* Try to continue without the interface being in a bridge. This
7340 * may be needed for some cases, e.g., with Open vSwitch, where
7341 * an external component will need to handle bridge
7342 * configuration. */
7343 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007344 }
7345 bss->added_if_into_bridge = 1;
7346
7347 return 0;
7348}
7349
7350
7351static void *i802_init(struct hostapd_data *hapd,
7352 struct wpa_init_params *params)
7353{
7354 struct wpa_driver_nl80211_data *drv;
7355 struct i802_bss *bss;
7356 size_t i;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007357 char master_ifname[IFNAMSIZ];
7358 int ifindex, br_ifindex = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007359 int br_added = 0;
7360
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08007361 bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
7362 params->global_priv, 1,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007363 params->bssid, params->driver_params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007364 if (bss == NULL)
7365 return NULL;
7366
7367 drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007368
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007369 if (linux_br_get(master_ifname, params->ifname) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007370 wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007371 params->ifname, master_ifname);
7372 br_ifindex = if_nametoindex(master_ifname);
7373 os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
7374 } else if ((params->num_bridge == 0 || !params->bridge[0]) &&
7375 linux_master_get(master_ifname, params->ifname) == 0) {
7376 wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in master %s",
7377 params->ifname, master_ifname);
7378 /* start listening for EAPOL on the master interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007379 add_ifidx(drv, if_nametoindex(master_ifname), drv->ifindex);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08007380
7381 /* check if master itself is under bridge */
7382 if (linux_br_get(master_ifname, master_ifname) == 0) {
7383 wpa_printf(MSG_DEBUG, "nl80211: which is in bridge %s",
7384 master_ifname);
7385 br_ifindex = if_nametoindex(master_ifname);
7386 os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
7387 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007388 } else {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007389 master_ifname[0] = '\0';
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007390 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007391
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007392 bss->br_ifindex = br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007393
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007394 for (i = 0; i < params->num_bridge; i++) {
7395 if (params->bridge[i]) {
7396 ifindex = if_nametoindex(params->bridge[i]);
7397 if (ifindex)
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007398 add_ifidx(drv, ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007399 if (ifindex == br_ifindex)
7400 br_added = 1;
7401 }
7402 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007403
7404 /* start listening for EAPOL on the default AP interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007405 add_ifidx(drv, drv->ifindex, IFIDX_ANY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007406
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007407 if (params->num_bridge && params->bridge[0]) {
7408 if (i802_check_bridge(drv, bss, params->bridge[0],
7409 params->ifname) < 0)
7410 goto failed;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007411 if (os_strcmp(params->bridge[0], master_ifname) != 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007412 br_added = 1;
7413 }
7414
7415 if (!br_added && br_ifindex &&
7416 (params->num_bridge == 0 || !params->bridge[0]))
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007417 add_ifidx(drv, br_ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007418
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007419#ifdef CONFIG_LIBNL3_ROUTE
Hai Shalomc9e41a12018-07-31 14:41:42 -07007420 if (bss->added_if_into_bridge || bss->already_in_bridge) {
Hai Shalomfdcde762020-04-02 11:19:20 -07007421 int err;
7422
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007423 drv->rtnl_sk = nl_socket_alloc();
7424 if (drv->rtnl_sk == NULL) {
7425 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
7426 goto failed;
7427 }
7428
Hai Shalomfdcde762020-04-02 11:19:20 -07007429 err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE);
7430 if (err) {
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007431 wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -07007432 nl_geterror(err));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007433 goto failed;
7434 }
7435 }
7436#endif /* CONFIG_LIBNL3_ROUTE */
7437
Hai Shalomb755a2a2020-04-23 21:49:02 -07007438 if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) {
7439 wpa_printf(MSG_DEBUG,
7440 "nl80211: Do not open EAPOL RX socket - using control port for RX");
7441 goto skip_eapol_sock;
7442 }
7443
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007444 drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
7445 if (drv->eapol_sock < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007446 wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
7447 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007448 goto failed;
7449 }
7450
7451 if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
7452 {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007453 wpa_printf(MSG_INFO, "nl80211: Could not register read socket for eapol");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007454 goto failed;
7455 }
Hai Shalomb755a2a2020-04-23 21:49:02 -07007456skip_eapol_sock:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007457
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007458 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
7459 params->own_addr))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007460 goto failed;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07007461 os_memcpy(drv->perm_addr, params->own_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007462
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007463 memcpy(bss->addr, params->own_addr, ETH_ALEN);
7464
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007465 return bss;
7466
7467failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007468 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007469 return NULL;
7470}
7471
7472
7473static void i802_deinit(void *priv)
7474{
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007475 struct i802_bss *bss = priv;
7476 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007477}
7478
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007479
7480static enum nl80211_iftype wpa_driver_nl80211_if_type(
7481 enum wpa_driver_if_type type)
7482{
7483 switch (type) {
7484 case WPA_IF_STATION:
7485 return NL80211_IFTYPE_STATION;
7486 case WPA_IF_P2P_CLIENT:
7487 case WPA_IF_P2P_GROUP:
7488 return NL80211_IFTYPE_P2P_CLIENT;
7489 case WPA_IF_AP_VLAN:
7490 return NL80211_IFTYPE_AP_VLAN;
7491 case WPA_IF_AP_BSS:
7492 return NL80211_IFTYPE_AP;
7493 case WPA_IF_P2P_GO:
7494 return NL80211_IFTYPE_P2P_GO;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007495 case WPA_IF_P2P_DEVICE:
7496 return NL80211_IFTYPE_P2P_DEVICE;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007497 case WPA_IF_MESH:
7498 return NL80211_IFTYPE_MESH_POINT;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007499 default:
7500 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007501 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007502}
7503
7504
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007505static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
7506{
7507 struct wpa_driver_nl80211_data *drv;
7508 dl_list_for_each(drv, &global->interfaces,
7509 struct wpa_driver_nl80211_data, list) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007510 if (os_memcmp(addr, drv->first_bss->addr, ETH_ALEN) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007511 return 1;
7512 }
7513 return 0;
7514}
7515
7516
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007517static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007518{
7519 unsigned int idx;
7520
7521 if (!drv->global)
7522 return -1;
7523
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007524 os_memcpy(new_addr, drv->first_bss->addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007525 for (idx = 0; idx < 64; idx++) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007526 new_addr[0] = drv->first_bss->addr[0] | 0x02;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007527 new_addr[0] ^= idx << 2;
7528 if (!nl80211_addr_in_use(drv->global, new_addr))
7529 break;
7530 }
7531 if (idx == 64)
7532 return -1;
7533
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007534 wpa_printf(MSG_DEBUG, "nl80211: Assigned new virtual interface address "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007535 MACSTR, MAC2STR(new_addr));
7536
7537 return 0;
7538}
7539
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007540
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007541struct wdev_info {
7542 u64 wdev_id;
7543 int wdev_id_set;
7544 u8 macaddr[ETH_ALEN];
7545};
7546
7547static int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
7548{
7549 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7550 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7551 struct wdev_info *wi = arg;
7552
7553 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7554 genlmsg_attrlen(gnlh, 0), NULL);
7555 if (tb[NL80211_ATTR_WDEV]) {
7556 wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
7557 wi->wdev_id_set = 1;
7558 }
7559
7560 if (tb[NL80211_ATTR_MAC])
7561 os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
7562 ETH_ALEN);
7563
7564 return NL_SKIP;
7565}
7566
7567
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007568static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
7569 const char *ifname, const u8 *addr,
7570 void *bss_ctx, void **drv_priv,
7571 char *force_ifname, u8 *if_addr,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007572 const char *bridge, int use_existing,
7573 int setup_ap)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007574{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007575 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007576 struct i802_bss *bss = priv;
7577 struct wpa_driver_nl80211_data *drv = bss->drv;
7578 int ifidx;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007579 int added = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007580
7581 if (addr)
7582 os_memcpy(if_addr, addr, ETH_ALEN);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007583 nlmode = wpa_driver_nl80211_if_type(type);
7584 if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
7585 struct wdev_info p2pdev_info;
7586
7587 os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
7588 ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
7589 0, nl80211_wdev_handler,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007590 &p2pdev_info, use_existing);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007591 if (!p2pdev_info.wdev_id_set || ifidx != 0) {
7592 wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
7593 ifname);
7594 return -1;
7595 }
7596
7597 drv->global->if_add_wdevid = p2pdev_info.wdev_id;
7598 drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
7599 if (!is_zero_ether_addr(p2pdev_info.macaddr))
7600 os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
7601 wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
7602 ifname,
7603 (long long unsigned int) p2pdev_info.wdev_id);
7604 } else {
7605 ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007606 0, NULL, NULL, use_existing);
7607 if (use_existing && ifidx == -ENFILE) {
7608 added = 0;
7609 ifidx = if_nametoindex(ifname);
7610 } else if (ifidx < 0) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007611 return -1;
7612 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007613 }
7614
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007615 if (!addr) {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07007616 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007617 os_memcpy(if_addr, bss->addr, ETH_ALEN);
7618 else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07007619 ifname, if_addr) < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007620 if (added)
7621 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007622 return -1;
7623 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007624 }
7625
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007626 if (!addr &&
7627 (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07007628 type == WPA_IF_P2P_GO || type == WPA_IF_MESH ||
7629 type == WPA_IF_STATION)) {
7630 /* Enforce unique address */
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007631 u8 new_addr[ETH_ALEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007632
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007633 if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007634 new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07007635 if (added)
7636 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007637 return -1;
7638 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007639 if (nl80211_addr_in_use(drv->global, new_addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007640 wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07007641 "for interface %s type %d", ifname, type);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007642 if (nl80211_vif_addr(drv, new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07007643 if (added)
7644 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007645 return -1;
7646 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007647 if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007648 new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07007649 if (added)
7650 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007651 return -1;
7652 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007653 }
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07007654 os_memcpy(if_addr, new_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007655 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007656
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007657 if (type == WPA_IF_AP_BSS && setup_ap) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007658 struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
7659 if (new_bss == NULL) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007660 if (added)
7661 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007662 return -1;
7663 }
7664
7665 if (bridge &&
7666 i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
7667 wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
7668 "interface %s to a bridge %s",
7669 ifname, bridge);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007670 if (added)
7671 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07007672 os_free(new_bss);
7673 return -1;
7674 }
7675
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007676 if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
7677 {
Dmitry Shmidt71757432014-06-02 13:50:35 -07007678 if (added)
7679 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007680 os_free(new_bss);
7681 return -1;
7682 }
7683 os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007684 os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007685 new_bss->ifindex = ifidx;
7686 new_bss->drv = drv;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007687 new_bss->next = drv->first_bss->next;
7688 new_bss->freq = drv->first_bss->freq;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08007689 new_bss->ctx = bss_ctx;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007690 new_bss->added_if = added;
7691 drv->first_bss->next = new_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007692 if (drv_priv)
7693 *drv_priv = new_bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007694 nl80211_init_bss(new_bss);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08007695
7696 /* Subscribe management frames for this WPA_IF_AP_BSS */
7697 if (nl80211_setup_ap(new_bss))
7698 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007699 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007700
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007701 if (drv->global)
7702 drv->global->if_add_ifindex = ifidx;
7703
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07007704 /*
7705 * Some virtual interfaces need to process EAPOL packets and events on
7706 * the parent interface. This is used mainly with hostapd.
7707 */
7708 if (ifidx > 0 &&
7709 (drv->hostapd ||
7710 nlmode == NL80211_IFTYPE_AP_VLAN ||
7711 nlmode == NL80211_IFTYPE_WDS ||
7712 nlmode == NL80211_IFTYPE_MONITOR))
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007713 add_ifidx(drv, ifidx, IFIDX_ANY);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007714
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007715 return 0;
7716}
7717
7718
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007719static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007720 enum wpa_driver_if_type type,
7721 const char *ifname)
7722{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007723 struct wpa_driver_nl80211_data *drv = bss->drv;
7724 int ifindex = if_nametoindex(ifname);
7725
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007726 wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
7727 __func__, type, ifname, ifindex, bss->added_if);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08007728 if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
Dmitry Shmidt051af732013-10-22 13:52:46 -07007729 nl80211_remove_iface(drv, ifindex);
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07007730 else if (ifindex > 0 && !bss->added_if) {
7731 struct wpa_driver_nl80211_data *drv2;
7732 dl_list_for_each(drv2, &drv->global->interfaces,
Dmitry Shmidt9c175262016-03-03 10:20:07 -08007733 struct wpa_driver_nl80211_data, list) {
7734 del_ifidx(drv2, ifindex, IFIDX_ANY);
7735 del_ifidx(drv2, IFIDX_ANY, ifindex);
7736 }
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07007737 }
Dmitry Shmidtaa532512012-09-24 10:35:31 -07007738
Dmitry Shmidtaa532512012-09-24 10:35:31 -07007739 if (type != WPA_IF_AP_BSS)
7740 return 0;
7741
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007742 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007743 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
7744 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007745 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
7746 "interface %s from bridge %s: %s",
7747 bss->ifname, bss->brname, strerror(errno));
7748 }
7749 if (bss->added_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007750 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007751 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
7752 "bridge %s: %s",
7753 bss->brname, strerror(errno));
7754 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007755
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007756 if (bss != drv->first_bss) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007757 struct i802_bss *tbss;
7758
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007759 wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it");
7760 for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007761 if (tbss->next == bss) {
7762 tbss->next = bss->next;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08007763 /* Unsubscribe management frames */
7764 nl80211_teardown_ap(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007765 nl80211_destroy_bss(bss);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07007766 if (!bss->added_if)
7767 i802_set_iface_flags(bss, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007768 os_free(bss);
7769 bss = NULL;
7770 break;
7771 }
7772 }
7773 if (bss)
7774 wpa_printf(MSG_INFO, "nl80211: %s - could not find "
7775 "BSS %p in the list", __func__, bss);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007776 } else {
7777 wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
7778 nl80211_teardown_ap(bss);
7779 if (!bss->added_if && !drv->first_bss->next)
Paul Stewart092955c2017-02-06 09:13:09 -08007780 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08007781 nl80211_destroy_bss(bss);
7782 if (!bss->added_if)
7783 i802_set_iface_flags(bss, 0);
7784 if (drv->first_bss->next) {
7785 drv->first_bss = drv->first_bss->next;
7786 drv->ctx = drv->first_bss->ctx;
7787 os_free(bss);
7788 } else {
7789 wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
7790 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007791 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007792
7793 return 0;
7794}
7795
7796
7797static int cookie_handler(struct nl_msg *msg, void *arg)
7798{
7799 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7800 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7801 u64 *cookie = arg;
7802 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7803 genlmsg_attrlen(gnlh, 0), NULL);
7804 if (tb[NL80211_ATTR_COOKIE])
7805 *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
7806 return NL_SKIP;
7807}
7808
7809
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007810static int nl80211_send_frame_cmd(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007811 unsigned int freq, unsigned int wait,
7812 const u8 *buf, size_t buf_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07007813 int save_cookie, int no_cck, int no_ack,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007814 int offchanok, const u16 *csa_offs,
7815 size_t csa_offs_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007816{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007817 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007818 struct nl_msg *msg;
7819 u64 cookie;
7820 int ret = -1;
7821
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07007822 wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
Dmitry Shmidt04949592012-07-19 12:16:46 -07007823 "no_ack=%d offchanok=%d",
7824 freq, wait, no_cck, no_ack, offchanok);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07007825 wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007826
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007827 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME)) ||
7828 (freq && nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
7829 (wait && nla_put_u32(msg, NL80211_ATTR_DURATION, wait)) ||
7830 (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
7831 drv->test_use_roc_tx) &&
7832 nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) ||
7833 (no_cck && nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) ||
7834 (no_ack && nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK)) ||
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007835 (csa_offs && nla_put(msg, NL80211_ATTR_CSA_C_OFFSETS_TX,
7836 csa_offs_len * sizeof(u16), csa_offs)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007837 nla_put(msg, NL80211_ATTR_FRAME, buf_len, buf))
7838 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007839
7840 cookie = 0;
7841 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
7842 msg = NULL;
7843 if (ret) {
7844 wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07007845 "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
7846 freq, wait);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007847 } else {
7848 wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
7849 "cookie 0x%llx", no_ack ? " (no ACK)" : "",
7850 (long long unsigned int) cookie);
7851
Hai Shalomfdcde762020-04-02 11:19:20 -07007852 if (save_cookie)
7853 drv->send_frame_cookie = no_ack ? (u64) -1 : cookie;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007854
Hai Shalomfdcde762020-04-02 11:19:20 -07007855 if (drv->num_send_frame_cookies == MAX_SEND_FRAME_COOKIES) {
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007856 wpa_printf(MSG_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07007857 "nl80211: Drop oldest pending send frame cookie 0x%llx",
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007858 (long long unsigned int)
Hai Shalomfdcde762020-04-02 11:19:20 -07007859 drv->send_frame_cookies[0]);
7860 os_memmove(&drv->send_frame_cookies[0],
7861 &drv->send_frame_cookies[1],
7862 (MAX_SEND_FRAME_COOKIES - 1) *
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007863 sizeof(u64));
Hai Shalomfdcde762020-04-02 11:19:20 -07007864 drv->num_send_frame_cookies--;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007865 }
Hai Shalomfdcde762020-04-02 11:19:20 -07007866 drv->send_frame_cookies[drv->num_send_frame_cookies] = cookie;
7867 drv->num_send_frame_cookies++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007868 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007869
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007870fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007871 nlmsg_free(msg);
7872 return ret;
7873}
7874
7875
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007876static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
7877 unsigned int freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007878 unsigned int wait_time,
7879 const u8 *dst, const u8 *src,
7880 const u8 *bssid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007881 const u8 *data, size_t data_len,
7882 int no_cck)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007883{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007884 struct wpa_driver_nl80211_data *drv = bss->drv;
7885 int ret = -1;
7886 u8 *buf;
7887 struct ieee80211_hdr *hdr;
Hai Shalomfdcde762020-04-02 11:19:20 -07007888 int offchanok = 1;
7889
Hai Shalom4fbc08f2020-05-18 12:37:00 -07007890 if (is_ap_interface(drv->nlmode) && (int) freq == bss->freq &&
7891 bss->beacon_set)
Hai Shalomfdcde762020-04-02 11:19:20 -07007892 offchanok = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007893
7894 wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
Hai Shalomfdcde762020-04-02 11:19:20 -07007895 "freq=%u MHz wait=%d ms no_cck=%d offchanok=%d)",
7896 drv->ifindex, freq, wait_time, no_cck, offchanok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007897
7898 buf = os_zalloc(24 + data_len);
7899 if (buf == NULL)
7900 return ret;
7901 os_memcpy(buf + 24, data, data_len);
7902 hdr = (struct ieee80211_hdr *) buf;
7903 hdr->frame_control =
7904 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
7905 os_memcpy(hdr->addr1, dst, ETH_ALEN);
7906 os_memcpy(hdr->addr2, src, ETH_ALEN);
7907 os_memcpy(hdr->addr3, bssid, ETH_ALEN);
7908
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08007909 if (os_memcmp(bss->addr, src, ETH_ALEN) != 0) {
7910 wpa_printf(MSG_DEBUG, "nl80211: Use random TA " MACSTR,
7911 MAC2STR(src));
7912 os_memcpy(bss->rand_addr, src, ETH_ALEN);
7913 } else {
7914 os_memset(bss->rand_addr, 0, ETH_ALEN);
7915 }
7916
Dmitry Shmidt56052862013-10-04 10:23:25 -07007917 if (is_ap_interface(drv->nlmode) &&
7918 (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
7919 (int) freq == bss->freq || drv->device_ap_sme ||
7920 !drv->use_monitor))
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007921 ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07007922 0, freq, no_cck, offchanok,
7923 wait_time, NULL, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007924 else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007925 ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007926 24 + data_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07007927 1, no_cck, 0, offchanok, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007928
7929 os_free(buf);
7930 return ret;
7931}
7932
7933
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007934static void nl80211_frame_wait_cancel(struct i802_bss *bss, u64 cookie)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007935{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007936 struct wpa_driver_nl80211_data *drv = bss->drv;
7937 struct nl_msg *msg;
7938 int ret;
7939
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08007940 wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007941 (long long unsigned int) cookie);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007942 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME_WAIT_CANCEL)) ||
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007943 nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007944 nlmsg_free(msg);
7945 return;
7946 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007947
7948 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007949 if (ret)
7950 wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
7951 "(%s)", ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007952}
7953
7954
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007955static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
7956{
7957 struct i802_bss *bss = priv;
7958 struct wpa_driver_nl80211_data *drv = bss->drv;
7959 unsigned int i;
7960 u64 cookie;
7961
7962 /* Cancel the last pending TX cookie */
Hai Shalomfdcde762020-04-02 11:19:20 -07007963 nl80211_frame_wait_cancel(bss, drv->send_frame_cookie);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007964
7965 /*
7966 * Cancel the other pending TX cookies, if any. This is needed since
7967 * the driver may keep a list of all pending offchannel TX operations
7968 * and free up the radio only once they have expired or cancelled.
7969 */
Hai Shalomfdcde762020-04-02 11:19:20 -07007970 for (i = drv->num_send_frame_cookies; i > 0; i--) {
7971 cookie = drv->send_frame_cookies[i - 1];
7972 if (cookie != drv->send_frame_cookie)
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007973 nl80211_frame_wait_cancel(bss, cookie);
7974 }
Hai Shalomfdcde762020-04-02 11:19:20 -07007975 drv->num_send_frame_cookies = 0;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08007976}
7977
7978
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007979static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
7980 unsigned int duration)
7981{
7982 struct i802_bss *bss = priv;
7983 struct wpa_driver_nl80211_data *drv = bss->drv;
7984 struct nl_msg *msg;
7985 int ret;
7986 u64 cookie;
7987
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007988 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REMAIN_ON_CHANNEL)) ||
7989 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
7990 nla_put_u32(msg, NL80211_ATTR_DURATION, duration)) {
7991 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007992 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007993 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007994
7995 cookie = 0;
7996 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
7997 if (ret == 0) {
7998 wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
7999 "0x%llx for freq=%u MHz duration=%u",
8000 (long long unsigned int) cookie, freq, duration);
8001 drv->remain_on_chan_cookie = cookie;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008002 drv->pending_remain_on_chan = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008003 return 0;
8004 }
8005 wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
8006 "(freq=%d duration=%u): %d (%s)",
8007 freq, duration, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008008 return -1;
8009}
8010
8011
8012static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
8013{
8014 struct i802_bss *bss = priv;
8015 struct wpa_driver_nl80211_data *drv = bss->drv;
8016 struct nl_msg *msg;
8017 int ret;
8018
8019 if (!drv->pending_remain_on_chan) {
8020 wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
8021 "to cancel");
8022 return -1;
8023 }
8024
8025 wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
8026 "0x%llx",
8027 (long long unsigned int) drv->remain_on_chan_cookie);
8028
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008029 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
8030 if (!msg ||
8031 nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie)) {
8032 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008033 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008034 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008035
8036 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
8037 if (ret == 0)
8038 return 0;
8039 wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
8040 "%d (%s)", ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008041 return -1;
8042}
8043
8044
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008045static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008046{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008047 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008048
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008049 if (!report) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008050 if (bss->nl_preq && drv->device_ap_sme &&
Dmitry Shmidt03658832014-08-13 11:03:49 -07008051 is_ap_interface(drv->nlmode) && !bss->in_deinit &&
8052 !bss->static_ap) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008053 /*
8054 * Do not disable Probe Request reporting that was
8055 * enabled in nl80211_setup_ap().
8056 */
8057 wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
8058 "Probe Request reporting nl_preq=%p while "
8059 "in AP mode", bss->nl_preq);
8060 } else if (bss->nl_preq) {
8061 wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
8062 "reporting nl_preq=%p", bss->nl_preq);
Roshan Pius3a1667e2018-07-03 15:17:14 -07008063 nl80211_destroy_eloop_handle(&bss->nl_preq, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008064 }
8065 return 0;
8066 }
8067
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008068 if (bss->nl_preq) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008069 wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008070 "already on! nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008071 return 0;
8072 }
8073
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008074 bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
8075 if (bss->nl_preq == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008076 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008077 wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
8078 "reporting nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008079
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008080 if (nl80211_register_frame(bss, bss->nl_preq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008081 (WLAN_FC_TYPE_MGMT << 2) |
8082 (WLAN_FC_STYPE_PROBE_REQ << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07008083 NULL, 0, false) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008084 goto out_err;
Dmitry Shmidt497c1d52011-07-21 15:19:46 -07008085
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008086 nl80211_register_eloop_read(&bss->nl_preq,
8087 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07008088 bss->nl_cb, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008089
8090 return 0;
8091
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008092 out_err:
8093 nl_destroy_handles(&bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008094 return -1;
8095}
8096
8097
8098static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
8099 int ifindex, int disabled)
8100{
8101 struct nl_msg *msg;
8102 struct nlattr *bands, *band;
8103 int ret;
8104
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008105 wpa_printf(MSG_DEBUG,
8106 "nl80211: NL80211_CMD_SET_TX_BITRATE_MASK (ifindex=%d %s)",
8107 ifindex, disabled ? "NL80211_TXRATE_LEGACY=OFDM-only" :
8108 "no NL80211_TXRATE_LEGACY constraint");
8109
8110 msg = nl80211_ifindex_msg(drv, ifindex, 0,
8111 NL80211_CMD_SET_TX_BITRATE_MASK);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008112 if (!msg)
8113 return -1;
8114
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008115 bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
8116 if (!bands)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008117 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008118
8119 /*
8120 * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
8121 * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
8122 * rates. All 5 GHz rates are left enabled.
8123 */
8124 band = nla_nest_start(msg, NL80211_BAND_2GHZ);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008125 if (!band ||
8126 (disabled && nla_put(msg, NL80211_TXRATE_LEGACY, 8,
8127 "\x0c\x12\x18\x24\x30\x48\x60\x6c")))
8128 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008129 nla_nest_end(msg, band);
8130
8131 nla_nest_end(msg, bands);
8132
8133 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008134 if (ret) {
8135 wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
8136 "(%s)", ret, strerror(-ret));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008137 } else
8138 drv->disabled_11b_rates = disabled;
8139
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008140 return ret;
8141
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008142fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008143 nlmsg_free(msg);
8144 return -1;
8145}
8146
8147
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008148static int wpa_driver_nl80211_deinit_ap(void *priv)
8149{
8150 struct i802_bss *bss = priv;
8151 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008152 if (!is_ap_interface(drv->nlmode))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008153 return -1;
Paul Stewart092955c2017-02-06 09:13:09 -08008154 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008155 bss->beacon_set = 0;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008156
8157 /*
8158 * If the P2P GO interface was dynamically added, then it is
8159 * possible that the interface change to station is not possible.
8160 */
8161 if (drv->nlmode == NL80211_IFTYPE_P2P_GO && bss->if_dynamic)
8162 return 0;
8163
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008164 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008165}
8166
8167
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008168static int wpa_driver_nl80211_stop_ap(void *priv)
8169{
8170 struct i802_bss *bss = priv;
8171 struct wpa_driver_nl80211_data *drv = bss->drv;
8172 if (!is_ap_interface(drv->nlmode))
8173 return -1;
Paul Stewart092955c2017-02-06 09:13:09 -08008174 wpa_driver_nl80211_del_beacon(bss);
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008175 bss->beacon_set = 0;
8176 return 0;
8177}
8178
8179
Dmitry Shmidt04949592012-07-19 12:16:46 -07008180static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
8181{
8182 struct i802_bss *bss = priv;
8183 struct wpa_driver_nl80211_data *drv = bss->drv;
8184 if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
8185 return -1;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008186
8187 /*
8188 * If the P2P Client interface was dynamically added, then it is
8189 * possible that the interface change to station is not possible.
8190 */
8191 if (bss->if_dynamic)
8192 return 0;
8193
Dmitry Shmidt04949592012-07-19 12:16:46 -07008194 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
8195}
8196
8197
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008198static void wpa_driver_nl80211_resume(void *priv)
8199{
8200 struct i802_bss *bss = priv;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008201 enum nl80211_iftype nlmode = nl80211_get_ifmode(bss);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008202
8203 if (i802_set_iface_flags(bss, 1))
8204 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event");
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008205
8206 if (is_p2p_net_interface(nlmode))
8207 nl80211_disable_11b_rates(bss->drv, bss->drv->ifindex, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008208}
8209
8210
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008211static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
8212{
8213 struct i802_bss *bss = priv;
8214 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008215 struct nl_msg *msg;
8216 struct nlattr *cqm;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008217
8218 wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
8219 "hysteresis=%d", threshold, hysteresis);
8220
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008221 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_CQM)) ||
8222 !(cqm = nla_nest_start(msg, NL80211_ATTR_CQM)) ||
8223 nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold) ||
8224 nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis)) {
8225 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008226 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008227 }
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07008228 nla_nest_end(msg, cqm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008229
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008230 return send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008231}
8232
8233
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008234static int get_channel_width(struct nl_msg *msg, void *arg)
8235{
8236 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8237 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8238 struct wpa_signal_info *sig_change = arg;
8239
8240 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8241 genlmsg_attrlen(gnlh, 0), NULL);
8242
8243 sig_change->center_frq1 = -1;
8244 sig_change->center_frq2 = -1;
8245 sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
8246
8247 if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
8248 sig_change->chanwidth = convert2width(
8249 nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
8250 if (tb[NL80211_ATTR_CENTER_FREQ1])
8251 sig_change->center_frq1 =
8252 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
8253 if (tb[NL80211_ATTR_CENTER_FREQ2])
8254 sig_change->center_frq2 =
8255 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
8256 }
8257
8258 return NL_SKIP;
8259}
8260
8261
8262static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
8263 struct wpa_signal_info *sig)
8264{
8265 struct nl_msg *msg;
8266
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008267 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008268 return send_and_recv_msgs(drv, msg, get_channel_width, sig);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008269}
8270
8271
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008272static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
8273{
8274 struct i802_bss *bss = priv;
8275 struct wpa_driver_nl80211_data *drv = bss->drv;
8276 int res;
8277
8278 os_memset(si, 0, sizeof(*si));
8279 res = nl80211_get_link_signal(drv, si);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08008280 if (res) {
8281 if (drv->nlmode != NL80211_IFTYPE_ADHOC &&
8282 drv->nlmode != NL80211_IFTYPE_MESH_POINT)
8283 return res;
8284 si->current_signal = 0;
8285 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008286
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008287 res = nl80211_get_channel_width(drv, si);
8288 if (res != 0)
8289 return res;
8290
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008291 return nl80211_get_link_noise(drv, si);
8292}
8293
8294
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008295static int nl80211_set_param(void *priv, const char *param)
8296{
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07008297 struct i802_bss *bss = priv;
8298 struct wpa_driver_nl80211_data *drv = bss->drv;
8299
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008300 if (param == NULL)
8301 return 0;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08008302 wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008303
8304#ifdef CONFIG_P2P
8305 if (os_strstr(param, "use_p2p_group_interface=1")) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008306 wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
8307 "interface");
8308 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
8309 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
8310 }
8311#endif /* CONFIG_P2P */
8312
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07008313 if (os_strstr(param, "use_monitor=1"))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008314 drv->use_monitor = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008315
8316 if (os_strstr(param, "force_connect_cmd=1")) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008317 drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07008318 drv->force_connect_cmd = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08008319 }
8320
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07008321 if (os_strstr(param, "force_bss_selection=1"))
8322 drv->capa.flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
8323
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08008324 if (os_strstr(param, "no_offchannel_tx=1")) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08008325 drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
8326 drv->test_use_roc_tx = 1;
8327 }
8328
Hai Shalomb755a2a2020-04-23 21:49:02 -07008329 if (os_strstr(param, "control_port=0")) {
Hai Shalomfdcde762020-04-02 11:19:20 -07008330 drv->capa.flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
Hai Shalomb755a2a2020-04-23 21:49:02 -07008331 drv->capa.flags2 &= ~WPA_DRIVER_FLAGS2_CONTROL_PORT_RX;
8332 }
8333
8334 if (os_strstr(param, "control_port_ap=1"))
8335 drv->control_port_ap = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -07008336
8337 if (os_strstr(param, "full_ap_client_state=0"))
8338 drv->capa.flags &= ~WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
8339
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008340 return 0;
8341}
8342
8343
Dmitry Shmidte4663042016-04-04 10:07:49 -07008344static void * nl80211_global_init(void *ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008345{
8346 struct nl80211_global *global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008347 struct netlink_config *cfg;
8348
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008349 global = os_zalloc(sizeof(*global));
8350 if (global == NULL)
8351 return NULL;
Dmitry Shmidte4663042016-04-04 10:07:49 -07008352 global->ctx = ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008353 global->ioctl_sock = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008354 dl_list_init(&global->interfaces);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008355 global->if_add_ifindex = -1;
8356
8357 cfg = os_zalloc(sizeof(*cfg));
8358 if (cfg == NULL)
8359 goto err;
8360
8361 cfg->ctx = global;
8362 cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
8363 cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
8364 global->netlink = netlink_init(cfg);
8365 if (global->netlink == NULL) {
8366 os_free(cfg);
8367 goto err;
8368 }
8369
8370 if (wpa_driver_nl80211_init_nl_global(global) < 0)
8371 goto err;
8372
8373 global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
8374 if (global->ioctl_sock < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008375 wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s",
8376 strerror(errno));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008377 goto err;
8378 }
8379
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008380 return global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008381
8382err:
8383 nl80211_global_deinit(global);
8384 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008385}
8386
8387
8388static void nl80211_global_deinit(void *priv)
8389{
8390 struct nl80211_global *global = priv;
8391 if (global == NULL)
8392 return;
8393 if (!dl_list_empty(&global->interfaces)) {
8394 wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at "
8395 "nl80211_global_deinit",
8396 dl_list_len(&global->interfaces));
8397 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008398
8399 if (global->netlink)
8400 netlink_deinit(global->netlink);
8401
8402 nl_destroy_handles(&global->nl);
8403
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008404 if (global->nl_event)
Roshan Pius3a1667e2018-07-03 15:17:14 -07008405 nl80211_destroy_eloop_handle(&global->nl_event, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008406
8407 nl_cb_put(global->nl_cb);
8408
8409 if (global->ioctl_sock >= 0)
8410 close(global->ioctl_sock);
8411
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008412 os_free(global);
8413}
8414
8415
8416static const char * nl80211_get_radio_name(void *priv)
8417{
8418 struct i802_bss *bss = priv;
8419 struct wpa_driver_nl80211_data *drv = bss->drv;
8420 return drv->phyname;
8421}
8422
8423
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008424static int nl80211_pmkid(struct i802_bss *bss, int cmd,
8425 struct wpa_pmkid_params *params)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008426{
8427 struct nl_msg *msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008428 const size_t PMK_MAX_LEN = 48; /* current cfg80211 limit */
Jouni Malinen75ecf522011-06-27 15:19:46 -07008429
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008430 if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008431 (params->pmkid &&
8432 nla_put(msg, NL80211_ATTR_PMKID, 16, params->pmkid)) ||
8433 (params->bssid &&
8434 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid)) ||
8435 (params->ssid_len &&
8436 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
8437 (params->fils_cache_id &&
8438 nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2,
8439 params->fils_cache_id)) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07008440 (params->pmk_lifetime &&
8441 nla_put_u32(msg, NL80211_ATTR_PMK_LIFETIME,
8442 params->pmk_lifetime)) ||
8443 (params->pmk_reauth_threshold &&
8444 nla_put_u8(msg, NL80211_ATTR_PMK_REAUTH_THRESHOLD,
8445 params->pmk_reauth_threshold)) ||
Hai Shalom021b0b52019-04-10 11:17:58 -07008446 (cmd != NL80211_CMD_DEL_PMKSA &&
8447 params->pmk_len && params->pmk_len <= PMK_MAX_LEN &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008448 nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
Hai Shalom74f70d42019-02-11 14:42:39 -08008449 nl80211_nlmsg_clear(msg);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008450 nlmsg_free(msg);
8451 return -ENOBUFS;
8452 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07008453
Hai Shalom74f70d42019-02-11 14:42:39 -08008454 return send_and_recv_msgs(bss->drv, msg, NULL, (void *) -1);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008455}
8456
8457
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008458static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008459{
8460 struct i802_bss *bss = priv;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008461 int ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008462
8463 if (params->bssid)
8464 wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR,
8465 MAC2STR(params->bssid));
8466 else if (params->fils_cache_id && params->ssid_len) {
8467 wpa_printf(MSG_DEBUG,
8468 "nl80211: Add PMKSA for cache id %02x%02x SSID %s",
8469 params->fils_cache_id[0], params->fils_cache_id[1],
8470 wpa_ssid_txt(params->ssid, params->ssid_len));
8471 }
8472
Roshan Pius3a1667e2018-07-03 15:17:14 -07008473 ret = nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params);
8474 if (ret < 0) {
8475 wpa_printf(MSG_DEBUG,
8476 "nl80211: NL80211_CMD_SET_PMKSA failed: %d (%s)",
8477 ret, strerror(-ret));
8478 }
8479
8480 return ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -07008481}
8482
8483
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008484static int nl80211_remove_pmkid(void *priv, struct wpa_pmkid_params *params)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008485{
8486 struct i802_bss *bss = priv;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008487 int ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008488
8489 if (params->bssid)
8490 wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
8491 MAC2STR(params->bssid));
8492 else if (params->fils_cache_id && params->ssid_len) {
8493 wpa_printf(MSG_DEBUG,
8494 "nl80211: Delete PMKSA for cache id %02x%02x SSID %s",
8495 params->fils_cache_id[0], params->fils_cache_id[1],
8496 wpa_ssid_txt(params->ssid, params->ssid_len));
8497 }
8498
Roshan Pius3a1667e2018-07-03 15:17:14 -07008499 ret = nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params);
8500 if (ret < 0) {
8501 wpa_printf(MSG_DEBUG,
8502 "nl80211: NL80211_CMD_DEL_PMKSA failed: %d (%s)",
8503 ret, strerror(-ret));
8504 }
8505
8506 return ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -07008507}
8508
8509
8510static int nl80211_flush_pmkid(void *priv)
8511{
8512 struct i802_bss *bss = priv;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008513 struct nl_msg *msg;
8514
Jouni Malinen75ecf522011-06-27 15:19:46 -07008515 wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008516 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_FLUSH_PMKSA);
8517 if (!msg)
8518 return -ENOBUFS;
8519 return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008520}
8521
8522
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008523static void clean_survey_results(struct survey_results *survey_results)
8524{
8525 struct freq_survey *survey, *tmp;
8526
8527 if (dl_list_empty(&survey_results->survey_list))
8528 return;
8529
8530 dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
8531 struct freq_survey, list) {
8532 dl_list_del(&survey->list);
8533 os_free(survey);
8534 }
8535}
8536
8537
8538static void add_survey(struct nlattr **sinfo, u32 ifidx,
8539 struct dl_list *survey_list)
8540{
8541 struct freq_survey *survey;
8542
8543 survey = os_zalloc(sizeof(struct freq_survey));
8544 if (!survey)
8545 return;
8546
8547 survey->ifidx = ifidx;
8548 survey->freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
8549 survey->filled = 0;
8550
8551 if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
8552 survey->nf = (int8_t)
8553 nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
8554 survey->filled |= SURVEY_HAS_NF;
8555 }
8556
8557 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) {
8558 survey->channel_time =
8559 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
8560 survey->filled |= SURVEY_HAS_CHAN_TIME;
8561 }
8562
8563 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
8564 survey->channel_time_busy =
8565 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
8566 survey->filled |= SURVEY_HAS_CHAN_TIME_BUSY;
8567 }
8568
8569 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) {
8570 survey->channel_time_rx =
8571 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]);
8572 survey->filled |= SURVEY_HAS_CHAN_TIME_RX;
8573 }
8574
8575 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) {
8576 survey->channel_time_tx =
8577 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]);
8578 survey->filled |= SURVEY_HAS_CHAN_TIME_TX;
8579 }
8580
8581 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)",
8582 survey->freq,
8583 survey->nf,
8584 (unsigned long int) survey->channel_time,
8585 (unsigned long int) survey->channel_time_busy,
8586 (unsigned long int) survey->channel_time_tx,
8587 (unsigned long int) survey->channel_time_rx,
8588 survey->filled);
8589
8590 dl_list_add_tail(survey_list, &survey->list);
8591}
8592
8593
8594static int check_survey_ok(struct nlattr **sinfo, u32 surveyed_freq,
8595 unsigned int freq_filter)
8596{
8597 if (!freq_filter)
8598 return 1;
8599
8600 return freq_filter == surveyed_freq;
8601}
8602
8603
8604static int survey_handler(struct nl_msg *msg, void *arg)
8605{
8606 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8607 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8608 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
8609 struct survey_results *survey_results;
8610 u32 surveyed_freq = 0;
8611 u32 ifidx;
8612
8613 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
8614 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
8615 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
8616 };
8617
8618 survey_results = (struct survey_results *) arg;
8619
8620 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8621 genlmsg_attrlen(gnlh, 0), NULL);
8622
Dmitry Shmidt97672262014-02-03 13:02:54 -08008623 if (!tb[NL80211_ATTR_IFINDEX])
8624 return NL_SKIP;
8625
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008626 ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
8627
8628 if (!tb[NL80211_ATTR_SURVEY_INFO])
8629 return NL_SKIP;
8630
8631 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
8632 tb[NL80211_ATTR_SURVEY_INFO],
8633 survey_policy))
8634 return NL_SKIP;
8635
8636 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) {
8637 wpa_printf(MSG_ERROR, "nl80211: Invalid survey data");
8638 return NL_SKIP;
8639 }
8640
8641 surveyed_freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
8642
8643 if (!check_survey_ok(sinfo, surveyed_freq,
8644 survey_results->freq_filter))
8645 return NL_SKIP;
8646
8647 if (survey_results->freq_filter &&
8648 survey_results->freq_filter != surveyed_freq) {
8649 wpa_printf(MSG_EXCESSIVE, "nl80211: Ignoring survey data for freq %d MHz",
8650 surveyed_freq);
8651 return NL_SKIP;
8652 }
8653
8654 add_survey(sinfo, ifidx, &survey_results->survey_list);
8655
8656 return NL_SKIP;
8657}
8658
8659
8660static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
8661{
8662 struct i802_bss *bss = priv;
8663 struct wpa_driver_nl80211_data *drv = bss->drv;
8664 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008665 int err;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008666 union wpa_event_data data;
8667 struct survey_results *survey_results;
8668
8669 os_memset(&data, 0, sizeof(data));
8670 survey_results = &data.survey_results;
8671
8672 dl_list_init(&survey_results->survey_list);
8673
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008674 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008675 if (!msg)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008676 return -ENOBUFS;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008677
8678 if (freq)
8679 data.survey_results.freq_filter = freq;
8680
8681 do {
8682 wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
8683 err = send_and_recv_msgs(drv, msg, survey_handler,
8684 survey_results);
8685 } while (err > 0);
8686
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008687 if (err)
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008688 wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008689 else
8690 wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008691
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008692 clean_survey_results(survey_results);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07008693 return err;
8694}
8695
8696
Dmitry Shmidt807291d2015-01-27 13:40:23 -08008697static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
8698 const u8 *kck, size_t kck_len,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008699 const u8 *replay_ctr)
8700{
8701 struct i802_bss *bss = priv;
8702 struct wpa_driver_nl80211_data *drv = bss->drv;
8703 struct nlattr *replay_nested;
8704 struct nl_msg *msg;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08008705 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008706
Dmitry Shmidtff787d52015-01-12 13:01:47 -08008707 if (!drv->set_rekey_offload)
8708 return;
8709
8710 wpa_printf(MSG_DEBUG, "nl80211: Set rekey offload");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008711 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
8712 !(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
Dmitry Shmidt807291d2015-01-27 13:40:23 -08008713 nla_put(msg, NL80211_REKEY_DATA_KEK, kek_len, kek) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008714 (kck_len && nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008715 nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
8716 replay_ctr)) {
8717 nl80211_nlmsg_clear(msg);
8718 nlmsg_free(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008719 return;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008720 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008721
8722 nla_nest_end(msg, replay_nested);
8723
Dmitry Shmidtff787d52015-01-12 13:01:47 -08008724 ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
8725 if (ret == -EOPNOTSUPP) {
8726 wpa_printf(MSG_DEBUG,
8727 "nl80211: Driver does not support rekey offload");
8728 drv->set_rekey_offload = 0;
8729 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008730}
8731
8732
8733static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
8734 const u8 *addr, int qos)
8735{
8736 /* send data frame to poll STA and check whether
8737 * this frame is ACKed */
8738 struct {
8739 struct ieee80211_hdr hdr;
8740 u16 qos_ctl;
8741 } STRUCT_PACKED nulldata;
8742 size_t size;
8743
8744 /* Send data frame to poll STA and check whether this frame is ACKed */
8745
8746 os_memset(&nulldata, 0, sizeof(nulldata));
8747
8748 if (qos) {
8749 nulldata.hdr.frame_control =
8750 IEEE80211_FC(WLAN_FC_TYPE_DATA,
8751 WLAN_FC_STYPE_QOS_NULL);
8752 size = sizeof(nulldata);
8753 } else {
8754 nulldata.hdr.frame_control =
8755 IEEE80211_FC(WLAN_FC_TYPE_DATA,
8756 WLAN_FC_STYPE_NULLFUNC);
8757 size = sizeof(struct ieee80211_hdr);
8758 }
8759
8760 nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
8761 os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
8762 os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
8763 os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
8764
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008765 if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -07008766 0, 0, NULL, 0, 0) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008767 wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
8768 "send poll frame");
8769}
8770
8771static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
8772 int qos)
8773{
8774 struct i802_bss *bss = priv;
8775 struct wpa_driver_nl80211_data *drv = bss->drv;
8776 struct nl_msg *msg;
Hai Shalom5f92bc92019-04-18 11:54:11 -07008777 u64 cookie;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08008778 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008779
8780 if (!drv->poll_command_supported) {
8781 nl80211_send_null_frame(bss, own_addr, addr, qos);
8782 return;
8783 }
8784
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008785 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_PROBE_CLIENT)) ||
8786 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
8787 nlmsg_free(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008788 return;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008789 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008790
Hai Shalom5f92bc92019-04-18 11:54:11 -07008791 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08008792 if (ret < 0) {
8793 wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
8794 MACSTR " failed: ret=%d (%s)",
8795 MAC2STR(addr), ret, strerror(-ret));
Hai Shalom5f92bc92019-04-18 11:54:11 -07008796 } else {
8797 wpa_printf(MSG_DEBUG,
8798 "nl80211: Client probe request addr=" MACSTR
8799 " cookie=%llu", MAC2STR(addr),
8800 (long long unsigned int) cookie);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08008801 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008802}
8803
8804
8805static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
8806{
8807 struct nl_msg *msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008808 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008809
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008810 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
8811 nla_put_u32(msg, NL80211_ATTR_PS_STATE,
8812 enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED)) {
8813 nlmsg_free(msg);
8814 return -ENOBUFS;
8815 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07008816
8817 ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
8818 if (ret < 0) {
8819 wpa_printf(MSG_DEBUG,
8820 "nl80211: Setting PS state %s failed: %d (%s)",
8821 enabled ? "enabled" : "disabled",
8822 ret, strerror(-ret));
8823 }
8824 return ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008825}
8826
8827
8828static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
8829 int ctwindow)
8830{
8831 struct i802_bss *bss = priv;
8832
8833 wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
8834 "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
8835
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08008836 if (opp_ps != -1 || ctwindow != -1) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008837#ifdef ANDROID_P2P
8838 wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08008839#else /* ANDROID_P2P */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008840 return -1; /* Not yet supported */
Dmitry Shmidt292b0c32013-11-22 12:54:42 -08008841#endif /* ANDROID_P2P */
8842 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008843
8844 if (legacy_ps == -1)
8845 return 0;
8846 if (legacy_ps != 0 && legacy_ps != 1)
8847 return -1; /* Not yet supported */
8848
8849 return nl80211_set_power_save(bss, legacy_ps);
8850}
8851
8852
Dmitry Shmidt051af732013-10-22 13:52:46 -07008853static int nl80211_start_radar_detection(void *priv,
8854 struct hostapd_freq_params *freq)
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008855{
8856 struct i802_bss *bss = priv;
8857 struct wpa_driver_nl80211_data *drv = bss->drv;
8858 struct nl_msg *msg;
8859 int ret;
8860
Hai Shalom81f62d82019-07-22 12:10:00 -07008861 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)",
8862 freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
Dmitry Shmidt051af732013-10-22 13:52:46 -07008863 freq->bandwidth, freq->center_freq1, freq->center_freq2);
8864
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008865 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
8866 wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
8867 "detection");
8868 return -1;
8869 }
8870
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008871 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_RADAR_DETECT)) ||
8872 nl80211_put_freq_params(msg, freq) < 0) {
8873 nlmsg_free(msg);
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008874 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008875 }
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008876
8877 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
8878 if (ret == 0)
8879 return 0;
8880 wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
8881 "%d (%s)", ret, strerror(-ret));
Dmitry Shmidtea69e842013-05-13 14:52:28 -07008882 return -1;
8883}
8884
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008885#ifdef CONFIG_TDLS
8886
8887static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
8888 u8 dialog_token, u16 status_code,
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07008889 u32 peer_capab, int initiator, const u8 *buf,
8890 size_t len)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008891{
8892 struct i802_bss *bss = priv;
8893 struct wpa_driver_nl80211_data *drv = bss->drv;
8894 struct nl_msg *msg;
8895
8896 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
8897 return -EOPNOTSUPP;
8898
8899 if (!dst)
8900 return -EINVAL;
8901
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008902 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_MGMT)) ||
8903 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
8904 nla_put_u8(msg, NL80211_ATTR_TDLS_ACTION, action_code) ||
8905 nla_put_u8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token) ||
8906 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status_code))
8907 goto fail;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008908 if (peer_capab) {
8909 /*
8910 * The internal enum tdls_peer_capability definition is
8911 * currently identical with the nl80211 enum
8912 * nl80211_tdls_peer_capability, so no conversion is needed
8913 * here.
8914 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008915 if (nla_put_u32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY,
8916 peer_capab))
8917 goto fail;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008918 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008919 if ((initiator &&
8920 nla_put_flag(msg, NL80211_ATTR_TDLS_INITIATOR)) ||
8921 nla_put(msg, NL80211_ATTR_IE, len, buf))
8922 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008923
8924 return send_and_recv_msgs(drv, msg, NULL, NULL);
8925
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008926fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008927 nlmsg_free(msg);
8928 return -ENOBUFS;
8929}
8930
8931
8932static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
8933{
8934 struct i802_bss *bss = priv;
8935 struct wpa_driver_nl80211_data *drv = bss->drv;
8936 struct nl_msg *msg;
8937 enum nl80211_tdls_operation nl80211_oper;
Paul Stewart092955c2017-02-06 09:13:09 -08008938 int res;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008939
8940 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
8941 return -EOPNOTSUPP;
8942
8943 switch (oper) {
8944 case TDLS_DISCOVERY_REQ:
8945 nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
8946 break;
8947 case TDLS_SETUP:
8948 nl80211_oper = NL80211_TDLS_SETUP;
8949 break;
8950 case TDLS_TEARDOWN:
8951 nl80211_oper = NL80211_TDLS_TEARDOWN;
8952 break;
8953 case TDLS_ENABLE_LINK:
8954 nl80211_oper = NL80211_TDLS_ENABLE_LINK;
8955 break;
8956 case TDLS_DISABLE_LINK:
8957 nl80211_oper = NL80211_TDLS_DISABLE_LINK;
8958 break;
8959 case TDLS_ENABLE:
8960 return 0;
8961 case TDLS_DISABLE:
8962 return 0;
8963 default:
8964 return -EINVAL;
8965 }
8966
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008967 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_OPER)) ||
8968 nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper) ||
8969 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) {
8970 nlmsg_free(msg);
8971 return -ENOBUFS;
8972 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008973
Paul Stewart092955c2017-02-06 09:13:09 -08008974 res = send_and_recv_msgs(drv, msg, NULL, NULL);
8975 wpa_printf(MSG_DEBUG, "nl80211: TDLS_OPER: oper=%d mac=" MACSTR
8976 " --> res=%d (%s)", nl80211_oper, MAC2STR(peer), res,
8977 strerror(-res));
8978 return res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008979}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008980
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008981
8982static int
8983nl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
8984 const struct hostapd_freq_params *params)
8985{
8986 struct i802_bss *bss = priv;
8987 struct wpa_driver_nl80211_data *drv = bss->drv;
8988 struct nl_msg *msg;
8989 int ret = -ENOBUFS;
8990
8991 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
8992 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
8993 return -EOPNOTSUPP;
8994
8995 wpa_printf(MSG_DEBUG, "nl80211: Enable TDLS channel switch " MACSTR
8996 " oper_class=%u freq=%u",
8997 MAC2STR(addr), oper_class, params->freq);
8998 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CHANNEL_SWITCH);
8999 if (!msg ||
9000 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
9001 nla_put_u8(msg, NL80211_ATTR_OPER_CLASS, oper_class) ||
9002 (ret = nl80211_put_freq_params(msg, params))) {
9003 nlmsg_free(msg);
9004 wpa_printf(MSG_DEBUG, "nl80211: Could not build TDLS chan switch");
9005 return ret;
9006 }
9007
9008 return send_and_recv_msgs(drv, msg, NULL, NULL);
9009}
9010
9011
9012static int
9013nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
9014{
9015 struct i802_bss *bss = priv;
9016 struct wpa_driver_nl80211_data *drv = bss->drv;
9017 struct nl_msg *msg;
9018
9019 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
9020 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
9021 return -EOPNOTSUPP;
9022
9023 wpa_printf(MSG_DEBUG, "nl80211: Disable TDLS channel switch " MACSTR,
9024 MAC2STR(addr));
9025 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH);
9026 if (!msg ||
9027 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
9028 nlmsg_free(msg);
9029 wpa_printf(MSG_DEBUG,
9030 "nl80211: Could not build TDLS cancel chan switch");
9031 return -ENOBUFS;
9032 }
9033
9034 return send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009035}
9036
9037#endif /* CONFIG TDLS */
9038
9039
Hai Shalomfdcde762020-04-02 11:19:20 -07009040static int driver_nl80211_set_key(void *priv,
9041 struct wpa_driver_set_key_params *params)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009042{
9043 struct i802_bss *bss = priv;
Hai Shalomfdcde762020-04-02 11:19:20 -07009044
9045 return wpa_driver_nl80211_set_key(bss, params);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009046}
9047
9048
9049static int driver_nl80211_scan2(void *priv,
9050 struct wpa_driver_scan_params *params)
9051{
9052 struct i802_bss *bss = priv;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009053#ifdef CONFIG_DRIVER_NL80211_QCA
9054 struct wpa_driver_nl80211_data *drv = bss->drv;
9055
9056 /*
9057 * Do a vendor specific scan if possible. If only_new_results is
9058 * set, do a normal scan since a kernel (cfg80211) BSS cache flush
9059 * cannot be achieved through a vendor scan. The below condition may
9060 * need to be modified if new scan flags are added in the future whose
9061 * functionality can only be achieved through a normal scan.
9062 */
9063 if (drv->scan_vendor_cmd_avail && !params->only_new_results)
9064 return wpa_driver_nl80211_vendor_scan(bss, params);
9065#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009066 return wpa_driver_nl80211_scan(bss, params);
9067}
9068
9069
9070static int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -07009071 u16 reason_code)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009072{
9073 struct i802_bss *bss = priv;
9074 return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
9075}
9076
9077
9078static int driver_nl80211_authenticate(void *priv,
9079 struct wpa_driver_auth_params *params)
9080{
9081 struct i802_bss *bss = priv;
9082 return wpa_driver_nl80211_authenticate(bss, params);
9083}
9084
9085
9086static void driver_nl80211_deinit(void *priv)
9087{
9088 struct i802_bss *bss = priv;
9089 wpa_driver_nl80211_deinit(bss);
9090}
9091
9092
9093static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
9094 const char *ifname)
9095{
9096 struct i802_bss *bss = priv;
9097 return wpa_driver_nl80211_if_remove(bss, type, ifname);
9098}
9099
9100
9101static int driver_nl80211_send_mlme(void *priv, const u8 *data,
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07009102 size_t data_len, int noack,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009103 unsigned int freq,
Hai Shalomfdcde762020-04-02 11:19:20 -07009104 const u16 *csa_offs, size_t csa_offs_len,
9105 int no_encrypt, unsigned int wait)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009106{
9107 struct i802_bss *bss = priv;
9108 return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
Hai Shalomfdcde762020-04-02 11:19:20 -07009109 freq, 0, 0, wait, csa_offs,
9110 csa_offs_len, no_encrypt);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009111}
9112
9113
9114static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
9115{
9116 struct i802_bss *bss = priv;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009117 return wpa_driver_nl80211_sta_remove(bss, addr, -1, 0);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009118}
9119
9120
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009121static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
9122 const char *ifname, int vlan_id)
9123{
9124 struct i802_bss *bss = priv;
9125 return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
9126}
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009127
9128
9129static int driver_nl80211_read_sta_data(void *priv,
9130 struct hostap_sta_driver_data *data,
9131 const u8 *addr)
9132{
9133 struct i802_bss *bss = priv;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08009134
9135 os_memset(data, 0, sizeof(*data));
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009136 return i802_read_sta_data(bss, data, addr);
9137}
9138
9139
9140static int driver_nl80211_send_action(void *priv, unsigned int freq,
9141 unsigned int wait_time,
9142 const u8 *dst, const u8 *src,
9143 const u8 *bssid,
9144 const u8 *data, size_t data_len,
9145 int no_cck)
9146{
9147 struct i802_bss *bss = priv;
9148 return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
9149 bssid, data, data_len, no_cck);
9150}
9151
9152
9153static int driver_nl80211_probe_req_report(void *priv, int report)
9154{
9155 struct i802_bss *bss = priv;
9156 return wpa_driver_nl80211_probe_req_report(bss, report);
9157}
9158
9159
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009160static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
9161 const u8 *ies, size_t ies_len)
9162{
9163 int ret;
9164 struct nl_msg *msg;
9165 struct i802_bss *bss = priv;
9166 struct wpa_driver_nl80211_data *drv = bss->drv;
9167 u16 mdid = WPA_GET_LE16(md);
9168
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009169 wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009170 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_FT_IES)) ||
9171 nla_put(msg, NL80211_ATTR_IE, ies_len, ies) ||
9172 nla_put_u16(msg, NL80211_ATTR_MDID, mdid)) {
9173 nlmsg_free(msg);
9174 return -ENOBUFS;
9175 }
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009176
9177 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
9178 if (ret) {
9179 wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
9180 "err=%d (%s)", ret, strerror(-ret));
9181 }
9182
9183 return ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -07009184}
9185
9186
Hai Shalom81f62d82019-07-22 12:10:00 -07009187static int nl80211_update_dh_ie(void *priv, const u8 *peer_mac,
9188 u16 reason_code, const u8 *ie, size_t ie_len)
9189{
9190 int ret;
9191 struct nl_msg *msg;
9192 struct i802_bss *bss = priv;
9193 struct wpa_driver_nl80211_data *drv = bss->drv;
9194
9195 wpa_printf(MSG_DEBUG, "nl80211: Updating DH IE peer: " MACSTR
9196 " reason %u", MAC2STR(peer_mac), reason_code);
9197 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UPDATE_OWE_INFO)) ||
9198 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer_mac) ||
9199 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, reason_code) ||
9200 (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie))) {
9201 nlmsg_free(msg);
9202 return -ENOBUFS;
9203 }
9204
9205 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
9206 if (ret) {
9207 wpa_printf(MSG_DEBUG,
9208 "nl80211: update_dh_ie failed err=%d (%s)",
9209 ret, strerror(-ret));
9210 }
9211
9212 return ret;
9213}
9214
9215
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07009216static const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009217{
9218 struct i802_bss *bss = priv;
9219 struct wpa_driver_nl80211_data *drv = bss->drv;
9220
9221 if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
9222 return NULL;
9223
9224 return bss->addr;
9225}
9226
9227
Dmitry Shmidt56052862013-10-04 10:23:25 -07009228static const char * scan_state_str(enum scan_states scan_state)
9229{
9230 switch (scan_state) {
9231 case NO_SCAN:
9232 return "NO_SCAN";
9233 case SCAN_REQUESTED:
9234 return "SCAN_REQUESTED";
9235 case SCAN_STARTED:
9236 return "SCAN_STARTED";
9237 case SCAN_COMPLETED:
9238 return "SCAN_COMPLETED";
9239 case SCAN_ABORTED:
9240 return "SCAN_ABORTED";
9241 case SCHED_SCAN_STARTED:
9242 return "SCHED_SCAN_STARTED";
9243 case SCHED_SCAN_STOPPED:
9244 return "SCHED_SCAN_STOPPED";
9245 case SCHED_SCAN_RESULTS:
9246 return "SCHED_SCAN_RESULTS";
9247 }
9248
9249 return "??";
9250}
9251
9252
9253static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
9254{
9255 struct i802_bss *bss = priv;
9256 struct wpa_driver_nl80211_data *drv = bss->drv;
9257 int res;
9258 char *pos, *end;
Hai Shalom74f70d42019-02-11 14:42:39 -08009259 struct nl_msg *msg;
9260 char alpha2[3] = { 0, 0, 0 };
Dmitry Shmidt56052862013-10-04 10:23:25 -07009261
9262 pos = buf;
9263 end = buf + buflen;
9264
9265 res = os_snprintf(pos, end - pos,
9266 "ifindex=%d\n"
9267 "ifname=%s\n"
9268 "brname=%s\n"
9269 "addr=" MACSTR "\n"
9270 "freq=%d\n"
Hai Shalomc9e41a12018-07-31 14:41:42 -07009271 "%s%s%s%s%s%s",
Dmitry Shmidt56052862013-10-04 10:23:25 -07009272 bss->ifindex,
9273 bss->ifname,
9274 bss->brname,
9275 MAC2STR(bss->addr),
9276 bss->freq,
9277 bss->beacon_set ? "beacon_set=1\n" : "",
9278 bss->added_if_into_bridge ?
9279 "added_if_into_bridge=1\n" : "",
Hai Shalomc9e41a12018-07-31 14:41:42 -07009280 bss->already_in_bridge ? "already_in_bridge=1\n" : "",
Dmitry Shmidt56052862013-10-04 10:23:25 -07009281 bss->added_bridge ? "added_bridge=1\n" : "",
9282 bss->in_deinit ? "in_deinit=1\n" : "",
9283 bss->if_dynamic ? "if_dynamic=1\n" : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009284 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -07009285 return pos - buf;
9286 pos += res;
9287
9288 if (bss->wdev_id_set) {
9289 res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
9290 (unsigned long long) bss->wdev_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009291 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -07009292 return pos - buf;
9293 pos += res;
9294 }
9295
9296 res = os_snprintf(pos, end - pos,
9297 "phyname=%s\n"
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07009298 "perm_addr=" MACSTR "\n"
Dmitry Shmidt56052862013-10-04 10:23:25 -07009299 "drv_ifindex=%d\n"
9300 "operstate=%d\n"
9301 "scan_state=%s\n"
9302 "auth_bssid=" MACSTR "\n"
9303 "auth_attempt_bssid=" MACSTR "\n"
9304 "bssid=" MACSTR "\n"
9305 "prev_bssid=" MACSTR "\n"
9306 "associated=%d\n"
9307 "assoc_freq=%u\n"
9308 "monitor_sock=%d\n"
9309 "monitor_ifidx=%d\n"
9310 "monitor_refcount=%d\n"
9311 "last_mgmt_freq=%u\n"
9312 "eapol_tx_sock=%d\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009313 "%s%s%s%s%s%s%s%s%s%s%s%s%s",
Dmitry Shmidt56052862013-10-04 10:23:25 -07009314 drv->phyname,
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07009315 MAC2STR(drv->perm_addr),
Dmitry Shmidt56052862013-10-04 10:23:25 -07009316 drv->ifindex,
9317 drv->operstate,
9318 scan_state_str(drv->scan_state),
9319 MAC2STR(drv->auth_bssid),
9320 MAC2STR(drv->auth_attempt_bssid),
9321 MAC2STR(drv->bssid),
9322 MAC2STR(drv->prev_bssid),
9323 drv->associated,
9324 drv->assoc_freq,
9325 drv->monitor_sock,
9326 drv->monitor_ifidx,
9327 drv->monitor_refcount,
9328 drv->last_mgmt_freq,
9329 drv->eapol_tx_sock,
9330 drv->ignore_if_down_event ?
9331 "ignore_if_down_event=1\n" : "",
9332 drv->scan_complete_events ?
9333 "scan_complete_events=1\n" : "",
9334 drv->disabled_11b_rates ?
9335 "disabled_11b_rates=1\n" : "",
9336 drv->pending_remain_on_chan ?
9337 "pending_remain_on_chan=1\n" : "",
9338 drv->in_interface_list ? "in_interface_list=1\n" : "",
9339 drv->device_ap_sme ? "device_ap_sme=1\n" : "",
9340 drv->poll_command_supported ?
9341 "poll_command_supported=1\n" : "",
9342 drv->data_tx_status ? "data_tx_status=1\n" : "",
9343 drv->scan_for_auth ? "scan_for_auth=1\n" : "",
9344 drv->retry_auth ? "retry_auth=1\n" : "",
9345 drv->use_monitor ? "use_monitor=1\n" : "",
9346 drv->ignore_next_local_disconnect ?
9347 "ignore_next_local_disconnect=1\n" : "",
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07009348 drv->ignore_next_local_deauth ?
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009349 "ignore_next_local_deauth=1\n" : "");
9350 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -07009351 return pos - buf;
9352 pos += res;
9353
9354 if (drv->has_capability) {
9355 res = os_snprintf(pos, end - pos,
9356 "capa.key_mgmt=0x%x\n"
9357 "capa.enc=0x%x\n"
9358 "capa.auth=0x%x\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009359 "capa.flags=0x%llx\n"
9360 "capa.rrm_flags=0x%x\n"
Dmitry Shmidt56052862013-10-04 10:23:25 -07009361 "capa.max_scan_ssids=%d\n"
9362 "capa.max_sched_scan_ssids=%d\n"
9363 "capa.sched_scan_supported=%d\n"
9364 "capa.max_match_sets=%d\n"
9365 "capa.max_remain_on_chan=%u\n"
9366 "capa.max_stations=%u\n"
9367 "capa.probe_resp_offloads=0x%x\n"
9368 "capa.max_acl_mac_addrs=%u\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009369 "capa.num_multichan_concurrent=%u\n"
9370 "capa.mac_addr_rand_sched_scan_supported=%d\n"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009371 "capa.mac_addr_rand_scan_supported=%d\n"
9372 "capa.conc_capab=%u\n"
9373 "capa.max_conc_chan_2_4=%u\n"
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009374 "capa.max_conc_chan_5_0=%u\n"
9375 "capa.max_sched_scan_plans=%u\n"
9376 "capa.max_sched_scan_plan_interval=%u\n"
9377 "capa.max_sched_scan_plan_iterations=%u\n",
Dmitry Shmidt56052862013-10-04 10:23:25 -07009378 drv->capa.key_mgmt,
9379 drv->capa.enc,
9380 drv->capa.auth,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009381 (unsigned long long) drv->capa.flags,
9382 drv->capa.rrm_flags,
Dmitry Shmidt56052862013-10-04 10:23:25 -07009383 drv->capa.max_scan_ssids,
9384 drv->capa.max_sched_scan_ssids,
9385 drv->capa.sched_scan_supported,
9386 drv->capa.max_match_sets,
9387 drv->capa.max_remain_on_chan,
9388 drv->capa.max_stations,
9389 drv->capa.probe_resp_offloads,
9390 drv->capa.max_acl_mac_addrs,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009391 drv->capa.num_multichan_concurrent,
9392 drv->capa.mac_addr_rand_sched_scan_supported,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009393 drv->capa.mac_addr_rand_scan_supported,
9394 drv->capa.conc_capab,
9395 drv->capa.max_conc_chan_2_4,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009396 drv->capa.max_conc_chan_5_0,
9397 drv->capa.max_sched_scan_plans,
9398 drv->capa.max_sched_scan_plan_interval,
9399 drv->capa.max_sched_scan_plan_iterations);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009400 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -07009401 return pos - buf;
9402 pos += res;
9403 }
9404
Hai Shalom74f70d42019-02-11 14:42:39 -08009405 msg = nlmsg_alloc();
9406 if (msg &&
9407 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG) &&
9408 nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx) == 0) {
9409 if (send_and_recv_msgs(drv, msg, nl80211_get_country,
9410 alpha2) == 0 &&
9411 alpha2[0]) {
9412 res = os_snprintf(pos, end - pos, "country=%s\n",
9413 alpha2);
9414 if (os_snprintf_error(end - pos, res))
9415 return pos - buf;
9416 pos += res;
9417 }
9418 } else {
9419 nlmsg_free(msg);
9420 }
9421
Dmitry Shmidt56052862013-10-04 10:23:25 -07009422 return pos - buf;
9423}
9424
9425
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009426static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
9427{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009428 if ((settings->head &&
9429 nla_put(msg, NL80211_ATTR_BEACON_HEAD,
9430 settings->head_len, settings->head)) ||
9431 (settings->tail &&
9432 nla_put(msg, NL80211_ATTR_BEACON_TAIL,
9433 settings->tail_len, settings->tail)) ||
9434 (settings->beacon_ies &&
9435 nla_put(msg, NL80211_ATTR_IE,
9436 settings->beacon_ies_len, settings->beacon_ies)) ||
9437 (settings->proberesp_ies &&
9438 nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
9439 settings->proberesp_ies_len, settings->proberesp_ies)) ||
9440 (settings->assocresp_ies &&
9441 nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
9442 settings->assocresp_ies_len, settings->assocresp_ies)) ||
9443 (settings->probe_resp &&
9444 nla_put(msg, NL80211_ATTR_PROBE_RESP,
9445 settings->probe_resp_len, settings->probe_resp)))
9446 return -ENOBUFS;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009447
9448 return 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009449}
9450
9451
9452static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
9453{
9454 struct nl_msg *msg;
9455 struct i802_bss *bss = priv;
9456 struct wpa_driver_nl80211_data *drv = bss->drv;
9457 struct nlattr *beacon_csa;
9458 int ret = -ENOBUFS;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009459 int csa_off_len = 0;
9460 int i;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009461
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08009462 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 -08009463 settings->cs_count, settings->block_tx,
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08009464 settings->freq_params.freq, settings->freq_params.bandwidth,
9465 settings->freq_params.center_freq1,
9466 settings->freq_params.center_freq2);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009467
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009468 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_AP_CSA)) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009469 wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
9470 return -EOPNOTSUPP;
9471 }
9472
Roshan Pius3a1667e2018-07-03 15:17:14 -07009473 if (drv->nlmode != NL80211_IFTYPE_AP &&
9474 drv->nlmode != NL80211_IFTYPE_P2P_GO &&
9475 drv->nlmode != NL80211_IFTYPE_MESH_POINT)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009476 return -EOPNOTSUPP;
9477
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009478 /*
9479 * Remove empty counters, assuming Probe Response and Beacon frame
9480 * counters match. This implementation assumes that there are only two
9481 * counters.
9482 */
9483 if (settings->counter_offset_beacon[0] &&
9484 !settings->counter_offset_beacon[1]) {
9485 csa_off_len = 1;
9486 } else if (settings->counter_offset_beacon[1] &&
9487 !settings->counter_offset_beacon[0]) {
9488 csa_off_len = 1;
9489 settings->counter_offset_beacon[0] =
9490 settings->counter_offset_beacon[1];
9491 settings->counter_offset_presp[0] =
9492 settings->counter_offset_presp[1];
9493 } else if (settings->counter_offset_beacon[1] &&
9494 settings->counter_offset_beacon[0]) {
9495 csa_off_len = 2;
9496 } else {
9497 wpa_printf(MSG_ERROR, "nl80211: No CSA counters provided");
9498 return -EINVAL;
9499 }
9500
9501 /* Check CSA counters validity */
9502 if (drv->capa.max_csa_counters &&
9503 csa_off_len > drv->capa.max_csa_counters) {
9504 wpa_printf(MSG_ERROR,
9505 "nl80211: Too many CSA counters provided");
9506 return -EINVAL;
9507 }
9508
9509 if (!settings->beacon_csa.tail)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009510 return -EINVAL;
9511
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009512 for (i = 0; i < csa_off_len; i++) {
9513 u16 csa_c_off_bcn = settings->counter_offset_beacon[i];
9514 u16 csa_c_off_presp = settings->counter_offset_presp[i];
9515
9516 if ((settings->beacon_csa.tail_len <= csa_c_off_bcn) ||
9517 (settings->beacon_csa.tail[csa_c_off_bcn] !=
9518 settings->cs_count))
9519 return -EINVAL;
9520
9521 if (settings->beacon_csa.probe_resp &&
9522 ((settings->beacon_csa.probe_resp_len <=
9523 csa_c_off_presp) ||
9524 (settings->beacon_csa.probe_resp[csa_c_off_presp] !=
9525 settings->cs_count)))
9526 return -EINVAL;
9527 }
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009528
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009529 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CHANNEL_SWITCH)) ||
9530 nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT,
9531 settings->cs_count) ||
9532 (ret = nl80211_put_freq_params(msg, &settings->freq_params)) ||
9533 (settings->block_tx &&
9534 nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)))
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009535 goto error;
9536
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009537 /* beacon_after params */
9538 ret = set_beacon_data(msg, &settings->beacon_after);
9539 if (ret)
9540 goto error;
9541
9542 /* beacon_csa params */
9543 beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
9544 if (!beacon_csa)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009545 goto fail;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009546
9547 ret = set_beacon_data(msg, &settings->beacon_csa);
9548 if (ret)
9549 goto error;
9550
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009551 if (nla_put(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
9552 csa_off_len * sizeof(u16),
9553 settings->counter_offset_beacon) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009554 (settings->beacon_csa.probe_resp &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009555 nla_put(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
9556 csa_off_len * sizeof(u16),
9557 settings->counter_offset_presp)))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009558 goto fail;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009559
9560 nla_nest_end(msg, beacon_csa);
9561 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
9562 if (ret) {
9563 wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
9564 ret, strerror(-ret));
9565 }
9566 return ret;
9567
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009568fail:
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08009569 ret = -ENOBUFS;
9570error:
9571 nlmsg_free(msg);
9572 wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request");
9573 return ret;
9574}
9575
9576
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009577static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr,
9578 u8 user_priority, u16 admitted_time)
9579{
9580 struct i802_bss *bss = priv;
9581 struct wpa_driver_nl80211_data *drv = bss->drv;
9582 struct nl_msg *msg;
9583 int ret;
9584
9585 wpa_printf(MSG_DEBUG,
9586 "nl80211: add_ts request: tsid=%u admitted_time=%u up=%d",
9587 tsid, admitted_time, user_priority);
9588
9589 if (!is_sta_interface(drv->nlmode))
9590 return -ENOTSUP;
9591
9592 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ADD_TX_TS);
9593 if (!msg ||
9594 nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
9595 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
9596 nla_put_u8(msg, NL80211_ATTR_USER_PRIO, user_priority) ||
9597 nla_put_u16(msg, NL80211_ATTR_ADMITTED_TIME, admitted_time)) {
9598 nlmsg_free(msg);
9599 return -ENOBUFS;
9600 }
9601
9602 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
9603 if (ret)
9604 wpa_printf(MSG_DEBUG, "nl80211: add_ts failed err=%d (%s)",
9605 ret, strerror(-ret));
9606 return ret;
9607}
9608
9609
9610static int nl80211_del_ts(void *priv, u8 tsid, const u8 *addr)
9611{
9612 struct i802_bss *bss = priv;
9613 struct wpa_driver_nl80211_data *drv = bss->drv;
9614 struct nl_msg *msg;
9615 int ret;
9616
9617 wpa_printf(MSG_DEBUG, "nl80211: del_ts request: tsid=%u", tsid);
9618
9619 if (!is_sta_interface(drv->nlmode))
9620 return -ENOTSUP;
9621
9622 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_TX_TS)) ||
9623 nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
9624 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
9625 nlmsg_free(msg);
9626 return -ENOBUFS;
9627 }
9628
9629 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
9630 if (ret)
9631 wpa_printf(MSG_DEBUG, "nl80211: del_ts failed err=%d (%s)",
9632 ret, strerror(-ret));
9633 return ret;
9634}
9635
9636
Dmitry Shmidta38abf92014-03-06 13:38:44 -08009637#ifdef CONFIG_TESTING_OPTIONS
9638static int cmd_reply_handler(struct nl_msg *msg, void *arg)
9639{
9640 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
9641 struct wpabuf *buf = arg;
9642
9643 if (!buf)
9644 return NL_SKIP;
9645
9646 if ((size_t) genlmsg_attrlen(gnlh, 0) > wpabuf_tailroom(buf)) {
9647 wpa_printf(MSG_INFO, "nl80211: insufficient buffer space for reply");
9648 return NL_SKIP;
9649 }
9650
9651 wpabuf_put_data(buf, genlmsg_attrdata(gnlh, 0),
9652 genlmsg_attrlen(gnlh, 0));
9653
9654 return NL_SKIP;
9655}
9656#endif /* CONFIG_TESTING_OPTIONS */
9657
9658
9659static int vendor_reply_handler(struct nl_msg *msg, void *arg)
9660{
9661 struct nlattr *tb[NL80211_ATTR_MAX + 1];
9662 struct nlattr *nl_vendor_reply, *nl;
9663 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
9664 struct wpabuf *buf = arg;
9665 int rem;
9666
9667 if (!buf)
9668 return NL_SKIP;
9669
9670 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
9671 genlmsg_attrlen(gnlh, 0), NULL);
9672 nl_vendor_reply = tb[NL80211_ATTR_VENDOR_DATA];
9673
9674 if (!nl_vendor_reply)
9675 return NL_SKIP;
9676
9677 if ((size_t) nla_len(nl_vendor_reply) > wpabuf_tailroom(buf)) {
9678 wpa_printf(MSG_INFO, "nl80211: Vendor command: insufficient buffer space for reply");
9679 return NL_SKIP;
9680 }
9681
9682 nla_for_each_nested(nl, nl_vendor_reply, rem) {
9683 wpabuf_put_data(buf, nla_data(nl), nla_len(nl));
9684 }
9685
9686 return NL_SKIP;
9687}
9688
9689
9690static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
9691 unsigned int subcmd, const u8 *data,
9692 size_t data_len, struct wpabuf *buf)
9693{
9694 struct i802_bss *bss = priv;
9695 struct wpa_driver_nl80211_data *drv = bss->drv;
9696 struct nl_msg *msg;
9697 int ret;
9698
Dmitry Shmidta38abf92014-03-06 13:38:44 -08009699#ifdef CONFIG_TESTING_OPTIONS
9700 if (vendor_id == 0xffffffff) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009701 msg = nlmsg_alloc();
9702 if (!msg)
9703 return -ENOMEM;
9704
Dmitry Shmidta38abf92014-03-06 13:38:44 -08009705 nl80211_cmd(drv, msg, 0, subcmd);
9706 if (nlmsg_append(msg, (void *) data, data_len, NLMSG_ALIGNTO) <
9707 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009708 goto fail;
Hai Shalomb755a2a2020-04-23 21:49:02 -07009709 /* This test vendor_cmd can be used with nl80211 commands that
9710 * need the connect nl_sock, so use the owner-setting variant
9711 * of send_and_recv_msgs(). */
9712 ret = send_and_recv_msgs_owner(drv, msg,
9713 get_connect_handle(bss), 0,
9714 cmd_reply_handler, buf);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08009715 if (ret)
9716 wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
9717 ret);
9718 return ret;
9719 }
9720#endif /* CONFIG_TESTING_OPTIONS */
9721
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009722 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
9723 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, vendor_id) ||
9724 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd) ||
9725 (data &&
9726 nla_put(msg, NL80211_ATTR_VENDOR_DATA, data_len, data)))
9727 goto fail;
Dmitry Shmidta38abf92014-03-06 13:38:44 -08009728
9729 ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf);
9730 if (ret)
9731 wpa_printf(MSG_DEBUG, "nl80211: vendor command failed err=%d",
9732 ret);
9733 return ret;
9734
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009735fail:
Dmitry Shmidta38abf92014-03-06 13:38:44 -08009736 nlmsg_free(msg);
9737 return -ENOBUFS;
9738}
9739
9740
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009741static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
9742 u8 qos_map_set_len)
9743{
9744 struct i802_bss *bss = priv;
9745 struct wpa_driver_nl80211_data *drv = bss->drv;
9746 struct nl_msg *msg;
9747 int ret;
9748
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009749 wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
9750 qos_map_set, qos_map_set_len);
9751
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009752 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_QOS_MAP)) ||
9753 nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) {
9754 nlmsg_free(msg);
9755 return -ENOBUFS;
9756 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009757
9758 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
9759 if (ret)
9760 wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
9761
9762 return ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08009763}
9764
9765
Hai Shalomfdcde762020-04-02 11:19:20 -07009766static int get_wowlan_handler(struct nl_msg *msg, void *arg)
9767{
9768 struct nlattr *tb[NL80211_ATTR_MAX + 1];
9769 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
9770 int *wowlan_enabled = arg;
9771
9772 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
9773 genlmsg_attrlen(gnlh, 0), NULL);
9774
9775 *wowlan_enabled = !!tb[NL80211_ATTR_WOWLAN_TRIGGERS];
9776
9777 return NL_SKIP;
9778}
9779
9780
9781static int nl80211_get_wowlan(void *priv)
9782{
9783 struct i802_bss *bss = priv;
9784 struct wpa_driver_nl80211_data *drv = bss->drv;
9785 struct nl_msg *msg;
9786 int wowlan_enabled;
9787 int ret;
9788
9789 wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status");
9790
9791 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_WOWLAN);
9792
9793 ret = send_and_recv_msgs(drv, msg, get_wowlan_handler, &wowlan_enabled);
9794 if (ret) {
9795 wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status failed");
9796 return 0;
9797 }
9798
9799 wpa_printf(MSG_DEBUG, "nl80211: wowlan is %s",
9800 wowlan_enabled ? "enabled" : "disabled");
9801
9802 return wowlan_enabled;
9803}
9804
9805
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07009806static int nl80211_set_wowlan(void *priv,
9807 const struct wowlan_triggers *triggers)
9808{
9809 struct i802_bss *bss = priv;
9810 struct wpa_driver_nl80211_data *drv = bss->drv;
9811 struct nl_msg *msg;
9812 struct nlattr *wowlan_triggers;
9813 int ret;
9814
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07009815 wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
9816
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07009817 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_WOWLAN)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009818 !(wowlan_triggers = nla_nest_start(msg,
9819 NL80211_ATTR_WOWLAN_TRIGGERS)) ||
9820 (triggers->any &&
9821 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
9822 (triggers->disconnect &&
9823 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
9824 (triggers->magic_pkt &&
9825 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
9826 (triggers->gtk_rekey_failure &&
9827 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
9828 (triggers->eap_identity_req &&
9829 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
9830 (triggers->four_way_handshake &&
9831 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
9832 (triggers->rfkill_release &&
9833 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) {
9834 nlmsg_free(msg);
9835 return -ENOBUFS;
9836 }
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07009837
9838 nla_nest_end(msg, wowlan_triggers);
9839
9840 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
9841 if (ret)
9842 wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
9843
9844 return ret;
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07009845}
9846
9847
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009848#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07009849static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
9850{
9851 struct i802_bss *bss = priv;
9852 struct wpa_driver_nl80211_data *drv = bss->drv;
9853 struct nl_msg *msg;
9854 struct nlattr *params;
9855
9856 wpa_printf(MSG_DEBUG, "nl80211: Roaming policy: allowed=%d", allowed);
9857
9858 if (!drv->roaming_vendor_cmd_avail) {
9859 wpa_printf(MSG_DEBUG,
9860 "nl80211: Ignore roaming policy change since driver does not provide command for setting it");
9861 return -1;
9862 }
9863
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009864 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
9865 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
9866 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
9867 QCA_NL80211_VENDOR_SUBCMD_ROAMING) ||
9868 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
9869 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
9870 allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
9871 QCA_ROAMING_NOT_ALLOWED) ||
9872 (bssid &&
9873 nla_put(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid))) {
9874 nlmsg_free(msg);
9875 return -1;
9876 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07009877 nla_nest_end(msg, params);
9878
9879 return send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07009880}
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009881
9882
Roshan Pius3a1667e2018-07-03 15:17:14 -07009883static int nl80211_disable_fils(void *priv, int disable)
9884{
9885 struct i802_bss *bss = priv;
9886 struct wpa_driver_nl80211_data *drv = bss->drv;
9887 struct nl_msg *msg;
9888 struct nlattr *params;
9889
9890 wpa_printf(MSG_DEBUG, "nl80211: Disable FILS=%d", disable);
9891
9892 if (!drv->set_wifi_conf_vendor_cmd_avail)
9893 return -1;
9894
9895 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
9896 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
9897 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
9898 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION) ||
9899 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
9900 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS,
9901 disable)) {
9902 nlmsg_free(msg);
9903 return -1;
9904 }
9905 nla_nest_end(msg, params);
9906
9907 return send_and_recv_msgs(drv, msg, NULL, NULL);
9908}
9909
9910
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009911/* Reserved QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID value for wpa_supplicant */
9912#define WPA_SUPPLICANT_CLIENT_ID 1
9913
9914static int nl80211_set_bssid_blacklist(void *priv, unsigned int num_bssid,
9915 const u8 *bssid)
9916{
9917 struct i802_bss *bss = priv;
9918 struct wpa_driver_nl80211_data *drv = bss->drv;
9919 struct nl_msg *msg;
9920 struct nlattr *params, *nlbssids, *attr;
9921 unsigned int i;
9922
9923 wpa_printf(MSG_DEBUG, "nl80211: Set blacklist BSSID (num=%u)",
9924 num_bssid);
9925
9926 if (!drv->roam_vendor_cmd_avail)
9927 return -1;
9928
9929 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
9930 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
9931 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
9932 QCA_NL80211_VENDOR_SUBCMD_ROAM) ||
9933 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
9934 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
Hai Shalomc3565922019-10-28 11:58:20 -07009935 QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07009936 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID,
9937 WPA_SUPPLICANT_CLIENT_ID) ||
9938 nla_put_u32(msg,
9939 QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID,
9940 num_bssid))
9941 goto fail;
9942
9943 nlbssids = nla_nest_start(
9944 msg, QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS);
9945 if (!nlbssids)
9946 goto fail;
9947
9948 for (i = 0; i < num_bssid; i++) {
9949 attr = nla_nest_start(msg, i);
9950 if (!attr)
9951 goto fail;
9952 if (nla_put(msg,
9953 QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID,
9954 ETH_ALEN, &bssid[i * ETH_ALEN]))
9955 goto fail;
9956 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%u]: " MACSTR, i,
9957 MAC2STR(&bssid[i * ETH_ALEN]));
9958 nla_nest_end(msg, attr);
9959 }
9960 nla_nest_end(msg, nlbssids);
9961 nla_nest_end(msg, params);
9962
9963 return send_and_recv_msgs(drv, msg, NULL, NULL);
9964
9965fail:
9966 nlmsg_free(msg);
9967 return -1;
9968}
9969
Hai Shalomc3565922019-10-28 11:58:20 -07009970
9971static int nl80211_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
9972{
9973 struct i802_bss *bss = priv;
9974 struct wpa_driver_nl80211_data *drv = bss->drv;
9975 struct nl_msg *msg;
9976 struct nlattr *params;
9977
9978 if (!drv->add_sta_node_vendor_cmd_avail)
9979 return -EOPNOTSUPP;
9980
9981 wpa_printf(MSG_DEBUG, "nl80211: Add STA node");
9982
9983 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
9984 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
9985 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
9986 QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE) ||
9987 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
9988 (addr &&
9989 nla_put(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_MAC_ADDR, ETH_ALEN,
9990 addr)) ||
9991 nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO,
9992 auth_alg)) {
9993 nlmsg_free(msg);
9994 wpa_printf(MSG_ERROR,
9995 "%s: err in adding vendor_cmd and vendor_data",
9996 __func__);
9997 return -1;
9998 }
9999 nla_nest_end(msg, params);
10000
10001 return send_and_recv_msgs(drv, msg, NULL, NULL);
10002}
10003
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010004#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010005
10006
10007static int nl80211_set_mac_addr(void *priv, const u8 *addr)
10008{
10009 struct i802_bss *bss = priv;
10010 struct wpa_driver_nl80211_data *drv = bss->drv;
10011 int new_addr = addr != NULL;
10012
Dmitry Shmidt849734c2016-05-27 09:59:01 -070010013 if (TEST_FAIL())
10014 return -1;
10015
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010016 if (!addr)
10017 addr = drv->perm_addr;
10018
10019 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) < 0)
10020 return -1;
10021
10022 if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, addr) < 0)
10023 {
10024 wpa_printf(MSG_DEBUG,
10025 "nl80211: failed to set_mac_addr for %s to " MACSTR,
10026 bss->ifname, MAC2STR(addr));
10027 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
10028 1) < 0) {
10029 wpa_printf(MSG_DEBUG,
10030 "nl80211: Could not restore interface UP after failed set_mac_addr");
10031 }
10032 return -1;
10033 }
10034
10035 wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR,
10036 bss->ifname, MAC2STR(addr));
10037 drv->addr_changed = new_addr;
10038 os_memcpy(bss->addr, addr, ETH_ALEN);
10039
10040 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0)
10041 {
10042 wpa_printf(MSG_DEBUG,
10043 "nl80211: Could not restore interface UP after set_mac_addr");
10044 }
10045
10046 return 0;
10047}
10048
10049
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010050#ifdef CONFIG_MESH
10051
10052static int wpa_driver_nl80211_init_mesh(void *priv)
10053{
10054 if (wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_MESH_POINT)) {
10055 wpa_printf(MSG_INFO,
10056 "nl80211: Failed to set interface into mesh mode");
10057 return -1;
10058 }
10059 return 0;
10060}
10061
10062
Dmitry Shmidtff787d52015-01-12 13:01:47 -080010063static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id,
10064 size_t mesh_id_len)
10065{
10066 if (mesh_id) {
Hai Shalom74f70d42019-02-11 14:42:39 -080010067 wpa_printf(MSG_DEBUG, " * Mesh ID (SSID)=%s",
10068 wpa_ssid_txt(mesh_id, mesh_id_len));
Dmitry Shmidtff787d52015-01-12 13:01:47 -080010069 return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
10070 }
10071
10072 return 0;
10073}
10074
10075
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070010076static int nl80211_put_mesh_config(struct nl_msg *msg,
10077 struct wpa_driver_mesh_bss_params *params)
10078{
10079 struct nlattr *container;
10080
10081 container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
10082 if (!container)
10083 return -1;
10084
10085 if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
Roshan Pius3a1667e2018-07-03 15:17:14 -070010086 nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
10087 params->auto_plinks)) ||
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070010088 ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) &&
10089 nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010090 params->max_peer_links)) ||
10091 ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD) &&
10092 nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
10093 params->rssi_threshold)))
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070010094 return -1;
10095
10096 /*
10097 * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
10098 * the timer could disconnect stations even in that case.
10099 */
10100 if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT) &&
10101 nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
10102 params->peer_link_timeout)) {
10103 wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
10104 return -1;
10105 }
10106
10107 if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE) &&
10108 nla_put_u16(msg, NL80211_MESHCONF_HT_OPMODE, params->ht_opmode)) {
10109 wpa_printf(MSG_ERROR, "nl80211: Failed to set HT_OP_MODE");
10110 return -1;
10111 }
10112
10113 nla_nest_end(msg, container);
10114
10115 return 0;
10116}
10117
10118
Dmitry Shmidt7f656022015-02-25 14:36:37 -080010119static int nl80211_join_mesh(struct i802_bss *bss,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010120 struct wpa_driver_mesh_join_params *params)
10121{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010122 struct wpa_driver_nl80211_data *drv = bss->drv;
10123 struct nl_msg *msg;
10124 struct nlattr *container;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -080010125 int ret = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010126
10127 wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
10128 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
Dmitry Shmidtff787d52015-01-12 13:01:47 -080010129 if (!msg ||
10130 nl80211_put_freq_params(msg, &params->freq) ||
10131 nl80211_put_basic_rates(msg, params->basic_rates) ||
10132 nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) ||
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070010133 nl80211_put_beacon_int(msg, params->beacon_int) ||
10134 nl80211_put_dtim_period(msg, params->dtim_period))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010135 goto fail;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010136
10137 wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags);
10138
10139 container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
10140 if (!container)
10141 goto fail;
10142
10143 if (params->ies) {
10144 wpa_hexdump(MSG_DEBUG, " * IEs", params->ies, params->ie_len);
10145 if (nla_put(msg, NL80211_MESH_SETUP_IE, params->ie_len,
10146 params->ies))
10147 goto fail;
10148 }
10149 /* WPA_DRIVER_MESH_FLAG_OPEN_AUTH is treated as default by nl80211 */
10150 if (params->flags & WPA_DRIVER_MESH_FLAG_SAE_AUTH) {
10151 if (nla_put_u8(msg, NL80211_MESH_SETUP_AUTH_PROTOCOL, 0x1) ||
10152 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AUTH))
10153 goto fail;
10154 }
10155 if ((params->flags & WPA_DRIVER_MESH_FLAG_AMPE) &&
10156 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AMPE))
10157 goto fail;
10158 if ((params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) &&
10159 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_MPM))
10160 goto fail;
10161 nla_nest_end(msg, container);
10162
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070010163 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
10164 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT;
10165 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS;
10166 if (nl80211_put_mesh_config(msg, &params->conf) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010167 goto fail;
10168
Hai Shalomb755a2a2020-04-23 21:49:02 -070010169 ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1,
10170 NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010171 msg = NULL;
10172 if (ret) {
10173 wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
10174 ret, strerror(-ret));
10175 goto fail;
10176 }
10177 ret = 0;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070010178 drv->assoc_freq = bss->freq = params->freq.freq;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010179 wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
10180
10181fail:
10182 nlmsg_free(msg);
10183 return ret;
10184}
10185
10186
Dmitry Shmidt7f656022015-02-25 14:36:37 -080010187static int
10188wpa_driver_nl80211_join_mesh(void *priv,
10189 struct wpa_driver_mesh_join_params *params)
10190{
10191 struct i802_bss *bss = priv;
10192 int ret, timeout;
10193
10194 timeout = params->conf.peer_link_timeout;
10195
10196 /* Disable kernel inactivity timer */
10197 if (params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM)
10198 params->conf.peer_link_timeout = 0;
10199
10200 ret = nl80211_join_mesh(bss, params);
10201 if (ret == -EINVAL && params->conf.peer_link_timeout == 0) {
10202 wpa_printf(MSG_DEBUG,
10203 "nl80211: Mesh join retry for peer_link_timeout");
10204 /*
10205 * Old kernel does not support setting
10206 * NL80211_MESHCONF_PLINK_TIMEOUT to zero, so set 60 seconds
10207 * into future from peer_link_timeout.
10208 */
10209 params->conf.peer_link_timeout = timeout + 60;
10210 ret = nl80211_join_mesh(priv, params);
10211 }
10212
10213 params->conf.peer_link_timeout = timeout;
10214 return ret;
10215}
10216
10217
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010218static int wpa_driver_nl80211_leave_mesh(void *priv)
10219{
10220 struct i802_bss *bss = priv;
10221 struct wpa_driver_nl80211_data *drv = bss->drv;
10222 struct nl_msg *msg;
10223 int ret;
10224
10225 wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
10226 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
Hai Shalomb755a2a2020-04-23 21:49:02 -070010227 ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 0,
10228 NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010229 if (ret) {
10230 wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
10231 ret, strerror(-ret));
10232 } else {
10233 wpa_printf(MSG_DEBUG,
10234 "nl80211: mesh leave request send successfully");
10235 }
10236
10237 if (wpa_driver_nl80211_set_mode(drv->first_bss,
10238 NL80211_IFTYPE_STATION)) {
10239 wpa_printf(MSG_INFO,
10240 "nl80211: Failed to set interface into station mode");
10241 }
10242 return ret;
10243}
10244
Hai Shalom81f62d82019-07-22 12:10:00 -070010245
10246static int nl80211_probe_mesh_link(void *priv, const u8 *addr, const u8 *eth,
10247 size_t len)
10248{
10249 struct i802_bss *bss = priv;
10250 struct wpa_driver_nl80211_data *drv = bss->drv;
10251 struct nl_msg *msg;
10252 int ret;
10253
10254 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_PROBE_MESH_LINK);
10255 if (!msg ||
10256 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
10257 nla_put(msg, NL80211_ATTR_FRAME, len, eth)) {
10258 nlmsg_free(msg);
10259 return -ENOBUFS;
10260 }
10261
10262 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
10263 if (ret) {
10264 wpa_printf(MSG_DEBUG, "nl80211: mesh link probe to " MACSTR
10265 " failed: ret=%d (%s)",
10266 MAC2STR(addr), ret, strerror(-ret));
10267 } else {
10268 wpa_printf(MSG_DEBUG, "nl80211: Mesh link to " MACSTR
10269 " probed successfully", MAC2STR(addr));
10270 }
10271
10272 return ret;
10273}
10274
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010275#endif /* CONFIG_MESH */
10276
10277
10278static int wpa_driver_br_add_ip_neigh(void *priv, u8 version,
10279 const u8 *ipaddr, int prefixlen,
10280 const u8 *addr)
10281{
10282#ifdef CONFIG_LIBNL3_ROUTE
10283 struct i802_bss *bss = priv;
10284 struct wpa_driver_nl80211_data *drv = bss->drv;
10285 struct rtnl_neigh *rn;
10286 struct nl_addr *nl_ipaddr = NULL;
10287 struct nl_addr *nl_lladdr = NULL;
10288 int family, addrsize;
10289 int res;
10290
10291 if (!ipaddr || prefixlen == 0 || !addr)
10292 return -EINVAL;
10293
10294 if (bss->br_ifindex == 0) {
10295 wpa_printf(MSG_DEBUG,
10296 "nl80211: bridge must be set before adding an ip neigh to it");
10297 return -1;
10298 }
10299
10300 if (!drv->rtnl_sk) {
10301 wpa_printf(MSG_DEBUG,
10302 "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
10303 return -1;
10304 }
10305
10306 if (version == 4) {
10307 family = AF_INET;
10308 addrsize = 4;
10309 } else if (version == 6) {
10310 family = AF_INET6;
10311 addrsize = 16;
10312 } else {
10313 return -EINVAL;
10314 }
10315
10316 rn = rtnl_neigh_alloc();
10317 if (rn == NULL)
10318 return -ENOMEM;
10319
10320 /* set the destination ip address for neigh */
10321 nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
10322 if (nl_ipaddr == NULL) {
10323 wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
10324 res = -ENOMEM;
10325 goto errout;
10326 }
10327 nl_addr_set_prefixlen(nl_ipaddr, prefixlen);
10328 res = rtnl_neigh_set_dst(rn, nl_ipaddr);
10329 if (res) {
10330 wpa_printf(MSG_DEBUG,
10331 "nl80211: neigh set destination addr failed");
10332 goto errout;
10333 }
10334
10335 /* set the corresponding lladdr for neigh */
10336 nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN);
10337 if (nl_lladdr == NULL) {
10338 wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed");
10339 res = -ENOMEM;
10340 goto errout;
10341 }
10342 rtnl_neigh_set_lladdr(rn, nl_lladdr);
10343
10344 rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
10345 rtnl_neigh_set_state(rn, NUD_PERMANENT);
10346
10347 res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE);
10348 if (res) {
10349 wpa_printf(MSG_DEBUG,
10350 "nl80211: Adding bridge ip neigh failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070010351 nl_geterror(res));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010352 }
10353errout:
10354 if (nl_lladdr)
10355 nl_addr_put(nl_lladdr);
10356 if (nl_ipaddr)
10357 nl_addr_put(nl_ipaddr);
10358 if (rn)
10359 rtnl_neigh_put(rn);
10360 return res;
10361#else /* CONFIG_LIBNL3_ROUTE */
10362 return -1;
10363#endif /* CONFIG_LIBNL3_ROUTE */
10364}
10365
10366
10367static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version,
10368 const u8 *ipaddr)
10369{
10370#ifdef CONFIG_LIBNL3_ROUTE
10371 struct i802_bss *bss = priv;
10372 struct wpa_driver_nl80211_data *drv = bss->drv;
10373 struct rtnl_neigh *rn;
10374 struct nl_addr *nl_ipaddr;
10375 int family, addrsize;
10376 int res;
10377
10378 if (!ipaddr)
10379 return -EINVAL;
10380
10381 if (version == 4) {
10382 family = AF_INET;
10383 addrsize = 4;
10384 } else if (version == 6) {
10385 family = AF_INET6;
10386 addrsize = 16;
10387 } else {
10388 return -EINVAL;
10389 }
10390
10391 if (bss->br_ifindex == 0) {
10392 wpa_printf(MSG_DEBUG,
10393 "nl80211: bridge must be set to delete an ip neigh");
10394 return -1;
10395 }
10396
10397 if (!drv->rtnl_sk) {
10398 wpa_printf(MSG_DEBUG,
10399 "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
10400 return -1;
10401 }
10402
10403 rn = rtnl_neigh_alloc();
10404 if (rn == NULL)
10405 return -ENOMEM;
10406
10407 /* set the destination ip address for neigh */
10408 nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
10409 if (nl_ipaddr == NULL) {
10410 wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
10411 res = -ENOMEM;
10412 goto errout;
10413 }
10414 res = rtnl_neigh_set_dst(rn, nl_ipaddr);
10415 if (res) {
10416 wpa_printf(MSG_DEBUG,
10417 "nl80211: neigh set destination addr failed");
10418 goto errout;
10419 }
10420
10421 rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
10422
10423 res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
10424 if (res) {
10425 wpa_printf(MSG_DEBUG,
10426 "nl80211: Deleting bridge ip neigh failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070010427 nl_geterror(res));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010428 }
10429errout:
10430 if (nl_ipaddr)
10431 nl_addr_put(nl_ipaddr);
10432 if (rn)
10433 rtnl_neigh_put(rn);
10434 return res;
10435#else /* CONFIG_LIBNL3_ROUTE */
10436 return -1;
10437#endif /* CONFIG_LIBNL3_ROUTE */
10438}
10439
10440
10441static int linux_write_system_file(const char *path, unsigned int val)
10442{
10443 char buf[50];
10444 int fd, len;
10445
10446 len = os_snprintf(buf, sizeof(buf), "%u\n", val);
10447 if (os_snprintf_error(sizeof(buf), len))
10448 return -1;
10449
10450 fd = open(path, O_WRONLY);
10451 if (fd < 0)
10452 return -1;
10453
10454 if (write(fd, buf, len) < 0) {
10455 wpa_printf(MSG_DEBUG,
10456 "nl80211: Failed to write Linux system file: %s with the value of %d",
10457 path, val);
10458 close(fd);
10459 return -1;
10460 }
10461 close(fd);
10462
10463 return 0;
10464}
10465
10466
10467static const char * drv_br_port_attr_str(enum drv_br_port_attr attr)
10468{
10469 switch (attr) {
10470 case DRV_BR_PORT_ATTR_PROXYARP:
Dmitry Shmidt4dd28dc2015-03-10 11:21:43 -070010471 return "proxyarp_wifi";
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010472 case DRV_BR_PORT_ATTR_HAIRPIN_MODE:
10473 return "hairpin_mode";
10474 }
10475
10476 return NULL;
10477}
10478
10479
10480static int wpa_driver_br_port_set_attr(void *priv, enum drv_br_port_attr attr,
10481 unsigned int val)
10482{
10483 struct i802_bss *bss = priv;
10484 char path[128];
10485 const char *attr_txt;
10486
10487 attr_txt = drv_br_port_attr_str(attr);
10488 if (attr_txt == NULL)
10489 return -EINVAL;
10490
10491 os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/%s",
10492 bss->ifname, attr_txt);
10493
10494 if (linux_write_system_file(path, val))
10495 return -1;
10496
10497 return 0;
10498}
10499
10500
10501static const char * drv_br_net_param_str(enum drv_br_net_param param)
10502{
10503 switch (param) {
10504 case DRV_BR_NET_PARAM_GARP_ACCEPT:
10505 return "arp_accept";
Dmitry Shmidt83474442015-04-15 13:47:09 -070010506 default:
10507 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010508 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010509}
10510
10511
10512static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
10513 unsigned int val)
10514{
10515 struct i802_bss *bss = priv;
10516 char path[128];
10517 const char *param_txt;
10518 int ip_version = 4;
10519
Dmitry Shmidt83474442015-04-15 13:47:09 -070010520 if (param == DRV_BR_MULTICAST_SNOOPING) {
10521 os_snprintf(path, sizeof(path),
10522 "/sys/devices/virtual/net/%s/bridge/multicast_snooping",
10523 bss->brname);
10524 goto set_val;
10525 }
10526
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010527 param_txt = drv_br_net_param_str(param);
10528 if (param_txt == NULL)
10529 return -EINVAL;
10530
10531 switch (param) {
10532 case DRV_BR_NET_PARAM_GARP_ACCEPT:
10533 ip_version = 4;
10534 break;
10535 default:
10536 return -EINVAL;
10537 }
10538
10539 os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
10540 ip_version, bss->brname, param_txt);
10541
Dmitry Shmidt83474442015-04-15 13:47:09 -070010542set_val:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010543 if (linux_write_system_file(path, val))
10544 return -1;
10545
10546 return 0;
10547}
10548
10549
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010550#ifdef CONFIG_DRIVER_NL80211_QCA
10551
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010552static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
10553{
10554 switch (hw_mode) {
10555 case HOSTAPD_MODE_IEEE80211B:
10556 return QCA_ACS_MODE_IEEE80211B;
10557 case HOSTAPD_MODE_IEEE80211G:
10558 return QCA_ACS_MODE_IEEE80211G;
10559 case HOSTAPD_MODE_IEEE80211A:
10560 return QCA_ACS_MODE_IEEE80211A;
10561 case HOSTAPD_MODE_IEEE80211AD:
10562 return QCA_ACS_MODE_IEEE80211AD;
Dmitry Shmidtb1e52102015-05-29 12:36:29 -070010563 case HOSTAPD_MODE_IEEE80211ANY:
10564 return QCA_ACS_MODE_IEEE80211ANY;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010565 default:
10566 return -1;
10567 }
10568}
10569
10570
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080010571static int add_acs_ch_list(struct nl_msg *msg, const int *freq_list)
10572{
10573 int num_channels = 0, num_freqs;
10574 u8 *ch_list;
10575 enum hostapd_hw_mode hw_mode;
10576 int ret = 0;
10577 int i;
10578
10579 if (!freq_list)
10580 return 0;
10581
10582 num_freqs = int_array_len(freq_list);
10583 ch_list = os_malloc(sizeof(u8) * num_freqs);
10584 if (!ch_list)
10585 return -1;
10586
10587 for (i = 0; i < num_freqs; i++) {
10588 const int freq = freq_list[i];
10589
10590 if (freq == 0)
10591 break;
10592 /* Send 2.4 GHz and 5 GHz channels with
10593 * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST to maintain backwards
10594 * compatibility.
10595 */
10596 if (!(freq >= 2412 && freq <= 2484) &&
10597 !(freq >= 5180 && freq <= 5900))
10598 continue;
10599 hw_mode = ieee80211_freq_to_chan(freq, &ch_list[num_channels]);
10600 if (hw_mode != NUM_HOSTAPD_MODES)
10601 num_channels++;
10602 }
10603
10604 if (num_channels)
10605 ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
10606 num_channels, ch_list);
10607
10608 os_free(ch_list);
10609 return ret;
10610}
10611
10612
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010613static int add_acs_freq_list(struct nl_msg *msg, const int *freq_list)
10614{
10615 int i, len, ret;
10616 u32 *freqs;
10617
10618 if (!freq_list)
10619 return 0;
10620 len = int_array_len(freq_list);
10621 freqs = os_malloc(sizeof(u32) * len);
10622 if (!freqs)
10623 return -1;
10624 for (i = 0; i < len; i++)
10625 freqs[i] = freq_list[i];
10626 ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
10627 sizeof(u32) * len, freqs);
10628 os_free(freqs);
10629 return ret;
10630}
10631
10632
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010633static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
10634{
10635 struct i802_bss *bss = priv;
10636 struct wpa_driver_nl80211_data *drv = bss->drv;
10637 struct nl_msg *msg;
10638 struct nlattr *data;
10639 int ret;
10640 int mode;
10641
10642 mode = hw_mode_to_qca_acs(params->hw_mode);
10643 if (mode < 0)
10644 return -1;
10645
10646 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10647 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10648 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10649 QCA_NL80211_VENDOR_SUBCMD_DO_ACS) ||
10650 !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10651 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, mode) ||
10652 (params->ht_enabled &&
10653 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
10654 (params->ht40_enabled &&
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070010655 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) ||
10656 (params->vht_enabled &&
10657 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
10658 nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
10659 params->ch_width) ||
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080010660 add_acs_ch_list(msg, params->freq_list) ||
Hai Shalomfdcde762020-04-02 11:19:20 -070010661 add_acs_freq_list(msg, params->freq_list) ||
10662 (params->edmg_enabled &&
10663 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010664 nlmsg_free(msg);
10665 return -ENOBUFS;
10666 }
10667 nla_nest_end(msg, data);
10668
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070010669 wpa_printf(MSG_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -070010670 "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d EDMG: %d",
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070010671 params->hw_mode, params->ht_enabled, params->ht40_enabled,
Hai Shalomfdcde762020-04-02 11:19:20 -070010672 params->vht_enabled, params->ch_width, params->edmg_enabled);
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070010673
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010674 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
10675 if (ret) {
10676 wpa_printf(MSG_DEBUG,
10677 "nl80211: Failed to invoke driver ACS function: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070010678 strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010679 }
10680 return ret;
10681}
10682
10683
Ravi Joshie6ccb162015-07-16 17:45:41 -070010684static int nl80211_set_band(void *priv, enum set_band band)
10685{
10686 struct i802_bss *bss = priv;
10687 struct wpa_driver_nl80211_data *drv = bss->drv;
10688 struct nl_msg *msg;
10689 struct nlattr *data;
10690 int ret;
10691 enum qca_set_band qca_band;
10692
10693 if (!drv->setband_vendor_cmd_avail)
10694 return -1;
10695
10696 switch (band) {
10697 case WPA_SETBAND_AUTO:
10698 qca_band = QCA_SETBAND_AUTO;
10699 break;
10700 case WPA_SETBAND_5G:
10701 qca_band = QCA_SETBAND_5G;
10702 break;
10703 case WPA_SETBAND_2G:
10704 qca_band = QCA_SETBAND_2G;
10705 break;
10706 default:
10707 return -1;
10708 }
10709
10710 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10711 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10712 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10713 QCA_NL80211_VENDOR_SUBCMD_SETBAND) ||
10714 !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10715 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE, qca_band)) {
10716 nlmsg_free(msg);
10717 return -ENOBUFS;
10718 }
10719 nla_nest_end(msg, data);
10720
10721 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
10722 if (ret) {
10723 wpa_printf(MSG_DEBUG,
10724 "nl80211: Driver setband function failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070010725 strerror(-ret));
Ravi Joshie6ccb162015-07-16 17:45:41 -070010726 }
10727 return ret;
10728}
10729
10730
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010731struct nl80211_pcl {
10732 unsigned int num;
10733 unsigned int *freq_list;
10734};
10735
10736static int preferred_freq_info_handler(struct nl_msg *msg, void *arg)
10737{
10738 struct nlattr *tb[NL80211_ATTR_MAX + 1];
10739 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
10740 struct nl80211_pcl *param = arg;
10741 struct nlattr *nl_vend, *attr;
10742 enum qca_iface_type iface_type;
10743 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
10744 unsigned int num, max_num;
10745 u32 *freqs;
10746
10747 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
10748 genlmsg_attrlen(gnlh, 0), NULL);
10749
10750 nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
10751 if (!nl_vend)
10752 return NL_SKIP;
10753
10754 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
10755 nla_data(nl_vend), nla_len(nl_vend), NULL);
10756
10757 attr = tb_vendor[
10758 QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE];
10759 if (!attr) {
10760 wpa_printf(MSG_ERROR, "nl80211: iface_type couldn't be found");
10761 param->num = 0;
10762 return NL_SKIP;
10763 }
10764
10765 iface_type = (enum qca_iface_type) nla_get_u32(attr);
10766 wpa_printf(MSG_DEBUG, "nl80211: Driver returned iface_type=%d",
10767 iface_type);
10768
10769 attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST];
10770 if (!attr) {
10771 wpa_printf(MSG_ERROR,
10772 "nl80211: preferred_freq_list couldn't be found");
10773 param->num = 0;
10774 return NL_SKIP;
10775 }
10776
10777 /*
10778 * param->num has the maximum number of entries for which there
10779 * is room in the freq_list provided by the caller.
10780 */
10781 freqs = nla_data(attr);
10782 max_num = nla_len(attr) / sizeof(u32);
10783 if (max_num > param->num)
10784 max_num = param->num;
10785 for (num = 0; num < max_num; num++)
10786 param->freq_list[num] = freqs[num];
10787 param->num = num;
10788
10789 return NL_SKIP;
10790}
10791
10792
10793static int nl80211_get_pref_freq_list(void *priv,
10794 enum wpa_driver_if_type if_type,
10795 unsigned int *num,
10796 unsigned int *freq_list)
10797{
10798 struct i802_bss *bss = priv;
10799 struct wpa_driver_nl80211_data *drv = bss->drv;
10800 struct nl_msg *msg;
10801 int ret;
10802 unsigned int i;
10803 struct nlattr *params;
10804 struct nl80211_pcl param;
10805 enum qca_iface_type iface_type;
10806
10807 if (!drv->get_pref_freq_list)
10808 return -1;
10809
10810 switch (if_type) {
10811 case WPA_IF_STATION:
10812 iface_type = QCA_IFACE_TYPE_STA;
10813 break;
10814 case WPA_IF_AP_BSS:
10815 iface_type = QCA_IFACE_TYPE_AP;
10816 break;
10817 case WPA_IF_P2P_GO:
10818 iface_type = QCA_IFACE_TYPE_P2P_GO;
10819 break;
10820 case WPA_IF_P2P_CLIENT:
10821 iface_type = QCA_IFACE_TYPE_P2P_CLIENT;
10822 break;
10823 case WPA_IF_IBSS:
10824 iface_type = QCA_IFACE_TYPE_IBSS;
10825 break;
10826 case WPA_IF_TDLS:
10827 iface_type = QCA_IFACE_TYPE_TDLS;
10828 break;
10829 default:
10830 return -1;
10831 }
10832
10833 param.num = *num;
10834 param.freq_list = freq_list;
10835
10836 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10837 nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) ||
10838 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10839 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10840 QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST) ||
10841 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10842 nla_put_u32(msg,
10843 QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE,
10844 iface_type)) {
10845 wpa_printf(MSG_ERROR,
10846 "%s: err in adding vendor_cmd and vendor_data",
10847 __func__);
10848 nlmsg_free(msg);
10849 return -1;
10850 }
10851 nla_nest_end(msg, params);
10852
10853 os_memset(freq_list, 0, *num * sizeof(freq_list[0]));
10854 ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, &param);
10855 if (ret) {
10856 wpa_printf(MSG_ERROR,
10857 "%s: err in send_and_recv_msgs", __func__);
10858 return ret;
10859 }
10860
10861 *num = param.num;
10862
10863 for (i = 0; i < *num; i++) {
10864 wpa_printf(MSG_DEBUG, "nl80211: preferred_channel_list[%d]=%d",
10865 i, freq_list[i]);
10866 }
10867
10868 return 0;
10869}
10870
10871
10872static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq)
10873{
10874 struct i802_bss *bss = priv;
10875 struct wpa_driver_nl80211_data *drv = bss->drv;
10876 struct nl_msg *msg;
10877 int ret;
10878 struct nlattr *params;
10879
10880 if (!drv->set_prob_oper_freq)
10881 return -1;
10882
10883 wpa_printf(MSG_DEBUG,
10884 "nl80211: Set P2P probable operating freq %u for ifindex %d",
10885 freq, bss->ifindex);
10886
10887 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10888 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10889 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10890 QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL) ||
10891 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10892 nla_put_u32(msg,
10893 QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE,
10894 QCA_IFACE_TYPE_P2P_CLIENT) ||
10895 nla_put_u32(msg,
10896 QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ,
10897 freq)) {
10898 wpa_printf(MSG_ERROR,
10899 "%s: err in adding vendor_cmd and vendor_data",
10900 __func__);
10901 nlmsg_free(msg);
10902 return -1;
10903 }
10904 nla_nest_end(msg, params);
10905
10906 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
10907 msg = NULL;
10908 if (ret) {
10909 wpa_printf(MSG_ERROR, "%s: err in send_and_recv_msgs",
10910 __func__);
10911 return ret;
10912 }
10913 nlmsg_free(msg);
10914 return 0;
10915}
10916
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070010917
10918static int nl80211_p2p_lo_start(void *priv, unsigned int freq,
10919 unsigned int period, unsigned int interval,
10920 unsigned int count, const u8 *device_types,
10921 size_t dev_types_len,
10922 const u8 *ies, size_t ies_len)
10923{
10924 struct i802_bss *bss = priv;
10925 struct wpa_driver_nl80211_data *drv = bss->drv;
10926 struct nl_msg *msg;
10927 struct nlattr *container;
10928 int ret;
10929
10930 wpa_printf(MSG_DEBUG,
10931 "nl80211: Start P2P Listen offload: freq=%u, period=%u, interval=%u, count=%u",
10932 freq, period, interval, count);
10933
10934 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
10935 return -1;
10936
10937 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10938 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10939 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10940 QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START))
10941 goto fail;
10942
10943 container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
10944 if (!container)
10945 goto fail;
10946
10947 if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL,
10948 freq) ||
10949 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD,
10950 period) ||
10951 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL,
10952 interval) ||
10953 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT,
10954 count) ||
10955 nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES,
10956 dev_types_len, device_types) ||
10957 nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE,
10958 ies_len, ies))
10959 goto fail;
10960
10961 nla_nest_end(msg, container);
10962 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
10963 msg = NULL;
10964 if (ret) {
10965 wpa_printf(MSG_DEBUG,
10966 "nl80211: Failed to send P2P Listen offload vendor command");
10967 goto fail;
10968 }
10969
10970 return 0;
10971
10972fail:
10973 nlmsg_free(msg);
10974 return -1;
10975}
10976
10977
10978static int nl80211_p2p_lo_stop(void *priv)
10979{
10980 struct i802_bss *bss = priv;
10981 struct wpa_driver_nl80211_data *drv = bss->drv;
10982 struct nl_msg *msg;
10983
10984 wpa_printf(MSG_DEBUG, "nl80211: Stop P2P Listen offload");
10985
10986 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
10987 return -1;
10988
10989 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10990 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10991 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10992 QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP)) {
10993 nlmsg_free(msg);
10994 return -1;
10995 }
10996
10997 return send_and_recv_msgs(drv, msg, NULL, NULL);
10998}
10999
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080011000
11001static int nl80211_set_tdls_mode(void *priv, int tdls_external_control)
11002{
11003 struct i802_bss *bss = priv;
11004 struct wpa_driver_nl80211_data *drv = bss->drv;
11005 struct nl_msg *msg;
11006 struct nlattr *params;
11007 int ret;
11008 u32 tdls_mode;
11009
11010 wpa_printf(MSG_DEBUG,
11011 "nl80211: Set TDKS mode: tdls_external_control=%d",
11012 tdls_external_control);
11013
11014 if (tdls_external_control == 1)
11015 tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT |
11016 QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL;
11017 else
11018 tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT;
11019
11020 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11021 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11022 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11023 QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS))
11024 goto fail;
11025
11026 params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
11027 if (!params)
11028 goto fail;
11029
11030 if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE,
11031 tdls_mode))
11032 goto fail;
11033
11034 nla_nest_end(msg, params);
11035
11036 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
11037 msg = NULL;
11038 if (ret) {
11039 wpa_printf(MSG_ERROR,
11040 "nl80211: Set TDLS mode failed: ret=%d (%s)",
11041 ret, strerror(-ret));
11042 goto fail;
11043 }
11044 return 0;
11045fail:
11046 nlmsg_free(msg);
11047 return -1;
11048}
11049
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011050
11051#ifdef CONFIG_MBO
11052
11053static enum mbo_transition_reject_reason
11054nl80211_mbo_reject_reason_mapping(enum qca_wlan_btm_candidate_status status)
11055{
11056 switch (status) {
11057 case QCA_STATUS_REJECT_EXCESSIVE_FRAME_LOSS_EXPECTED:
11058 return MBO_TRANSITION_REJECT_REASON_FRAME_LOSS;
11059 case QCA_STATUS_REJECT_EXCESSIVE_DELAY_EXPECTED:
11060 return MBO_TRANSITION_REJECT_REASON_DELAY;
11061 case QCA_STATUS_REJECT_INSUFFICIENT_QOS_CAPACITY:
11062 return MBO_TRANSITION_REJECT_REASON_QOS_CAPACITY;
11063 case QCA_STATUS_REJECT_LOW_RSSI:
11064 return MBO_TRANSITION_REJECT_REASON_RSSI;
11065 case QCA_STATUS_REJECT_HIGH_INTERFERENCE:
11066 return MBO_TRANSITION_REJECT_REASON_INTERFERENCE;
11067 case QCA_STATUS_REJECT_UNKNOWN:
11068 default:
11069 return MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
11070 }
11071}
11072
11073
11074static void nl80211_parse_btm_candidate_info(struct candidate_list *candidate,
11075 struct nlattr *tb[], int num)
11076{
11077 enum qca_wlan_btm_candidate_status status;
11078 char buf[50];
11079
11080 os_memcpy(candidate->bssid,
11081 nla_data(tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]),
11082 ETH_ALEN);
11083
11084 status = nla_get_u32(
11085 tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS]);
11086 candidate->is_accept = status == QCA_STATUS_ACCEPT;
11087 candidate->reject_reason = nl80211_mbo_reject_reason_mapping(status);
11088
11089 if (candidate->is_accept)
11090 os_snprintf(buf, sizeof(buf), "Accepted");
11091 else
11092 os_snprintf(buf, sizeof(buf),
11093 "Rejected, Reject_reason: %d",
11094 candidate->reject_reason);
11095 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%d]: " MACSTR " %s",
11096 num, MAC2STR(candidate->bssid), buf);
11097}
11098
11099
11100static int
11101nl80211_get_bss_transition_status_handler(struct nl_msg *msg, void *arg)
11102{
11103 struct wpa_bss_candidate_info *info = arg;
11104 struct candidate_list *candidate = info->candidates;
11105 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
11106 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
11107 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1];
11108 static struct nla_policy policy[
11109 QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1] = {
11110 [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] = {
11111 .minlen = ETH_ALEN
11112 },
11113 [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS] = {
11114 .type = NLA_U32,
11115 },
11116 };
11117 struct nlattr *attr;
11118 int rem;
11119 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
11120 u8 num;
11121
11122 num = info->num; /* number of candidates sent to driver */
11123 info->num = 0;
11124 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
11125 genlmsg_attrlen(gnlh, 0), NULL);
11126
11127 if (!tb_msg[NL80211_ATTR_VENDOR_DATA] ||
11128 nla_parse_nested(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
11129 tb_msg[NL80211_ATTR_VENDOR_DATA], NULL) ||
11130 !tb_vendor[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO])
11131 return NL_SKIP;
11132
11133 wpa_printf(MSG_DEBUG,
11134 "nl80211: WNM Candidate list received from driver");
11135 nla_for_each_nested(attr,
11136 tb_vendor[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO],
11137 rem) {
11138 if (info->num >= num ||
11139 nla_parse_nested(
11140 tb, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX,
11141 attr, policy) ||
11142 !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] ||
11143 !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS])
11144 break;
11145
11146 nl80211_parse_btm_candidate_info(candidate, tb, info->num);
11147
11148 candidate++;
11149 info->num++;
11150 }
11151
11152 return NL_SKIP;
11153}
11154
11155
11156static struct wpa_bss_candidate_info *
11157nl80211_get_bss_transition_status(void *priv, struct wpa_bss_trans_info *params)
11158{
11159 struct i802_bss *bss = priv;
11160 struct wpa_driver_nl80211_data *drv = bss->drv;
11161 struct nl_msg *msg;
11162 struct nlattr *attr, *attr1, *attr2;
11163 struct wpa_bss_candidate_info *info;
11164 u8 i;
11165 int ret;
11166 u8 *pos;
11167
11168 if (!drv->fetch_bss_trans_status)
11169 return NULL;
11170
11171 info = os_zalloc(sizeof(*info));
11172 if (!info)
11173 return NULL;
11174 /* Allocate memory for number of candidates sent to driver */
11175 info->candidates = os_calloc(params->n_candidates,
11176 sizeof(*info->candidates));
11177 if (!info->candidates) {
11178 os_free(info);
11179 return NULL;
11180 }
11181
11182 /* Copy the number of candidates being sent to driver. This is used in
11183 * nl80211_get_bss_transition_status_handler() to limit the number of
11184 * candidates that can be populated in info->candidates and will be
11185 * later overwritten with the actual number of candidates received from
11186 * the driver.
11187 */
11188 info->num = params->n_candidates;
11189
11190 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11191 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11192 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11193 QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS))
11194 goto fail;
11195
11196 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
11197 if (!attr)
11198 goto fail;
11199
11200 if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON,
11201 params->mbo_transition_reason))
11202 goto fail;
11203
11204 attr1 = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO);
11205 if (!attr1)
11206 goto fail;
11207
11208 wpa_printf(MSG_DEBUG,
11209 "nl80211: WNM Candidate list info sending to driver: mbo_transition_reason: %d n_candidates: %d",
11210 params->mbo_transition_reason, params->n_candidates);
11211 pos = params->bssid;
11212 for (i = 0; i < params->n_candidates; i++) {
11213 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%d]: " MACSTR, i,
11214 MAC2STR(pos));
11215 attr2 = nla_nest_start(msg, i);
11216 if (!attr2 ||
11217 nla_put(msg, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID,
11218 ETH_ALEN, pos))
11219 goto fail;
11220 pos += ETH_ALEN;
11221 nla_nest_end(msg, attr2);
11222 }
11223
11224 nla_nest_end(msg, attr1);
11225 nla_nest_end(msg, attr);
11226
11227 ret = send_and_recv_msgs(drv, msg,
11228 nl80211_get_bss_transition_status_handler,
11229 info);
11230 msg = NULL;
11231 if (ret) {
11232 wpa_printf(MSG_ERROR,
11233 "nl80211: WNM Get BSS transition status failed: ret=%d (%s)",
11234 ret, strerror(-ret));
11235 goto fail;
11236 }
11237 return info;
11238
11239fail:
11240 nlmsg_free(msg);
11241 os_free(info->candidates);
11242 os_free(info);
11243 return NULL;
11244}
11245
11246
11247/**
11248 * nl80211_ignore_assoc_disallow - Configure driver to ignore assoc_disallow
11249 * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
11250 * @ignore_assoc_disallow: 0 to not ignore, 1 to ignore
11251 * Returns: 0 on success, -1 on failure
11252 */
11253static int nl80211_ignore_assoc_disallow(void *priv, int ignore_disallow)
11254{
11255 struct i802_bss *bss = priv;
11256 struct wpa_driver_nl80211_data *drv = bss->drv;
11257 struct nl_msg *msg;
11258 struct nlattr *attr;
11259 int ret = -1;
11260
11261 if (!drv->set_wifi_conf_vendor_cmd_avail)
11262 return -1;
11263
11264 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
11265 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
11266 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
11267 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION))
11268 goto fail;
11269
11270 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
11271 if (!attr)
11272 goto fail;
11273
11274 wpa_printf(MSG_DEBUG, "nl80211: Set ignore_assoc_disallow %d",
11275 ignore_disallow);
11276 if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED,
11277 ignore_disallow))
11278 goto fail;
11279
11280 nla_nest_end(msg, attr);
11281
11282 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
11283 msg = NULL;
11284 if (ret) {
11285 wpa_printf(MSG_ERROR,
11286 "nl80211: Set ignore_assoc_disallow failed: ret=%d (%s)",
11287 ret, strerror(-ret));
11288 goto fail;
11289 }
11290
11291fail:
11292 nlmsg_free(msg);
11293 return ret;
11294}
11295
11296#endif /* CONFIG_MBO */
11297
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011298#endif /* CONFIG_DRIVER_NL80211_QCA */
11299
11300
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011301static int nl80211_write_to_file(const char *name, unsigned int val)
11302{
11303 int fd, len;
11304 char tmp[128];
Hai Shalomc3565922019-10-28 11:58:20 -070011305 int ret = 0;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011306
11307 fd = open(name, O_RDWR);
11308 if (fd < 0) {
Hai Shalomc3565922019-10-28 11:58:20 -070011309 int level;
11310 /*
11311 * Flags may not exist on older kernels, or while we're tearing
11312 * down a disappearing device.
11313 */
11314 if (errno == ENOENT) {
11315 ret = 0;
11316 level = MSG_DEBUG;
11317 } else {
11318 ret = -1;
11319 level = MSG_ERROR;
11320 }
11321 wpa_printf(level, "nl80211: Failed to open %s: %s",
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011322 name, strerror(errno));
Hai Shalomc3565922019-10-28 11:58:20 -070011323 return ret;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011324 }
11325
11326 len = os_snprintf(tmp, sizeof(tmp), "%u\n", val);
11327 len = write(fd, tmp, len);
Hai Shalomc3565922019-10-28 11:58:20 -070011328 if (len < 0) {
11329 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011330 wpa_printf(MSG_ERROR, "nl80211: Failed to write to %s: %s",
11331 name, strerror(errno));
Hai Shalomc3565922019-10-28 11:58:20 -070011332 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011333 close(fd);
11334
Hai Shalomc3565922019-10-28 11:58:20 -070011335 return ret;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011336}
11337
11338
11339static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags)
11340{
11341 struct i802_bss *bss = priv;
11342 char path[128];
11343 int ret;
11344
11345 wpa_printf(MSG_DEBUG, "nl80211: Data frame filter flags=0x%x",
11346 filter_flags);
11347
11348 /* Configure filtering of unicast frame encrypted using GTK */
11349 ret = os_snprintf(path, sizeof(path),
11350 "/proc/sys/net/ipv4/conf/%s/drop_unicast_in_l2_multicast",
11351 bss->ifname);
11352 if (os_snprintf_error(sizeof(path), ret))
11353 return -1;
11354
11355 ret = nl80211_write_to_file(path,
11356 !!(filter_flags &
11357 WPA_DATA_FRAME_FILTER_FLAG_GTK));
11358 if (ret) {
11359 wpa_printf(MSG_ERROR,
11360 "nl80211: Failed to set IPv4 unicast in multicast filter");
11361 return ret;
11362 }
11363
11364 os_snprintf(path, sizeof(path),
11365 "/proc/sys/net/ipv6/conf/%s/drop_unicast_in_l2_multicast",
11366 bss->ifname);
11367 ret = nl80211_write_to_file(path,
11368 !!(filter_flags &
11369 WPA_DATA_FRAME_FILTER_FLAG_GTK));
11370
11371 if (ret) {
11372 wpa_printf(MSG_ERROR,
11373 "nl80211: Failed to set IPv6 unicast in multicast filter");
11374 return ret;
11375 }
11376
11377 /* Configure filtering of unicast frame encrypted using GTK */
11378 os_snprintf(path, sizeof(path),
11379 "/proc/sys/net/ipv4/conf/%s/drop_gratuitous_arp",
11380 bss->ifname);
11381 ret = nl80211_write_to_file(path,
11382 !!(filter_flags &
11383 WPA_DATA_FRAME_FILTER_FLAG_ARP));
11384 if (ret) {
11385 wpa_printf(MSG_ERROR,
11386 "nl80211: Failed set gratuitous ARP filter");
11387 return ret;
11388 }
11389
11390 /* Configure filtering of IPv6 NA frames */
11391 os_snprintf(path, sizeof(path),
11392 "/proc/sys/net/ipv6/conf/%s/drop_unsolicited_na",
11393 bss->ifname);
11394 ret = nl80211_write_to_file(path,
11395 !!(filter_flags &
11396 WPA_DATA_FRAME_FILTER_FLAG_NA));
11397 if (ret) {
11398 wpa_printf(MSG_ERROR,
11399 "nl80211: Failed to set unsolicited NA filter");
11400 return ret;
11401 }
11402
11403 return 0;
11404}
11405
11406
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070011407static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type,
11408 const u8 **ext_capa, const u8 **ext_capa_mask,
11409 unsigned int *ext_capa_len)
11410{
11411 struct i802_bss *bss = priv;
11412 struct wpa_driver_nl80211_data *drv = bss->drv;
11413 enum nl80211_iftype nlmode;
11414 unsigned int i;
11415
11416 if (!ext_capa || !ext_capa_mask || !ext_capa_len)
11417 return -1;
11418
11419 nlmode = wpa_driver_nl80211_if_type(type);
11420
11421 /* By default, use the per-radio values */
11422 *ext_capa = drv->extended_capa;
11423 *ext_capa_mask = drv->extended_capa_mask;
11424 *ext_capa_len = drv->extended_capa_len;
11425
11426 /* Replace the default value if a per-interface type value exists */
11427 for (i = 0; i < drv->num_iface_ext_capa; i++) {
11428 if (nlmode == drv->iface_ext_capa[i].iftype) {
11429 *ext_capa = drv->iface_ext_capa[i].ext_capa;
11430 *ext_capa_mask = drv->iface_ext_capa[i].ext_capa_mask;
11431 *ext_capa_len = drv->iface_ext_capa[i].ext_capa_len;
11432 break;
11433 }
11434 }
11435
11436 return 0;
11437}
11438
11439
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011440static int nl80211_update_connection_params(
11441 void *priv, struct wpa_driver_associate_params *params,
11442 enum wpa_drv_update_connect_params_mask mask)
11443{
11444 struct i802_bss *bss = priv;
11445 struct wpa_driver_nl80211_data *drv = bss->drv;
11446 struct nl_msg *msg;
11447 int ret = -1;
11448 enum nl80211_auth_type type;
11449
Hai Shalomc3565922019-10-28 11:58:20 -070011450 /* Update Connection Params is intended for drivers that implement
11451 * internal SME and expect these updated connection params from
11452 * wpa_supplicant. Do not send this request for the drivers using
11453 * SME from wpa_supplicant.
11454 */
11455 if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
11456 return 0;
11457
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011458 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_CONNECT_PARAMS);
11459 if (!msg)
11460 goto fail;
11461
11462 wpa_printf(MSG_DEBUG, "nl80211: Update connection params (ifindex=%d)",
11463 drv->ifindex);
11464
11465 if ((mask & WPA_DRV_UPDATE_ASSOC_IES) && params->wpa_ie) {
11466 if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
11467 params->wpa_ie))
11468 goto fail;
11469 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie,
11470 params->wpa_ie_len);
11471 }
11472
11473 if (mask & WPA_DRV_UPDATE_AUTH_TYPE) {
11474 type = get_nl_auth_type(params->auth_alg);
11475 if (type == NL80211_AUTHTYPE_MAX ||
11476 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
11477 goto fail;
11478 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
11479 }
11480
11481 if ((mask & WPA_DRV_UPDATE_FILS_ERP_INFO) &&
11482 nl80211_put_fils_connect_params(drv, params, msg))
11483 goto fail;
11484
11485 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
11486 msg = NULL;
11487 if (ret)
11488 wpa_dbg(drv->ctx, MSG_DEBUG,
11489 "nl80211: Update connect params command failed: ret=%d (%s)",
11490 ret, strerror(-ret));
11491
11492fail:
11493 nlmsg_free(msg);
11494 return ret;
11495}
11496
11497
Roshan Pius3a1667e2018-07-03 15:17:14 -070011498static int nl80211_send_external_auth_status(void *priv,
11499 struct external_auth *params)
11500{
11501 struct i802_bss *bss = priv;
11502 struct wpa_driver_nl80211_data *drv = bss->drv;
11503 struct nl_msg *msg = NULL;
11504 int ret = -1;
11505
Hai Shalom5f92bc92019-04-18 11:54:11 -070011506 /* External auth command/status is intended for drivers that implement
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080011507 * internal SME but want to offload authentication processing (e.g.,
11508 * SAE) to hostapd/wpa_supplicant. Do not send the status to drivers
Hai Shalom5f92bc92019-04-18 11:54:11 -070011509 * which do not support AP SME or use wpa_supplicant/hostapd SME.
11510 */
Hai Shalom81f62d82019-07-22 12:10:00 -070011511 if ((is_ap_interface(drv->nlmode) && !bss->drv->device_ap_sme) ||
Hai Shalom5f92bc92019-04-18 11:54:11 -070011512 (drv->capa.flags & WPA_DRIVER_FLAGS_SME))
11513 return -1;
11514
Roshan Pius3a1667e2018-07-03 15:17:14 -070011515 wpa_dbg(drv->ctx, MSG_DEBUG,
11516 "nl80211: External auth status: %u", params->status);
11517
11518 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_EXTERNAL_AUTH);
11519 if (!msg ||
11520 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, params->status) ||
Hai Shalom5f92bc92019-04-18 11:54:11 -070011521 (params->ssid && params->ssid_len &&
11522 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
11523 (params->pmkid &&
11524 nla_put(msg, NL80211_ATTR_PMKID, PMKID_LEN, params->pmkid)) ||
11525 (params->bssid &&
11526 nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid)))
Roshan Pius3a1667e2018-07-03 15:17:14 -070011527 goto fail;
11528 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
11529 msg = NULL;
11530 if (ret) {
11531 wpa_printf(MSG_DEBUG,
11532 "nl80211: External Auth status update failed: ret=%d (%s)",
11533 ret, strerror(-ret));
11534 goto fail;
11535 }
11536fail:
11537 nlmsg_free(msg);
11538 return ret;
11539}
11540
11541
Hai Shalom74f70d42019-02-11 14:42:39 -080011542static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname,
11543 int val)
11544{
11545 struct i802_bss *bss = priv;
11546 struct wpa_driver_nl80211_data *drv = bss->drv;
11547 struct nl_msg *msg;
11548 int ret = -ENOBUFS;
11549
11550 wpa_printf(MSG_DEBUG, "nl80211: %s 4addr mode (bridge_ifname: %s)",
11551 val ? "Enable" : "Disable", bridge_ifname);
11552
11553 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
11554 if (!msg || nla_put_u8(msg, NL80211_ATTR_4ADDR, val))
11555 goto fail;
11556
11557 if (bridge_ifname[0] && bss->added_if_into_bridge && !val) {
11558 if (linux_br_del_if(drv->global->ioctl_sock,
11559 bridge_ifname, bss->ifname)) {
11560 wpa_printf(MSG_ERROR,
11561 "nl80211: Failed to remove interface %s from bridge %s",
11562 bss->ifname, bridge_ifname);
11563 return -1;
11564 }
11565 bss->added_if_into_bridge = 0;
11566 }
11567
11568 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
11569 msg = NULL;
11570 if (!ret) {
11571 if (bridge_ifname[0] && val &&
11572 i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0)
11573 return -1;
11574 return 0;
11575 }
11576
11577fail:
11578 nlmsg_free(msg);
11579 wpa_printf(MSG_ERROR, "nl80211: Failed to enable/disable 4addr");
11580
11581 return ret;
11582}
11583
11584
Hai Shalome21d4e82020-04-29 16:34:06 -070011585#ifdef CONFIG_DPP
11586static int nl80211_dpp_listen(void *priv, bool enable)
11587{
11588 struct i802_bss *bss = priv;
11589 struct wpa_driver_nl80211_data *drv = bss->drv;
11590 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
11591 struct nl_sock *handle;
11592
11593 if (!drv->multicast_registrations || !bss->nl_mgmt)
11594 return 0; /* cannot do more than hope broadcast RX works */
11595
11596 wpa_printf(MSG_DEBUG,
11597 "nl80211: Update DPP Public Action frame registration (%s multicast RX)",
11598 enable ? "enable" : "disable");
11599 handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID);
11600 return nl80211_register_frame(bss, handle, type,
11601 (u8 *) "\x04\x09\x50\x6f\x9a\x1a", 6,
11602 enable);
11603}
11604#endif /* CONFIG_DPP */
11605
11606
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011607const struct wpa_driver_ops wpa_driver_nl80211_ops = {
11608 .name = "nl80211",
11609 .desc = "Linux nl80211/cfg80211",
11610 .get_bssid = wpa_driver_nl80211_get_bssid,
11611 .get_ssid = wpa_driver_nl80211_get_ssid,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011612 .set_key = driver_nl80211_set_key,
11613 .scan2 = driver_nl80211_scan2,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080011614 .sched_scan = wpa_driver_nl80211_sched_scan,
11615 .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011616 .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080011617 .abort_scan = wpa_driver_nl80211_abort_scan,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011618 .deauthenticate = driver_nl80211_deauthenticate,
11619 .authenticate = driver_nl80211_authenticate,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011620 .associate = wpa_driver_nl80211_associate,
11621 .global_init = nl80211_global_init,
11622 .global_deinit = nl80211_global_deinit,
11623 .init2 = wpa_driver_nl80211_init,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011624 .deinit = driver_nl80211_deinit,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011625 .get_capa = wpa_driver_nl80211_get_capa,
11626 .set_operstate = wpa_driver_nl80211_set_operstate,
11627 .set_supp_port = wpa_driver_nl80211_set_supp_port,
11628 .set_country = wpa_driver_nl80211_set_country,
Dmitry Shmidtcce06662013-11-04 18:44:24 -080011629 .get_country = wpa_driver_nl80211_get_country,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080011630 .set_ap = wpa_driver_nl80211_set_ap,
Dmitry Shmidt8bae4132013-06-06 11:25:10 -070011631 .set_acl = wpa_driver_nl80211_set_acl,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011632 .if_add = wpa_driver_nl80211_if_add,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011633 .if_remove = driver_nl80211_if_remove,
11634 .send_mlme = driver_nl80211_send_mlme,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011635 .get_hw_feature_data = nl80211_get_hw_feature_data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011636 .sta_add = wpa_driver_nl80211_sta_add,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011637 .sta_remove = driver_nl80211_sta_remove,
Hai Shalomfdcde762020-04-02 11:19:20 -070011638 .tx_control_port = nl80211_tx_control_port,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011639 .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
11640 .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
Hai Shalom81f62d82019-07-22 12:10:00 -070011641 .sta_set_airtime_weight = driver_nl80211_sta_set_airtime_weight,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011642 .hapd_init = i802_init,
11643 .hapd_deinit = i802_deinit,
Jouni Malinen75ecf522011-06-27 15:19:46 -070011644 .set_wds_sta = i802_set_wds_sta,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011645 .get_seqnum = i802_get_seqnum,
11646 .flush = i802_flush,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011647 .get_inact_sec = i802_get_inact_sec,
11648 .sta_clear_stats = i802_sta_clear_stats,
11649 .set_rts = i802_set_rts,
11650 .set_frag = i802_set_frag,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011651 .set_tx_queue_params = i802_set_tx_queue_params,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011652 .set_sta_vlan = driver_nl80211_set_sta_vlan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011653 .sta_deauth = i802_sta_deauth,
11654 .sta_disassoc = i802_sta_disassoc,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011655 .read_sta_data = driver_nl80211_read_sta_data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011656 .set_freq = i802_set_freq,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011657 .send_action = driver_nl80211_send_action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011658 .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
11659 .remain_on_channel = wpa_driver_nl80211_remain_on_channel,
11660 .cancel_remain_on_channel =
11661 wpa_driver_nl80211_cancel_remain_on_channel,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011662 .probe_req_report = driver_nl80211_probe_req_report,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011663 .deinit_ap = wpa_driver_nl80211_deinit_ap,
Dmitry Shmidt04949592012-07-19 12:16:46 -070011664 .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011665 .resume = wpa_driver_nl80211_resume,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011666 .signal_monitor = nl80211_signal_monitor,
11667 .signal_poll = nl80211_signal_poll,
Hai Shalom74f70d42019-02-11 14:42:39 -080011668 .channel_info = nl80211_channel_info,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011669 .set_param = nl80211_set_param,
11670 .get_radio_name = nl80211_get_radio_name,
Jouni Malinen75ecf522011-06-27 15:19:46 -070011671 .add_pmkid = nl80211_add_pmkid,
11672 .remove_pmkid = nl80211_remove_pmkid,
11673 .flush_pmkid = nl80211_flush_pmkid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080011674 .set_rekey_info = nl80211_set_rekey_info,
11675 .poll_client = nl80211_poll_client,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080011676 .set_p2p_powersave = nl80211_set_p2p_powersave,
Dmitry Shmidtea69e842013-05-13 14:52:28 -070011677 .start_dfs_cac = nl80211_start_radar_detection,
11678 .stop_ap = wpa_driver_nl80211_stop_ap,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080011679#ifdef CONFIG_TDLS
11680 .send_tdls_mgmt = nl80211_send_tdls_mgmt,
11681 .tdls_oper = nl80211_tdls_oper,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011682 .tdls_enable_channel_switch = nl80211_tdls_enable_channel_switch,
11683 .tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080011684#endif /* CONFIG_TDLS */
Dmitry Shmidt700a1372013-03-15 14:14:44 -070011685 .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
Hai Shalom81f62d82019-07-22 12:10:00 -070011686 .update_dh_ie = nl80211_update_dh_ie,
Dmitry Shmidt34af3062013-07-11 10:46:32 -070011687 .get_mac_addr = wpa_driver_nl80211_get_macaddr,
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070011688 .get_survey = wpa_driver_nl80211_get_survey,
Dmitry Shmidt56052862013-10-04 10:23:25 -070011689 .status = wpa_driver_nl80211_status,
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011690 .switch_channel = nl80211_switch_channel,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080011691#ifdef ANDROID_P2P
Dmitry Shmidt6e933c12011-09-27 12:29:26 -070011692 .set_noa = wpa_driver_set_p2p_noa,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080011693 .get_noa = wpa_driver_get_p2p_noa,
Dmitry Shmidt6e933c12011-09-27 12:29:26 -070011694 .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
Dmitry Shmidt292b0c32013-11-22 12:54:42 -080011695#endif /* ANDROID_P2P */
Dmitry Shmidt738a26e2011-07-07 14:22:14 -070011696#ifdef ANDROID
Dmitry Shmidt41712582015-06-29 11:02:15 -070011697#ifndef ANDROID_LIB_STUB
Dmitry Shmidt738a26e2011-07-07 14:22:14 -070011698 .driver_cmd = wpa_driver_nl80211_driver_cmd,
Dmitry Shmidt41712582015-06-29 11:02:15 -070011699#endif /* !ANDROID_LIB_STUB */
Dmitry Shmidt292b0c32013-11-22 12:54:42 -080011700#endif /* ANDROID */
Dmitry Shmidta38abf92014-03-06 13:38:44 -080011701 .vendor_cmd = nl80211_vendor_cmd,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080011702 .set_qos_map = nl80211_set_qos_map,
Hai Shalomfdcde762020-04-02 11:19:20 -070011703 .get_wowlan = nl80211_get_wowlan,
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070011704 .set_wowlan = nl80211_set_wowlan,
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070011705 .set_mac_addr = nl80211_set_mac_addr,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011706#ifdef CONFIG_MESH
11707 .init_mesh = wpa_driver_nl80211_init_mesh,
11708 .join_mesh = wpa_driver_nl80211_join_mesh,
11709 .leave_mesh = wpa_driver_nl80211_leave_mesh,
Hai Shalom81f62d82019-07-22 12:10:00 -070011710 .probe_mesh_link = nl80211_probe_mesh_link,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011711#endif /* CONFIG_MESH */
11712 .br_add_ip_neigh = wpa_driver_br_add_ip_neigh,
11713 .br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh,
11714 .br_port_set_attr = wpa_driver_br_port_set_attr,
11715 .br_set_net_param = wpa_driver_br_set_net_param,
11716 .add_tx_ts = nl80211_add_ts,
11717 .del_tx_ts = nl80211_del_ts,
Dmitry Shmidte4663042016-04-04 10:07:49 -070011718 .get_ifindex = nl80211_get_ifindex,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011719#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070011720 .roaming = nl80211_roaming,
Roshan Pius3a1667e2018-07-03 15:17:14 -070011721 .disable_fils = nl80211_disable_fils,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011722 .do_acs = wpa_driver_do_acs,
Ravi Joshie6ccb162015-07-16 17:45:41 -070011723 .set_band = nl80211_set_band,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011724 .get_pref_freq_list = nl80211_get_pref_freq_list,
11725 .set_prob_oper_freq = nl80211_set_prob_oper_freq,
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070011726 .p2p_lo_start = nl80211_p2p_lo_start,
11727 .p2p_lo_stop = nl80211_p2p_lo_stop,
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -070011728 .set_default_scan_ies = nl80211_set_default_scan_ies,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080011729 .set_tdls_mode = nl80211_set_tdls_mode,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011730#ifdef CONFIG_MBO
11731 .get_bss_transition_status = nl80211_get_bss_transition_status,
11732 .ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
11733#endif /* CONFIG_MBO */
11734 .set_bssid_blacklist = nl80211_set_bssid_blacklist,
Hai Shalomc3565922019-10-28 11:58:20 -070011735 .add_sta_node = nl80211_add_sta_node,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011736#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt849734c2016-05-27 09:59:01 -070011737 .configure_data_frame_filters = nl80211_configure_data_frame_filters,
Ajay Davanagerib921bb82020-09-16 12:49:08 +053011738#if defined(CONFIG_DRIVER_NL80211_BRCM)
11739 .do_acs = wpa_driver_do_broadcom_acs,
11740#endif /* CONFIG_DRIVER_NL80211_BRCM */
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070011741 .get_ext_capab = nl80211_get_ext_capab,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070011742 .update_connect_params = nl80211_update_connection_params,
Roshan Pius3a1667e2018-07-03 15:17:14 -070011743 .send_external_auth_status = nl80211_send_external_auth_status,
Hai Shalom74f70d42019-02-11 14:42:39 -080011744 .set_4addr_mode = nl80211_set_4addr_mode,
Hai Shalome21d4e82020-04-29 16:34:06 -070011745#ifdef CONFIG_DPP
11746 .dpp_listen = nl80211_dpp_listen,
11747#endif /* CONFIG_DPP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011748};