blob: 5890ac6f4df2fabe0f00b4311acb92162e4d1bfe [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>
Sunil Ravib0ac25f2024-07-12 01:42:03 +000015#include <sys/utsname.h>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070016#include <fcntl.h>
17#include <net/if.h>
18#include <netlink/genl/genl.h>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070019#include <netlink/genl/ctrl.h>
Sunil Ravib0ac25f2024-07-12 01:42:03 +000020#include <netlink/genl/family.h>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070021#include <linux/rtnetlink.h>
22#include <netpacket/packet.h>
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080023#include <linux/errqueue.h>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070024
25#include "common.h"
26#include "eloop.h"
Dmitry Shmidtcf32e602014-01-28 10:57:39 -080027#include "common/qca-vendor.h"
Dmitry Shmidt7832adb2014-04-29 10:53:02 -070028#include "common/qca-vendor-attr.h"
Hai Shalomc1a21442022-02-04 13:43:00 -080029#include "common/brcm_vendor.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"
Sunil Ravic0f5d412024-09-11 22:12:49 +000033#include "common/nan.h"
34#include "common/nan_de.h"
Sunil Ravi89eba102022-09-13 21:04:37 -070035#include "crypto/sha256.h"
36#include "crypto/sha384.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070037#include "netlink.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080038#include "linux_defines.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070039#include "linux_ioctl.h"
40#include "radiotap.h"
41#include "radiotap_iter.h"
42#include "rfkill.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080043#include "driver_nl80211.h"
Andy Kuoaba17c12022-04-14 16:05:31 +080044#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Ajay Davanagerib921bb82020-09-16 12:49:08 +053045#include "common/brcm_vendor.h"
Andy Kuoaba17c12022-04-14 16:05:31 +080046#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080047
Hai Shalom74f70d42019-02-11 14:42:39 -080048#ifndef NETLINK_CAP_ACK
49#define NETLINK_CAP_ACK 10
50#endif /* NETLINK_CAP_ACK */
Hai Shalom39ba6fc2019-01-22 12:40:38 -080051/* support for extack if compilation headers are too old */
52#ifndef NETLINK_EXT_ACK
53#define NETLINK_EXT_ACK 11
54enum nlmsgerr_attrs {
55 NLMSGERR_ATTR_UNUSED,
56 NLMSGERR_ATTR_MSG,
57 NLMSGERR_ATTR_OFFS,
58 NLMSGERR_ATTR_COOKIE,
59
60 __NLMSGERR_ATTR_MAX,
61 NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
62};
63#endif
64#ifndef NLM_F_CAPPED
65#define NLM_F_CAPPED 0x100
66#endif
67#ifndef NLM_F_ACK_TLVS
68#define NLM_F_ACK_TLVS 0x200
69#endif
70#ifndef SOL_NETLINK
71#define SOL_NETLINK 270
72#endif
73
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070074
Dmitry Shmidt54605472013-11-08 11:10:19 -080075#ifdef ANDROID
76/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
Dmitry Shmidt54605472013-11-08 11:10:19 -080077#undef nl_socket_set_nonblocking
78#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080079
Dmitry Shmidt54605472013-11-08 11:10:19 -080080#endif /* ANDROID */
81
82
Hai Shalomfdcde762020-04-02 11:19:20 -070083static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080084{
Hai Shalomfdcde762020-04-02 11:19:20 -070085 struct nl_sock *handle;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080086
Hai Shalomfdcde762020-04-02 11:19:20 -070087 handle = nl_socket_alloc_cb(cb);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080088 if (handle == NULL) {
89 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
90 "callbacks (%s)", dbg);
91 return NULL;
92 }
93
94 if (genl_connect(handle)) {
95 wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
96 "netlink (%s)", dbg);
Hai Shalomfdcde762020-04-02 11:19:20 -070097 nl_socket_free(handle);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080098 return NULL;
99 }
100
101 return handle;
102}
103
104
Hai Shalomfdcde762020-04-02 11:19:20 -0700105static void nl_destroy_handles(struct nl_sock **handle)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800106{
107 if (*handle == NULL)
108 return;
Hai Shalomfdcde762020-04-02 11:19:20 -0700109 nl_socket_free(*handle);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800110 *handle = NULL;
111}
112
113
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700114#if __WORDSIZE == 64
115#define ELOOP_SOCKET_INVALID (intptr_t) 0x8888888888888889ULL
116#else
117#define ELOOP_SOCKET_INVALID (intptr_t) 0x88888889ULL
118#endif
119
Hai Shalomfdcde762020-04-02 11:19:20 -0700120static void nl80211_register_eloop_read(struct nl_sock **handle,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700121 eloop_sock_handler handler,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700122 void *eloop_data, int persist)
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700123{
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800124 /*
125 * libnl uses a pretty small buffer (32 kB that gets converted to 64 kB)
126 * by default. It is possible to hit that limit in some cases where
127 * operations are blocked, e.g., with a burst of Deauthentication frames
128 * to hostapd and STA entry deletion. Try to increase the buffer to make
129 * this less likely to occur.
130 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700131 int err;
132
133 err = nl_socket_set_buffer_size(*handle, 262144, 0);
134 if (err < 0) {
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800135 wpa_printf(MSG_DEBUG,
136 "nl80211: Could not set nl_socket RX buffer size: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -0700137 nl_geterror(err));
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800138 /* continue anyway with the default (smaller) buffer */
139 }
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800140
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700141 nl_socket_set_nonblocking(*handle);
142 eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
143 eloop_data, *handle);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700144 if (!persist)
145 *handle = (void *) (((intptr_t) *handle) ^
146 ELOOP_SOCKET_INVALID);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700147}
148
149
Hai Shalomfdcde762020-04-02 11:19:20 -0700150static void nl80211_destroy_eloop_handle(struct nl_sock **handle, int persist)
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700151{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700152 if (!persist)
153 *handle = (void *) (((intptr_t) *handle) ^
154 ELOOP_SOCKET_INVALID);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700155 eloop_unregister_read_sock(nl_socket_get_fd(*handle));
156 nl_destroy_handles(handle);
157}
158
159
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800160static void nl80211_global_deinit(void *priv);
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800161static void nl80211_check_global(struct nl80211_global *global);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800162
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800163static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -0700164static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
165 struct hostapd_freq_params *freq);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -0700166
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700167static int
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800168wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800169 const u8 *set_addr, int first,
170 const char *driver_params);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800171static int nl80211_send_frame_cmd(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700172 unsigned int freq, unsigned int wait,
Hai Shalomfdcde762020-04-02 11:19:20 -0700173 const u8 *buf, size_t buf_len,
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000174 int save_cookie, int no_cck, int no_ack,
175 int offchanok, const u16 *csa_offs,
176 size_t csa_offs_len, int link_id);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800177static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
178 int report);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700179
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800180#define IFIDX_ANY -1
181
182static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
183 int ifidx_reason);
184static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
185 int ifidx_reason);
186static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
187 int ifidx_reason);
Dmitry Shmidt738a26e2011-07-07 14:22:14 -0700188
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700189static int nl80211_set_channel(struct i802_bss *bss,
190 struct hostapd_freq_params *freq, int set_chan);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700191static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
192 int ifindex, int disabled);
193
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800194static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
195 int reset_mode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800196
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700197static int i802_set_iface_flags(struct i802_bss *bss, int up);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800198static int nl80211_set_param(void *priv, const char *param);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000199static void nl80211_remove_links(struct i802_bss *bss);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -0700200#ifdef CONFIG_MESH
201static int nl80211_put_mesh_config(struct nl_msg *msg,
202 struct wpa_driver_mesh_bss_params *params);
203#endif /* CONFIG_MESH */
Dmitry Shmidt29333592017-01-09 12:27:11 -0800204static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -0700205 u16 reason);
Winnie Chen4138eec2022-11-10 16:32:53 +0800206#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Vinayak Yadawade62409f2022-01-20 12:32:07 +0530207static int nl80211_set_td_policy(void *priv, u32 td_policy);
Winnie Chen4138eec2022-11-10 16:32:53 +0800208#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700209
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800210/* Converts nl80211_chan_width to a common format */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800211enum chan_width convert2width(int width)
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800212{
213 switch (width) {
214 case NL80211_CHAN_WIDTH_20_NOHT:
215 return CHAN_WIDTH_20_NOHT;
216 case NL80211_CHAN_WIDTH_20:
217 return CHAN_WIDTH_20;
218 case NL80211_CHAN_WIDTH_40:
219 return CHAN_WIDTH_40;
220 case NL80211_CHAN_WIDTH_80:
221 return CHAN_WIDTH_80;
222 case NL80211_CHAN_WIDTH_80P80:
223 return CHAN_WIDTH_80P80;
224 case NL80211_CHAN_WIDTH_160:
225 return CHAN_WIDTH_160;
Sunil8cd6f4d2022-06-28 18:40:46 +0000226 case NL80211_CHAN_WIDTH_320:
227 return CHAN_WIDTH_320;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000228 default:
229 return CHAN_WIDTH_UNKNOWN;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800230 }
Dmitry Shmidt04f534e2013-12-09 15:50:16 -0800231}
232
233
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800234int is_ap_interface(enum nl80211_iftype nlmode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800235{
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700236 return nlmode == NL80211_IFTYPE_AP ||
237 nlmode == NL80211_IFTYPE_P2P_GO;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800238}
239
240
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800241int is_sta_interface(enum nl80211_iftype nlmode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800242{
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700243 return nlmode == NL80211_IFTYPE_STATION ||
244 nlmode == NL80211_IFTYPE_P2P_CLIENT;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800245}
246
247
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700248static int is_p2p_net_interface(enum nl80211_iftype nlmode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800249{
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700250 return nlmode == NL80211_IFTYPE_P2P_CLIENT ||
251 nlmode == NL80211_IFTYPE_P2P_GO;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800252}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700253
254
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800255struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
256 int ifindex)
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -0700257{
258 struct i802_bss *bss;
259
260 for (bss = drv->first_bss; bss; bss = bss->next) {
261 if (bss->ifindex == ifindex)
262 return bss;
263 }
264
265 return NULL;
266}
267
268
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800269static int is_mesh_interface(enum nl80211_iftype nlmode)
270{
271 return nlmode == NL80211_IFTYPE_MESH_POINT;
272}
273
274
275void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
Dmitry Shmidt8bae4132013-06-06 11:25:10 -0700276{
277 if (drv->associated)
278 os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
279 drv->associated = 0;
Sunil Ravi77d572f2023-01-17 23:58:31 +0000280 os_memset(&drv->sta_mlo_info, 0, sizeof(drv->sta_mlo_info));
Dmitry Shmidt8bae4132013-06-06 11:25:10 -0700281 os_memset(drv->bssid, 0, ETH_ALEN);
Sunil Ravi036cec52023-03-29 11:35:17 -0700282 drv->first_bss->flink->freq = 0;
Sunil Ravi89eba102022-09-13 21:04:37 -0700283#ifdef CONFIG_DRIVER_NL80211_QCA
284 os_free(drv->pending_roam_data);
285 drv->pending_roam_data = NULL;
Sunil Ravi640215c2023-06-28 23:08:09 +0000286 os_free(drv->pending_t2lm_data);
287 drv->pending_t2lm_data = NULL;
288 os_free(drv->pending_link_reconfig_data);
289 drv->pending_link_reconfig_data = NULL;
Sunil Ravi89eba102022-09-13 21:04:37 -0700290#endif /* CONFIG_DRIVER_NL80211_QCA */
Sunil Ravi77d572f2023-01-17 23:58:31 +0000291
292 drv->auth_mld = false;
293 drv->auth_mld_link_id = -1;
294 os_memset(drv->auth_ap_mld_addr, 0, ETH_ALEN);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -0700295}
296
297
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700298/* nl80211 code */
299static int ack_handler(struct nl_msg *msg, void *arg)
300{
301 int *err = arg;
302 *err = 0;
303 return NL_STOP;
304}
305
Hai Shalom899fcc72020-10-19 14:38:18 -0700306
307struct nl80211_ack_ext_arg {
308 int *err;
309 void *ext_data;
310};
311
312
313static int ack_handler_cookie(struct nl_msg *msg, void *arg)
314{
315 struct nl80211_ack_ext_arg *ext_arg = arg;
316 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
317 u64 *cookie = ext_arg->ext_data;
318 struct nlattr *attrs;
319 size_t ack_len, attr_len;
320
321 *ext_arg->err = 0;
322 ack_len = sizeof(struct nlmsghdr) + sizeof(int) +
323 sizeof(struct nlmsghdr);
324 attrs = (struct nlattr *)
325 ((u8 *) nlmsg_data(nlmsg_hdr(msg)) + sizeof(struct nlmsghdr) +
326 sizeof(int));
327 if (nlmsg_hdr(msg)->nlmsg_len <= ack_len)
328 return NL_STOP;
329
330 attr_len = nlmsg_hdr(msg)->nlmsg_len - ack_len;
331
332 if(!(nlmsg_hdr(msg)->nlmsg_flags & NLM_F_ACK_TLVS))
333 return NL_STOP;
334
335 nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, attr_len, NULL);
336 if (tb[NLMSGERR_ATTR_COOKIE])
337 *cookie = nla_get_u64(tb[NLMSGERR_ATTR_COOKIE]);
338
339 return NL_STOP;
340}
341
342
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700343static int finish_handler(struct nl_msg *msg, void *arg)
344{
345 int *ret = arg;
346 *ret = 0;
347 return NL_SKIP;
348}
349
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000350struct nl80211_ack_err_args {
351 int err;
352 struct nl_msg *orig_msg;
353 struct nl80211_err_info *err_info;
354};
355
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700356static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
357 void *arg)
358{
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000359 struct nl80211_ack_err_args *err_args = arg;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800360 struct nlmsghdr *nlh = (struct nlmsghdr *) err - 1;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000361 struct nlmsghdr *orig_nlh = nlmsg_hdr(err_args->orig_msg);
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800362 int len = nlh->nlmsg_len;
363 struct nlattr *attrs;
364 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800365 int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000366 struct nlattr *mlo_links, *link_attr;
367 u32 offset;
368 int rem;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800369
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000370 err_args->err = err->error;
371 if (err_args->err_info)
372 err_args->err_info->link_id = -1;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800373
374 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
375 return NL_SKIP;
376
377 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
378 ack_len += err->msg.nlmsg_len - sizeof(*nlh);
379
380 if (len <= ack_len)
381 return NL_STOP;
382
383 attrs = (void *) ((unsigned char *) nlh + ack_len);
384 len -= ack_len;
385
386 nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, len, NULL);
387 if (tb[NLMSGERR_ATTR_MSG]) {
388 len = strnlen((char *) nla_data(tb[NLMSGERR_ATTR_MSG]),
389 nla_len(tb[NLMSGERR_ATTR_MSG]));
390 wpa_printf(MSG_ERROR, "nl80211: kernel reports: %*s",
391 len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG]));
392 }
393
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000394 if (!err_args->err_info)
395 return NL_SKIP;
396
397 /* Check if it was a per-link error report */
398
399 if (!tb[NLMSGERR_ATTR_OFFS] ||
400 os_memcmp(orig_nlh, &err->msg, sizeof(err->msg)) != 0)
401 return NL_SKIP;
402
403 offset = nla_get_u32(tb[NLMSGERR_ATTR_OFFS]);
404
405 mlo_links = nlmsg_find_attr(orig_nlh, GENL_HDRLEN,
406 NL80211_ATTR_MLO_LINKS);
407 if (!mlo_links)
408 return NL_SKIP;
409
410 nla_for_each_nested(link_attr, mlo_links, rem) {
411 struct nlattr *link_id;
412 size_t link_offset = (u8 *) link_attr - (u8 *) orig_nlh;
413
414 if (offset < link_offset ||
415 offset >= link_offset + link_attr->nla_len)
416 continue;
417
418 link_id = nla_find(nla_data(link_attr), nla_len(link_attr),
419 NL80211_ATTR_MLO_LINK_ID);
420 if (link_id) {
421 err_args->err_info->link_id = nla_get_u8(link_id);
422 wpa_printf(MSG_DEBUG,
423 "nl80211: kernel reports error for link: %d",
424 err_args->err_info->link_id);
425 break;
426 }
427 }
428
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700429 return NL_SKIP;
430}
431
432
433static int no_seq_check(struct nl_msg *msg, void *arg)
434{
435 return NL_OK;
436}
437
438
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800439static void nl80211_nlmsg_clear(struct nl_msg *msg)
440{
441 /*
442 * Clear nlmsg data, e.g., to make sure key material is not left in
443 * heap memory for unnecessarily long time.
444 */
445 if (msg) {
446 struct nlmsghdr *hdr = nlmsg_hdr(msg);
447 void *data = nlmsg_data(hdr);
448 /*
449 * This would use nlmsg_datalen() or the older nlmsg_len() if
450 * only libnl were to maintain a stable API.. Neither will work
451 * with all released versions, so just calculate the length
452 * here.
453 */
454 int len = hdr->nlmsg_len - NLMSG_HDRLEN;
455
456 os_memset(data, 0, len);
457 }
458}
459
460
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000461static int send_event_marker(struct wpa_driver_nl80211_data *drv)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700462{
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000463 struct nl_sock *handle;
464 struct nl_msg *msg;
465 struct nlmsghdr *hdr;
466 int res = 0;
467 int err = -NLE_NOMEM;
468
469 msg = nlmsg_alloc();
470 if (!msg)
471 goto out;
472
473 /* We only care about the returned sequence number for matching. */
474 if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES))
475 goto out;
476
477 handle = (void *) (((intptr_t) drv->global->nl_event) ^
478 ELOOP_SOCKET_INVALID);
479
480 err = nl_send_auto_complete(handle, msg);
481 if (err < 0)
482 goto out;
483
484 hdr = nlmsg_hdr(msg);
485 res = hdr->nlmsg_seq;
486
487out:
488 nlmsg_free(msg);
489 if (err)
490 wpa_printf(MSG_INFO, "nl80211: %s failed: %s",
491 __func__, nl_geterror(err));
492 return res;
493}
494
495
496int send_and_recv(struct nl80211_global *global,
497 struct nl_sock *nl_handle, struct nl_msg *msg,
498 int (*valid_handler)(struct nl_msg *, void *),
499 void *valid_data,
500 int (*ack_handler_custom)(struct nl_msg *, void *),
501 void *ack_data,
502 struct nl80211_err_info *err_info)
503{
504 struct nl_cb *cb, *s_nl_cb;
505 struct nl80211_ack_err_args err;
506 int opt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700507
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800508 if (!msg)
509 return -ENOMEM;
510
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000511 err.err = -ENOMEM;
512
513 s_nl_cb = nl_socket_get_cb(nl_handle);
514 cb = nl_cb_clone(s_nl_cb);
515 nl_cb_put(s_nl_cb);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700516 if (!cb)
517 goto out;
518
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800519 /* try to set NETLINK_EXT_ACK to 1, ignoring errors */
520 opt = 1;
521 setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
522 NETLINK_EXT_ACK, &opt, sizeof(opt));
523
Hai Shalom74f70d42019-02-11 14:42:39 -0800524 /* try to set NETLINK_CAP_ACK to 1, ignoring errors */
525 opt = 1;
526 setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
527 NETLINK_CAP_ACK, &opt, sizeof(opt));
528
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000529 err.err = nl_send_auto_complete(nl_handle, msg);
530 if (err.err < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700531 wpa_printf(MSG_INFO,
532 "nl80211: nl_send_auto_complete() failed: %s",
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000533 nl_geterror(err.err));
Hai Shalomfdcde762020-04-02 11:19:20 -0700534 /* Need to convert libnl error code to an errno value. For now,
535 * just hardcode this to EBADF; the real error reason is shown
536 * in that error print above. */
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000537 err.err = -EBADF;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700538 goto out;
Hai Shalomfdcde762020-04-02 11:19:20 -0700539 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700540
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000541 err.err = 1;
542 err.orig_msg = msg;
543 err.err_info = err_info;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700544
545 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000546 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err.err);
Hai Shalom899fcc72020-10-19 14:38:18 -0700547 if (ack_handler_custom) {
548 struct nl80211_ack_ext_arg *ext_arg = ack_data;
549
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000550 ext_arg->err = &err.err;
Hai Shalom899fcc72020-10-19 14:38:18 -0700551 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM,
552 ack_handler_custom, ack_data);
553 } else {
554 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
555 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700556
557 if (valid_handler)
558 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
559 valid_handler, valid_data);
560
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000561 while (err.err > 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700562 int res = nl_recvmsgs(nl_handle, cb);
Hai Shalomfdcde762020-04-02 11:19:20 -0700563
564 if (res == -NLE_DUMP_INTR) {
565 /* Most likely one of the nl80211 dump routines hit a
566 * case where internal results changed while the dump
567 * was being sent. The most common known case for this
568 * is scan results fetching while associated were every
569 * received Beacon frame from the AP may end up
570 * incrementing bss_generation. This
571 * NL80211_CMD_GET_SCAN case tries again in the caller;
572 * other cases (of which there are no known common ones)
573 * will stop and return an error. */
574 wpa_printf(MSG_DEBUG, "nl80211: %s; convert to -EAGAIN",
575 nl_geterror(res));
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000576 err.err = -EAGAIN;
Hai Shalomfdcde762020-04-02 11:19:20 -0700577 } else if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700578 wpa_printf(MSG_INFO,
Hai Shalomfdcde762020-04-02 11:19:20 -0700579 "nl80211: %s->nl_recvmsgs failed: %d (%s)",
580 __func__, res, nl_geterror(res));
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700581 }
582 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700583 out:
584 nl_cb_put(cb);
Hai Shalom60840252021-02-19 19:02:11 -0800585 /* Always clear the message as it can potentially contain keys */
586 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700587 nlmsg_free(msg);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000588 return err.err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700589}
590
591
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000592static int nl80211_put_control_port(struct wpa_driver_nl80211_data *drv,
593 struct nl_msg *msg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700594{
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000595 if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT) ||
596 nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
597 ((drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) &&
598 (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) ||
599 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_PREAUTH))))
Hai Shalomb755a2a2020-04-23 21:49:02 -0700600 return -1;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000601 return 0;
Hai Shalomb755a2a2020-04-23 21:49:02 -0700602}
603
604
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700605struct family_data {
606 const char *group;
607 int id;
608};
609
610
611static int family_handler(struct nl_msg *msg, void *arg)
612{
613 struct family_data *res = arg;
614 struct nlattr *tb[CTRL_ATTR_MAX + 1];
615 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
616 struct nlattr *mcgrp;
617 int i;
618
619 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
620 genlmsg_attrlen(gnlh, 0), NULL);
621 if (!tb[CTRL_ATTR_MCAST_GROUPS])
622 return NL_SKIP;
623
624 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
625 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
626 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
627 nla_len(mcgrp), NULL);
628 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
629 !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
630 os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
631 res->group,
632 nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
633 continue;
634 res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
635 break;
636 };
637
638 return NL_SKIP;
639}
640
641
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800642static int nl_get_multicast_id(struct nl80211_global *global,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700643 const char *family, const char *group)
644{
645 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800646 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700647 struct family_data res = { group, -ENOENT };
648
649 msg = nlmsg_alloc();
650 if (!msg)
651 return -ENOMEM;
Hai Shalomc1a21442022-02-04 13:43:00 -0800652 if (!genlmsg_put(msg, 0, 0, global->nlctrl_id,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800653 0, 0, CTRL_CMD_GETFAMILY, 0) ||
654 nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family)) {
655 nlmsg_free(msg);
656 return -1;
657 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700658
Hai Shalom899fcc72020-10-19 14:38:18 -0700659 ret = send_and_recv(global, global->nl, msg, family_handler, &res,
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000660 NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700661 if (ret == 0)
662 ret = res.id;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700663 return ret;
664}
665
666
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800667void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
668 struct nl_msg *msg, int flags, uint8_t cmd)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800669{
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700670 if (TEST_FAIL())
671 return NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800672 return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
673 0, flags, cmd, 0);
674}
675
676
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800677static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
678{
679 if (bss->wdev_id_set)
680 return nla_put_u64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
681 return nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
682}
683
684
685struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd)
686{
687 struct nl_msg *msg;
688
689 msg = nlmsg_alloc();
690 if (!msg)
691 return NULL;
692
693 if (!nl80211_cmd(bss->drv, msg, flags, cmd) ||
694 nl80211_set_iface_id(msg, bss) < 0) {
695 nlmsg_free(msg);
696 return NULL;
697 }
698
699 return msg;
700}
701
702
703static struct nl_msg *
Hai Shalomc1a21442022-02-04 13:43:00 -0800704nl80211_ifindex_msg_build(struct wpa_driver_nl80211_data *drv,
705 struct nl_msg *msg, int ifindex, int flags,
706 uint8_t cmd)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800707{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800708 if (!msg)
709 return NULL;
710
711 if (!nl80211_cmd(drv, msg, flags, cmd) ||
712 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
713 nlmsg_free(msg);
714 return NULL;
715 }
716
717 return msg;
718}
719
720
Hai Shalomc1a21442022-02-04 13:43:00 -0800721static struct nl_msg *
722nl80211_ifindex_msg(struct wpa_driver_nl80211_data *drv, int ifindex,
723 int flags, uint8_t cmd)
724{
725 return nl80211_ifindex_msg_build(drv, nlmsg_alloc(), ifindex, flags,
726 cmd);
727}
728
729
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800730struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
731 uint8_t cmd)
732{
733 return nl80211_ifindex_msg(drv, drv->ifindex, flags, cmd);
734}
735
736
737struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd)
738{
739 return nl80211_ifindex_msg(bss->drv, bss->ifindex, flags, cmd);
740}
741
742
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800743struct wiphy_idx_data {
744 int wiphy_idx;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700745 enum nl80211_iftype nlmode;
746 u8 *macaddr;
Hai Shalom60840252021-02-19 19:02:11 -0800747 u8 use_4addr;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800748};
749
750
751static int netdev_info_handler(struct nl_msg *msg, void *arg)
752{
753 struct nlattr *tb[NL80211_ATTR_MAX + 1];
754 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
755 struct wiphy_idx_data *info = arg;
756
757 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
758 genlmsg_attrlen(gnlh, 0), NULL);
759
760 if (tb[NL80211_ATTR_WIPHY])
761 info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
762
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700763 if (tb[NL80211_ATTR_IFTYPE])
764 info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]);
765
766 if (tb[NL80211_ATTR_MAC] && info->macaddr)
767 os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
768 ETH_ALEN);
769
Hai Shalom60840252021-02-19 19:02:11 -0800770 if (tb[NL80211_ATTR_4ADDR])
771 info->use_4addr = nla_get_u8(tb[NL80211_ATTR_4ADDR]);
772
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800773 return NL_SKIP;
774}
775
776
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800777int nl80211_get_wiphy_index(struct i802_bss *bss)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800778{
779 struct nl_msg *msg;
780 struct wiphy_idx_data data = {
781 .wiphy_idx = -1,
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700782 .macaddr = NULL,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800783 };
784
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800785 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
786 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800787
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000788 if (send_and_recv_resp(bss->drv, msg, netdev_info_handler, &data) == 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800789 return data.wiphy_idx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800790 return -1;
791}
792
793
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700794static enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
795{
796 struct nl_msg *msg;
797 struct wiphy_idx_data data = {
798 .nlmode = NL80211_IFTYPE_UNSPECIFIED,
799 .macaddr = NULL,
800 };
801
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800802 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
803 return NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700804
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000805 if (send_and_recv_resp(bss->drv, msg, netdev_info_handler, &data) == 0)
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700806 return data.nlmode;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700807 return NL80211_IFTYPE_UNSPECIFIED;
808}
809
810
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700811static int nl80211_get_macaddr(struct i802_bss *bss)
812{
813 struct nl_msg *msg;
814 struct wiphy_idx_data data = {
815 .macaddr = bss->addr,
816 };
817
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800818 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
819 return -1;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700820
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000821 return send_and_recv_resp(bss->drv, msg, netdev_info_handler, &data);
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700822}
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700823
824
Hai Shalom60840252021-02-19 19:02:11 -0800825static int nl80211_get_4addr(struct i802_bss *bss)
826{
827 struct nl_msg *msg;
828 struct wiphy_idx_data data = {
829 .use_4addr = 0,
830 };
831
832 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)) ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000833 send_and_recv_resp(bss->drv, msg, netdev_info_handler, &data))
Hai Shalom60840252021-02-19 19:02:11 -0800834 return -1;
835 return data.use_4addr;
836}
837
838
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800839static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
840 struct nl80211_wiphy_data *w)
841{
842 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800843 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800844
845 msg = nlmsg_alloc();
846 if (!msg)
847 return -1;
848
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800849 if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS) ||
850 nla_put_u32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx)) {
851 nlmsg_free(msg);
852 return -1;
853 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800854
Hai Shalom899fcc72020-10-19 14:38:18 -0700855 ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL,
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000856 NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800857 if (ret) {
858 wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
859 "failed: ret=%d (%s)",
860 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800861 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800862 return ret;
863}
864
865
866static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
867{
868 struct nl80211_wiphy_data *w = eloop_ctx;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700869 int res;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800870
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800871 wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800872
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700873 res = nl_recvmsgs(handle, w->nl_cb);
Dmitry Shmidt71757432014-06-02 13:50:35 -0700874 if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700875 wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
876 __func__, res);
877 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800878}
879
880
881static int process_beacon_event(struct nl_msg *msg, void *arg)
882{
883 struct nl80211_wiphy_data *w = arg;
884 struct wpa_driver_nl80211_data *drv;
885 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
886 struct nlattr *tb[NL80211_ATTR_MAX + 1];
887 union wpa_event_data event;
888
889 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
890 genlmsg_attrlen(gnlh, 0), NULL);
891
892 if (gnlh->cmd != NL80211_CMD_FRAME) {
893 wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
894 gnlh->cmd);
895 return NL_SKIP;
896 }
897
898 if (!tb[NL80211_ATTR_FRAME])
899 return NL_SKIP;
900
901 dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
902 wiphy_list) {
903 os_memset(&event, 0, sizeof(event));
904 event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
905 event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
906 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
907 }
908
909 return NL_SKIP;
910}
911
912
913static struct nl80211_wiphy_data *
914nl80211_get_wiphy_data_ap(struct i802_bss *bss)
915{
916 static DEFINE_DL_LIST(nl80211_wiphys);
917 struct nl80211_wiphy_data *w;
918 int wiphy_idx, found = 0;
919 struct i802_bss *tmp_bss;
Paul Stewart092955c2017-02-06 09:13:09 -0800920 u8 channel;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800921
922 if (bss->wiphy_data != NULL)
923 return bss->wiphy_data;
924
925 wiphy_idx = nl80211_get_wiphy_index(bss);
926
927 dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
928 if (w->wiphy_idx == wiphy_idx)
929 goto add;
930 }
931
932 /* alloc new one */
933 w = os_zalloc(sizeof(*w));
934 if (w == NULL)
935 return NULL;
936 w->wiphy_idx = wiphy_idx;
937 dl_list_init(&w->bsss);
938 dl_list_init(&w->drvs);
939
Paul Stewart092955c2017-02-06 09:13:09 -0800940 /* Beacon frames not supported in IEEE 802.11ad */
Sunil Ravi036cec52023-03-29 11:35:17 -0700941 if (ieee80211_freq_to_chan(bss->flink->freq, &channel) !=
Paul Stewart092955c2017-02-06 09:13:09 -0800942 HOSTAPD_MODE_IEEE80211AD) {
943 w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
944 if (!w->nl_cb) {
945 os_free(w);
946 return NULL;
947 }
948 nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
949 no_seq_check, NULL);
950 nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
951 process_beacon_event, w);
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000952
Paul Stewart092955c2017-02-06 09:13:09 -0800953 w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
954 "wiphy beacons");
955 if (w->nl_beacons == NULL) {
956 os_free(w);
957 return NULL;
958 }
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000959
Paul Stewart092955c2017-02-06 09:13:09 -0800960 if (nl80211_register_beacons(bss->drv, w)) {
961 nl_destroy_handles(&w->nl_beacons);
962 os_free(w);
963 return NULL;
964 }
Rebecca Silberstein055a67c2017-02-01 23:05:56 +0000965
Paul Stewart092955c2017-02-06 09:13:09 -0800966 nl80211_register_eloop_read(&w->nl_beacons,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700967 nl80211_recv_beacons, w, 0);
Paul Stewart092955c2017-02-06 09:13:09 -0800968 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800969
970 dl_list_add(&nl80211_wiphys, &w->list);
971
972add:
973 /* drv entry for this bss already there? */
974 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
975 if (tmp_bss->drv == bss->drv) {
976 found = 1;
977 break;
978 }
979 }
980 /* if not add it */
981 if (!found)
982 dl_list_add(&w->drvs, &bss->drv->wiphy_list);
983
984 dl_list_add(&w->bsss, &bss->wiphy_list);
985 bss->wiphy_data = w;
986 return w;
987}
988
989
990static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
991{
992 struct nl80211_wiphy_data *w = bss->wiphy_data;
993 struct i802_bss *tmp_bss;
994 int found = 0;
995
996 if (w == NULL)
997 return;
998 bss->wiphy_data = NULL;
999 dl_list_del(&bss->wiphy_list);
1000
1001 /* still any for this drv present? */
1002 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
1003 if (tmp_bss->drv == bss->drv) {
1004 found = 1;
1005 break;
1006 }
1007 }
1008 /* if not remove it */
1009 if (!found)
1010 dl_list_del(&bss->drv->wiphy_list);
1011
1012 if (!dl_list_empty(&w->bsss))
1013 return;
1014
Paul Stewart092955c2017-02-06 09:13:09 -08001015 if (w->nl_beacons)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001016 nl80211_destroy_eloop_handle(&w->nl_beacons, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001017
1018 nl_cb_put(w->nl_cb);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001019 dl_list_del(&w->list);
1020 os_free(w);
1021}
1022
1023
Dmitry Shmidte4663042016-04-04 10:07:49 -07001024static unsigned int nl80211_get_ifindex(void *priv)
1025{
1026 struct i802_bss *bss = priv;
1027 struct wpa_driver_nl80211_data *drv = bss->drv;
1028
1029 return drv->ifindex;
1030}
1031
1032
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001033static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
1034{
1035 struct i802_bss *bss = priv;
1036 struct wpa_driver_nl80211_data *drv = bss->drv;
1037 if (!drv->associated)
1038 return -1;
1039 os_memcpy(bssid, drv->bssid, ETH_ALEN);
1040 return 0;
1041}
1042
1043
1044static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
1045{
1046 struct i802_bss *bss = priv;
1047 struct wpa_driver_nl80211_data *drv = bss->drv;
1048 if (!drv->associated)
1049 return -1;
1050 os_memcpy(ssid, drv->ssid, drv->ssid_len);
1051 return drv->ssid_len;
1052}
1053
1054
Sunil Ravi77d572f2023-01-17 23:58:31 +00001055static int get_mlo_info(struct nl_msg *msg, void *arg)
1056{
1057 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1058 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1059 struct nlattr *link_attr, *link_data[NL80211_ATTR_MAX + 1];
1060 static struct nla_policy link_policy[NL80211_ATTR_MAX + 1] = {
1061 [NL80211_ATTR_MLO_LINK_ID] = { .type = NLA_U8 },
1062 [NL80211_ATTR_MAC] = { .minlen = ETH_ALEN, .maxlen = ETH_ALEN },
1063 };
1064 struct driver_sta_mlo_info *info = arg;
1065 int rem;
1066
1067 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1068 genlmsg_attrlen(gnlh, 0), NULL);
1069
1070 if (!tb[NL80211_ATTR_MLO_LINKS])
1071 return NL_SKIP;
1072
1073 info->valid_links = 0;
1074 nla_for_each_nested(link_attr, tb[NL80211_ATTR_MLO_LINKS], rem) {
1075 u8 link_id;
1076
1077 if (nla_parse_nested(link_data, NL80211_ATTR_MAX,
1078 link_attr, link_policy) != 0)
1079 continue;
1080
1081 if (!link_data[NL80211_ATTR_MLO_LINK_ID] ||
1082 !link_data[NL80211_ATTR_MAC])
1083 continue;
1084
1085 link_id = nla_get_u8(link_data[NL80211_ATTR_MLO_LINK_ID]);
1086 if (link_id >= MAX_NUM_MLD_LINKS)
1087 continue;
1088 info->valid_links |= BIT(link_id);
1089 os_memcpy(info->links[link_id].addr,
1090 nla_data(link_data[NL80211_ATTR_MAC]), ETH_ALEN);
1091 if (link_data[NL80211_ATTR_WIPHY_FREQ])
1092 info->links[link_id].freq =
1093 nla_get_u32(link_data[NL80211_ATTR_WIPHY_FREQ]);
1094 }
1095
1096 return NL_SKIP;
1097}
1098
1099
Sunil Ravi89eba102022-09-13 21:04:37 -07001100static int nl80211_get_sta_mlo_info(void *priv,
1101 struct driver_sta_mlo_info *mlo_info)
1102{
1103 struct i802_bss *bss = priv;
1104 struct wpa_driver_nl80211_data *drv = bss->drv;
1105
1106 if (!drv->associated)
1107 return -1;
1108
Sunil Ravi77d572f2023-01-17 23:58:31 +00001109 if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
1110 struct nl_msg *msg;
1111
1112 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001113 if (send_and_recv_resp(drv, msg, get_mlo_info,
1114 &drv->sta_mlo_info))
Sunil Ravi77d572f2023-01-17 23:58:31 +00001115 return -1;
1116 }
1117
Sunil Ravi89eba102022-09-13 21:04:37 -07001118 os_memcpy(mlo_info, &drv->sta_mlo_info, sizeof(*mlo_info));
1119 return 0;
1120}
1121
1122
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001123static void wpa_driver_nl80211_event_newlink(
Dmitry Shmidte4663042016-04-04 10:07:49 -07001124 struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
1125 int ifindex, const char *ifname)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001126{
1127 union wpa_event_data event;
1128
Dmitry Shmidte4663042016-04-04 10:07:49 -07001129 if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001130 if (if_nametoindex(drv->first_bss->ifname) == 0) {
1131 wpa_printf(MSG_DEBUG, "nl80211: Interface %s does not exist - ignore RTM_NEWLINK",
1132 drv->first_bss->ifname);
1133 return;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001134 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001135 if (!drv->if_removed)
1136 return;
1137 wpa_printf(MSG_DEBUG, "nl80211: Mark if_removed=0 for %s based on RTM_NEWLINK event",
1138 drv->first_bss->ifname);
1139 drv->if_removed = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001140 }
1141
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001142 os_memset(&event, 0, sizeof(event));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001143 event.interface_status.ifindex = ifindex;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001144 os_strlcpy(event.interface_status.ifname, ifname,
1145 sizeof(event.interface_status.ifname));
1146 event.interface_status.ievent = EVENT_INTERFACE_ADDED;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001147 if (drv)
1148 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
1149 else
1150 wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
1151 &event);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001152}
1153
1154
1155static void wpa_driver_nl80211_event_dellink(
Dmitry Shmidte4663042016-04-04 10:07:49 -07001156 struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
1157 int ifindex, const char *ifname)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001158{
1159 union wpa_event_data event;
1160
Dmitry Shmidte4663042016-04-04 10:07:49 -07001161 if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001162 if (drv->if_removed) {
1163 wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s",
1164 ifname);
1165 return;
1166 }
1167 wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed - mark if_removed=1",
1168 ifname);
1169 drv->if_removed = 1;
1170 } else {
1171 wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed",
1172 ifname);
1173 }
1174
1175 os_memset(&event, 0, sizeof(event));
Dmitry Shmidte4663042016-04-04 10:07:49 -07001176 event.interface_status.ifindex = ifindex;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001177 os_strlcpy(event.interface_status.ifname, ifname,
1178 sizeof(event.interface_status.ifname));
1179 event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
Dmitry Shmidte4663042016-04-04 10:07:49 -07001180 if (drv)
1181 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
1182 else
1183 wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
1184 &event);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001185}
1186
1187
1188static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
1189 u8 *buf, size_t len)
1190{
1191 int attrlen, rta_len;
1192 struct rtattr *attr;
1193
1194 attrlen = len;
1195 attr = (struct rtattr *) buf;
1196
1197 rta_len = RTA_ALIGN(sizeof(struct rtattr));
1198 while (RTA_OK(attr, attrlen)) {
1199 if (attr->rta_type == IFLA_IFNAME) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001200 if (os_strcmp(((char *) attr) + rta_len,
1201 drv->first_bss->ifname) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001202 return 1;
1203 else
1204 break;
1205 }
1206 attr = RTA_NEXT(attr, attrlen);
1207 }
1208
1209 return 0;
1210}
1211
1212
1213static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
1214 int ifindex, u8 *buf, size_t len)
1215{
1216 if (drv->ifindex == ifindex)
1217 return 1;
1218
1219 if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001220 nl80211_check_global(drv->global);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001221 wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
1222 "interface");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001223 if (wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL) < 0)
1224 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001225 return 1;
1226 }
1227
1228 return 0;
1229}
1230
1231
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001232static struct wpa_driver_nl80211_data *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001233nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len,
1234 int *init_failed)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001235{
1236 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001237 int res;
1238
1239 if (init_failed)
1240 *init_failed = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001241 dl_list_for_each(drv, &global->interfaces,
1242 struct wpa_driver_nl80211_data, list) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001243 res = wpa_driver_nl80211_own_ifindex(drv, idx, buf, len);
1244 if (res < 0) {
1245 wpa_printf(MSG_DEBUG,
1246 "nl80211: Found matching own interface, but failed to complete reinitialization");
1247 if (init_failed)
1248 *init_failed = 1;
1249 return drv;
1250 }
1251 if (res > 0 || have_ifidx(drv, idx, IFIDX_ANY))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001252 return drv;
1253 }
1254 return NULL;
1255}
1256
1257
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001258static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001259 int ifindex, int notify)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001260{
1261 struct i802_bss *bss;
1262 u8 addr[ETH_ALEN];
1263
1264 bss = get_bss_ifindex(drv, ifindex);
1265 if (bss &&
1266 linux_get_ifhwaddr(drv->global->ioctl_sock,
1267 bss->ifname, addr) < 0) {
1268 wpa_printf(MSG_DEBUG,
1269 "nl80211: %s: failed to re-read MAC address",
1270 bss->ifname);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001271 } else if (bss && !ether_addr_equal(addr, bss->addr)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001272 wpa_printf(MSG_DEBUG,
1273 "nl80211: Own MAC address on ifindex %d (%s) changed from "
1274 MACSTR " to " MACSTR,
1275 ifindex, bss->ifname,
1276 MAC2STR(bss->addr), MAC2STR(addr));
Sunil Ravi77d572f2023-01-17 23:58:31 +00001277 os_memcpy(bss->prev_addr, bss->addr, ETH_ALEN);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001278 os_memcpy(bss->addr, addr, ETH_ALEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001279 if (notify)
1280 wpa_supplicant_event(drv->ctx,
1281 EVENT_INTERFACE_MAC_CHANGED, NULL);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001282 }
1283}
1284
1285
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001286static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
1287 struct ifinfomsg *ifi,
1288 u8 *buf, size_t len)
1289{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001290 struct nl80211_global *global = ctx;
1291 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001292 int attrlen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001293 struct rtattr *attr;
1294 u32 brid = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001295 char namebuf[IFNAMSIZ];
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001296 char ifname[IFNAMSIZ + 1];
1297 char extra[100], *pos, *end;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001298 int init_failed;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001299
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001300 extra[0] = '\0';
1301 pos = extra;
1302 end = pos + sizeof(extra);
1303 ifname[0] = '\0';
1304
1305 attrlen = len;
1306 attr = (struct rtattr *) buf;
1307 while (RTA_OK(attr, attrlen)) {
1308 switch (attr->rta_type) {
1309 case IFLA_IFNAME:
Hai Shalomfdcde762020-04-02 11:19:20 -07001310 if (RTA_PAYLOAD(attr) > IFNAMSIZ)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001311 break;
1312 os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
1313 ifname[RTA_PAYLOAD(attr)] = '\0';
1314 break;
1315 case IFLA_MASTER:
1316 brid = nla_get_u32((struct nlattr *) attr);
1317 pos += os_snprintf(pos, end - pos, " master=%u", brid);
1318 break;
1319 case IFLA_WIRELESS:
1320 pos += os_snprintf(pos, end - pos, " wext");
1321 break;
1322 case IFLA_OPERSTATE:
1323 pos += os_snprintf(pos, end - pos, " operstate=%u",
1324 nla_get_u32((struct nlattr *) attr));
1325 break;
1326 case IFLA_LINKMODE:
1327 pos += os_snprintf(pos, end - pos, " linkmode=%u",
1328 nla_get_u32((struct nlattr *) attr));
1329 break;
1330 }
1331 attr = RTA_NEXT(attr, attrlen);
1332 }
1333 extra[sizeof(extra) - 1] = '\0';
1334
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001335 wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
1336 ifi->ifi_index, ifname, extra, ifi->ifi_family,
1337 ifi->ifi_flags,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001338 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
1339 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
1340 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
1341 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
1342
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001343 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, &init_failed);
Dmitry Shmidte4663042016-04-04 10:07:49 -07001344 if (!drv)
1345 goto event_newlink;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001346 if (init_failed)
1347 return; /* do not update interface state */
Dmitry Shmidte4663042016-04-04 10:07:49 -07001348
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001349 if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001350 namebuf[0] = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001351 if (if_indextoname(ifi->ifi_index, namebuf) &&
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001352 linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001353 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
1354 "event since interface %s is up", namebuf);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001355 drv->ignore_if_down_event = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001356 /* Re-read MAC address as it may have changed */
1357 nl80211_refresh_mac(drv, ifi->ifi_index, 1);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001358 return;
1359 }
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001360 wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
1361 namebuf, ifname);
1362 if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
1363 wpa_printf(MSG_DEBUG,
1364 "nl80211: Not the main interface (%s) - do not indicate interface down",
1365 drv->first_bss->ifname);
1366 } else if (drv->ignore_if_down_event) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001367 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
1368 "event generated by mode change");
1369 drv->ignore_if_down_event = 0;
1370 } else {
1371 drv->if_disabled = 1;
1372 wpa_supplicant_event(drv->ctx,
1373 EVENT_INTERFACE_DISABLED, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08001374
1375 /*
1376 * Try to get drv again, since it may be removed as
1377 * part of the EVENT_INTERFACE_DISABLED handling for
1378 * dynamic interfaces
1379 */
1380 drv = nl80211_find_drv(global, ifi->ifi_index,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001381 buf, len, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08001382 if (!drv)
1383 return;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001384 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001385 }
1386
1387 if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
Hai Shalomc9e41a12018-07-31 14:41:42 -07001388 namebuf[0] = '\0';
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001389 if (if_indextoname(ifi->ifi_index, namebuf) &&
Dmitry Shmidt7f656022015-02-25 14:36:37 -08001390 linux_iface_up(drv->global->ioctl_sock, namebuf) == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001391 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1392 "event since interface %s is down",
1393 namebuf);
Hai Shalomc9e41a12018-07-31 14:41:42 -07001394 return;
1395 }
1396 wpa_printf(MSG_DEBUG, "nl80211: Interface up (%s/%s)",
1397 namebuf, ifname);
1398 if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
1399 wpa_printf(MSG_DEBUG,
1400 "nl80211: Not the main interface (%s) - do not indicate interface up",
1401 drv->first_bss->ifname);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001402 } else if (if_nametoindex(drv->first_bss->ifname) == 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001403 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1404 "event since interface %s does not exist",
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001405 drv->first_bss->ifname);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001406 } else if (drv->if_removed) {
1407 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
1408 "event since interface %s is marked "
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001409 "removed", drv->first_bss->ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001410 } else {
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07001411 /* Re-read MAC address as it may have changed */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001412 nl80211_refresh_mac(drv, ifi->ifi_index, 0);
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07001413
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001414 drv->if_disabled = 0;
1415 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
1416 NULL);
1417 }
Sunil Ravi90775442020-09-24 11:53:19 -07001418 } else if (ifi->ifi_flags & IFF_UP) {
1419 /* Re-read MAC address as it may have changed */
1420 nl80211_refresh_mac(drv, ifi->ifi_index, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001421 }
1422
1423 /*
1424 * Some drivers send the association event before the operup event--in
1425 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
1426 * fails. This will hit us when wpa_supplicant does not need to do
1427 * IEEE 802.1X authentication
1428 */
1429 if (drv->operstate == 1 &&
1430 (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001431 !(ifi->ifi_flags & IFF_RUNNING)) {
1432 wpa_printf(MSG_DEBUG, "nl80211: Set IF_OPER_UP again based on ifi_flags and expected operstate");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001433 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001434 -1, IF_OPER_UP);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001435 }
1436
Dmitry Shmidte4663042016-04-04 10:07:49 -07001437event_newlink:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001438 if (ifname[0])
Dmitry Shmidte4663042016-04-04 10:07:49 -07001439 wpa_driver_nl80211_event_newlink(global, drv, ifi->ifi_index,
1440 ifname);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001441
Dmitry Shmidte4663042016-04-04 10:07:49 -07001442 if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001443 struct i802_bss *bss;
1444
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001445 /* device has been added to bridge */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001446 if (!if_indextoname(brid, namebuf)) {
1447 wpa_printf(MSG_DEBUG,
1448 "nl80211: Could not find bridge ifname for ifindex %u",
1449 brid);
1450 return;
1451 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001452 wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
1453 brid, namebuf);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001454 add_ifidx(drv, brid, ifi->ifi_index);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001455
1456 for (bss = drv->first_bss; bss; bss = bss->next) {
1457 if (os_strcmp(ifname, bss->ifname) == 0) {
1458 os_strlcpy(bss->brname, namebuf, IFNAMSIZ);
1459 break;
1460 }
1461 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001462 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001463}
1464
1465
1466static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
1467 struct ifinfomsg *ifi,
1468 u8 *buf, size_t len)
1469{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001470 struct nl80211_global *global = ctx;
1471 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001472 int attrlen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001473 struct rtattr *attr;
1474 u32 brid = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001475 char ifname[IFNAMSIZ + 1];
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001476 char extra[100], *pos, *end;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001477
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001478 extra[0] = '\0';
1479 pos = extra;
1480 end = pos + sizeof(extra);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001481 ifname[0] = '\0';
1482
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001483 attrlen = len;
1484 attr = (struct rtattr *) buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001485 while (RTA_OK(attr, attrlen)) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001486 switch (attr->rta_type) {
1487 case IFLA_IFNAME:
Hai Shalomfdcde762020-04-02 11:19:20 -07001488 if (RTA_PAYLOAD(attr) > IFNAMSIZ)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001489 break;
1490 os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
1491 ifname[RTA_PAYLOAD(attr)] = '\0';
1492 break;
1493 case IFLA_MASTER:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001494 brid = nla_get_u32((struct nlattr *) attr);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001495 pos += os_snprintf(pos, end - pos, " master=%u", brid);
1496 break;
1497 case IFLA_OPERSTATE:
1498 pos += os_snprintf(pos, end - pos, " operstate=%u",
1499 nla_get_u32((struct nlattr *) attr));
1500 break;
1501 case IFLA_LINKMODE:
1502 pos += os_snprintf(pos, end - pos, " linkmode=%u",
1503 nla_get_u32((struct nlattr *) attr));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001504 break;
1505 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001506 attr = RTA_NEXT(attr, attrlen);
1507 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001508 extra[sizeof(extra) - 1] = '\0';
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001509
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001510 wpa_printf(MSG_DEBUG, "RTM_DELLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
1511 ifi->ifi_index, ifname, extra, ifi->ifi_family,
1512 ifi->ifi_flags,
1513 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
1514 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
1515 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
1516 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
1517
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001518 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001519
Dmitry Shmidte4663042016-04-04 10:07:49 -07001520 if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001521 /* device has been removed from bridge */
1522 char namebuf[IFNAMSIZ];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001523
1524 if (!if_indextoname(brid, namebuf)) {
1525 wpa_printf(MSG_DEBUG,
1526 "nl80211: Could not find bridge ifname for ifindex %u",
1527 brid);
1528 } else {
1529 wpa_printf(MSG_DEBUG,
1530 "nl80211: Remove ifindex %u for bridge %s",
1531 brid, namebuf);
1532 }
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001533 del_ifidx(drv, brid, ifi->ifi_index);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001534 }
Dmitry Shmidte4663042016-04-04 10:07:49 -07001535
1536 if (ifi->ifi_family != AF_BRIDGE || !brid)
1537 wpa_driver_nl80211_event_dellink(global, drv, ifi->ifi_index,
1538 ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001539}
1540
1541
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001542struct nl80211_get_assoc_freq_arg {
1543 struct wpa_driver_nl80211_data *drv;
1544 unsigned int assoc_freq;
1545 unsigned int ibss_freq;
1546 u8 assoc_bssid[ETH_ALEN];
1547 u8 assoc_ssid[SSID_MAX_LEN];
1548 u8 assoc_ssid_len;
Sunil Ravi89eba102022-09-13 21:04:37 -07001549 u8 bssid[MAX_NUM_MLD_LINKS][ETH_ALEN];
1550 unsigned int freq[MAX_NUM_MLD_LINKS];
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001551};
1552
1553static int nl80211_get_assoc_freq_handler(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 *bss[NL80211_BSS_MAX + 1];
1558 static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
1559 [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
1560 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
1561 [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
1562 [NL80211_BSS_STATUS] = { .type = NLA_U32 },
Sunil Ravi89eba102022-09-13 21:04:37 -07001563 [NL80211_BSS_MLO_LINK_ID] = { .type = NLA_U8 },
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001564 };
1565 struct nl80211_get_assoc_freq_arg *ctx = arg;
1566 enum nl80211_bss_status status;
Sunil Ravi89eba102022-09-13 21:04:37 -07001567 struct wpa_driver_nl80211_data *drv = ctx->drv;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001568
1569 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1570 genlmsg_attrlen(gnlh, 0), NULL);
1571 if (!tb[NL80211_ATTR_BSS] ||
1572 nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
1573 bss_policy) ||
1574 !bss[NL80211_BSS_STATUS])
1575 return NL_SKIP;
1576
1577 status = nla_get_u32(bss[NL80211_BSS_STATUS]);
1578 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1579 bss[NL80211_BSS_FREQUENCY]) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001580 int link_id = -1;
1581 u32 freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
1582
1583 if (bss[NL80211_BSS_MLO_LINK_ID])
1584 link_id = nla_get_u8(bss[NL80211_BSS_MLO_LINK_ID]);
1585
1586 if (link_id >= 0 && link_id < MAX_NUM_MLD_LINKS) {
1587 ctx->freq[link_id] = freq;
1588 wpa_printf(MSG_DEBUG,
1589 "nl80211: MLO link %d associated on %u MHz",
1590 link_id, ctx->freq[link_id]);
1591 }
1592
1593 if (!drv->sta_mlo_info.valid_links ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001594 drv->sta_mlo_info.assoc_link_id == link_id) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001595 ctx->assoc_freq = freq;
1596 wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
1597 ctx->assoc_freq);
1598 }
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001599 }
1600 if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
1601 bss[NL80211_BSS_FREQUENCY]) {
1602 ctx->ibss_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
1603 wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
1604 ctx->ibss_freq);
1605 }
1606 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1607 bss[NL80211_BSS_BSSID]) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001608 int link_id = -1;
1609 const u8 *bssid = nla_data(bss[NL80211_BSS_BSSID]);
1610
1611 if (bss[NL80211_BSS_MLO_LINK_ID])
1612 link_id = nla_get_u8(bss[NL80211_BSS_MLO_LINK_ID]);
1613
1614 if (link_id >= 0 && link_id < MAX_NUM_MLD_LINKS) {
1615 os_memcpy(ctx->bssid[link_id], bssid, ETH_ALEN);
1616 wpa_printf(MSG_DEBUG,
1617 "nl80211: MLO link %d associated with "
1618 MACSTR, link_id, MAC2STR(bssid));
1619 }
1620
1621 if (!drv->sta_mlo_info.valid_links ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00001622 drv->sta_mlo_info.assoc_link_id == link_id) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001623 os_memcpy(ctx->assoc_bssid, bssid, ETH_ALEN);
1624 wpa_printf(MSG_DEBUG, "nl80211: Associated with "
1625 MACSTR, MAC2STR(bssid));
1626 }
1627
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001628 }
1629
1630 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
1631 bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
1632 const u8 *ie, *ssid;
1633 size_t ie_len;
1634
1635 ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1636 ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1637 ssid = get_ie(ie, ie_len, WLAN_EID_SSID);
1638 if (ssid && ssid[1] > 0 && ssid[1] <= SSID_MAX_LEN) {
1639 ctx->assoc_ssid_len = ssid[1];
1640 os_memcpy(ctx->assoc_ssid, ssid + 2, ssid[1]);
1641 }
1642 }
1643
1644 return NL_SKIP;
1645}
1646
1647
1648int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid)
Jouni Malinen87fd2792011-05-16 18:35:42 +03001649{
1650 struct nl_msg *msg;
1651 int ret;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001652 struct nl80211_get_assoc_freq_arg arg;
Hai Shalomfdcde762020-04-02 11:19:20 -07001653 int count = 0;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001654
Hai Shalomfdcde762020-04-02 11:19:20 -07001655try_again:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001656 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
Jouni Malinen87fd2792011-05-16 18:35:42 +03001657 os_memset(&arg, 0, sizeof(arg));
Jouni Malinen87fd2792011-05-16 18:35:42 +03001658 arg.drv = drv;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001659 ret = send_and_recv_resp(drv, msg, nl80211_get_assoc_freq_handler,
1660 &arg);
Hai Shalomfdcde762020-04-02 11:19:20 -07001661 if (ret == -EAGAIN) {
1662 count++;
1663 if (count >= 10) {
1664 wpa_printf(MSG_INFO,
1665 "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid");
1666 } else {
1667 wpa_printf(MSG_DEBUG,
1668 "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid - try again");
1669 goto try_again;
1670 }
1671 }
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001672 if (ret == 0) {
1673 os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len);
1674 return arg.assoc_ssid_len;
1675 }
1676 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d (%s)",
1677 ret, strerror(-ret));
1678 return ret;
1679}
1680
1681
1682unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
1683{
1684 struct nl_msg *msg;
1685 int ret;
1686 struct nl80211_get_assoc_freq_arg arg;
Hai Shalomfdcde762020-04-02 11:19:20 -07001687 int count = 0;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001688
Hai Shalomfdcde762020-04-02 11:19:20 -07001689try_again:
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001690 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
1691 os_memset(&arg, 0, sizeof(arg));
1692 arg.drv = drv;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001693 ret = send_and_recv_resp(drv, msg, nl80211_get_assoc_freq_handler,
1694 &arg);
Hai Shalomfdcde762020-04-02 11:19:20 -07001695 if (ret == -EAGAIN) {
1696 count++;
1697 if (count >= 10) {
1698 wpa_printf(MSG_INFO,
1699 "nl80211: Failed to receive consistent scan result dump for get_assoc_freq");
1700 } else {
1701 wpa_printf(MSG_DEBUG,
1702 "nl80211: Failed to receive consistent scan result dump for get_assoc_freq - try again");
1703 goto try_again;
1704 }
1705 }
Jouni Malinen87fd2792011-05-16 18:35:42 +03001706 if (ret == 0) {
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07001707 unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
1708 arg.ibss_freq : arg.assoc_freq;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001709 wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
Dmitry Shmidt6dc03bd2014-05-16 10:40:13 -07001710 "associated BSS from scan results: %u MHz", freq);
1711 if (freq)
1712 drv->assoc_freq = freq;
Sunil Ravi89eba102022-09-13 21:04:37 -07001713
1714 if (drv->sta_mlo_info.valid_links) {
1715 int i;
1716
1717 for (i = 0; i < MAX_NUM_MLD_LINKS; i++)
1718 drv->sta_mlo_info.links[i].freq = arg.freq[i];
1719 }
1720
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07001721 return drv->assoc_freq;
Jouni Malinen87fd2792011-05-16 18:35:42 +03001722 }
1723 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
1724 "(%s)", ret, strerror(-ret));
Jouni Malinen87fd2792011-05-16 18:35:42 +03001725 return drv->assoc_freq;
1726}
1727
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001728static int get_link_noise(struct nl_msg *msg, void *arg)
1729{
1730 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1731 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1732 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
1733 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
1734 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
1735 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
1736 };
1737 struct wpa_signal_info *sig_change = arg;
1738
1739 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1740 genlmsg_attrlen(gnlh, 0), NULL);
1741
1742 if (!tb[NL80211_ATTR_SURVEY_INFO]) {
1743 wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
1744 return NL_SKIP;
1745 }
1746
1747 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
1748 tb[NL80211_ATTR_SURVEY_INFO],
1749 survey_policy)) {
1750 wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested "
1751 "attributes!");
1752 return NL_SKIP;
1753 }
1754
1755 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
1756 return NL_SKIP;
1757
1758 if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
1759 sig_change->frequency)
1760 return NL_SKIP;
1761
1762 if (!sinfo[NL80211_SURVEY_INFO_NOISE])
1763 return NL_SKIP;
1764
1765 sig_change->current_noise =
1766 (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
1767
1768 return NL_SKIP;
1769}
1770
1771
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001772int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
1773 struct wpa_signal_info *sig_change)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001774{
1775 struct nl_msg *msg;
1776
Hai Shalom74f70d42019-02-11 14:42:39 -08001777 sig_change->current_noise = WPA_INVALID_NOISE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001778 sig_change->frequency = drv->assoc_freq;
1779
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001780 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001781 return send_and_recv_resp(drv, msg, get_link_noise, sig_change);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001782}
1783
1784
Hai Shalom74f70d42019-02-11 14:42:39 -08001785static int get_channel_info(struct nl_msg *msg, void *arg)
1786{
1787 struct nlattr *tb[NL80211_ATTR_MAX + 1] = { 0 };
1788 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1789 struct wpa_channel_info *chan_info = arg;
1790
1791 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1792 genlmsg_attrlen(gnlh, 0), NULL);
1793
1794 os_memset(chan_info, 0, sizeof(struct wpa_channel_info));
1795 chan_info->chanwidth = CHAN_WIDTH_UNKNOWN;
1796
1797 if (tb[NL80211_ATTR_WIPHY_FREQ])
1798 chan_info->frequency =
1799 nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
1800 if (tb[NL80211_ATTR_CHANNEL_WIDTH])
1801 chan_info->chanwidth = convert2width(
1802 nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
1803 if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
1804 enum nl80211_channel_type ct =
1805 nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
1806
1807 switch (ct) {
1808 case NL80211_CHAN_HT40MINUS:
1809 chan_info->sec_channel = -1;
1810 break;
1811 case NL80211_CHAN_HT40PLUS:
1812 chan_info->sec_channel = 1;
1813 break;
1814 default:
1815 chan_info->sec_channel = 0;
1816 break;
1817 }
1818 }
1819 if (tb[NL80211_ATTR_CENTER_FREQ1])
1820 chan_info->center_frq1 =
1821 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
1822 if (tb[NL80211_ATTR_CENTER_FREQ2])
1823 chan_info->center_frq2 =
1824 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
1825
1826 if (chan_info->center_frq2) {
1827 u8 seg1_idx = 0;
1828
1829 if (ieee80211_freq_to_chan(chan_info->center_frq2, &seg1_idx) !=
1830 NUM_HOSTAPD_MODES)
1831 chan_info->seg1_idx = seg1_idx;
1832 }
1833
1834 return NL_SKIP;
1835}
1836
1837
1838static int nl80211_channel_info(void *priv, struct wpa_channel_info *ci)
1839{
1840 struct i802_bss *bss = priv;
1841 struct wpa_driver_nl80211_data *drv = bss->drv;
1842 struct nl_msg *msg;
1843
1844 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001845 return send_and_recv_resp(drv, msg, get_channel_info, ci);
Hai Shalom74f70d42019-02-11 14:42:39 -08001846}
1847
1848
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001849static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
1850 void *handle)
1851{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001852 struct nl_cb *cb = eloop_ctx;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001853 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001854
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07001855 wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001856
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001857 res = nl_recvmsgs(handle, cb);
Dmitry Shmidt71757432014-06-02 13:50:35 -07001858 if (res < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001859 wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
1860 __func__, res);
1861 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001862}
1863
1864
1865/**
1866 * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
1867 * @priv: driver_nl80211 private data
1868 * @alpha2_arg: country to which to switch to
1869 * Returns: 0 on success, -1 on failure
1870 *
1871 * This asks nl80211 to set the regulatory domain for given
1872 * country ISO / IEC alpha2.
1873 */
1874static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
1875{
1876 struct i802_bss *bss = priv;
1877 struct wpa_driver_nl80211_data *drv = bss->drv;
1878 char alpha2[3];
1879 struct nl_msg *msg;
1880
1881 msg = nlmsg_alloc();
1882 if (!msg)
1883 return -ENOMEM;
1884
1885 alpha2[0] = alpha2_arg[0];
1886 alpha2[1] = alpha2_arg[1];
1887 alpha2[2] = '\0';
1888
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001889 if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG) ||
1890 nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, alpha2)) {
1891 nlmsg_free(msg);
1892 return -EINVAL;
1893 }
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001894 if (send_and_recv_cmd(drv, msg))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001895 return -EINVAL;
1896 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001897}
1898
1899
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001900static int nl80211_get_country(struct nl_msg *msg, void *arg)
1901{
1902 char *alpha2 = arg;
1903 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
1904 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1905
1906 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1907 genlmsg_attrlen(gnlh, 0), NULL);
1908 if (!tb_msg[NL80211_ATTR_REG_ALPHA2]) {
1909 wpa_printf(MSG_DEBUG, "nl80211: No country information available");
1910 return NL_SKIP;
1911 }
1912 os_strlcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3);
1913 return NL_SKIP;
1914}
1915
1916
1917static int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
1918{
1919 struct i802_bss *bss = priv;
1920 struct wpa_driver_nl80211_data *drv = bss->drv;
1921 struct nl_msg *msg;
1922 int ret;
1923
1924 msg = nlmsg_alloc();
1925 if (!msg)
1926 return -ENOMEM;
1927
1928 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
Sunil Ravi036cec52023-03-29 11:35:17 -07001929
1930 if (drv->capa.flags & WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY) {
1931 /* put wiphy idx to get the interface specific country code
1932 * instead of the global one. */
1933 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx)) {
1934 nlmsg_free(msg);
1935 return -1;
1936 }
1937 }
1938
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001939 alpha2[0] = '\0';
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001940 ret = send_and_recv_resp(drv, msg, nl80211_get_country, alpha2);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001941 if (!alpha2[0])
1942 ret = -1;
1943
1944 return ret;
1945}
1946
1947
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001948static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001949{
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001950 struct nl_cache *cache = NULL;
1951 struct genl_family *family = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001952 int ret;
1953
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001954 global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
1955 if (global->nl_cb == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001956 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
1957 "callbacks");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001958 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001959 }
1960
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001961 global->nl = nl_create_handle(global->nl_cb, "nl");
1962 if (global->nl == NULL)
1963 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001964
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001965 global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
1966 if (global->nl80211_id < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001967 wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
1968 "found");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001969 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001970 }
1971
Hai Shalomc1a21442022-02-04 13:43:00 -08001972 global->nlctrl_id = genl_ctrl_resolve(global->nl, "nlctrl");
1973 if (global->nlctrl_id < 0) {
1974 wpa_printf(MSG_ERROR,
1975 "nl80211: 'nlctrl' generic netlink not found");
1976 goto err;
1977 }
1978
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001979 global->nl_event = nl_create_handle(global->nl_cb, "event");
1980 if (global->nl_event == NULL)
1981 goto err;
1982
1983 ret = nl_get_multicast_id(global, "nl80211", "scan");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001984 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001985 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001986 if (ret < 0) {
1987 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
1988 "membership for scan events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001989 ret, nl_geterror(ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001990 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001991 }
1992
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001993 ret = nl_get_multicast_id(global, "nl80211", "mlme");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001994 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001995 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001996 if (ret < 0) {
1997 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
1998 "membership for mlme events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07001999 ret, nl_geterror(ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002000 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002001 }
2002
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002003 ret = nl_get_multicast_id(global, "nl80211", "regulatory");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002004 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002005 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002006 if (ret < 0) {
2007 wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
2008 "membership for regulatory events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07002009 ret, nl_geterror(ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002010 /* Continue without regulatory events */
2011 }
2012
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002013 ret = nl_get_multicast_id(global, "nl80211", "vendor");
2014 if (ret >= 0)
2015 ret = nl_socket_add_membership(global->nl_event, ret);
2016 if (ret < 0) {
2017 wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
2018 "membership for vendor events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07002019 ret, nl_geterror(ret));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002020 /* Continue without vendor events */
2021 }
2022
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002023 /* Resolve maxattr for kernel support checks */
2024 ret = genl_ctrl_alloc_cache(global->nl, &cache);
2025 if (ret < 0) {
2026 wpa_printf(MSG_DEBUG,
2027 "nl80211: Could not allocate genl cache: %d (%s)",
2028 ret, nl_geterror(ret));
2029 goto err;
2030 }
2031
2032 family = genl_ctrl_search(cache, global->nl80211_id);
2033 if (!family) {
2034 wpa_printf(MSG_DEBUG,
2035 "nl80211: Could not get nl80211 family from cache: %d (%s)",
2036 ret, nl_geterror(ret));
2037 goto err;
2038 }
2039
2040 global->nl80211_maxattr = genl_family_get_maxattr(family);
2041 wpa_printf(MSG_DEBUG, "nl80211: Maximum supported attribute ID: %u",
2042 global->nl80211_maxattr);
2043 genl_family_put(family);
2044 nl_cache_free(cache);
2045
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002046 nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
2047 no_seq_check, NULL);
2048 nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
2049 process_global_event, global);
2050
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002051 nl80211_register_eloop_read(&global->nl_event,
2052 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002053 global->nl_cb, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002054
2055 return 0;
2056
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002057err:
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002058 genl_family_put(family);
2059 nl_cache_free(cache);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002060 nl_destroy_handles(&global->nl_event);
2061 nl_destroy_handles(&global->nl);
2062 nl_cb_put(global->nl_cb);
2063 global->nl_cb = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002064 return -1;
2065}
2066
2067
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002068static void nl80211_check_global(struct nl80211_global *global)
2069{
Hai Shalomfdcde762020-04-02 11:19:20 -07002070 struct nl_sock *handle;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002071 const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL };
2072 int ret;
2073 unsigned int i;
2074
2075 /*
2076 * Try to re-add memberships to handle case of cfg80211 getting reloaded
2077 * and all registration having been cleared.
2078 */
2079 handle = (void *) (((intptr_t) global->nl_event) ^
2080 ELOOP_SOCKET_INVALID);
2081
2082 for (i = 0; groups[i]; i++) {
2083 ret = nl_get_multicast_id(global, "nl80211", groups[i]);
2084 if (ret >= 0)
2085 ret = nl_socket_add_membership(handle, ret);
2086 if (ret < 0) {
2087 wpa_printf(MSG_INFO,
2088 "nl80211: Could not re-add multicast membership for %s events: %d (%s)",
Hai Shalomfdcde762020-04-02 11:19:20 -07002089 groups[i], ret, nl_geterror(ret));
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002090 }
2091 }
2092}
2093
2094
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002095static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
2096{
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002097 struct wpa_driver_nl80211_data *drv = ctx;
2098
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002099 wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002100
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002101 /*
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002102 * rtnetlink ifdown handler will report interfaces other than the P2P
2103 * Device interface as disabled.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002104 */
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002105 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
2106 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002107}
2108
2109
2110static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
2111{
2112 struct wpa_driver_nl80211_data *drv = ctx;
2113 wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002114 if (i802_set_iface_flags(drv->first_bss, 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002115 wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
2116 "after rfkill unblock");
2117 return;
2118 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002119
2120 if (is_p2p_net_interface(drv->nlmode))
2121 nl80211_disable_11b_rates(drv, drv->ifindex, 1);
2122
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002123 /*
2124 * rtnetlink ifup handler will report interfaces other than the P2P
2125 * Device interface as enabled.
2126 */
2127 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
2128 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002129}
2130
2131
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002132static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
2133 void *eloop_ctx,
2134 void *handle)
2135{
2136 struct wpa_driver_nl80211_data *drv = eloop_ctx;
2137 u8 data[2048];
2138 struct msghdr msg;
2139 struct iovec entry;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002140 u8 control[512];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002141 struct cmsghdr *cmsg;
2142 int res, found_ee = 0, found_wifi = 0, acked = 0;
2143 union wpa_event_data event;
2144
2145 memset(&msg, 0, sizeof(msg));
2146 msg.msg_iov = &entry;
2147 msg.msg_iovlen = 1;
2148 entry.iov_base = data;
2149 entry.iov_len = sizeof(data);
2150 msg.msg_control = &control;
2151 msg.msg_controllen = sizeof(control);
2152
2153 res = recvmsg(sock, &msg, MSG_ERRQUEUE);
2154 /* if error or not fitting 802.3 header, return */
2155 if (res < 14)
2156 return;
2157
2158 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
2159 {
2160 if (cmsg->cmsg_level == SOL_SOCKET &&
2161 cmsg->cmsg_type == SCM_WIFI_STATUS) {
2162 int *ack;
2163
2164 found_wifi = 1;
2165 ack = (void *)CMSG_DATA(cmsg);
2166 acked = *ack;
2167 }
2168
2169 if (cmsg->cmsg_level == SOL_PACKET &&
2170 cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
2171 struct sock_extended_err *err =
2172 (struct sock_extended_err *)CMSG_DATA(cmsg);
2173
2174 if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
2175 found_ee = 1;
2176 }
2177 }
2178
2179 if (!found_ee || !found_wifi)
2180 return;
2181
2182 memset(&event, 0, sizeof(event));
2183 event.eapol_tx_status.dst = data;
2184 event.eapol_tx_status.data = data + 14;
2185 event.eapol_tx_status.data_len = res - 14;
2186 event.eapol_tx_status.ack = acked;
2187 wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
2188}
2189
2190
Hai Shalomb755a2a2020-04-23 21:49:02 -07002191static int nl80211_init_connect_handle(struct i802_bss *bss)
2192{
2193 if (bss->nl_connect) {
2194 wpa_printf(MSG_DEBUG,
2195 "nl80211: Connect handle already created (nl_connect=%p)",
2196 bss->nl_connect);
2197 return -1;
2198 }
2199
2200 bss->nl_connect = nl_create_handle(bss->nl_cb, "connect");
2201 if (!bss->nl_connect)
2202 return -1;
2203 nl80211_register_eloop_read(&bss->nl_connect,
2204 wpa_driver_nl80211_event_receive,
2205 bss->nl_cb, 1);
2206 return 0;
2207}
2208
2209
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002210static int nl80211_init_bss(struct i802_bss *bss)
2211{
2212 bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
2213 if (!bss->nl_cb)
2214 return -1;
2215
2216 nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
2217 no_seq_check, NULL);
2218 nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
2219 process_bss_event, bss);
2220
Hai Shalomb755a2a2020-04-23 21:49:02 -07002221 nl80211_init_connect_handle(bss);
2222
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002223 return 0;
2224}
2225
2226
2227static void nl80211_destroy_bss(struct i802_bss *bss)
2228{
2229 nl_cb_put(bss->nl_cb);
2230 bss->nl_cb = NULL;
Hai Shalomb755a2a2020-04-23 21:49:02 -07002231
2232 if (bss->nl_connect)
2233 nl80211_destroy_eloop_handle(&bss->nl_connect, 1);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002234}
2235
2236
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08002237static void
2238wpa_driver_nl80211_drv_init_rfkill(struct wpa_driver_nl80211_data *drv)
2239{
2240 struct rfkill_config *rcfg;
2241
2242 if (drv->rfkill)
2243 return;
2244
2245 rcfg = os_zalloc(sizeof(*rcfg));
2246 if (!rcfg)
2247 return;
2248
2249 rcfg->ctx = drv;
2250
2251 /* rfkill uses netdev sysfs for initialization. However, P2P Device is
2252 * not associated with a netdev, so use the name of some other interface
2253 * sharing the same wiphy as the P2P Device interface.
2254 *
2255 * Note: This is valid, as a P2P Device interface is always dynamically
2256 * created and is created only once another wpa_s interface was added.
2257 */
2258 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
2259 struct nl80211_global *global = drv->global;
2260 struct wpa_driver_nl80211_data *tmp1;
2261
2262 dl_list_for_each(tmp1, &global->interfaces,
2263 struct wpa_driver_nl80211_data, list) {
2264 if (drv == tmp1 || drv->wiphy_idx != tmp1->wiphy_idx ||
2265 !tmp1->rfkill)
2266 continue;
2267
2268 wpa_printf(MSG_DEBUG,
2269 "nl80211: Use (%s) to initialize P2P Device rfkill",
2270 tmp1->first_bss->ifname);
2271 os_strlcpy(rcfg->ifname, tmp1->first_bss->ifname,
2272 sizeof(rcfg->ifname));
2273 break;
2274 }
2275 } else {
2276 os_strlcpy(rcfg->ifname, drv->first_bss->ifname,
2277 sizeof(rcfg->ifname));
2278 }
2279
2280 rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
2281 rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
2282 drv->rfkill = rfkill_init(rcfg);
2283 if (!drv->rfkill) {
2284 wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
2285 os_free(rcfg);
2286 }
2287}
2288
2289
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002290static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
2291 void *global_priv, int hostapd,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002292 const u8 *set_addr,
2293 const char *driver_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002294{
2295 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002296 struct i802_bss *bss;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002297 char path[128], buf[200], *pos;
2298 ssize_t len;
2299 int ret;
2300
2301 ret = os_snprintf(path, sizeof(path), "/sys/class/net/%s/device/driver",
2302 ifname);
2303 if (!os_snprintf_error(sizeof(path), ret)) {
2304 len = readlink(path, buf, sizeof(buf));
2305 if (len > 0 && (size_t) len < sizeof(buf)) {
2306 buf[len] = '\0';
2307 pos = strrchr(buf, '/');
2308 if (pos)
2309 pos++;
2310 else
2311 pos = buf;
2312 wpa_printf(MSG_DEBUG,
2313 "nl80211: Initialize interface %s (driver: %s)",
2314 ifname, pos);
2315 }
2316 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002317
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002318 if (global_priv == NULL)
2319 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002320 drv = os_zalloc(sizeof(*drv));
2321 if (drv == NULL)
2322 return NULL;
2323 drv->global = global_priv;
2324 drv->ctx = ctx;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002325 drv->hostapd = !!hostapd;
2326 drv->eapol_sock = -1;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002327
2328 /*
2329 * There is no driver capability flag for this, so assume it is
2330 * supported and disable this on first attempt to use if the driver
2331 * rejects the command due to missing support.
2332 */
2333 drv->set_rekey_offload = 1;
2334
Hai Shalom81f62d82019-07-22 12:10:00 -07002335 drv->num_if_indices = ARRAY_SIZE(drv->default_if_indices);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002336 drv->if_indices = drv->default_if_indices;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002337
2338 drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
2339 if (!drv->first_bss) {
2340 os_free(drv);
2341 return NULL;
2342 }
2343 bss = drv->first_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002344 bss->drv = drv;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002345 bss->ctx = ctx;
2346
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002347 os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
2348 drv->monitor_ifidx = -1;
2349 drv->monitor_sock = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002350 drv->eapol_tx_sock = -1;
2351 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002352
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002353 if (nl80211_init_bss(bss))
2354 goto failed;
2355
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002356 if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002357 goto failed;
2358
Hai Shalom899fcc72020-10-19 14:38:18 -07002359 if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS) {
2360 drv->control_port_ap = 1;
2361 goto skip_wifi_status;
2362 }
2363
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002364 drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
2365 if (drv->eapol_tx_sock < 0)
2366 goto failed;
2367
2368 if (drv->data_tx_status) {
2369 int enabled = 1;
2370
2371 if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
2372 &enabled, sizeof(enabled)) < 0) {
2373 wpa_printf(MSG_DEBUG,
Hai Shalom899fcc72020-10-19 14:38:18 -07002374 "nl80211: wifi status sockopt failed: %s",
2375 strerror(errno));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002376 drv->data_tx_status = 0;
2377 if (!drv->use_monitor)
2378 drv->capa.flags &=
2379 ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
2380 } else {
Hai Shalom899fcc72020-10-19 14:38:18 -07002381 eloop_register_read_sock(
2382 drv->eapol_tx_sock,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002383 wpa_driver_nl80211_handle_eapol_tx_status,
2384 drv, NULL);
2385 }
2386 }
Hai Shalom899fcc72020-10-19 14:38:18 -07002387skip_wifi_status:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002388
2389 if (drv->global) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002390 nl80211_check_global(drv->global);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002391 dl_list_add(&drv->global->interfaces, &drv->list);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002392 drv->in_interface_list = 1;
2393 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002394
Sunil Ravi036cec52023-03-29 11:35:17 -07002395 /*
Sunil Ravi99c035e2024-07-12 01:42:03 +00002396 * Use link ID 0 for the single "link" of a non-MLD.
Sunil Ravi036cec52023-03-29 11:35:17 -07002397 */
Sunil Ravi99c035e2024-07-12 01:42:03 +00002398 bss->valid_links = 0;
Sunil Ravi036cec52023-03-29 11:35:17 -07002399 bss->flink = &bss->links[0];
Sunil Ravi036cec52023-03-29 11:35:17 -07002400 os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN);
2401
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002402 return bss;
2403
2404failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002405 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002406 return NULL;
2407}
2408
2409
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002410/**
2411 * wpa_driver_nl80211_init - Initialize nl80211 driver interface
2412 * @ctx: context to be used when calling wpa_supplicant functions,
2413 * e.g., wpa_supplicant_event()
2414 * @ifname: interface name, e.g., wlan0
2415 * @global_priv: private driver global data from global_init()
2416 * Returns: Pointer to private data, %NULL on failure
2417 */
2418static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
2419 void *global_priv)
2420{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002421 return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL,
2422 NULL);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002423}
2424
2425
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002426static int nl80211_register_frame(struct i802_bss *bss,
Hai Shalomfdcde762020-04-02 11:19:20 -07002427 struct nl_sock *nl_handle,
Hai Shalome21d4e82020-04-29 16:34:06 -07002428 u16 type, const u8 *match, size_t match_len,
2429 bool multicast)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002430{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002431 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002432 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002433 int ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002434 char buf[30];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002435
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002436 buf[0] = '\0';
2437 wpa_snprintf_hex(buf, sizeof(buf), match, match_len);
Hai Shalome21d4e82020-04-29 16:34:06 -07002438 wpa_printf(MSG_DEBUG,
2439 "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s multicast=%d",
2440 type, fc2str(type), nl_handle, buf, multicast);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002441
Hai Shalomfdcde762020-04-02 11:19:20 -07002442 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_FRAME)) ||
Hai Shalome21d4e82020-04-29 16:34:06 -07002443 (multicast && nla_put_flag(msg, NL80211_ATTR_RECEIVE_MULTICAST)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002444 nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type) ||
2445 nla_put(msg, NL80211_ATTR_FRAME_MATCH, match_len, match)) {
2446 nlmsg_free(msg);
2447 return -1;
2448 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002449
Hai Shalom899fcc72020-10-19 14:38:18 -07002450 ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002451 NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002452 if (ret) {
2453 wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
2454 "failed (type=%u): ret=%d (%s)",
2455 type, ret, strerror(-ret));
2456 wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
2457 match, match_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002458 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002459 return ret;
2460}
2461
2462
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002463static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
2464{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002465 if (bss->nl_mgmt) {
2466 wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
2467 "already on! (nl_mgmt=%p)", bss->nl_mgmt);
2468 return -1;
2469 }
2470
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002471 bss->nl_mgmt = nl_create_handle(bss->nl_cb, "mgmt");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002472 if (bss->nl_mgmt == NULL)
2473 return -1;
2474
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002475 return 0;
2476}
2477
2478
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002479static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss)
2480{
2481 nl80211_register_eloop_read(&bss->nl_mgmt,
2482 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002483 bss->nl_cb, 0);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002484}
2485
2486
Sunil Ravi7f769292024-07-23 22:21:32 +00002487static int nl80211_register_action_frame2(struct i802_bss *bss,
2488 const u8 *match, size_t match_len,
2489 bool multicast)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002490{
2491 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002492 return nl80211_register_frame(bss, bss->nl_mgmt,
Sunil Ravi7f769292024-07-23 22:21:32 +00002493 type, match, match_len, multicast);
2494}
2495
2496
2497static int nl80211_register_action_frame(struct i802_bss *bss,
2498 const u8 *match, size_t match_len)
2499{
2500 return nl80211_register_action_frame2(bss, match, match_len, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002501}
2502
2503
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002504static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002505{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002506 struct wpa_driver_nl80211_data *drv = bss->drv;
Hai Shalomfdcde762020-04-02 11:19:20 -07002507 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002508 int ret = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002509
2510 if (nl80211_alloc_mgmt_handle(bss))
2511 return -1;
2512 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
2513 "handle %p", bss->nl_mgmt);
2514
Hai Shalomfdcde762020-04-02 11:19:20 -07002515 if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002516 /* register for any AUTH message */
Hai Shalome21d4e82020-04-29 16:34:06 -07002517 nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0, false);
Hai Shalomfdcde762020-04-02 11:19:20 -07002518 } else if ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
2519 !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
2520 /* register for SAE Authentication frames */
2521 nl80211_register_frame(bss, bss->nl_mgmt, type,
Hai Shalome21d4e82020-04-29 16:34:06 -07002522 (u8 *) "\x03\x00", 2, false);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002523 }
2524
Hai Shalom60840252021-02-19 19:02:11 -08002525#ifdef CONFIG_PASN
2526 /* register for PASN Authentication frames */
Sunil Ravi89eba102022-09-13 21:04:37 -07002527 if (nl80211_register_frame(bss, bss->nl_mgmt, type,
Hai Shalom60840252021-02-19 19:02:11 -08002528 (u8 *) "\x07\x00", 2, false))
2529 ret = -1;
2530#endif /* CONFIG_PASN */
2531
Dmitry Shmidt051af732013-10-22 13:52:46 -07002532#ifdef CONFIG_INTERWORKING
2533 /* QoS Map Configure */
2534 if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002535 ret = -1;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002536#endif /* CONFIG_INTERWORKING */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002537#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002538 /* GAS Initial Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002539 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002540 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002541 /* GAS Initial Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002542 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002543 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002544 /* GAS Comeback Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002545 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002546 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002547 /* GAS Comeback Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002548 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002549 ret = -1;
Dmitry Shmidt18463232014-01-24 12:29:41 -08002550 /* Protected GAS Initial Request */
2551 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0a", 2) < 0)
2552 ret = -1;
2553 /* Protected GAS Initial Response */
2554 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0b", 2) < 0)
2555 ret = -1;
2556 /* Protected GAS Comeback Request */
2557 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0c", 2) < 0)
2558 ret = -1;
2559 /* Protected GAS Comeback Response */
2560 if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0d", 2) < 0)
2561 ret = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002562#endif /* CONFIG_P2P || CONFIG_INTERWORKING || CONFIG_DPP */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002563#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002564 /* P2P Public Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002565 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002566 (u8 *) "\x04\x09\x50\x6f\x9a\x09",
2567 6) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002568 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002569 /* P2P Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002570 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002571 (u8 *) "\x7f\x50\x6f\x9a\x09",
2572 5) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002573 ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002574#endif /* CONFIG_P2P */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002575#ifdef CONFIG_NAN_USD
Sunil Ravi7f769292024-07-23 22:21:32 +00002576#define NAN_PUB_ACTION ((u8 *) "\x04\x09\x50\x6f\x9a\x13")
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002577 /* NAN SDF Public Action */
Sunil Ravi7f769292024-07-23 22:21:32 +00002578 if (nl80211_register_action_frame2(bss, NAN_PUB_ACTION, 6, true) < 0) {
2579 /* fallback to non-multicast */
2580 if (nl80211_register_action_frame2(bss, NAN_PUB_ACTION, 6,
2581 false) < 0)
2582 ret = -1;
2583 }
2584#undef NAN_PUB_ACTION
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002585#endif /* CONFIG_NAN_USD */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002586#ifdef CONFIG_DPP
2587 /* DPP Public Action */
2588 if (nl80211_register_action_frame(bss,
2589 (u8 *) "\x04\x09\x50\x6f\x9a\x1a",
2590 6) < 0)
2591 ret = -1;
2592#endif /* CONFIG_DPP */
Hai Shalom74f70d42019-02-11 14:42:39 -08002593#ifdef CONFIG_OCV
2594 /* SA Query Request */
2595 if (nl80211_register_action_frame(bss, (u8 *) "\x08\x00", 2) < 0)
2596 ret = -1;
2597#endif /* CONFIG_OCV */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002598 /* SA Query Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002599 if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002600 ret = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002601#ifdef CONFIG_TDLS
2602 if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
2603 /* TDLS Discovery Response */
2604 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
2605 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002606 ret = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002607 }
2608#endif /* CONFIG_TDLS */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002609#ifdef CONFIG_FST
2610 /* FST Action frames */
2611 if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
2612 ret = -1;
2613#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002614
2615 /* FT Action frames */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002616 if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002617 ret = -1;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002618 else if (!drv->has_driver_key_mgmt) {
2619 int i;
2620
2621 /* Update supported AKMs only if the driver doesn't advertize
2622 * any AKM capabilities. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002623 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
2624 WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
2625
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002626 /* Update per interface supported AKMs */
2627 for (i = 0; i < WPA_IF_MAX; i++)
2628 drv->capa.key_mgmt_iftype[i] = drv->capa.key_mgmt;
2629 }
2630
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002631 /* WNM - BSS Transition Management Request */
2632 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002633 ret = -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002634 /* WNM-Sleep Mode Response */
2635 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002636 ret = -1;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08002637#ifdef CONFIG_WNM
2638 /* WNM - Collocated Interference Request */
2639 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x0b", 2) < 0)
2640 ret = -1;
2641#endif /* CONFIG_WNM */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002642
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002643#ifdef CONFIG_HS20
2644 /* WNM-Notification */
2645 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x1a", 2) < 0)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002646 ret = -1;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002647#endif /* CONFIG_HS20 */
2648
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002649 /* WMM-AC ADDTS Response */
2650 if (nl80211_register_action_frame(bss, (u8 *) "\x11\x01", 2) < 0)
2651 ret = -1;
2652
2653 /* WMM-AC DELTS */
2654 if (nl80211_register_action_frame(bss, (u8 *) "\x11\x02", 2) < 0)
2655 ret = -1;
2656
2657 /* Radio Measurement - Neighbor Report Response */
2658 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
2659 ret = -1;
2660
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002661 /* Radio Measurement - Radio Measurement Request */
Hai Shalom899fcc72020-10-19 14:38:18 -07002662 if (!drv->no_rrm &&
2663 nl80211_register_action_frame(bss, (u8 *) "\x05\x00", 2) < 0)
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002664 ret = -1;
2665
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002666 /* Radio Measurement - Link Measurement Request */
2667 if ((drv->capa.rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) &&
2668 (nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
2669 ret = -1;
2670
Hai Shalomc1a21442022-02-04 13:43:00 -08002671 /* Robust AV SCS Response */
2672 if (nl80211_register_action_frame(bss, (u8 *) "\x13\x01", 2) < 0)
2673 ret = -1;
2674
Hai Shalom899fcc72020-10-19 14:38:18 -07002675 /* Robust AV MSCS Response */
2676 if (nl80211_register_action_frame(bss, (u8 *) "\x13\x05", 2) < 0)
2677 ret = -1;
2678
Hai Shalomc1a21442022-02-04 13:43:00 -08002679 /* Protected QoS Management Action frame */
2680 if (nl80211_register_action_frame(bss, (u8 *) "\x7e\x50\x6f\x9a\x1a",
2681 5) < 0)
2682 ret = -1;
2683
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002684 nl80211_mgmt_handle_register_eloop(bss);
2685
2686 return ret;
2687}
2688
2689
2690static int nl80211_mgmt_subscribe_mesh(struct i802_bss *bss)
2691{
2692 int ret = 0;
2693
2694 if (nl80211_alloc_mgmt_handle(bss))
2695 return -1;
2696
2697 wpa_printf(MSG_DEBUG,
2698 "nl80211: Subscribe to mgmt frames with mesh handle %p",
2699 bss->nl_mgmt);
2700
2701 /* Auth frames for mesh SAE */
2702 if (nl80211_register_frame(bss, bss->nl_mgmt,
2703 (WLAN_FC_TYPE_MGMT << 2) |
2704 (WLAN_FC_STYPE_AUTH << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07002705 NULL, 0, false) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002706 ret = -1;
2707
2708 /* Mesh peering open */
2709 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x01", 2) < 0)
2710 ret = -1;
2711 /* Mesh peering confirm */
2712 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x02", 2) < 0)
2713 ret = -1;
2714 /* Mesh peering close */
2715 if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x03", 2) < 0)
2716 ret = -1;
2717
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002718 nl80211_mgmt_handle_register_eloop(bss);
2719
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002720 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002721}
2722
2723
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002724static int nl80211_register_spurious_class3(struct i802_bss *bss)
2725{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002726 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002727 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002728
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002729 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
Hai Shalom899fcc72020-10-19 14:38:18 -07002730 ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002731 NULL, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002732 if (ret) {
2733 wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
2734 "failed: ret=%d (%s)",
2735 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002736 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002737 return ret;
2738}
2739
2740
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002741static int nl80211_action_subscribe_ap(struct i802_bss *bss)
2742{
2743 int ret = 0;
2744
2745 /* Public Action frames */
2746 if (nl80211_register_action_frame(bss, (u8 *) "\x04", 1) < 0)
2747 ret = -1;
2748 /* RRM Measurement Report */
2749 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x01", 2) < 0)
2750 ret = -1;
Paul Stewart092955c2017-02-06 09:13:09 -08002751 /* RRM Link Measurement Report */
2752 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x03", 2) < 0)
2753 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002754 /* RRM Neighbor Report Request */
2755 if (nl80211_register_action_frame(bss, (u8 *) "\x05\x04", 2) < 0)
2756 ret = -1;
2757 /* FT Action frames */
2758 if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
2759 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002760 /* SA Query */
2761 if (nl80211_register_action_frame(bss, (u8 *) "\x08", 1) < 0)
2762 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002763 /* Protected Dual of Public Action */
2764 if (nl80211_register_action_frame(bss, (u8 *) "\x09", 1) < 0)
2765 ret = -1;
2766 /* WNM */
2767 if (nl80211_register_action_frame(bss, (u8 *) "\x0a", 1) < 0)
2768 ret = -1;
2769 /* WMM */
2770 if (nl80211_register_action_frame(bss, (u8 *) "\x11", 1) < 0)
2771 ret = -1;
2772#ifdef CONFIG_FST
2773 /* FST Action frames */
2774 if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
2775 ret = -1;
2776#endif /* CONFIG_FST */
2777 /* Vendor-specific */
2778 if (nl80211_register_action_frame(bss, (u8 *) "\x7f", 1) < 0)
2779 ret = -1;
2780
2781 return ret;
2782}
2783
2784
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002785static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
2786{
2787 static const int stypes[] = {
2788 WLAN_FC_STYPE_AUTH,
2789 WLAN_FC_STYPE_ASSOC_REQ,
2790 WLAN_FC_STYPE_REASSOC_REQ,
2791 WLAN_FC_STYPE_DISASSOC,
2792 WLAN_FC_STYPE_DEAUTH,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002793 WLAN_FC_STYPE_PROBE_REQ,
2794/* Beacon doesn't work as mac80211 doesn't currently allow
2795 * it, but it wouldn't really be the right thing anyway as
2796 * it isn't per interface ... maybe just dump the scan
2797 * results periodically for OLBC?
2798 */
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07002799 /* WLAN_FC_STYPE_BEACON, */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002800 };
2801 unsigned int i;
2802
2803 if (nl80211_alloc_mgmt_handle(bss))
2804 return -1;
2805 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
2806 "handle %p", bss->nl_mgmt);
2807
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002808 for (i = 0; i < ARRAY_SIZE(stypes); i++) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002809 if (nl80211_register_frame(bss, bss->nl_mgmt,
2810 (WLAN_FC_TYPE_MGMT << 2) |
2811 (stypes[i] << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07002812 NULL, 0, false) < 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002813 goto out_err;
2814 }
2815 }
2816
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002817 if (nl80211_action_subscribe_ap(bss))
2818 goto out_err;
2819
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002820 if (nl80211_register_spurious_class3(bss))
2821 goto out_err;
2822
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002823 nl80211_mgmt_handle_register_eloop(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002824 return 0;
2825
2826out_err:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002827 nl_destroy_handles(&bss->nl_mgmt);
2828 return -1;
2829}
2830
2831
2832static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
2833{
2834 if (nl80211_alloc_mgmt_handle(bss))
2835 return -1;
2836 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
2837 "handle %p (device SME)", bss->nl_mgmt);
2838
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002839 if (nl80211_action_subscribe_ap(bss))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002840 goto out_err;
2841
Hai Shalom5f92bc92019-04-18 11:54:11 -07002842 if (bss->drv->device_ap_sme) {
2843 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
2844
2845 /* Register for all Authentication frames */
Hai Shalome21d4e82020-04-29 16:34:06 -07002846 if (nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0,
2847 false) < 0)
Hai Shalom5f92bc92019-04-18 11:54:11 -07002848 wpa_printf(MSG_DEBUG,
2849 "nl80211: Failed to subscribe to handle Authentication frames - SAE offload may not work");
2850 }
2851
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002852 nl80211_mgmt_handle_register_eloop(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002853 return 0;
2854
2855out_err:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002856 nl_destroy_handles(&bss->nl_mgmt);
2857 return -1;
2858}
2859
2860
2861static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
2862{
2863 if (bss->nl_mgmt == NULL)
2864 return;
2865 wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
2866 "(%s)", bss->nl_mgmt, reason);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002867 nl80211_destroy_eloop_handle(&bss->nl_mgmt, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002868
2869 nl80211_put_wiphy_data_ap(bss);
2870}
2871
2872
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002873static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
2874{
2875 wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
2876}
2877
2878
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002879static void nl80211_del_p2pdev(struct i802_bss *bss)
2880{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002881 struct nl_msg *msg;
2882 int ret;
2883
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002884 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002885 ret = send_and_recv_cmd(bss->drv, msg);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002886
2887 wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
2888 bss->ifname, (long long unsigned int) bss->wdev_id,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002889 strerror(-ret));
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002890}
2891
2892
2893static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
2894{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002895 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002896 int ret;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002897
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002898 msg = nl80211_cmd_msg(bss, 0, start ? NL80211_CMD_START_P2P_DEVICE :
2899 NL80211_CMD_STOP_P2P_DEVICE);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002900 ret = send_and_recv_cmd(bss->drv, msg);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002901
2902 wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
2903 start ? "Start" : "Stop",
2904 bss->ifname, (long long unsigned int) bss->wdev_id,
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07002905 strerror(-ret));
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002906 return ret;
2907}
2908
2909
2910static int i802_set_iface_flags(struct i802_bss *bss, int up)
2911{
2912 enum nl80211_iftype nlmode;
2913
2914 nlmode = nl80211_get_ifmode(bss);
2915 if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
2916 return linux_set_iface_flags(bss->drv->global->ioctl_sock,
2917 bss->ifname, up);
2918 }
2919
2920 /* P2P Device has start/stop which is equivalent */
2921 return nl80211_set_p2pdev(bss, up);
2922}
2923
2924
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002925#ifdef CONFIG_TESTING_OPTIONS
2926static int qca_vendor_test_cmd_handler(struct nl_msg *msg, void *arg)
2927{
2928 /* struct wpa_driver_nl80211_data *drv = arg; */
2929 struct nlattr *tb[NL80211_ATTR_MAX + 1];
2930 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2931
2932
2933 wpa_printf(MSG_DEBUG,
2934 "nl80211: QCA vendor test command response received");
2935
2936 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2937 genlmsg_attrlen(gnlh, 0), NULL);
2938 if (!tb[NL80211_ATTR_VENDOR_DATA]) {
2939 wpa_printf(MSG_DEBUG, "nl80211: No vendor data attribute");
2940 return NL_SKIP;
2941 }
2942
2943 wpa_hexdump(MSG_DEBUG,
2944 "nl80211: Received QCA vendor test command response",
2945 nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
2946 nla_len(tb[NL80211_ATTR_VENDOR_DATA]));
2947
2948 return NL_SKIP;
2949}
2950#endif /* CONFIG_TESTING_OPTIONS */
2951
2952
2953static void qca_vendor_test(struct wpa_driver_nl80211_data *drv)
2954{
2955#ifdef CONFIG_TESTING_OPTIONS
2956 struct nl_msg *msg;
2957 struct nlattr *params;
2958 int ret;
2959
2960 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
2961 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
2962 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
2963 QCA_NL80211_VENDOR_SUBCMD_TEST) ||
2964 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
2965 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TEST, 123)) {
2966 nlmsg_free(msg);
2967 return;
2968 }
2969 nla_nest_end(msg, params);
2970
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002971 ret = send_and_recv_resp(drv, msg, qca_vendor_test_cmd_handler, drv);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002972 wpa_printf(MSG_DEBUG,
2973 "nl80211: QCA vendor test command returned %d (%s)",
2974 ret, strerror(-ret));
2975#endif /* CONFIG_TESTING_OPTIONS */
2976}
2977
2978
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002979static int
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002980wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002981 const u8 *set_addr, int first,
2982 const char *driver_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002983{
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002984 struct i802_bss *bss = drv->first_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002985 int send_rfkill_event = 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002986 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002987
2988 drv->ifindex = if_nametoindex(bss->ifname);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002989 bss->ifindex = drv->ifindex;
2990 bss->wdev_id = drv->global->if_add_wdevid;
2991 bss->wdev_id_set = drv->global->if_add_wdevid_set;
2992
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07002993 bss->if_dynamic = drv->ifindex == drv->global->if_add_ifindex;
2994 bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002995 drv->global->if_add_wdevid_set = 0;
2996
Dmitry Shmidt03658832014-08-13 11:03:49 -07002997 if (!bss->if_dynamic && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
2998 bss->static_ap = 1;
2999
Dmitry Shmidt014a3ff2015-12-28 13:27:49 -08003000 if (first &&
3001 nl80211_get_ifmode(bss) != NL80211_IFTYPE_P2P_DEVICE &&
3002 linux_iface_up(drv->global->ioctl_sock, bss->ifname) > 0)
3003 drv->start_iface_up = 1;
3004
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003005 if (wpa_driver_nl80211_capa(drv))
3006 return -1;
3007
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003008 if (driver_params && nl80211_set_param(bss, driver_params) < 0)
3009 return -1;
3010
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003011 wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
3012 bss->ifname, drv->phyname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003013
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003014 if (set_addr &&
3015 (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) ||
3016 linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
3017 set_addr)))
3018 return -1;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003019
Hai Shalomc1a21442022-02-04 13:43:00 -08003020 if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_STATION)
3021 drv->start_mode_sta = 1;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003022
Dmitry Shmidt03658832014-08-13 11:03:49 -07003023 if (drv->hostapd || bss->static_ap)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003024 nlmode = NL80211_IFTYPE_AP;
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -07003025 else if (bss->if_dynamic ||
3026 nl80211_get_ifmode(bss) == NL80211_IFTYPE_MESH_POINT)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003027 nlmode = nl80211_get_ifmode(bss);
3028 else
3029 nlmode = NL80211_IFTYPE_STATION;
3030
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003031 if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003032 wpa_printf(MSG_ERROR, "nl80211: Could not configure driver mode");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003033 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003034 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003035
Dmitry Shmidt98660862014-03-11 17:26:21 -07003036 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003037 nl80211_get_macaddr(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003038
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08003039 wpa_driver_nl80211_drv_init_rfkill(drv);
3040
Dmitry Shmidt98660862014-03-11 17:26:21 -07003041 if (!rfkill_is_blocked(drv->rfkill)) {
3042 int ret = i802_set_iface_flags(bss, 1);
3043 if (ret) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003044 wpa_printf(MSG_ERROR, "nl80211: Could not set "
3045 "interface '%s' UP", bss->ifname);
Dmitry Shmidt98660862014-03-11 17:26:21 -07003046 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003047 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003048
3049 if (is_p2p_net_interface(nlmode))
3050 nl80211_disable_11b_rates(bss->drv,
3051 bss->drv->ifindex, 1);
3052
Dmitry Shmidt98660862014-03-11 17:26:21 -07003053 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
3054 return ret;
3055 } else {
3056 wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
3057 "interface '%s' due to rfkill", bss->ifname);
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08003058 if (nlmode != NL80211_IFTYPE_P2P_DEVICE)
3059 drv->if_disabled = 1;
3060
Dmitry Shmidt98660862014-03-11 17:26:21 -07003061 send_rfkill_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003062 }
3063
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08003064 if (!drv->hostapd && nlmode != NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003065 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
3066 1, IF_OPER_DORMANT);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003067
Dmitry Shmidt7d56b752015-12-22 10:59:44 -08003068 if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
3069 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
3070 bss->addr))
3071 return -1;
3072 os_memcpy(drv->perm_addr, bss->addr, ETH_ALEN);
3073 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003074
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003075 if (send_rfkill_event) {
3076 eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
3077 drv, drv->ctx);
3078 }
3079
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003080 if (drv->vendor_cmd_test_avail)
3081 qca_vendor_test(drv);
3082
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003083 return 0;
3084}
3085
3086
Sunil Ravi036cec52023-03-29 11:35:17 -07003087static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss,
Sunil Ravi99c035e2024-07-12 01:42:03 +00003088 int link_id)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003089{
3090 struct nl_msg *msg;
Paul Stewart092955c2017-02-06 09:13:09 -08003091 struct wpa_driver_nl80211_data *drv = bss->drv;
Sunil Ravi99c035e2024-07-12 01:42:03 +00003092 struct i802_link *link = nl80211_get_link(bss, link_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003093
Sunil Ravic0f5d412024-09-11 22:12:49 +00003094 if (!link || !link->beacon_set)
Sunil Ravi036cec52023-03-29 11:35:17 -07003095 return 0;
3096
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003097 wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
Sunil Ravi99c035e2024-07-12 01:42:03 +00003098 bss->ifindex);
Sunil Ravi036cec52023-03-29 11:35:17 -07003099 link->beacon_set = 0;
3100 link->freq = 0;
3101
Paul Stewart092955c2017-02-06 09:13:09 -08003102 nl80211_put_wiphy_data_ap(bss);
Sunil Ravi99c035e2024-07-12 01:42:03 +00003103 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_BEACON);
Sunil Ravi036cec52023-03-29 11:35:17 -07003104 if (!msg)
3105 return -ENOBUFS;
3106
Sunil Ravi99c035e2024-07-12 01:42:03 +00003107 if (link_id != NL80211_DRV_LINK_ID_NA) {
Sunil Ravi036cec52023-03-29 11:35:17 -07003108 wpa_printf(MSG_DEBUG,
3109 "nl80211: MLD: stop beaconing on link=%u",
Sunil Ravi99c035e2024-07-12 01:42:03 +00003110 link_id);
Sunil Ravi036cec52023-03-29 11:35:17 -07003111
Sunil Ravi99c035e2024-07-12 01:42:03 +00003112 if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) {
Sunil Ravi036cec52023-03-29 11:35:17 -07003113 nlmsg_free(msg);
3114 return -ENOBUFS;
3115 }
3116 }
3117
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003118 return send_and_recv_cmd(drv, msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003119}
3120
3121
Sunil Ravi036cec52023-03-29 11:35:17 -07003122static void wpa_driver_nl80211_del_beacon_all(struct i802_bss *bss)
3123{
Sunil Ravi99c035e2024-07-12 01:42:03 +00003124 int link_id;
Sunil Ravi036cec52023-03-29 11:35:17 -07003125
Sunil Ravi99c035e2024-07-12 01:42:03 +00003126 for_each_link_default(bss->valid_links, link_id, NL80211_DRV_LINK_ID_NA)
3127 wpa_driver_nl80211_del_beacon(bss, link_id);
Sunil Ravi036cec52023-03-29 11:35:17 -07003128}
3129
3130
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003131/**
3132 * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003133 * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003134 *
3135 * Shut down driver interface and processing of driver events. Free
3136 * private data buffer if one was allocated in wpa_driver_nl80211_init().
3137 */
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003138static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003139{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003140 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07003141 unsigned int i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003142
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003143 wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
3144 bss->ifname, drv->disabled_11b_rates);
3145
Dmitry Shmidt04949592012-07-19 12:16:46 -07003146 bss->in_deinit = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003147 if (drv->data_tx_status)
3148 eloop_unregister_read_sock(drv->eapol_tx_sock);
3149 if (drv->eapol_tx_sock >= 0)
3150 close(drv->eapol_tx_sock);
3151
3152 if (bss->nl_preq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003153 wpa_driver_nl80211_probe_req_report(bss, 0);
3154 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003155 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
3156 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003157 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
3158 "interface %s from bridge %s: %s",
3159 bss->ifname, bss->brname, strerror(errno));
3160 }
Hai Shalomc9e41a12018-07-31 14:41:42 -07003161
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003162 if (bss->added_bridge) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003163 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
3164 0) < 0)
3165 wpa_printf(MSG_INFO,
3166 "nl80211: Could not set bridge %s down",
3167 bss->brname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003168 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003169 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
3170 "bridge %s: %s",
3171 bss->brname, strerror(errno));
3172 }
3173
3174 nl80211_remove_monitor_interface(drv);
3175
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003176 if (is_ap_interface(drv->nlmode)) {
Sunil Ravi036cec52023-03-29 11:35:17 -07003177 wpa_driver_nl80211_del_beacon_all(bss);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003178 nl80211_remove_links(bss);
3179 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003180
Sunil Ravic0f5d412024-09-11 22:12:49 +00003181 if (drv->rtnl_sk)
3182 nl_socket_free(drv->rtnl_sk);
3183
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003184 if (drv->eapol_sock >= 0) {
3185 eloop_unregister_read_sock(drv->eapol_sock);
3186 close(drv->eapol_sock);
3187 }
3188
3189 if (drv->if_indices != drv->default_if_indices)
3190 os_free(drv->if_indices);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003191
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003192 if (drv->disabled_11b_rates)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003193 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
3194
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003195 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
3196 IF_OPER_UP);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07003197 eloop_cancel_timeout(wpa_driver_nl80211_send_rfkill, drv, drv->ctx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003198 rfkill_deinit(drv->rfkill);
3199
Sunil Ravic0f5d412024-09-11 22:12:49 +00003200 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, bss->ctx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003201
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003202 if (!drv->start_iface_up)
3203 (void) i802_set_iface_flags(bss, 0);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003204
3205 if (drv->addr_changed) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003206 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
3207 0) < 0) {
3208 wpa_printf(MSG_DEBUG,
3209 "nl80211: Could not set interface down to restore permanent MAC address");
3210 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07003211 if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
3212 drv->perm_addr) < 0) {
3213 wpa_printf(MSG_DEBUG,
3214 "nl80211: Could not restore permanent MAC address");
3215 }
3216 }
3217
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003218 if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
Hai Shalomc1a21442022-02-04 13:43:00 -08003219 if (drv->start_mode_sta)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08003220 wpa_driver_nl80211_set_mode(bss,
3221 NL80211_IFTYPE_STATION);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07003222 nl80211_mgmt_unsubscribe(bss, "deinit");
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003223 } else {
3224 nl80211_mgmt_unsubscribe(bss, "deinit");
3225 nl80211_del_p2pdev(bss);
3226 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003227
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003228 nl80211_destroy_bss(drv->first_bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003229
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003230 os_free(drv->filter_ssids);
3231
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003232 os_free(drv->auth_ie);
Hai Shalom60840252021-02-19 19:02:11 -08003233 os_free(drv->auth_data);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003234
3235 if (drv->in_interface_list)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003236 dl_list_del(&drv->list);
3237
Dmitry Shmidt444d5672013-04-01 13:08:44 -07003238 os_free(drv->extended_capa);
3239 os_free(drv->extended_capa_mask);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003240 for (i = 0; i < drv->num_iface_capa; i++) {
3241 os_free(drv->iface_capa[i].ext_capa);
3242 os_free(drv->iface_capa[i].ext_capa_mask);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07003243 }
Dmitry Shmidtcce06662013-11-04 18:44:24 -08003244 os_free(drv->first_bss);
Hai Shalom60840252021-02-19 19:02:11 -08003245#ifdef CONFIG_DRIVER_NL80211_QCA
3246 os_free(drv->pending_roam_data);
3247#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003248 os_free(drv);
3249}
3250
3251
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003252static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len)
3253{
3254 switch (alg) {
3255 case WPA_ALG_WEP:
3256 if (key_len == 5)
Paul Stewart092955c2017-02-06 09:13:09 -08003257 return RSN_CIPHER_SUITE_WEP40;
3258 return RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003259 case WPA_ALG_TKIP:
Paul Stewart092955c2017-02-06 09:13:09 -08003260 return RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003261 case WPA_ALG_CCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003262 return RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003263 case WPA_ALG_GCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003264 return RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003265 case WPA_ALG_CCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003266 return RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003267 case WPA_ALG_GCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003268 return RSN_CIPHER_SUITE_GCMP_256;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003269 case WPA_ALG_BIP_CMAC_128:
Paul Stewart092955c2017-02-06 09:13:09 -08003270 return RSN_CIPHER_SUITE_AES_128_CMAC;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003271 case WPA_ALG_BIP_GMAC_128:
Paul Stewart092955c2017-02-06 09:13:09 -08003272 return RSN_CIPHER_SUITE_BIP_GMAC_128;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003273 case WPA_ALG_BIP_GMAC_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003274 return RSN_CIPHER_SUITE_BIP_GMAC_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003275 case WPA_ALG_BIP_CMAC_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003276 return RSN_CIPHER_SUITE_BIP_CMAC_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003277 case WPA_ALG_SMS4:
Paul Stewart092955c2017-02-06 09:13:09 -08003278 return RSN_CIPHER_SUITE_SMS4;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003279 case WPA_ALG_KRK:
Paul Stewart092955c2017-02-06 09:13:09 -08003280 return RSN_CIPHER_SUITE_KRK;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003281 case WPA_ALG_NONE:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003282 wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d",
3283 alg);
3284 return 0;
3285 }
3286
3287 wpa_printf(MSG_ERROR, "nl80211: Unsupported encryption algorithm %d",
3288 alg);
3289 return 0;
3290}
3291
3292
3293static u32 wpa_cipher_to_cipher_suite(unsigned int cipher)
3294{
3295 switch (cipher) {
3296 case WPA_CIPHER_CCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003297 return RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003298 case WPA_CIPHER_GCMP_256:
Paul Stewart092955c2017-02-06 09:13:09 -08003299 return RSN_CIPHER_SUITE_GCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003300 case WPA_CIPHER_CCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003301 return RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003302 case WPA_CIPHER_GCMP:
Paul Stewart092955c2017-02-06 09:13:09 -08003303 return RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003304 case WPA_CIPHER_TKIP:
Paul Stewart092955c2017-02-06 09:13:09 -08003305 return RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003306 case WPA_CIPHER_WEP104:
Paul Stewart092955c2017-02-06 09:13:09 -08003307 return RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003308 case WPA_CIPHER_WEP40:
Paul Stewart092955c2017-02-06 09:13:09 -08003309 return RSN_CIPHER_SUITE_WEP40;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08003310 case WPA_CIPHER_GTK_NOT_USED:
Paul Stewart092955c2017-02-06 09:13:09 -08003311 return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
Sunil Ravi77d572f2023-01-17 23:58:31 +00003312 default:
3313 return 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003314 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003315}
3316
3317
3318static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[],
3319 int max_suites)
3320{
3321 int num_suites = 0;
3322
3323 if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP_256)
Paul Stewart092955c2017-02-06 09:13:09 -08003324 suites[num_suites++] = RSN_CIPHER_SUITE_CCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003325 if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP_256)
Paul Stewart092955c2017-02-06 09:13:09 -08003326 suites[num_suites++] = RSN_CIPHER_SUITE_GCMP_256;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003327 if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP)
Paul Stewart092955c2017-02-06 09:13:09 -08003328 suites[num_suites++] = RSN_CIPHER_SUITE_CCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003329 if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP)
Paul Stewart092955c2017-02-06 09:13:09 -08003330 suites[num_suites++] = RSN_CIPHER_SUITE_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003331 if (num_suites < max_suites && ciphers & WPA_CIPHER_TKIP)
Paul Stewart092955c2017-02-06 09:13:09 -08003332 suites[num_suites++] = RSN_CIPHER_SUITE_TKIP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003333 if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP104)
Paul Stewart092955c2017-02-06 09:13:09 -08003334 suites[num_suites++] = RSN_CIPHER_SUITE_WEP104;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003335 if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP40)
Paul Stewart092955c2017-02-06 09:13:09 -08003336 suites[num_suites++] = RSN_CIPHER_SUITE_WEP40;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003337
3338 return num_suites;
3339}
3340
3341
Hai Shalomfdcde762020-04-02 11:19:20 -07003342static int wpa_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
3343 int max_suites)
3344{
3345 int num_suites = 0;
3346
3347#define __AKM(a, b) \
3348 if (num_suites < max_suites && \
3349 (key_mgmt_suites & (WPA_KEY_MGMT_ ## a))) \
3350 suites[num_suites++] = (RSN_AUTH_KEY_MGMT_ ## b)
3351 __AKM(IEEE8021X, UNSPEC_802_1X);
3352 __AKM(PSK, PSK_OVER_802_1X);
3353 __AKM(FT_IEEE8021X, FT_802_1X);
3354 __AKM(FT_PSK, FT_PSK);
3355 __AKM(IEEE8021X_SHA256, 802_1X_SHA256);
3356 __AKM(PSK_SHA256, PSK_SHA256);
3357 __AKM(SAE, SAE);
Sunil Ravi89eba102022-09-13 21:04:37 -07003358 __AKM(SAE_EXT_KEY, SAE_EXT_KEY);
Hai Shalomfdcde762020-04-02 11:19:20 -07003359 __AKM(FT_SAE, FT_SAE);
Sunil Ravi89eba102022-09-13 21:04:37 -07003360 __AKM(FT_SAE_EXT_KEY, FT_SAE_EXT_KEY);
Hai Shalomfdcde762020-04-02 11:19:20 -07003361 __AKM(CCKM, CCKM);
3362 __AKM(OSEN, OSEN);
3363 __AKM(IEEE8021X_SUITE_B, 802_1X_SUITE_B);
3364 __AKM(IEEE8021X_SUITE_B_192, 802_1X_SUITE_B_192);
3365 __AKM(FILS_SHA256, FILS_SHA256);
3366 __AKM(FILS_SHA384, FILS_SHA384);
3367 __AKM(FT_FILS_SHA256, FT_FILS_SHA256);
3368 __AKM(FT_FILS_SHA384, FT_FILS_SHA384);
3369 __AKM(OWE, OWE);
3370 __AKM(DPP, DPP);
3371 __AKM(FT_IEEE8021X_SHA384, FT_802_1X_SHA384);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003372 __AKM(IEEE8021X_SHA384, 802_1X_SHA384);
Hai Shalomfdcde762020-04-02 11:19:20 -07003373#undef __AKM
3374
3375 return num_suites;
3376}
3377
3378
Isaac Chiou6ce580d2024-04-24 17:07:24 +08003379#if (defined(CONFIG_DRIVER_NL80211_BRCM) && !defined(WIFI_BRCM_OPEN_SOURCE_MULTI_AKM)) || \
3380 defined(CONFIG_DRIVER_NL80211_SYNA)
Vinayak Yadawad14709082022-03-17 14:25:11 +05303381static int wpa_cross_akm_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
3382 int max_suites)
3383{
3384 int num_suites = 0;
3385
3386#define __AKM_TO_SUITES_ARRAY(a, b) \
3387 if (num_suites < max_suites && \
3388 (key_mgmt_suites & (WPA_KEY_MGMT_ ## a))) \
3389 suites[num_suites++] = (RSN_AUTH_KEY_MGMT_ ## b)
3390 __AKM_TO_SUITES_ARRAY(PSK, PSK_OVER_802_1X);
3391 __AKM_TO_SUITES_ARRAY(SAE, SAE);
3392#undef __AKM_TO_SUITES_ARRAY
3393
3394 return num_suites;
3395}
Isaac Chiou6ce580d2024-04-24 17:07:24 +08003396#endif /* (CONFIG_DRIVER_NL80211_BRCM && !WIFI_BRCM_OPEN_SOURCE_MULTI_AKM) ||
3397 * CONFIG_DRIVER_NL80211_SYNA */
Vinayak Yadawad14709082022-03-17 14:25:11 +05303398
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003399
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003400#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003401static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
3402 const u8 *key, size_t key_len)
3403{
3404 struct nl_msg *msg;
3405 int ret;
3406
3407 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
3408 return 0;
3409
3410 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
3411 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
3412 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
3413 QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY) ||
3414 nla_put(msg, NL80211_ATTR_VENDOR_DATA, key_len, key)) {
3415 nl80211_nlmsg_clear(msg);
3416 nlmsg_free(msg);
3417 return -1;
3418 }
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003419 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003420 if (ret) {
3421 wpa_printf(MSG_DEBUG,
3422 "nl80211: Key management set key failed: ret=%d (%s)",
3423 ret, strerror(-ret));
3424 }
3425
3426 return ret;
3427}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003428#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003429
3430
Andy Kuoaba17c12022-04-14 16:05:31 +08003431#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Mir Ali677e7482020-11-12 19:49:02 +05303432static int key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
3433 const u8 *key, size_t key_len)
3434{
3435 struct nl_msg *msg;
3436 int ret;
3437 struct nlattr *params;
3438
3439 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
3440 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
3441 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
Hai Shalomc1a21442022-02-04 13:43:00 -08003442 BRCM_VENDOR_SCMD_SET_PMK) ||
Mir Ali677e7482020-11-12 19:49:02 +05303443 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
3444 nla_put(msg, BRCM_ATTR_DRIVER_KEY_PMK, key_len, key)) {
3445 nl80211_nlmsg_clear(msg);
3446 nlmsg_free(msg);
3447 return -ENOBUFS;
3448 }
3449 nla_nest_end(msg, params);
3450
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003451 ret = send_and_recv_cmd(drv, msg);
Mir Ali677e7482020-11-12 19:49:02 +05303452 if (ret) {
3453 wpa_printf(MSG_DEBUG, "nl80211: Key mgmt set key failed: ret=%d (%s)",
3454 ret, strerror(-ret));
3455 }
3456
3457 return ret;
3458}
Andy Kuoaba17c12022-04-14 16:05:31 +08003459#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
3460
Mir Ali677e7482020-11-12 19:49:02 +05303461
Roshan Pius3a1667e2018-07-03 15:17:14 -07003462static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
3463 const u8 *key, size_t key_len,
3464 const u8 *addr)
3465{
3466 struct nl_msg *msg = NULL;
3467 int ret;
3468
3469 /*
3470 * If the authenticator address is not set, assume it is
3471 * the current BSSID.
3472 */
3473 if (!addr && drv->associated)
3474 addr = drv->bssid;
3475 else if (!addr)
3476 return -1;
3477
3478 wpa_printf(MSG_DEBUG, "nl80211: Set PMK to the driver for " MACSTR,
3479 MAC2STR(addr));
3480 wpa_hexdump_key(MSG_DEBUG, "nl80211: PMK", key, key_len);
3481 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_PMK);
3482 if (!msg ||
3483 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
3484 nla_put(msg, NL80211_ATTR_PMK, key_len, key)) {
3485 nl80211_nlmsg_clear(msg);
3486 nlmsg_free(msg);
3487 return -ENOBUFS;
3488 }
3489
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003490 ret = send_and_recv_cmd(drv, msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003491 if (ret) {
3492 wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)",
3493 ret, strerror(-ret));
3494 }
3495
3496 return ret;
3497}
3498
3499
Hai Shalomfdcde762020-04-02 11:19:20 -07003500static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
3501 struct wpa_driver_set_key_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003502{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003503 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003504 int ifindex;
Hai Shalomc3565922019-10-28 11:58:20 -07003505 struct nl_msg *msg;
3506 struct nl_msg *key_msg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003507 int ret;
Hai Shalomfdcde762020-04-02 11:19:20 -07003508 int skip_set_key = 1;
3509 const char *ifname = params->ifname;
3510 enum wpa_alg alg = params->alg;
3511 const u8 *addr = params->addr;
3512 int key_idx = params->key_idx;
3513 int set_tx = params->set_tx;
3514 const u8 *seq = params->seq;
3515 size_t seq_len = params->seq_len;
3516 const u8 *key = params->key;
3517 size_t key_len = params->key_len;
3518 int vlan_id = params->vlan_id;
3519 enum key_flag key_flag = params->key_flag;
Sunil Ravi77d572f2023-01-17 23:58:31 +00003520 int link_id = params->link_id;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003521
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003522 /* Ignore for P2P Device */
3523 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
3524 return 0;
3525
3526 ifindex = if_nametoindex(ifname);
3527 wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
Sunil Ravi77d572f2023-01-17 23:58:31 +00003528 "set_tx=%d seq_len=%lu key_len=%lu key_flag=0x%x link_id=%d",
Dmitry Shmidt34af3062013-07-11 10:46:32 -07003529 __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
Sunil Ravi77d572f2023-01-17 23:58:31 +00003530 (unsigned long) seq_len, (unsigned long) key_len, key_flag,
3531 link_id);
Hai Shalomfdcde762020-04-02 11:19:20 -07003532
3533 if (check_key_flag(key_flag)) {
3534 wpa_printf(MSG_DEBUG, "%s: invalid key_flag", __func__);
3535 return -EINVAL;
Dmitry Shmidtd5c075b2013-08-05 14:36:10 -07003536 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003537
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003538#ifdef CONFIG_DRIVER_NL80211_QCA
Hai Shalomfdcde762020-04-02 11:19:20 -07003539 if ((key_flag & KEY_FLAG_PMK) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003540 (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
3541 wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
3542 __func__);
3543 ret = issue_key_mgmt_set_key(drv, key, key_len);
3544 return ret;
3545 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003546#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003547
Hai Shalomfdcde762020-04-02 11:19:20 -07003548 if (key_flag & KEY_FLAG_PMK) {
3549 if (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)
3550 return nl80211_set_pmk(drv, key, key_len, addr);
Andy Kuoaba17c12022-04-14 16:05:31 +08003551#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Mir Ali677e7482020-11-12 19:49:02 +05303552 if (drv->vendor_set_pmk) {
Jay Patel731adae2021-02-17 14:55:58 -08003553 wpa_printf(MSG_INFO, "nl80211: key_mgmt_set_key with key_len %lu", (unsigned long) key_len);
Mir Ali677e7482020-11-12 19:49:02 +05303554 return key_mgmt_set_key(drv, key, key_len);
3555 }
Andy Kuoaba17c12022-04-14 16:05:31 +08003556#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
3557
Hai Shalomfdcde762020-04-02 11:19:20 -07003558 /* The driver does not have any offload mechanism for PMK, so
3559 * there is no need to configure this key. */
3560 return 0;
3561 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07003562
Hai Shalomfdcde762020-04-02 11:19:20 -07003563 ret = -ENOBUFS;
Hai Shalomc3565922019-10-28 11:58:20 -07003564 key_msg = nlmsg_alloc();
3565 if (!key_msg)
Hai Shalomfdcde762020-04-02 11:19:20 -07003566 return ret;
Hai Shalomc3565922019-10-28 11:58:20 -07003567
Hai Shalomfdcde762020-04-02 11:19:20 -07003568 if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3569 KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
3570 wpa_printf(MSG_DEBUG,
3571 "nl80211: SET_KEY (pairwise RX/TX modify)");
3572 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
3573 if (!msg)
3574 goto fail2;
3575 } else if (alg == WPA_ALG_NONE && (key_flag & KEY_FLAG_RX_TX)) {
3576 wpa_printf(MSG_DEBUG, "%s: invalid key_flag to delete key",
3577 __func__);
3578 ret = -EINVAL;
3579 goto fail2;
3580 } else if (alg == WPA_ALG_NONE) {
3581 wpa_printf(MSG_DEBUG, "nl80211: DEL_KEY");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003582 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
3583 if (!msg)
Hai Shalomc3565922019-10-28 11:58:20 -07003584 goto fail2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003585 } else {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003586 u32 suite;
3587
3588 suite = wpa_alg_to_cipher_suite(alg, key_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07003589 if (!suite) {
3590 ret = -EINVAL;
Hai Shalomc3565922019-10-28 11:58:20 -07003591 goto fail2;
Hai Shalomfdcde762020-04-02 11:19:20 -07003592 }
3593 wpa_printf(MSG_DEBUG, "nl80211: NEW_KEY");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003594 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
Hai Shalomc3565922019-10-28 11:58:20 -07003595 if (!msg)
3596 goto fail2;
3597 if (nla_put(key_msg, NL80211_KEY_DATA, key_len, key) ||
3598 nla_put_u32(key_msg, NL80211_KEY_CIPHER, suite))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003599 goto fail;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003600 wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003601
Hai Shalomfdcde762020-04-02 11:19:20 -07003602 if (seq && seq_len) {
3603 if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq))
3604 goto fail;
3605 wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ",
3606 seq, seq_len);
3607 }
Dmitry Shmidt98660862014-03-11 17:26:21 -07003608 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003609
3610 if (addr && !is_broadcast_ether_addr(addr)) {
3611 wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003612 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
3613 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003614
Hai Shalomfdcde762020-04-02 11:19:20 -07003615 if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3616 KEY_FLAG_PAIRWISE_RX ||
3617 (key_flag & KEY_FLAG_PAIRWISE_MASK) ==
3618 KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
3619 if (nla_put_u8(key_msg, NL80211_KEY_MODE,
3620 key_flag == KEY_FLAG_PAIRWISE_RX ?
3621 NL80211_KEY_NO_TX : NL80211_KEY_SET_TX))
3622 goto fail;
3623 } else if ((key_flag & KEY_FLAG_GROUP_MASK) ==
3624 KEY_FLAG_GROUP_RX) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003625 wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
Hai Shalomc3565922019-10-28 11:58:20 -07003626 if (nla_put_u32(key_msg, NL80211_KEY_TYPE,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003627 NL80211_KEYTYPE_GROUP))
3628 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003629 } else if (!(key_flag & KEY_FLAG_PAIRWISE)) {
3630 wpa_printf(MSG_DEBUG,
3631 " key_flag missing PAIRWISE when setting a pairwise key");
3632 ret = -EINVAL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003633 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003634 } else if (alg == WPA_ALG_WEP &&
3635 (key_flag & KEY_FLAG_RX_TX) == KEY_FLAG_RX_TX) {
3636 wpa_printf(MSG_DEBUG, " unicast WEP key");
3637 skip_set_key = 0;
3638 } else {
3639 wpa_printf(MSG_DEBUG, " pairwise key");
3640 }
3641 } else if ((key_flag & KEY_FLAG_PAIRWISE) ||
3642 !(key_flag & KEY_FLAG_GROUP)) {
3643 wpa_printf(MSG_DEBUG,
3644 " invalid key_flag for a broadcast key");
3645 ret = -EINVAL;
3646 goto fail;
3647 } else {
3648 wpa_printf(MSG_DEBUG, " broadcast key");
3649 if (key_flag & KEY_FLAG_DEFAULT)
3650 skip_set_key = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003651 }
Hai Shalomc3565922019-10-28 11:58:20 -07003652 if (nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
3653 nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003654 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003655 nl80211_nlmsg_clear(key_msg);
3656 nlmsg_free(key_msg);
3657 key_msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003658
Hai Shalomfdcde762020-04-02 11:19:20 -07003659 if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
3660 wpa_printf(MSG_DEBUG, "nl80211: VLAN ID %d", vlan_id);
3661 if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
3662 goto fail;
3663 }
3664
Sunil Ravi77d572f2023-01-17 23:58:31 +00003665 if (link_id != -1) {
3666 wpa_printf(MSG_DEBUG, "nl80211: Link ID %d", link_id);
3667 if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id))
3668 goto fail;
3669 }
3670
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003671 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003672 if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
3673 ret = 0;
3674 if (ret)
Hai Shalomfdcde762020-04-02 11:19:20 -07003675 wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003676 ret, strerror(-ret));
3677
3678 /*
Hai Shalomfdcde762020-04-02 11:19:20 -07003679 * If we failed or don't need to set the key as default (below),
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003680 * we're done here.
3681 */
Hai Shalomfdcde762020-04-02 11:19:20 -07003682 if (ret || skip_set_key)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003683 return ret;
Hai Shalomfdcde762020-04-02 11:19:20 -07003684 wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_SET_KEY - default key");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003685
Hai Shalomfdcde762020-04-02 11:19:20 -07003686 ret = -ENOBUFS;
Hai Shalomc3565922019-10-28 11:58:20 -07003687 key_msg = nlmsg_alloc();
3688 if (!key_msg)
Hai Shalomfdcde762020-04-02 11:19:20 -07003689 return ret;
Hai Shalomc3565922019-10-28 11:58:20 -07003690
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003691 msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
Hai Shalomc3565922019-10-28 11:58:20 -07003692 if (!msg)
3693 goto fail2;
3694 if (!key_msg ||
3695 nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003696 nla_put_flag(key_msg, wpa_alg_bip(alg) ?
Hai Shalomfdcde762020-04-02 11:19:20 -07003697 (key_idx == 6 || key_idx == 7 ?
3698 NL80211_KEY_DEFAULT_BEACON :
3699 NL80211_KEY_DEFAULT_MGMT) :
3700 NL80211_KEY_DEFAULT))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003701 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003702 if (addr && is_broadcast_ether_addr(addr)) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003703 struct nlattr *types;
3704
Hai Shalomc3565922019-10-28 11:58:20 -07003705 types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003706 if (!types ||
Hai Shalomc3565922019-10-28 11:58:20 -07003707 nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003708 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003709 nla_nest_end(key_msg, types);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003710 } else if (addr) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07003711 struct nlattr *types;
3712
Hai Shalomc3565922019-10-28 11:58:20 -07003713 types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003714 if (!types ||
Hai Shalomc3565922019-10-28 11:58:20 -07003715 nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003716 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003717 nla_nest_end(key_msg, types);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003718 }
3719
Hai Shalomc3565922019-10-28 11:58:20 -07003720 if (nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
3721 goto fail;
3722 nl80211_nlmsg_clear(key_msg);
3723 nlmsg_free(key_msg);
3724 key_msg = NULL;
3725
Hai Shalomfdcde762020-04-02 11:19:20 -07003726 if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
3727 wpa_printf(MSG_DEBUG, "nl80211: set_key default - VLAN ID %d",
3728 vlan_id);
3729 if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
3730 goto fail;
3731 }
3732
Sunil Ravi77d572f2023-01-17 23:58:31 +00003733 if (link_id != -1) {
3734 wpa_printf(MSG_DEBUG, "nl80211: set_key default - Link ID %d",
3735 link_id);
3736 if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id))
3737 goto fail;
3738 }
3739
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003740 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003741 if (ret)
Hai Shalomfdcde762020-04-02 11:19:20 -07003742 wpa_printf(MSG_DEBUG,
3743 "nl80211: set_key default failed; err=%d %s",
3744 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003745 return ret;
3746
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003747fail:
3748 nl80211_nlmsg_clear(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003749 nlmsg_free(msg);
Hai Shalomc3565922019-10-28 11:58:20 -07003750fail2:
3751 nl80211_nlmsg_clear(key_msg);
3752 nlmsg_free(key_msg);
Hai Shalomfdcde762020-04-02 11:19:20 -07003753 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003754}
3755
3756
3757static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
3758 int key_idx, int defkey,
3759 const u8 *seq, size_t seq_len,
3760 const u8 *key, size_t key_len)
3761{
3762 struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003763 u32 suite;
3764
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003765 if (!key_attr)
3766 return -1;
3767
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003768 suite = wpa_alg_to_cipher_suite(alg, key_len);
3769 if (!suite)
3770 return -1;
3771
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003772 if (defkey && wpa_alg_bip(alg)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003773 if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT))
3774 return -1;
3775 } else if (defkey) {
3776 if (nla_put_flag(msg, NL80211_KEY_DEFAULT))
3777 return -1;
3778 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003779
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003780 if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) ||
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07003781 nla_put_u32(msg, NL80211_KEY_CIPHER, suite) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003782 (seq && seq_len &&
3783 nla_put(msg, NL80211_KEY_SEQ, seq_len, seq)) ||
3784 nla_put(msg, NL80211_KEY_DATA, key_len, key))
3785 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003786
3787 nla_nest_end(msg, key_attr);
3788
3789 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003790}
3791
3792
3793static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
3794 struct nl_msg *msg)
3795{
3796 int i, privacy = 0;
3797 struct nlattr *nl_keys, *nl_key;
3798
3799 for (i = 0; i < 4; i++) {
3800 if (!params->wep_key[i])
3801 continue;
3802 privacy = 1;
3803 break;
3804 }
3805 if (params->wps == WPS_MODE_PRIVACY)
3806 privacy = 1;
3807 if (params->pairwise_suite &&
3808 params->pairwise_suite != WPA_CIPHER_NONE)
3809 privacy = 1;
3810
3811 if (!privacy)
3812 return 0;
3813
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003814 if (nla_put_flag(msg, NL80211_ATTR_PRIVACY))
3815 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003816
3817 nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
3818 if (!nl_keys)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003819 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003820
3821 for (i = 0; i < 4; i++) {
3822 if (!params->wep_key[i])
3823 continue;
3824
3825 nl_key = nla_nest_start(msg, i);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003826 if (!nl_key ||
3827 nla_put(msg, NL80211_KEY_DATA, params->wep_key_len[i],
3828 params->wep_key[i]) ||
3829 nla_put_u32(msg, NL80211_KEY_CIPHER,
3830 params->wep_key_len[i] == 5 ?
Paul Stewart092955c2017-02-06 09:13:09 -08003831 RSN_CIPHER_SUITE_WEP40 :
3832 RSN_CIPHER_SUITE_WEP104) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003833 nla_put_u8(msg, NL80211_KEY_IDX, i) ||
3834 (i == params->wep_tx_keyidx &&
3835 nla_put_flag(msg, NL80211_KEY_DEFAULT)))
3836 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003837
3838 nla_nest_end(msg, nl_key);
3839 }
3840 nla_nest_end(msg, nl_keys);
3841
3842 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003843}
3844
3845
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003846int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
3847 const u8 *addr, int cmd, u16 reason_code,
Hai Shalom74f70d42019-02-11 14:42:39 -08003848 int local_state_change,
Hai Shalomc1a21442022-02-04 13:43:00 -08003849 struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003850{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003851 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003852 struct nl_msg *msg;
3853
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003854 if (!(msg = nl80211_drv_msg(drv, 0, cmd)) ||
3855 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code) ||
3856 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
3857 (local_state_change &&
3858 nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))) {
3859 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003860 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003861 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003862
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003863 ret = send_and_recv(drv->global, bss->nl_connect, msg,
3864 NULL, NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003865 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003866 wpa_dbg(drv->ctx, MSG_DEBUG,
3867 "nl80211: MLME command failed: reason=%u ret=%d (%s)",
3868 reason_code, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003869 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003870 return ret;
3871}
3872
3873
3874static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
Hai Shalom81f62d82019-07-22 12:10:00 -07003875 u16 reason_code,
Hai Shalomc1a21442022-02-04 13:43:00 -08003876 struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003877{
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003878 int ret;
3879
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003880 wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003881 nl80211_mark_disconnected(drv);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08003882 /* Disconnect command doesn't need BSSID - it uses cached value */
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003883 ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
Hai Shalomc1a21442022-02-04 13:43:00 -08003884 reason_code, 0, bss);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003885 /*
3886 * For locally generated disconnect, supplicant already generates a
3887 * DEAUTH event, so ignore the event from NL80211.
3888 */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003889 if (ret == 0)
3890 drv->ignore_next_local_disconnect = send_event_marker(drv);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07003891
3892 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003893}
3894
3895
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003896static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
Hai Shalom81f62d82019-07-22 12:10:00 -07003897 const u8 *addr, u16 reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003898{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003899 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003900 int ret;
Dmitry Shmidt413dde72014-04-11 10:23:22 -07003901
3902 if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
3903 nl80211_mark_disconnected(drv);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003904 return nl80211_leave_ibss(drv, 1);
Dmitry Shmidt413dde72014-04-11 10:23:22 -07003905 }
Hai Shalom74f70d42019-02-11 14:42:39 -08003906 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
Hai Shalomc1a21442022-02-04 13:43:00 -08003907 return wpa_driver_nl80211_disconnect(drv, reason_code, bss);
Hai Shalom74f70d42019-02-11 14:42:39 -08003908 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003909 wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
3910 __func__, MAC2STR(addr), reason_code);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07003911 nl80211_mark_disconnected(drv);
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003912 ret = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
Hai Shalomc1a21442022-02-04 13:43:00 -08003913 reason_code, 0, bss);
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003914 /*
3915 * For locally generated deauthenticate, supplicant already generates a
3916 * DEAUTH event, so ignore the event from NL80211.
3917 */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003918 if (ret == 0)
3919 drv->ignore_next_local_deauth = send_event_marker(drv);
Hai Shalomce48b4a2018-09-05 11:41:35 -07003920
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -07003921 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003922}
3923
3924
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003925static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
3926 struct wpa_driver_auth_params *params)
3927{
3928 int i;
3929
3930 drv->auth_freq = params->freq;
3931 drv->auth_alg = params->auth_alg;
3932 drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
3933 drv->auth_local_state_change = params->local_state_change;
3934 drv->auth_p2p = params->p2p;
3935
3936 if (params->bssid)
3937 os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
3938 else
3939 os_memset(drv->auth_bssid_, 0, ETH_ALEN);
3940
3941 if (params->ssid) {
3942 os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
3943 drv->auth_ssid_len = params->ssid_len;
3944 } else
3945 drv->auth_ssid_len = 0;
3946
3947
3948 os_free(drv->auth_ie);
3949 drv->auth_ie = NULL;
3950 drv->auth_ie_len = 0;
3951 if (params->ie) {
3952 drv->auth_ie = os_malloc(params->ie_len);
3953 if (drv->auth_ie) {
3954 os_memcpy(drv->auth_ie, params->ie, params->ie_len);
3955 drv->auth_ie_len = params->ie_len;
3956 }
3957 }
3958
Sunil Ravi77d572f2023-01-17 23:58:31 +00003959 if (params->mld && params->ap_mld_addr) {
3960 drv->auth_mld = params->mld;
3961 drv->auth_mld_link_id = params->mld_link_id;
3962 os_memcpy(drv->auth_ap_mld_addr, params->ap_mld_addr, ETH_ALEN);
3963 } else {
3964 drv->auth_mld = false;
3965 drv->auth_mld_link_id = -1;
3966 }
3967
Hai Shalom60840252021-02-19 19:02:11 -08003968 os_free(drv->auth_data);
3969 drv->auth_data = NULL;
3970 drv->auth_data_len = 0;
3971 if (params->auth_data) {
3972 drv->auth_data = os_memdup(params->auth_data,
3973 params->auth_data_len);
3974 if (drv->auth_data)
3975 drv->auth_data_len = params->auth_data_len;
3976 }
3977
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003978 for (i = 0; i < 4; i++) {
3979 if (params->wep_key[i] && params->wep_key_len[i] &&
3980 params->wep_key_len[i] <= 16) {
3981 os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
3982 params->wep_key_len[i]);
3983 drv->auth_wep_key_len[i] = params->wep_key_len[i];
3984 } else
3985 drv->auth_wep_key_len[i] = 0;
3986 }
3987}
3988
3989
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003990static void nl80211_unmask_11b_rates(struct i802_bss *bss)
3991{
3992 struct wpa_driver_nl80211_data *drv = bss->drv;
3993
3994 if (is_p2p_net_interface(drv->nlmode) || !drv->disabled_11b_rates)
3995 return;
3996
3997 /*
3998 * Looks like we failed to unmask 11b rates previously. This could
3999 * happen, e.g., if the interface was down at the point in time when a
4000 * P2P group was terminated.
4001 */
4002 wpa_printf(MSG_DEBUG,
4003 "nl80211: Interface %s mode is for non-P2P, but 11b rates were disabled - re-enable them",
4004 bss->ifname);
4005 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
4006}
4007
4008
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004009static enum nl80211_auth_type get_nl_auth_type(int wpa_auth_alg)
4010{
4011 if (wpa_auth_alg & WPA_AUTH_ALG_OPEN)
4012 return NL80211_AUTHTYPE_OPEN_SYSTEM;
4013 if (wpa_auth_alg & WPA_AUTH_ALG_SHARED)
4014 return NL80211_AUTHTYPE_SHARED_KEY;
4015 if (wpa_auth_alg & WPA_AUTH_ALG_LEAP)
4016 return NL80211_AUTHTYPE_NETWORK_EAP;
4017 if (wpa_auth_alg & WPA_AUTH_ALG_FT)
4018 return NL80211_AUTHTYPE_FT;
4019 if (wpa_auth_alg & WPA_AUTH_ALG_SAE)
4020 return NL80211_AUTHTYPE_SAE;
4021 if (wpa_auth_alg & WPA_AUTH_ALG_FILS)
4022 return NL80211_AUTHTYPE_FILS_SK;
4023 if (wpa_auth_alg & WPA_AUTH_ALG_FILS_SK_PFS)
4024 return NL80211_AUTHTYPE_FILS_SK_PFS;
4025
4026 return NL80211_AUTHTYPE_MAX;
4027}
4028
4029
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004030static int wpa_driver_nl80211_authenticate(
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004031 struct i802_bss *bss, struct wpa_driver_auth_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004032{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004033 struct wpa_driver_nl80211_data *drv = bss->drv;
4034 int ret = -1, i;
4035 struct nl_msg *msg;
4036 enum nl80211_auth_type type;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004037 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004038 int count = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004039 int is_retry;
Hai Shalomfdcde762020-04-02 11:19:20 -07004040 struct wpa_driver_set_key_params p;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004041
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004042 nl80211_unmask_11b_rates(bss);
4043
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004044 is_retry = drv->retry_auth;
4045 drv->retry_auth = 0;
Dmitry Shmidt98660862014-03-11 17:26:21 -07004046 drv->ignore_deauth_event = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004047
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004048 nl80211_mark_disconnected(drv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004049 os_memset(drv->auth_bssid, 0, ETH_ALEN);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004050 if (params->bssid)
4051 os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
4052 else
4053 os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004054 /* FIX: IBSS mode */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004055 nlmode = params->p2p ?
4056 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
4057 if (drv->nlmode != nlmode &&
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004058 wpa_driver_nl80211_set_mode(bss, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004059 return -1;
4060
4061retry:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004062 wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
4063 drv->ifindex);
4064
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004065 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_AUTHENTICATE);
4066 if (!msg)
4067 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004068
Hai Shalomfdcde762020-04-02 11:19:20 -07004069 os_memset(&p, 0, sizeof(p));
4070 p.ifname = bss->ifname;
4071 p.alg = WPA_ALG_WEP;
Sunil Ravi77d572f2023-01-17 23:58:31 +00004072 p.link_id = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004073 for (i = 0; i < 4; i++) {
4074 if (!params->wep_key[i])
4075 continue;
Hai Shalomfdcde762020-04-02 11:19:20 -07004076 p.key_idx = i;
4077 p.set_tx = i == params->wep_tx_keyidx;
4078 p.key = params->wep_key[i];
4079 p.key_len = params->wep_key_len[i];
4080 p.key_flag = i == params->wep_tx_keyidx ?
4081 KEY_FLAG_GROUP_RX_TX_DEFAULT :
4082 KEY_FLAG_GROUP_RX_TX;
4083 wpa_driver_nl80211_set_key(bss, &p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004084 if (params->wep_tx_keyidx != i)
4085 continue;
4086 if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004087 params->wep_key[i], params->wep_key_len[i]))
4088 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004089 }
4090
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004091 if (params->bssid) {
4092 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
4093 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004094 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
4095 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004096 }
4097 if (params->freq) {
4098 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004099 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
4100 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004101 }
4102 if (params->ssid) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004103 wpa_printf(MSG_DEBUG, " * SSID=%s",
4104 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004105 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
4106 params->ssid))
4107 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004108 }
4109 wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004110 if (params->ie &&
4111 nla_put(msg, NL80211_ATTR_IE, params->ie_len, params->ie))
4112 goto fail;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004113 if (params->auth_data) {
4114 wpa_hexdump(MSG_DEBUG, " * auth_data", params->auth_data,
4115 params->auth_data_len);
4116 if (nla_put(msg, NL80211_ATTR_SAE_DATA, params->auth_data_len,
4117 params->auth_data))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004118 goto fail;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004119 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004120 type = get_nl_auth_type(params->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004121 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004122 if (type == NL80211_AUTHTYPE_MAX ||
4123 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004124 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004125 if (params->local_state_change) {
4126 wpa_printf(MSG_DEBUG, " * Local state change only");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004127 if (nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))
4128 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004129 }
4130
Sunil Ravi77d572f2023-01-17 23:58:31 +00004131 if (params->mld && params->ap_mld_addr) {
4132 wpa_printf(MSG_DEBUG, " * MLD: link_id=%u, MLD addr=" MACSTR,
4133 params->mld_link_id, MAC2STR(params->ap_mld_addr));
4134
4135 if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID,
4136 params->mld_link_id) ||
4137 nla_put(msg, NL80211_ATTR_MLD_ADDR, ETH_ALEN,
4138 params->ap_mld_addr))
4139 goto fail;
4140 }
4141
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004142 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004143 msg = NULL;
4144 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004145 wpa_dbg(drv->ctx, MSG_DEBUG,
Roshan Pius3a1667e2018-07-03 15:17:14 -07004146 "nl80211: MLME command failed (auth): count=%d ret=%d (%s)",
4147 count, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004148 count++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004149 if ((ret == -EALREADY || ret == -EEXIST) && count == 1 &&
4150 params->bssid && !params->local_state_change) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004151 /*
4152 * mac80211 does not currently accept new
4153 * authentication if we are already authenticated. As a
4154 * workaround, force deauthentication and try again.
4155 */
4156 wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
4157 "after forced deauthentication");
Dmitry Shmidt98660862014-03-11 17:26:21 -07004158 drv->ignore_deauth_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004159 wpa_driver_nl80211_deauthenticate(
4160 bss, params->bssid,
4161 WLAN_REASON_PREV_AUTH_NOT_VALID);
4162 nlmsg_free(msg);
4163 goto retry;
4164 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004165
4166 if (ret == -ENOENT && params->freq && !is_retry) {
4167 /*
4168 * cfg80211 has likely expired the BSS entry even
4169 * though it was previously available in our internal
4170 * BSS table. To recover quickly, start a single
4171 * channel scan on the specified channel.
4172 */
4173 struct wpa_driver_scan_params scan;
4174 int freqs[2];
4175
4176 os_memset(&scan, 0, sizeof(scan));
4177 scan.num_ssids = 1;
4178 if (params->ssid) {
4179 scan.ssids[0].ssid = params->ssid;
4180 scan.ssids[0].ssid_len = params->ssid_len;
4181 }
4182 freqs[0] = params->freq;
4183 freqs[1] = 0;
4184 scan.freqs = freqs;
4185 wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
4186 "channel scan to refresh cfg80211 BSS "
4187 "entry");
4188 ret = wpa_driver_nl80211_scan(bss, &scan);
4189 if (ret == 0) {
4190 nl80211_copy_auth_params(drv, params);
4191 drv->scan_for_auth = 1;
4192 }
4193 } else if (is_retry) {
4194 /*
4195 * Need to indicate this with an event since the return
4196 * value from the retry is not delivered to core code.
4197 */
4198 union wpa_event_data event;
4199 wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
4200 "failed");
4201 os_memset(&event, 0, sizeof(event));
4202 os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
4203 ETH_ALEN);
4204 wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
4205 &event);
4206 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004207 } else {
4208 wpa_printf(MSG_DEBUG,
4209 "nl80211: Authentication request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004210 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004211
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004212fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004213 nlmsg_free(msg);
4214 return ret;
4215}
4216
4217
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004218int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004219{
4220 struct wpa_driver_auth_params params;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08004221 struct i802_bss *bss = drv->first_bss;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004222 u8 ap_mld_addr[ETH_ALEN];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004223 int i;
4224
4225 wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
4226
4227 os_memset(&params, 0, sizeof(params));
4228 params.freq = drv->auth_freq;
4229 params.auth_alg = drv->auth_alg;
4230 params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
4231 params.local_state_change = drv->auth_local_state_change;
4232 params.p2p = drv->auth_p2p;
4233
4234 if (!is_zero_ether_addr(drv->auth_bssid_))
4235 params.bssid = drv->auth_bssid_;
4236
4237 if (drv->auth_ssid_len) {
4238 params.ssid = drv->auth_ssid;
4239 params.ssid_len = drv->auth_ssid_len;
4240 }
4241
4242 params.ie = drv->auth_ie;
4243 params.ie_len = drv->auth_ie_len;
Hai Shalom60840252021-02-19 19:02:11 -08004244 params.auth_data = drv->auth_data;
4245 params.auth_data_len = drv->auth_data_len;
Sunil Ravi77d572f2023-01-17 23:58:31 +00004246 params.mld = drv->auth_mld;
4247 params.mld_link_id = drv->auth_mld_link_id;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004248 if (drv->auth_mld) {
4249 os_memcpy(ap_mld_addr, drv->auth_ap_mld_addr, ETH_ALEN);
4250 params.ap_mld_addr = ap_mld_addr;
4251 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004252
4253 for (i = 0; i < 4; i++) {
4254 if (drv->auth_wep_key_len[i]) {
4255 params.wep_key[i] = drv->auth_wep_key[i];
4256 params.wep_key_len[i] = drv->auth_wep_key_len[i];
4257 }
4258 }
4259
4260 drv->retry_auth = 1;
4261 return wpa_driver_nl80211_authenticate(bss, &params);
4262}
4263
4264
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004265struct i802_link * nl80211_get_link(struct i802_bss *bss, s8 link_id)
4266{
Sunil Ravi99c035e2024-07-12 01:42:03 +00004267 if (link_id < 0 || link_id >= MAX_NUM_MLD_LINKS)
4268 return bss->flink;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004269
Sunil Ravi99c035e2024-07-12 01:42:03 +00004270 if (BIT(link_id) & bss->valid_links)
4271 return &bss->links[link_id];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004272
4273 return bss->flink;
4274}
4275
4276
Sunil Ravic0f5d412024-09-11 22:12:49 +00004277u8 nl80211_get_link_id_from_link(struct i802_bss *bss, struct i802_link *link)
4278{
4279 u8 link_id;
4280
4281 if (link == bss->flink)
4282 return 0;
4283
4284 for_each_link(bss->valid_links, link_id) {
4285 if (&bss->links[link_id] == link)
4286 return link_id;
4287 }
4288
4289 return 0;
4290}
4291
4292
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004293static void nl80211_link_set_freq(struct i802_bss *bss, s8 link_id, int freq)
4294{
4295 struct i802_link *link = nl80211_get_link(bss, link_id);
4296
4297 link->freq = freq;
4298}
4299
4300
4301static int nl80211_get_link_freq(struct i802_bss *bss, const u8 *addr,
4302 bool bss_freq_debug)
4303{
Sunil Ravi99c035e2024-07-12 01:42:03 +00004304 u8 i;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004305
Sunil Ravi99c035e2024-07-12 01:42:03 +00004306 for_each_link(bss->valid_links, i) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004307 if (ether_addr_equal(bss->links[i].addr, addr)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004308 wpa_printf(MSG_DEBUG,
4309 "nl80211: Use link freq=%d for address "
4310 MACSTR,
4311 bss->links[i].freq, MAC2STR(addr));
4312 return bss->links[i].freq;
4313 }
4314 }
4315
4316 if (bss_freq_debug)
4317 wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d",
4318 bss->flink->freq);
4319
4320 return bss->flink->freq;
4321}
4322
4323
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004324static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
4325 size_t data_len, int noack,
4326 unsigned int freq, int no_cck,
4327 int offchanok,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004328 unsigned int wait_time,
4329 const u16 *csa_offs,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004330 size_t csa_offs_len, int no_encrypt,
4331 int link_id)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004332{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004333 struct wpa_driver_nl80211_data *drv = bss->drv;
4334 struct ieee80211_mgmt *mgmt;
Hai Shalomfdcde762020-04-02 11:19:20 -07004335 int encrypt = !no_encrypt;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004336 u16 fc;
Hai Shalomfdcde762020-04-02 11:19:20 -07004337 int use_cookie = 1;
4338 int res;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004339 struct i802_link *link = nl80211_get_link(bss, link_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004340
4341 mgmt = (struct ieee80211_mgmt *) data;
4342 fc = le_to_host16(mgmt->frame_control);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004343 wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR " sa=" MACSTR
4344 " bssid=" MACSTR
Hai Shalomfdcde762020-04-02 11:19:20 -07004345 " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u no_encrypt=%d fc=0x%x (%s) nlmode=%d",
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004346 MAC2STR(mgmt->da), MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid),
4347 noack, freq, no_cck, offchanok, wait_time,
Hai Shalomfdcde762020-04-02 11:19:20 -07004348 no_encrypt, fc, fc2str(fc), drv->nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004349
Dmitry Shmidt34af3062013-07-11 10:46:32 -07004350 if ((is_sta_interface(drv->nlmode) ||
4351 drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004352 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4353 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
4354 /*
4355 * The use of last_mgmt_freq is a bit of a hack,
4356 * but it works due to the single-threaded nature
4357 * of wpa_supplicant.
4358 */
Dmitry Shmidt56052862013-10-04 10:23:25 -07004359 if (freq == 0) {
4360 wpa_printf(MSG_DEBUG, "nl80211: Use last_mgmt_freq=%d",
4361 drv->last_mgmt_freq);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004362 freq = drv->last_mgmt_freq;
Dmitry Shmidt56052862013-10-04 10:23:25 -07004363 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004364 wait_time = 0;
4365 use_cookie = 0;
4366 no_cck = 1;
4367 offchanok = 1;
4368 goto send_frame_cmd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004369 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004370
4371 if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004372 unsigned int link_freq = nl80211_get_link_freq(bss, mgmt->sa,
4373 !freq);
4374
4375 if (!freq)
4376 freq = link_freq;
4377
4378 if (freq == link_freq)
Hai Shalomfdcde762020-04-02 11:19:20 -07004379 wait_time = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004380
Hai Shalomfdcde762020-04-02 11:19:20 -07004381 goto send_frame_cmd;
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07004382 }
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07004383
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004384 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4385 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
4386 /*
4387 * Only one of the authentication frame types is encrypted.
4388 * In order for static WEP encryption to work properly (i.e.,
4389 * to not encrypt the frame), we need to tell mac80211 about
4390 * the frames that must not be encrypted.
4391 */
4392 u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
4393 u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
4394 if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
4395 encrypt = 0;
4396 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004397
Hai Shalom60840252021-02-19 19:02:11 -08004398 if (is_sta_interface(drv->nlmode) &&
Hai Shalomfdcde762020-04-02 11:19:20 -07004399 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4400 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
Hai Shalom60840252021-02-19 19:02:11 -08004401 if (freq == 0 &&
4402 (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
4403 !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
4404 freq = nl80211_get_assoc_freq(drv);
4405 wpa_printf(MSG_DEBUG,
4406 "nl80211: send_mlme - Use assoc_freq=%u for external auth",
4407 freq);
4408 }
4409
4410 /* Allow off channel for PASN authentication */
4411 if (data_len >= IEEE80211_HDRLEN + 2 &&
4412 WPA_GET_LE16(data + IEEE80211_HDRLEN) == WLAN_AUTH_PASN &&
4413 !offchanok) {
4414 wpa_printf(MSG_DEBUG,
4415 "nl80211: send_mlme: allow off channel for PASN");
4416 offchanok = 1;
4417 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004418 }
4419
Hai Shalomc1a21442022-02-04 13:43:00 -08004420#ifdef CONFIG_PASN
4421 if (is_sta_interface(drv->nlmode) &&
4422 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
4423 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_DEAUTH) {
4424 wpa_printf(MSG_DEBUG,
4425 "nl80211: send_mlme: allow Deauthentication frame for PASN");
4426
4427 use_cookie = 0;
4428 offchanok = 1;
4429 goto send_frame_cmd;
4430 }
4431#endif /* CONFIG_PASN */
4432
Hai Shalomfdcde762020-04-02 11:19:20 -07004433 if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
4434 freq = nl80211_get_assoc_freq(drv);
4435 wpa_printf(MSG_DEBUG,
4436 "nl80211: send_mlme - Use assoc_freq=%u for IBSS",
4437 freq);
4438 }
4439 if (freq == 0) {
4440 wpa_printf(MSG_DEBUG, "nl80211: send_mlme - Use bss->freq=%u",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004441 link->freq);
4442 freq = link->freq;
Hai Shalomfdcde762020-04-02 11:19:20 -07004443 }
4444
Hai Shalomc1a21442022-02-04 13:43:00 -08004445 if (drv->use_monitor && is_ap_interface(drv->nlmode)) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004446 wpa_printf(MSG_DEBUG,
4447 "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004448 freq, link->freq);
Hai Shalomfdcde762020-04-02 11:19:20 -07004449 return nl80211_send_monitor(drv, data, data_len, encrypt,
4450 noack);
4451 }
4452
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004453 if ((noack || WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
4454 WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) &&
4455 link_id == NL80211_DRV_LINK_ID_NA)
Hai Shalomfdcde762020-04-02 11:19:20 -07004456 use_cookie = 0;
4457send_frame_cmd:
4458#ifdef CONFIG_TESTING_OPTIONS
4459 if (no_encrypt && !encrypt && !drv->use_monitor) {
4460 wpa_printf(MSG_DEBUG,
4461 "nl80211: Request to send an unencrypted frame - use a monitor interface for this");
4462 if (nl80211_create_monitor_interface(drv) < 0)
4463 return -1;
4464 res = nl80211_send_monitor(drv, data, data_len, encrypt,
4465 noack);
4466 nl80211_remove_monitor_interface(drv);
4467 return res;
4468 }
4469#endif /* CONFIG_TESTING_OPTIONS */
4470
4471 wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame_cmd");
4472 res = nl80211_send_frame_cmd(bss, freq, wait_time, data, data_len,
4473 use_cookie, no_cck, noack, offchanok,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004474 csa_offs, csa_offs_len, link_id);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004475 if (!res)
4476 drv->send_frame_link_id = link_id;
Hai Shalomfdcde762020-04-02 11:19:20 -07004477
4478 return res;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08004479}
4480
4481
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004482static int nl80211_put_basic_rates(struct nl_msg *msg, const int *basic_rates)
4483{
4484 u8 rates[NL80211_MAX_SUPP_RATES];
4485 u8 rates_len = 0;
4486 int i;
4487
4488 if (!basic_rates)
4489 return 0;
4490
4491 for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
4492 rates[rates_len++] = basic_rates[i] / 5;
4493
4494 return nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
4495}
4496
4497
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004498static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
4499 int slot, int ht_opmode, int ap_isolate,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004500 const int *basic_rates, int link_id)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004501{
4502 struct wpa_driver_nl80211_data *drv = bss->drv;
4503 struct nl_msg *msg;
4504
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004505 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_BSS)) ||
4506 (cts >= 0 &&
4507 nla_put_u8(msg, NL80211_ATTR_BSS_CTS_PROT, cts)) ||
4508 (preamble >= 0 &&
4509 nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble)) ||
4510 (slot >= 0 &&
4511 nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot)) ||
4512 (ht_opmode >= 0 &&
4513 nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) ||
4514 (ap_isolate >= 0 &&
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004515 nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)) ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004516 nl80211_put_basic_rates(msg, basic_rates) ||
4517 (link_id != NL80211_DRV_LINK_ID_NA &&
4518 nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id))) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004519 nlmsg_free(msg);
4520 return -ENOBUFS;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004521 }
4522
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004523 return send_and_recv_cmd(drv, msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004524}
4525
4526
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004527static int wpa_driver_nl80211_set_acl(void *priv,
4528 struct hostapd_acl_params *params)
4529{
4530 struct i802_bss *bss = priv;
4531 struct wpa_driver_nl80211_data *drv = bss->drv;
4532 struct nl_msg *msg;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004533 struct nl_msg *acl;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004534 unsigned int i;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004535 int ret;
Hai Shalomc1a21442022-02-04 13:43:00 -08004536 size_t acl_nla_sz, acl_nlmsg_sz, nla_sz, nlmsg_sz;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004537
4538 if (!(drv->capa.max_acl_mac_addrs))
4539 return -ENOTSUP;
4540
4541 if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
4542 return -ENOTSUP;
4543
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004544 wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
4545 params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
4546
Hai Shalomc1a21442022-02-04 13:43:00 -08004547 acl_nla_sz = nla_total_size(ETH_ALEN) * params->num_mac_acl;
4548 acl_nlmsg_sz = nlmsg_total_size(acl_nla_sz);
4549 acl = nlmsg_alloc_size(acl_nlmsg_sz);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004550 if (!acl)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004551 return -ENOMEM;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004552 for (i = 0; i < params->num_mac_acl; i++) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004553 if (nla_put(acl, i + 1, ETH_ALEN, params->mac_acl[i].addr)) {
4554 nlmsg_free(acl);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004555 return -ENOMEM;
4556 }
4557 }
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004558
Hai Shalomc1a21442022-02-04 13:43:00 -08004559 /*
4560 * genetlink message header (Length of user header is 0) +
4561 * u32 attr: NL80211_ATTR_IFINDEX +
4562 * u32 attr: NL80211_ATTR_ACL_POLICY +
4563 * nested acl attr
4564 */
4565 nla_sz = GENL_HDRLEN +
4566 nla_total_size(4) * 2 +
4567 nla_total_size(acl_nla_sz);
4568 nlmsg_sz = nlmsg_total_size(nla_sz);
4569 if (!(msg = nl80211_ifindex_msg_build(drv, nlmsg_alloc_size(nlmsg_sz),
4570 drv->ifindex, 0,
4571 NL80211_CMD_SET_MAC_ACL)) ||
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004572 nla_put_u32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
4573 NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
4574 NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED) ||
4575 nla_put_nested(msg, NL80211_ATTR_MAC_ADDRS, acl)) {
4576 nlmsg_free(msg);
4577 nlmsg_free(acl);
4578 return -ENOMEM;
4579 }
4580 nlmsg_free(acl);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004581
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004582 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004583 if (ret) {
4584 wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
4585 ret, strerror(-ret));
4586 }
4587
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07004588 return ret;
4589}
4590
4591
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004592static int nl80211_put_beacon_int(struct nl_msg *msg, int beacon_int)
4593{
4594 if (beacon_int > 0) {
4595 wpa_printf(MSG_DEBUG, " * beacon_int=%d", beacon_int);
4596 return nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
4597 beacon_int);
4598 }
4599
4600 return 0;
4601}
4602
4603
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004604static int nl80211_put_dtim_period(struct nl_msg *msg, int dtim_period)
4605{
4606 if (dtim_period > 0) {
4607 wpa_printf(MSG_DEBUG, " * dtim_period=%d", dtim_period);
4608 return nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
4609 }
4610
4611 return 0;
4612}
4613
4614
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004615#ifdef CONFIG_MESH
4616static int nl80211_set_mesh_config(void *priv,
4617 struct wpa_driver_mesh_bss_params *params)
4618{
4619 struct i802_bss *bss = priv;
4620 struct wpa_driver_nl80211_data *drv = bss->drv;
4621 struct nl_msg *msg;
4622 int ret;
4623
4624 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MESH_CONFIG);
4625 if (!msg)
4626 return -1;
4627
4628 ret = nl80211_put_mesh_config(msg, params);
4629 if (ret < 0) {
4630 nlmsg_free(msg);
4631 return ret;
4632 }
4633
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004634 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07004635 if (ret) {
4636 wpa_printf(MSG_ERROR,
4637 "nl80211: Mesh config set failed: %d (%s)",
4638 ret, strerror(-ret));
4639 return ret;
4640 }
4641 return 0;
4642}
4643#endif /* CONFIG_MESH */
4644
4645
Hai Shalom60840252021-02-19 19:02:11 -08004646static int nl80211_put_beacon_rate(struct nl_msg *msg, u64 flags, u64 flags2,
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004647 struct wpa_driver_ap_params *params)
4648{
4649 struct nlattr *bands, *band;
4650 struct nl80211_txrate_vht vht_rate;
Hai Shalom60840252021-02-19 19:02:11 -08004651 struct nl80211_txrate_he he_rate;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004652
4653 if (!params->freq ||
4654 (params->beacon_rate == 0 &&
4655 params->rate_type == BEACON_RATE_LEGACY))
4656 return 0;
4657
4658 bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
4659 if (!bands)
4660 return -1;
4661
4662 switch (params->freq->mode) {
4663 case HOSTAPD_MODE_IEEE80211B:
4664 case HOSTAPD_MODE_IEEE80211G:
4665 band = nla_nest_start(msg, NL80211_BAND_2GHZ);
4666 break;
4667 case HOSTAPD_MODE_IEEE80211A:
Hai Shalom60840252021-02-19 19:02:11 -08004668 if (is_6ghz_freq(params->freq->freq))
4669 band = nla_nest_start(msg, NL80211_BAND_6GHZ);
4670 else
4671 band = nla_nest_start(msg, NL80211_BAND_5GHZ);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004672 break;
4673 case HOSTAPD_MODE_IEEE80211AD:
4674 band = nla_nest_start(msg, NL80211_BAND_60GHZ);
4675 break;
4676 default:
4677 return 0;
4678 }
4679
4680 if (!band)
4681 return -1;
4682
4683 os_memset(&vht_rate, 0, sizeof(vht_rate));
Hai Shalom60840252021-02-19 19:02:11 -08004684 os_memset(&he_rate, 0, sizeof(he_rate));
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004685
4686 switch (params->rate_type) {
4687 case BEACON_RATE_LEGACY:
4688 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY)) {
4689 wpa_printf(MSG_INFO,
4690 "nl80211: Driver does not support setting Beacon frame rate (legacy)");
4691 return -1;
4692 }
4693
4694 if (nla_put_u8(msg, NL80211_TXRATE_LEGACY,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004695 (u8) (params->beacon_rate / 5)) ||
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004696 nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
4697 (params->freq->vht_enabled &&
4698 nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4699 &vht_rate)))
4700 return -1;
4701
4702 wpa_printf(MSG_DEBUG, " * beacon_rate = legacy:%u (* 100 kbps)",
4703 params->beacon_rate);
4704 break;
4705 case BEACON_RATE_HT:
4706 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_HT)) {
4707 wpa_printf(MSG_INFO,
4708 "nl80211: Driver does not support setting Beacon frame rate (HT)");
4709 return -1;
4710 }
4711 if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
4712 nla_put_u8(msg, NL80211_TXRATE_HT, params->beacon_rate) ||
4713 (params->freq->vht_enabled &&
4714 nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4715 &vht_rate)))
4716 return -1;
4717 wpa_printf(MSG_DEBUG, " * beacon_rate = HT-MCS %u",
4718 params->beacon_rate);
4719 break;
4720 case BEACON_RATE_VHT:
4721 if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_VHT)) {
4722 wpa_printf(MSG_INFO,
4723 "nl80211: Driver does not support setting Beacon frame rate (VHT)");
4724 return -1;
4725 }
4726 vht_rate.mcs[0] = BIT(params->beacon_rate);
4727 if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL))
4728 return -1;
4729 if (nla_put(msg, NL80211_TXRATE_HT, 0, NULL))
4730 return -1;
4731 if (nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4732 &vht_rate))
4733 return -1;
4734 wpa_printf(MSG_DEBUG, " * beacon_rate = VHT-MCS %u",
4735 params->beacon_rate);
4736 break;
Hai Shalom60840252021-02-19 19:02:11 -08004737 case BEACON_RATE_HE:
4738 if (!(flags2 & WPA_DRIVER_FLAGS2_BEACON_RATE_HE)) {
4739 wpa_printf(MSG_INFO,
4740 "nl80211: Driver does not support setting Beacon frame rate (HE)");
4741 return -1;
4742 }
4743 he_rate.mcs[0] = BIT(params->beacon_rate);
4744 if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
4745 nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
4746 nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
4747 &vht_rate) ||
4748 nla_put(msg, NL80211_TXRATE_HE, sizeof(he_rate), &he_rate))
4749 return -1;
4750 wpa_printf(MSG_DEBUG, " * beacon_rate = HE-MCS %u",
4751 params->beacon_rate);
4752 break;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004753 }
4754
4755 nla_nest_end(msg, band);
4756 nla_nest_end(msg, bands);
4757
4758 return 0;
4759}
4760
4761
4762static int nl80211_set_multicast_to_unicast(struct i802_bss *bss,
4763 int multicast_to_unicast)
4764{
4765 struct wpa_driver_nl80211_data *drv = bss->drv;
4766 struct nl_msg *msg;
4767 int ret;
4768
4769 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_MULTICAST_TO_UNICAST);
4770 if (!msg ||
4771 (multicast_to_unicast &&
4772 nla_put_flag(msg, NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED))) {
4773 wpa_printf(MSG_ERROR,
4774 "nl80211: Failed to build NL80211_CMD_SET_MULTICAST_TO_UNICAST msg for %s",
4775 bss->ifname);
4776 nlmsg_free(msg);
4777 return -ENOBUFS;
4778 }
4779
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004780 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004781
4782 switch (ret) {
4783 case 0:
4784 wpa_printf(MSG_DEBUG,
4785 "nl80211: multicast to unicast %s on interface %s",
4786 multicast_to_unicast ? "enabled" : "disabled",
4787 bss->ifname);
4788 break;
4789 case -EOPNOTSUPP:
4790 if (!multicast_to_unicast)
4791 break;
4792 wpa_printf(MSG_INFO,
4793 "nl80211: multicast to unicast not supported on interface %s",
4794 bss->ifname);
4795 break;
4796 default:
4797 wpa_printf(MSG_ERROR,
4798 "nl80211: %s multicast to unicast failed with %d (%s) on interface %s",
4799 multicast_to_unicast ? "enabling" : "disabling",
4800 ret, strerror(-ret), bss->ifname);
4801 break;
4802 }
4803
4804 return ret;
4805}
4806
4807
Hai Shalom60840252021-02-19 19:02:11 -08004808#ifdef CONFIG_SAE
Sunil Ravi77d572f2023-01-17 23:58:31 +00004809static int nl80211_put_sae_pwe(struct nl_msg *msg, enum sae_pwe pwe)
Hai Shalom60840252021-02-19 19:02:11 -08004810{
4811 u8 sae_pwe;
4812
4813 wpa_printf(MSG_DEBUG, "nl802111: sae_pwe=%d", pwe);
Sunil Ravi77d572f2023-01-17 23:58:31 +00004814 if (pwe == SAE_PWE_HUNT_AND_PECK)
Hai Shalom60840252021-02-19 19:02:11 -08004815 sae_pwe = NL80211_SAE_PWE_HUNT_AND_PECK;
Sunil Ravi77d572f2023-01-17 23:58:31 +00004816 else if (pwe == SAE_PWE_HASH_TO_ELEMENT)
Hai Shalom60840252021-02-19 19:02:11 -08004817 sae_pwe = NL80211_SAE_PWE_HASH_TO_ELEMENT;
Sunil Ravi77d572f2023-01-17 23:58:31 +00004818 else if (pwe == SAE_PWE_BOTH)
Hai Shalom60840252021-02-19 19:02:11 -08004819 sae_pwe = NL80211_SAE_PWE_BOTH;
Sunil Ravi77d572f2023-01-17 23:58:31 +00004820 else if (pwe == SAE_PWE_FORCE_HUNT_AND_PECK)
Hai Shalom60840252021-02-19 19:02:11 -08004821 return 0; /* special test mode */
4822 else
4823 return -1;
4824 if (nla_put_u8(msg, NL80211_ATTR_SAE_PWE, sae_pwe))
4825 return -1;
4826
4827 return 0;
4828}
4829#endif /* CONFIG_SAE */
4830
4831
4832#ifdef CONFIG_FILS
4833static int nl80211_fils_discovery(struct i802_bss *bss, struct nl_msg *msg,
4834 struct wpa_driver_ap_params *params)
4835{
4836 struct nlattr *attr;
4837
4838 if (!bss->drv->fils_discovery) {
4839 wpa_printf(MSG_ERROR,
4840 "nl80211: Driver does not support FILS Discovery frame transmission for %s",
4841 bss->ifname);
4842 return -1;
4843 }
4844
4845 attr = nla_nest_start(msg, NL80211_ATTR_FILS_DISCOVERY);
4846 if (!attr ||
4847 nla_put_u32(msg, NL80211_FILS_DISCOVERY_ATTR_INT_MIN,
4848 params->fd_min_int) ||
4849 nla_put_u32(msg, NL80211_FILS_DISCOVERY_ATTR_INT_MAX,
4850 params->fd_max_int) ||
4851 (params->fd_frame_tmpl &&
4852 nla_put(msg, NL80211_FILS_DISCOVERY_ATTR_TMPL,
4853 params->fd_frame_tmpl_len, params->fd_frame_tmpl)))
4854 return -1;
4855
4856 nla_nest_end(msg, attr);
4857 return 0;
4858}
4859#endif /* CONFIG_FILS */
4860
4861
4862#ifdef CONFIG_IEEE80211AX
Sunil Ravi77d572f2023-01-17 23:58:31 +00004863
Hai Shalom60840252021-02-19 19:02:11 -08004864static int nl80211_unsol_bcast_probe_resp(struct i802_bss *bss,
4865 struct nl_msg *msg,
Sunil Ravi7f769292024-07-23 22:21:32 +00004866 struct unsol_bcast_probe_resp *ubpr)
Hai Shalom60840252021-02-19 19:02:11 -08004867{
4868 struct nlattr *attr;
4869
4870 if (!bss->drv->unsol_bcast_probe_resp) {
4871 wpa_printf(MSG_ERROR,
4872 "nl80211: Driver does not support unsolicited broadcast Probe Response frame transmission for %s",
4873 bss->ifname);
4874 return -1;
4875 }
4876
4877 wpa_printf(MSG_DEBUG,
4878 "nl80211: Unsolicited broadcast Probe Response frame interval: %u",
Sunil Ravi7f769292024-07-23 22:21:32 +00004879 ubpr->unsol_bcast_probe_resp_interval);
Hai Shalom60840252021-02-19 19:02:11 -08004880 attr = nla_nest_start(msg, NL80211_ATTR_UNSOL_BCAST_PROBE_RESP);
4881 if (!attr ||
4882 nla_put_u32(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT,
Sunil Ravi7f769292024-07-23 22:21:32 +00004883 ubpr->unsol_bcast_probe_resp_interval) ||
4884 (ubpr->unsol_bcast_probe_resp_tmpl &&
Hai Shalom60840252021-02-19 19:02:11 -08004885 nla_put(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL,
Sunil Ravi7f769292024-07-23 22:21:32 +00004886 ubpr->unsol_bcast_probe_resp_tmpl_len,
4887 ubpr->unsol_bcast_probe_resp_tmpl)))
Hai Shalom60840252021-02-19 19:02:11 -08004888 return -1;
4889
4890 nla_nest_end(msg, attr);
4891 return 0;
4892}
Sunil Ravi77d572f2023-01-17 23:58:31 +00004893
4894
4895static int nl80211_mbssid(struct nl_msg *msg,
4896 struct wpa_driver_ap_params *params)
4897{
4898 struct nlattr *config, *elems;
4899 int ifidx;
4900
4901 if (!params->mbssid_tx_iface)
4902 return 0;
4903
4904 config = nla_nest_start(msg, NL80211_ATTR_MBSSID_CONFIG);
4905 if (!config ||
4906 nla_put_u8(msg, NL80211_MBSSID_CONFIG_ATTR_INDEX,
4907 params->mbssid_index))
4908 return -1;
4909
4910 if (params->mbssid_tx_iface) {
4911 ifidx = if_nametoindex(params->mbssid_tx_iface);
4912 if (ifidx <= 0 ||
4913 nla_put_u32(msg, NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX,
4914 ifidx))
4915 return -1;
4916 }
4917
4918 if (params->ema && nla_put_flag(msg, NL80211_MBSSID_CONFIG_ATTR_EMA))
4919 return -1;
4920
4921 nla_nest_end(msg, config);
4922
4923 if (params->mbssid_elem_count && params->mbssid_elem_len &&
4924 params->mbssid_elem_offset && *params->mbssid_elem_offset) {
4925 u8 i, **offs = params->mbssid_elem_offset;
4926
4927 elems = nla_nest_start(msg, NL80211_ATTR_MBSSID_ELEMS);
4928 if (!elems)
4929 return -1;
4930
4931 for (i = 0; i < params->mbssid_elem_count - 1; i++) {
4932 if (nla_put(msg, i + 1, offs[i + 1] - offs[i], offs[i]))
4933 return -1;
4934 }
4935
4936 if (nla_put(msg, i + 1,
4937 *offs + params->mbssid_elem_len - offs[i],
4938 offs[i]))
4939 return -1;
4940
4941 nla_nest_end(msg, elems);
4942 }
4943
Sunil Ravi640215c2023-06-28 23:08:09 +00004944 if (!params->ema)
4945 return 0;
4946
4947 if (params->rnr_elem_count && params->rnr_elem_len &&
4948 params->rnr_elem_offset && *params->rnr_elem_offset) {
4949 u8 i, **offs = params->rnr_elem_offset;
4950
4951 elems = nla_nest_start(msg, NL80211_ATTR_EMA_RNR_ELEMS);
4952 if (!elems)
4953 return -1;
4954
4955 for (i = 0; i < params->rnr_elem_count - 1; i++) {
4956 if (nla_put(msg, i + 1, offs[i + 1] - offs[i], offs[i]))
4957 return -1;
4958 }
4959
4960 if (nla_put(msg, i + 1, *offs + params->rnr_elem_len - offs[i],
4961 offs[i]))
4962 return -1;
4963 nla_nest_end(msg, elems);
4964 }
4965
Sunil Ravi77d572f2023-01-17 23:58:31 +00004966 return 0;
4967}
4968
Hai Shalom60840252021-02-19 19:02:11 -08004969#endif /* CONFIG_IEEE80211AX */
4970
4971
Sunil Ravi640215c2023-06-28 23:08:09 +00004972#ifdef CONFIG_DRIVER_NL80211_QCA
4973static void qca_set_allowed_ap_freqs(struct wpa_driver_nl80211_data *drv,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004974 const int *freqs, int num_freqs,
4975 int link_id)
Sunil Ravi640215c2023-06-28 23:08:09 +00004976{
4977 struct nl_msg *msg;
4978 struct nlattr *params, *freqs_list;
4979 int i, ret;
4980
4981 if (!drv->set_wifi_conf_vendor_cmd_avail || !drv->qca_ap_allowed_freqs)
4982 return;
4983
4984 wpa_printf(MSG_DEBUG, "nl80211: Set AP allowed frequency list");
4985
4986 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
4987 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
4988 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
4989 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION) ||
4990 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)))
4991 goto err;
4992
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004993 if (link_id != NL80211_DRV_LINK_ID_NA &&
4994 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID, link_id))
4995 goto err;
4996
Sunil Ravi640215c2023-06-28 23:08:09 +00004997 freqs_list = nla_nest_start(
4998 msg, QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST);
4999 if (!freqs_list)
5000 goto err;
5001
5002 for (i = 0; i < num_freqs; i++) {
5003 if (nla_put_u32(msg, i, freqs[i]))
5004 goto err;
5005 }
5006
5007 nla_nest_end(msg, freqs_list);
5008 nla_nest_end(msg, params);
5009
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005010 ret = send_and_recv_cmd(drv, msg);
Sunil Ravi640215c2023-06-28 23:08:09 +00005011 if (ret)
5012 wpa_printf(MSG_ERROR,
5013 "nl80211: Failed set AP alllowed frequency list: %d (%s)",
5014 ret, strerror(-ret));
5015
5016 return;
5017err:
5018 nlmsg_free(msg);
5019}
5020#endif /* CONFIG_DRIVER_NL80211_QCA */
5021
5022
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005023static int nl80211_put_freq_params(struct nl_msg *msg,
5024 const struct hostapd_freq_params *freq)
5025{
5026 enum hostapd_hw_mode hw_mode;
5027 int is_24ghz;
5028 u8 channel;
5029
5030 wpa_printf(MSG_DEBUG, " * freq=%d", freq->freq);
5031 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
5032 return -ENOBUFS;
5033
5034 wpa_printf(MSG_DEBUG, " * eht_enabled=%d", freq->eht_enabled);
5035 wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled);
5036 wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
5037 wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
5038 wpa_printf(MSG_DEBUG, " * radar_background=%d",
5039 freq->radar_background);
5040
5041 hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
5042 is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
5043 hw_mode == HOSTAPD_MODE_IEEE80211B;
5044
5045 if (freq->vht_enabled ||
5046 ((freq->he_enabled || freq->eht_enabled) && !is_24ghz)) {
5047 enum nl80211_chan_width cw;
5048
5049 wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth);
5050 switch (freq->bandwidth) {
5051 case 20:
5052 cw = NL80211_CHAN_WIDTH_20;
5053 break;
5054 case 40:
5055 cw = NL80211_CHAN_WIDTH_40;
5056 break;
5057 case 80:
5058 if (freq->center_freq2)
5059 cw = NL80211_CHAN_WIDTH_80P80;
5060 else
5061 cw = NL80211_CHAN_WIDTH_80;
5062 break;
5063 case 160:
5064 cw = NL80211_CHAN_WIDTH_160;
5065 break;
5066 case 320:
5067 cw = NL80211_CHAN_WIDTH_320;
5068 break;
5069 default:
5070 return -EINVAL;
5071 }
5072
5073 wpa_printf(MSG_DEBUG, " * channel_width=%d", cw);
5074 wpa_printf(MSG_DEBUG, " * center_freq1=%d",
5075 freq->center_freq1);
5076 wpa_printf(MSG_DEBUG, " * center_freq2=%d",
5077 freq->center_freq2);
5078 if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) ||
5079 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1,
5080 freq->center_freq1) ||
5081 (freq->center_freq2 &&
5082 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2,
5083 freq->center_freq2)))
5084 return -ENOBUFS;
5085 } else if (freq->ht_enabled) {
5086 enum nl80211_channel_type ct;
5087
5088 wpa_printf(MSG_DEBUG, " * sec_channel_offset=%d",
5089 freq->sec_channel_offset);
5090 switch (freq->sec_channel_offset) {
5091 case -1:
5092 ct = NL80211_CHAN_HT40MINUS;
5093 break;
5094 case 1:
5095 ct = NL80211_CHAN_HT40PLUS;
5096 break;
5097 default:
5098 ct = NL80211_CHAN_HT20;
5099 break;
5100 }
5101
5102 wpa_printf(MSG_DEBUG, " * channel_type=%d", ct);
5103 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
5104 return -ENOBUFS;
5105 } else if (freq->edmg.channels && freq->edmg.bw_config) {
5106 wpa_printf(MSG_DEBUG,
5107 " * EDMG configuration: channels=0x%x bw_config=%d",
5108 freq->edmg.channels, freq->edmg.bw_config);
5109 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
5110 freq->edmg.channels) ||
5111 nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
5112 freq->edmg.bw_config))
5113 return -1;
5114 } else {
5115 wpa_printf(MSG_DEBUG, " * channel_type=%d",
5116 NL80211_CHAN_NO_HT);
5117 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
5118 NL80211_CHAN_NO_HT))
5119 return -ENOBUFS;
5120 }
5121 if (freq->radar_background &&
5122 nla_put_flag(msg, NL80211_ATTR_RADAR_BACKGROUND))
5123 return -ENOBUFS;
5124
5125 return 0;
5126}
5127
5128
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005129static int wpa_driver_nl80211_set_ap(void *priv,
5130 struct wpa_driver_ap_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005131{
5132 struct i802_bss *bss = priv;
5133 struct wpa_driver_nl80211_data *drv = bss->drv;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005134 struct i802_link *link = bss->flink;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005135 struct nl_msg *msg;
5136 u8 cmd = NL80211_CMD_NEW_BEACON;
Hai Shalom74f70d42019-02-11 14:42:39 -08005137 int ret = -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005138 int beacon_set;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005139 int num_suites;
Hai Shalomfdcde762020-04-02 11:19:20 -07005140 u32 suites[20], suite;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005141 u32 ver;
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07005142#ifdef CONFIG_MESH
5143 struct wpa_driver_mesh_bss_params mesh_params;
5144#endif /* CONFIG_MESH */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005145
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005146 if (params->mld_ap) {
Sunil Ravi99c035e2024-07-12 01:42:03 +00005147 if (!nl80211_link_valid(bss->valid_links,
5148 params->mld_link_id)) {
5149 wpa_printf(MSG_DEBUG,
5150 "nl80211: Link ID=%u invalid (valid: 0x%04x)",
5151 params->mld_link_id, bss->valid_links);
Sunil Ravi88611412024-06-28 17:34:56 +00005152 return -EINVAL;
5153 }
Sunil Ravi99c035e2024-07-12 01:42:03 +00005154
5155 link = nl80211_get_link(bss, params->mld_link_id);
5156 } else if (bss->valid_links) {
5157 wpa_printf(MSG_DEBUG, "nl80211: MLD configuration expected");
5158 return -EINVAL;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005159 }
5160
5161 beacon_set = params->reenable ? 0 : link->beacon_set;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005162
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005163 wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
5164 beacon_set);
5165 if (beacon_set)
5166 cmd = NL80211_CMD_SET_BEACON;
Paul Stewart092955c2017-02-06 09:13:09 -08005167 else if (!drv->device_ap_sme && !drv->use_monitor &&
5168 !nl80211_get_wiphy_data_ap(bss))
5169 return -ENOBUFS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005170
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005171 wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
5172 params->head, params->head_len);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005173 wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
5174 params->tail, params->tail_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005175 wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005176 wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08005177 wpa_printf(MSG_DEBUG, "nl80211: beacon_rate=%u", params->beacon_rate);
5178 wpa_printf(MSG_DEBUG, "nl80211: rate_type=%d", params->rate_type);
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005179 wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
Hai Shalom74f70d42019-02-11 14:42:39 -08005180 wpa_printf(MSG_DEBUG, "nl80211: ssid=%s",
5181 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005182 if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
5183 nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
5184 params->head) ||
5185 nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
5186 params->tail) ||
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005187 nl80211_put_beacon_int(msg, params->beacon_int) ||
Hai Shalom60840252021-02-19 19:02:11 -08005188 nl80211_put_beacon_rate(msg, drv->capa.flags, drv->capa.flags2,
5189 params) ||
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005190 nl80211_put_dtim_period(msg, params->dtim_period) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005191 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
5192 goto fail;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005193
5194 if (params->mld_ap) {
5195 wpa_printf(MSG_DEBUG, "nl80211: link_id=%u",
5196 params->mld_link_id);
5197
5198 if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID,
Sunil Ravi99c035e2024-07-12 01:42:03 +00005199 params->mld_link_id))
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005200 goto fail;
5201
Sunil Ravi99c035e2024-07-12 01:42:03 +00005202 if (params->freq)
5203 nl80211_link_set_freq(bss, params->mld_link_id,
5204 params->freq->freq);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005205 }
5206
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005207 if (params->proberesp && params->proberesp_len) {
5208 wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
5209 params->proberesp, params->proberesp_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005210 if (nla_put(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
5211 params->proberesp))
5212 goto fail;
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005213 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005214 switch (params->hide_ssid) {
5215 case NO_SSID_HIDING:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005216 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005217 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
5218 NL80211_HIDDEN_SSID_NOT_IN_USE))
5219 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005220 break;
5221 case HIDDEN_SSID_ZERO_LEN:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005222 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005223 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
5224 NL80211_HIDDEN_SSID_ZERO_LEN))
5225 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005226 break;
5227 case HIDDEN_SSID_ZERO_CONTENTS:
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005228 wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005229 if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
5230 NL80211_HIDDEN_SSID_ZERO_CONTENTS))
5231 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005232 break;
5233 }
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005234 wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005235 if (params->privacy &&
5236 nla_put_flag(msg, NL80211_ATTR_PRIVACY))
5237 goto fail;
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005238 wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005239 if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
5240 (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
5241 /* Leave out the attribute */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005242 } else if (params->auth_algs & WPA_AUTH_ALG_SHARED) {
5243 if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
5244 NL80211_AUTHTYPE_SHARED_KEY))
5245 goto fail;
5246 } else {
5247 if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
5248 NL80211_AUTHTYPE_OPEN_SYSTEM))
5249 goto fail;
5250 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005251
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005252 wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005253 ver = 0;
5254 if (params->wpa_version & WPA_PROTO_WPA)
5255 ver |= NL80211_WPA_VERSION_1;
5256 if (params->wpa_version & WPA_PROTO_RSN)
5257 ver |= NL80211_WPA_VERSION_2;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005258 if (ver &&
5259 nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
5260 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005261
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005262 wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
5263 params->key_mgmt_suites);
Hai Shalomfdcde762020-04-02 11:19:20 -07005264 num_suites = wpa_key_mgmt_to_suites(params->key_mgmt_suites,
5265 suites, ARRAY_SIZE(suites));
Sunil Ravi7f769292024-07-23 22:21:32 +00005266 if ((unsigned int) num_suites > drv->capa.max_num_akms)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005267 wpa_printf(MSG_DEBUG,
Sunil Ravi7f769292024-07-23 22:21:32 +00005268 "nl80211: Not enough room for all AKM suites (num_suites=%d > %d)",
5269 num_suites, drv->capa.max_num_akms);
Hai Shalomfdcde762020-04-02 11:19:20 -07005270 else if (num_suites &&
5271 nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
5272 suites))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005273 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005274
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005275 if (wpa_key_mgmt_wpa_psk_no_sae(params->key_mgmt_suites) &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005276 (drv->capa.flags2 & WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK) &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005277 params->psk_len &&
5278 nla_put(msg, NL80211_ATTR_PMK, params->psk_len, params->psk))
5279 goto fail;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005280
5281 if (wpa_key_mgmt_sae(params->key_mgmt_suites) &&
5282 (drv->capa.flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP) &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005283 params->sae_password &&
5284 nla_put(msg, NL80211_ATTR_SAE_PASSWORD,
5285 os_strlen(params->sae_password), params->sae_password))
5286 goto fail;
5287
5288 if (nl80211_put_control_port(drv, msg) < 0)
5289 goto fail;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005290
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005291 if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07005292 (!params->pairwise_ciphers ||
5293 params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005294 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005295 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005296
Sunil Ravia04bd252022-05-02 22:54:18 -07005297 if (drv->device_ap_sme) {
5298 u32 flags = 0;
5299
Sunil Ravi89eba102022-09-13 21:04:37 -07005300 if (params->key_mgmt_suites & (WPA_KEY_MGMT_SAE |
5301 WPA_KEY_MGMT_SAE_EXT_KEY)) {
Sunil Ravia04bd252022-05-02 22:54:18 -07005302 /* Add the previously used flag attribute to support
5303 * older kernel versions and the newer flag bit for
5304 * newer kernels. */
5305 if (nla_put_flag(msg,
5306 NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
5307 goto fail;
5308 flags |= NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;
5309 }
5310
5311 flags |= NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT;
5312
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005313 if (nl80211_attr_supported(drv,
5314 NL80211_ATTR_AP_SETTINGS_FLAGS) &&
5315 nla_put_u32(msg, NL80211_ATTR_AP_SETTINGS_FLAGS, flags))
Sunil Ravia04bd252022-05-02 22:54:18 -07005316 goto fail;
5317 }
Hai Shalom5f92bc92019-04-18 11:54:11 -07005318
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005319 wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
5320 params->pairwise_ciphers);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005321 num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers,
5322 suites, ARRAY_SIZE(suites));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005323 if (num_suites &&
5324 nla_put(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
5325 num_suites * sizeof(u32), suites))
5326 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005327
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005328 wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
5329 params->group_cipher);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005330 suite = wpa_cipher_to_cipher_suite(params->group_cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005331 if (suite &&
5332 nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
5333 goto fail;
5334
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005335 if (params->beacon_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005336 wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
5337 params->beacon_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005338 if (nla_put(msg, NL80211_ATTR_IE,
5339 wpabuf_len(params->beacon_ies),
5340 wpabuf_head(params->beacon_ies)))
5341 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005342 }
5343 if (params->proberesp_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005344 wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
5345 params->proberesp_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005346 if (nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
5347 wpabuf_len(params->proberesp_ies),
5348 wpabuf_head(params->proberesp_ies)))
5349 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005350 }
5351 if (params->assocresp_ies) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005352 wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
5353 params->assocresp_ies);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005354 if (nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
5355 wpabuf_len(params->assocresp_ies),
5356 wpabuf_head(params->assocresp_ies)))
5357 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005358 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005359
Dmitry Shmidt04949592012-07-19 12:16:46 -07005360 if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER) {
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005361 wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
5362 params->ap_max_inactivity);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005363 if (nla_put_u16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
5364 params->ap_max_inactivity))
5365 goto fail;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005366 }
5367
Dmitry Shmidt7f656022015-02-25 14:36:37 -08005368#ifdef CONFIG_P2P
5369 if (params->p2p_go_ctwindow > 0) {
5370 if (drv->p2p_go_ctwindow_supported) {
5371 wpa_printf(MSG_DEBUG, "nl80211: P2P GO ctwindow=%d",
5372 params->p2p_go_ctwindow);
5373 if (nla_put_u8(msg, NL80211_ATTR_P2P_CTWINDOW,
5374 params->p2p_go_ctwindow))
5375 goto fail;
5376 } else {
5377 wpa_printf(MSG_INFO,
5378 "nl80211: Driver does not support CTWindow configuration - ignore this parameter");
5379 }
5380 }
5381#endif /* CONFIG_P2P */
5382
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005383 if (params->pbss) {
5384 wpa_printf(MSG_DEBUG, "nl80211: PBSS");
5385 if (nla_put_flag(msg, NL80211_ATTR_PBSS))
5386 goto fail;
5387 }
5388
Hai Shalom74f70d42019-02-11 14:42:39 -08005389 if (params->ftm_responder) {
5390 struct nlattr *ftm;
5391
5392 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_FTM_RESPONDER)) {
5393 ret = -ENOTSUP;
5394 goto fail;
5395 }
5396
5397 ftm = nla_nest_start(msg, NL80211_ATTR_FTM_RESPONDER);
5398 if (!ftm ||
5399 nla_put_flag(msg, NL80211_FTM_RESP_ATTR_ENABLED) ||
5400 (params->lci &&
5401 nla_put(msg, NL80211_FTM_RESP_ATTR_LCI,
5402 wpabuf_len(params->lci),
5403 wpabuf_head(params->lci))) ||
5404 (params->civic &&
5405 nla_put(msg, NL80211_FTM_RESP_ATTR_CIVICLOC,
5406 wpabuf_len(params->civic),
5407 wpabuf_head(params->civic))))
5408 goto fail;
5409 nla_nest_end(msg, ftm);
5410 }
5411
Sunil Ravi99c035e2024-07-12 01:42:03 +00005412 if (params->freq && nl80211_put_freq_params(msg, params->freq) < 0)
5413 goto fail;
5414
Hai Shalomc3565922019-10-28 11:58:20 -07005415#ifdef CONFIG_IEEE80211AX
Hai Shalom60840252021-02-19 19:02:11 -08005416 if (params->he_spr_ctrl) {
Hai Shalomc3565922019-10-28 11:58:20 -07005417 struct nlattr *spr;
5418
5419 spr = nla_nest_start(msg, NL80211_ATTR_HE_OBSS_PD);
Hai Shalom60840252021-02-19 19:02:11 -08005420 wpa_printf(MSG_DEBUG, "nl80211: he_spr_ctrl=0x%x",
5421 params->he_spr_ctrl);
Hai Shalomc3565922019-10-28 11:58:20 -07005422
Hai Shalomfdcde762020-04-02 11:19:20 -07005423 if (!spr ||
Hai Shalom60840252021-02-19 19:02:11 -08005424 nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_SR_CTRL,
5425 params->he_spr_ctrl) ||
5426 ((params->he_spr_ctrl &
5427 SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) &&
5428 nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET,
5429 params->he_spr_non_srg_obss_pd_max_offset)))
5430 goto fail;
5431
5432 if ((params->he_spr_ctrl &
5433 SPATIAL_REUSE_SRG_INFORMATION_PRESENT) &&
5434 (nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
5435 params->he_spr_srg_obss_pd_min_offset) ||
5436 nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
5437 params->he_spr_srg_obss_pd_max_offset) ||
5438 nla_put(msg, NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP,
5439 sizeof(params->he_spr_bss_color_bitmap),
5440 params->he_spr_bss_color_bitmap) ||
5441 nla_put(msg, NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP,
5442 sizeof(params->he_spr_partial_bssid_bitmap),
5443 params->he_spr_partial_bssid_bitmap)))
Hai Shalomc3565922019-10-28 11:58:20 -07005444 goto fail;
5445
5446 nla_nest_end(msg, spr);
5447 }
Hai Shalomfdcde762020-04-02 11:19:20 -07005448
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005449 if (params->freq && params->freq->he_enabled &&
5450 nl80211_attr_supported(drv, NL80211_ATTR_HE_BSS_COLOR)) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005451 struct nlattr *bss_color;
5452
5453 bss_color = nla_nest_start(msg, NL80211_ATTR_HE_BSS_COLOR);
5454 if (!bss_color ||
5455 (params->he_bss_color_disabled &&
5456 nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_DISABLED)) ||
5457 (params->he_bss_color_partial &&
5458 nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_PARTIAL)) ||
5459 nla_put_u8(msg, NL80211_HE_BSS_COLOR_ATTR_COLOR,
5460 params->he_bss_color))
5461 goto fail;
5462 nla_nest_end(msg, bss_color);
5463 }
5464
5465 if (params->twt_responder) {
5466 wpa_printf(MSG_DEBUG, "nl80211: twt_responder=%d",
5467 params->twt_responder);
5468 if (nla_put_flag(msg, NL80211_ATTR_TWT_RESPONDER))
5469 goto fail;
5470 }
Hai Shalom60840252021-02-19 19:02:11 -08005471
Sunil Ravi7f769292024-07-23 22:21:32 +00005472 if (params->ubpr.unsol_bcast_probe_resp_interval &&
5473 nl80211_unsol_bcast_probe_resp(bss, msg, &params->ubpr) < 0)
Hai Shalom60840252021-02-19 19:02:11 -08005474 goto fail;
Sunil Ravi77d572f2023-01-17 23:58:31 +00005475
5476 if (nl80211_mbssid(msg, params) < 0)
5477 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07005478#endif /* CONFIG_IEEE80211AX */
5479
Hai Shalom60840252021-02-19 19:02:11 -08005480#ifdef CONFIG_SAE
Sunil Ravi89eba102022-09-13 21:04:37 -07005481 if (wpa_key_mgmt_sae(params->key_mgmt_suites) &&
Hai Shalom60840252021-02-19 19:02:11 -08005482 nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
5483 goto fail;
5484#endif /* CONFIG_SAE */
5485
5486#ifdef CONFIG_FILS
5487 if (params->fd_max_int && nl80211_fils_discovery(bss, msg, params) < 0)
5488 goto fail;
5489#endif /* CONFIG_FILS */
5490
Sunil Ravi036cec52023-03-29 11:35:17 -07005491 if (params->punct_bitmap) {
5492 wpa_printf(MSG_DEBUG, "nl80211: Puncturing bitmap=0x%04x",
5493 params->punct_bitmap);
5494 if (nla_put_u32(msg, NL80211_ATTR_PUNCT_BITMAP,
5495 params->punct_bitmap))
5496 goto fail;
5497 }
5498
Sunil Ravi640215c2023-06-28 23:08:09 +00005499#ifdef CONFIG_DRIVER_NL80211_QCA
5500 if (cmd == NL80211_CMD_NEW_BEACON && params->allowed_freqs)
5501 qca_set_allowed_ap_freqs(drv, params->allowed_freqs,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005502 int_array_len(params->allowed_freqs),
5503 params->mld_ap ? params->mld_link_id :
5504 NL80211_DRV_LINK_ID_NA);
Sunil Ravi640215c2023-06-28 23:08:09 +00005505#endif /* CONFIG_DRIVER_NL80211_QCA */
5506
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005507 if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
5508 goto fail;
5509 ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL,
5510 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005511 if (ret) {
5512 wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
5513 ret, strerror(-ret));
5514 } else {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005515 link->beacon_set = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005516 nl80211_set_bss(bss, params->cts_protect, params->preamble,
5517 params->short_slot_time, params->ht_opmode,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005518 params->isolate, params->basic_rates,
5519 params->mld_ap ? params->mld_link_id :
5520 NL80211_DRV_LINK_ID_NA);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08005521 nl80211_set_multicast_to_unicast(bss,
5522 params->multicast_to_unicast);
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005523 if (beacon_set && params->freq &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005524 params->freq->bandwidth != link->bandwidth) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005525 wpa_printf(MSG_DEBUG,
5526 "nl80211: Update BSS %s bandwidth: %d -> %d",
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005527 bss->ifname, link->bandwidth,
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005528 params->freq->bandwidth);
5529 ret = nl80211_set_channel(bss, params->freq, 1);
5530 if (ret) {
5531 wpa_printf(MSG_DEBUG,
5532 "nl80211: Frequency set failed: %d (%s)",
5533 ret, strerror(-ret));
5534 } else {
5535 wpa_printf(MSG_DEBUG,
5536 "nl80211: Frequency set succeeded for ht2040 coex");
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005537 link->bandwidth = params->freq->bandwidth;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005538 }
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005539 } else if (!beacon_set && params->freq) {
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005540 /*
5541 * cfg80211 updates the driver on frequence change in AP
5542 * mode only at the point when beaconing is started, so
5543 * set the initial value here.
5544 */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005545 link->bandwidth = params->freq->bandwidth;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005546 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005547 }
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07005548
5549#ifdef CONFIG_MESH
5550 if (is_mesh_interface(drv->nlmode) && params->ht_opmode != -1) {
5551 os_memset(&mesh_params, 0, sizeof(mesh_params));
5552 mesh_params.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
5553 mesh_params.ht_opmode = params->ht_opmode;
5554 ret = nl80211_set_mesh_config(priv, &mesh_params);
5555 if (ret < 0)
5556 return ret;
5557 }
5558#endif /* CONFIG_MESH */
5559
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005560 return ret;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005561fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005562 nlmsg_free(msg);
Hai Shalom74f70d42019-02-11 14:42:39 -08005563 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005564}
5565
5566
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07005567static int nl80211_set_channel(struct i802_bss *bss,
5568 struct hostapd_freq_params *freq, int set_chan)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005569{
5570 struct wpa_driver_nl80211_data *drv = bss->drv;
5571 struct nl_msg *msg;
5572 int ret;
5573
5574 wpa_printf(MSG_DEBUG,
Sunil Ravia04bd252022-05-02 22:54:18 -07005575 "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, eht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
5576 freq->freq, freq->ht_enabled, freq->vht_enabled,
5577 freq->he_enabled, freq->eht_enabled, freq->bandwidth,
5578 freq->center_freq1, freq->center_freq2);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005579
5580 msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
5581 NL80211_CMD_SET_WIPHY);
5582 if (!msg || nl80211_put_freq_params(msg, freq) < 0) {
5583 nlmsg_free(msg);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08005584 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005585 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005586
Sunil Ravi99c035e2024-07-12 01:42:03 +00005587 if (nl80211_link_valid(bss->valid_links, freq->link_id)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005588 wpa_printf(MSG_DEBUG, "nl80211: Set link_id=%u for freq",
5589 freq->link_id);
5590
5591 if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, freq->link_id)) {
5592 nlmsg_free(msg);
5593 return -ENOBUFS;
5594 }
5595 }
5596
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005597 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005598 if (ret == 0) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005599 nl80211_link_set_freq(bss, freq->link_id, freq->freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005600 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005601 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005602 wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005603 "%d (%s)", freq->freq, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005604 return -1;
5605}
5606
5607
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005608static u32 sta_flags_nl80211(int flags)
5609{
5610 u32 f = 0;
5611
5612 if (flags & WPA_STA_AUTHORIZED)
5613 f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
5614 if (flags & WPA_STA_WMM)
5615 f |= BIT(NL80211_STA_FLAG_WME);
5616 if (flags & WPA_STA_SHORT_PREAMBLE)
5617 f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
5618 if (flags & WPA_STA_MFP)
5619 f |= BIT(NL80211_STA_FLAG_MFP);
5620 if (flags & WPA_STA_TDLS_PEER)
5621 f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005622 if (flags & WPA_STA_AUTHENTICATED)
5623 f |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005624 if (flags & WPA_STA_ASSOCIATED)
5625 f |= BIT(NL80211_STA_FLAG_ASSOCIATED);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005626
5627 return f;
5628}
5629
5630
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005631#ifdef CONFIG_MESH
5632static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
5633{
5634 switch (state) {
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005635 case PLINK_IDLE:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005636 return NL80211_PLINK_LISTEN;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005637 case PLINK_OPN_SNT:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005638 return NL80211_PLINK_OPN_SNT;
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005639 case PLINK_OPN_RCVD:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005640 return NL80211_PLINK_OPN_RCVD;
5641 case PLINK_CNF_RCVD:
5642 return NL80211_PLINK_CNF_RCVD;
5643 case PLINK_ESTAB:
5644 return NL80211_PLINK_ESTAB;
5645 case PLINK_HOLDING:
5646 return NL80211_PLINK_HOLDING;
5647 case PLINK_BLOCKED:
5648 return NL80211_PLINK_BLOCKED;
5649 default:
5650 wpa_printf(MSG_ERROR, "nl80211: Invalid mesh plink state %d",
5651 state);
5652 }
5653 return -1;
5654}
5655#endif /* CONFIG_MESH */
5656
5657
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005658static int wpa_driver_nl80211_sta_add(void *priv,
5659 struct hostapd_sta_add_params *params)
5660{
5661 struct i802_bss *bss = priv;
5662 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005663 struct nl_msg *msg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005664 struct nl80211_sta_flag_update upd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005665 int ret = -ENOBUFS;
Sunil Ravi036cec52023-03-29 11:35:17 -07005666 u8 cmd;
5667 const char *cmd_string;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005668
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005669 if ((params->flags & WPA_STA_TDLS_PEER) &&
5670 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
5671 return -EOPNOTSUPP;
5672
Sunil Ravi036cec52023-03-29 11:35:17 -07005673 if (params->mld_link_sta) {
5674 cmd = params->set ? NL80211_CMD_MODIFY_LINK_STA :
5675 NL80211_CMD_ADD_LINK_STA;
5676 cmd_string = params->set ? "NL80211_CMD_MODIFY_LINK_STA" :
5677 "NL80211_CMD_ADD_LINK_STA";
5678 } else {
5679 cmd = params->set ? NL80211_CMD_SET_STATION :
5680 NL80211_CMD_NEW_STATION;
5681 cmd_string = params->set ? "NL80211_CMD_SET_STATION" :
5682 "NL80211_CMD_NEW_STATION";
5683 }
5684
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005685 wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
Sunil Ravi036cec52023-03-29 11:35:17 -07005686 cmd_string, MAC2STR(params->addr));
5687 msg = nl80211_bss_msg(bss, 0, cmd);
5688 if (!msg)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005689 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005690
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005691 /*
5692 * Set the below properties only in one of the following cases:
5693 * 1. New station is added, already associated.
5694 * 2. Set WPA_STA_TDLS_PEER station.
5695 * 3. Set an already added unassociated station, if driver supports
5696 * full AP client state. (Set these properties after station became
5697 * associated will be rejected by the driver).
5698 */
5699 if (!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
5700 (params->set && FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags) &&
5701 (params->flags & WPA_STA_ASSOCIATED))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005702 wpa_hexdump(MSG_DEBUG, " * supported rates",
5703 params->supp_rates, params->supp_rates_len);
5704 wpa_printf(MSG_DEBUG, " * capability=0x%x",
5705 params->capability);
5706 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_RATES,
5707 params->supp_rates_len, params->supp_rates) ||
5708 nla_put_u16(msg, NL80211_ATTR_STA_CAPABILITY,
5709 params->capability))
5710 goto fail;
5711
5712 if (params->ht_capabilities) {
5713 wpa_hexdump(MSG_DEBUG, " * ht_capabilities",
5714 (u8 *) params->ht_capabilities,
5715 sizeof(*params->ht_capabilities));
5716 if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY,
5717 sizeof(*params->ht_capabilities),
5718 params->ht_capabilities))
5719 goto fail;
5720 }
5721
5722 if (params->vht_capabilities) {
5723 wpa_hexdump(MSG_DEBUG, " * vht_capabilities",
5724 (u8 *) params->vht_capabilities,
5725 sizeof(*params->vht_capabilities));
5726 if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY,
5727 sizeof(*params->vht_capabilities),
5728 params->vht_capabilities))
5729 goto fail;
5730 }
5731
Hai Shalom81f62d82019-07-22 12:10:00 -07005732 if (params->he_capab) {
5733 wpa_hexdump(MSG_DEBUG, " * he_capab",
5734 params->he_capab, params->he_capab_len);
5735 if (nla_put(msg, NL80211_ATTR_HE_CAPABILITY,
5736 params->he_capab_len, params->he_capab))
5737 goto fail;
5738 }
5739
Hai Shalom60840252021-02-19 19:02:11 -08005740 if (params->he_6ghz_capab) {
5741 wpa_hexdump(MSG_DEBUG, " * he_6ghz_capab",
5742 params->he_6ghz_capab,
5743 sizeof(*params->he_6ghz_capab));
5744 if (nla_put(msg, NL80211_ATTR_HE_6GHZ_CAPABILITY,
5745 sizeof(*params->he_6ghz_capab),
5746 params->he_6ghz_capab))
5747 goto fail;
5748 }
5749
Sunil Ravia04bd252022-05-02 22:54:18 -07005750 if (params->eht_capab) {
5751 wpa_hexdump(MSG_DEBUG, " * eht_capab",
5752 params->eht_capab, params->eht_capab_len);
5753 if (nla_put(msg, NL80211_ATTR_EHT_CAPABILITY,
5754 params->eht_capab_len, params->eht_capab))
5755 goto fail;
5756 }
5757
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005758 if (params->ext_capab) {
5759 wpa_hexdump(MSG_DEBUG, " * ext_capab",
5760 params->ext_capab, params->ext_capab_len);
5761 if (nla_put(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
5762 params->ext_capab_len, params->ext_capab))
5763 goto fail;
5764 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -07005765
5766 if (is_ap_interface(drv->nlmode) &&
5767 nla_put_u8(msg, NL80211_ATTR_STA_SUPPORT_P2P_PS,
5768 params->support_p2p_ps ?
5769 NL80211_P2P_PS_SUPPORTED :
5770 NL80211_P2P_PS_UNSUPPORTED))
5771 goto fail;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005772 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005773 if (!params->set) {
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005774 if (params->aid) {
5775 wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005776 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid))
5777 goto fail;
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005778 } else {
5779 /*
5780 * cfg80211 validates that AID is non-zero, so we have
5781 * to make this a non-zero value for the TDLS case where
Hai Shalomc1a21442022-02-04 13:43:00 -08005782 * a stub STA entry is used for now and for a station
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005783 * that is still not associated.
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005784 */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005785 wpa_printf(MSG_DEBUG, " * aid=1 (%s workaround)",
5786 (params->flags & WPA_STA_TDLS_PEER) ?
5787 "TDLS" : "UNASSOC_STA");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005788 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, 1))
5789 goto fail;
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07005790 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005791 wpa_printf(MSG_DEBUG, " * listen_interval=%u",
5792 params->listen_interval);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005793 if (nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
5794 params->listen_interval))
5795 goto fail;
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07005796 } else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
5797 wpa_printf(MSG_DEBUG, " * peer_aid=%u", params->aid);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005798 if (nla_put_u16(msg, NL80211_ATTR_PEER_AID, params->aid))
5799 goto fail;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005800 } else if (FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags) &&
5801 (params->flags & WPA_STA_ASSOCIATED)) {
5802 wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
5803 wpa_printf(MSG_DEBUG, " * listen_interval=%u",
5804 params->listen_interval);
5805 if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid) ||
5806 nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
5807 params->listen_interval))
5808 goto fail;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005809 }
5810
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08005811 if (params->vht_opmode_enabled) {
5812 wpa_printf(MSG_DEBUG, " * opmode=%u", params->vht_opmode);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005813 if (nla_put_u8(msg, NL80211_ATTR_OPMODE_NOTIF,
5814 params->vht_opmode))
5815 goto fail;
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005816 }
5817
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005818 if (params->supp_channels) {
5819 wpa_hexdump(MSG_DEBUG, " * supported channels",
5820 params->supp_channels, params->supp_channels_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005821 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
5822 params->supp_channels_len, params->supp_channels))
5823 goto fail;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005824 }
5825
5826 if (params->supp_oper_classes) {
5827 wpa_hexdump(MSG_DEBUG, " * supported operating classes",
5828 params->supp_oper_classes,
5829 params->supp_oper_classes_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005830 if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
5831 params->supp_oper_classes_len,
5832 params->supp_oper_classes))
5833 goto fail;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08005834 }
5835
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005836 os_memset(&upd, 0, sizeof(upd));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005837 upd.set = sta_flags_nl80211(params->flags);
5838 upd.mask = upd.set | sta_flags_nl80211(params->flags_mask);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005839
5840 /*
5841 * If the driver doesn't support full AP client state, ignore ASSOC/AUTH
5842 * flags, as nl80211 driver moves a new station, by default, into
5843 * associated state.
5844 *
5845 * On the other hand, if the driver supports that feature and the
5846 * station is added in unauthenticated state, set the
5847 * authenticated/associated bits in the mask to prevent moving this
5848 * station to associated state before it is actually associated.
5849 *
5850 * This is irrelevant for mesh mode where the station is added to the
5851 * driver as authenticated already, and ASSOCIATED isn't part of the
5852 * nl80211 API.
5853 */
5854 if (!is_mesh_interface(drv->nlmode)) {
5855 if (!FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) {
5856 wpa_printf(MSG_DEBUG,
5857 "nl80211: Ignore ASSOC/AUTH flags since driver doesn't support full AP client state");
5858 upd.mask &= ~(BIT(NL80211_STA_FLAG_ASSOCIATED) |
5859 BIT(NL80211_STA_FLAG_AUTHENTICATED));
5860 } else if (!params->set &&
5861 !(params->flags & WPA_STA_TDLS_PEER)) {
5862 if (!(params->flags & WPA_STA_AUTHENTICATED))
5863 upd.mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
5864 if (!(params->flags & WPA_STA_ASSOCIATED))
5865 upd.mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
5866 }
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07005867#ifdef CONFIG_MESH
5868 } else {
5869 if (params->plink_state == PLINK_ESTAB && params->peer_aid) {
5870 ret = nla_put_u16(msg, NL80211_ATTR_MESH_PEER_AID,
5871 params->peer_aid);
5872 if (ret)
5873 goto fail;
5874 }
5875#endif /* CONFIG_MESH */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08005876 }
5877
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005878 wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x",
5879 upd.set, upd.mask);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005880 if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
5881 goto fail;
5882
5883#ifdef CONFIG_MESH
5884 if (params->plink_state &&
5885 nla_put_u8(msg, NL80211_ATTR_STA_PLINK_STATE,
5886 sta_plink_state_nl80211(params->plink_state)))
5887 goto fail;
5888#endif /* CONFIG_MESH */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005889
Hai Shalomc3565922019-10-28 11:58:20 -07005890 if ((!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
5891 FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) &&
5892 (params->flags & WPA_STA_WMM)) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005893 struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
5894
Dmitry Shmidtf8623282013-02-20 14:34:59 -08005895 wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005896 if (!wme ||
5897 nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
5898 params->qosinfo & WMM_QOSINFO_STA_AC_MASK) ||
5899 nla_put_u8(msg, NL80211_STA_WME_MAX_SP,
5900 (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
5901 WMM_QOSINFO_STA_SP_MASK))
5902 goto fail;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07005903 nla_nest_end(msg, wme);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005904 }
5905
Sunil Ravi036cec52023-03-29 11:35:17 -07005906 /* In case we are an AP MLD need to always specify the link ID */
5907 if (params->mld_link_id >= 0) {
5908 wpa_printf(MSG_DEBUG, " * mld_link_id=%d",
5909 params->mld_link_id);
5910 if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID,
5911 params->mld_link_id))
5912 goto fail;
5913
5914 /*
5915 * If the link address is specified the station is a non-AP MLD
5916 * and thus need to provide the MLD address as the station
5917 * address, and the non-AP MLD link address as the link address.
5918 */
5919 if (params->mld_link_addr) {
5920 wpa_printf(MSG_DEBUG, " * mld_link_addr=" MACSTR,
5921 MAC2STR(params->mld_link_addr));
5922
5923 if (nla_put(msg, NL80211_ATTR_MLD_ADDR,
5924 ETH_ALEN, params->addr) ||
5925 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
5926 params->mld_link_addr))
5927 goto fail;
5928 } else {
5929 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
5930 params->addr))
5931 goto fail;
5932 }
5933 } else {
5934 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
5935 goto fail;
5936 }
5937
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005938 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005939 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005940 if (ret)
Sunil Ravi036cec52023-03-29 11:35:17 -07005941 wpa_printf(MSG_DEBUG, "nl80211: %s result: %d (%s)",
5942 cmd_string, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005943 if (ret == -EEXIST)
5944 ret = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005945fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005946 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005947 return ret;
5948}
5949
5950
Sunil Ravic0f5d412024-09-11 22:12:49 +00005951static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr,
5952 bool is_bridge)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005953{
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005954 struct wpa_driver_nl80211_data *drv = bss->drv;
Sunil Ravi99c035e2024-07-12 01:42:03 +00005955 struct ndmsg nhdr = {
5956 .ndm_state = NUD_PERMANENT,
Sunil Ravic0f5d412024-09-11 22:12:49 +00005957 .ndm_ifindex = is_bridge ? bss->br_ifindex : bss->ifindex,
Sunil Ravi99c035e2024-07-12 01:42:03 +00005958 .ndm_family = AF_BRIDGE,
Sunil Ravic0f5d412024-09-11 22:12:49 +00005959 .ndm_type = is_bridge ? NTF_SELF : 0,
Sunil Ravi99c035e2024-07-12 01:42:03 +00005960 };
5961 struct nl_msg *msg;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005962 int err;
5963
Sunil Ravi99c035e2024-07-12 01:42:03 +00005964 msg = nlmsg_alloc_simple(RTM_DELNEIGH, NLM_F_CREATE);
5965 if (!msg)
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005966 return;
5967
Sunil Ravi99c035e2024-07-12 01:42:03 +00005968 if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0 ||
5969 nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *) addr) ||
5970 nl_send_auto_complete(drv->rtnl_sk, msg) < 0)
5971 goto errout;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005972
Sunil Ravi99c035e2024-07-12 01:42:03 +00005973 err = nl_wait_for_ack(drv->rtnl_sk);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005974 if (err < 0) {
5975 wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for "
Sunil Ravic0f5d412024-09-11 22:12:49 +00005976 MACSTR " ifindex=%d ifname %s failed: %s",
5977 MAC2STR(addr),
5978 is_bridge ? bss->br_ifindex : bss->ifindex,
5979 is_bridge ? bss->brname : bss->ifname,
5980 nl_geterror(err));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07005981 } else {
Sunil Ravic0f5d412024-09-11 22:12:49 +00005982 wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry "
5983 MACSTR " from %s",
5984 MAC2STR(addr),
5985 is_bridge ? bss->brname : bss->ifname);
5986 }
5987
5988errout:
5989 nlmsg_free(msg);
5990}
5991
5992
5993static void rtnl_neigh_add_fdb_entry(struct i802_bss *bss, const u8 *addr,
5994 bool is_bridge)
5995{
5996 struct wpa_driver_nl80211_data *drv = bss->drv;
5997 struct ndmsg nhdr = {
5998 .ndm_state = NUD_PERMANENT,
5999 .ndm_ifindex = is_bridge ? bss->br_ifindex : bss->ifindex,
6000 .ndm_family = AF_BRIDGE,
6001 /* TODO: remove this check if this flag needs to be used,
6002 * for other interfaces type.
6003 */
6004 .ndm_flags = is_bridge ? NTF_SELF : 0,
6005 };
6006 struct nl_msg *msg;
6007 int err;
6008
6009 msg = nlmsg_alloc_simple(RTM_NEWNEIGH, NLM_F_CREATE);
6010 if (!msg)
6011 return;
6012
6013 if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0 ||
6014 nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *) addr) ||
6015 nl_send_auto_complete(drv->rtnl_sk, msg) < 0)
6016 goto errout;
6017
6018 err = nl_wait_for_ack(drv->rtnl_sk);
6019 if (err < 0) {
6020 wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry addition for "
6021 MACSTR " ifindex=%d ifname %s failed: %s",
6022 MAC2STR(addr),
6023 is_bridge ? bss->br_ifindex : bss->ifindex,
6024 is_bridge ? bss->brname : bss->ifname,
6025 nl_geterror(err));
6026 } else {
6027 wpa_printf(MSG_DEBUG, "nl80211: added bridge FDB entry " MACSTR
6028 " to %s",
6029 MAC2STR(addr),
6030 is_bridge ? bss->brname : bss->ifname);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07006031 }
6032
Sunil Ravi99c035e2024-07-12 01:42:03 +00006033errout:
6034 nlmsg_free(msg);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07006035}
6036
6037
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006038static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
6039 int deauth, u16 reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006040{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006041 struct wpa_driver_nl80211_data *drv = bss->drv;
6042 struct nl_msg *msg;
6043 int ret;
6044
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006045 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION)) ||
6046 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
6047 (deauth == 0 &&
6048 nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
6049 WLAN_FC_STYPE_DISASSOC)) ||
6050 (deauth == 1 &&
6051 nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
6052 WLAN_FC_STYPE_DEAUTH)) ||
6053 (reason_code &&
6054 nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code))) {
6055 nlmsg_free(msg);
6056 return -ENOBUFS;
6057 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006058
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006059 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07006060 wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
6061 " --> %d (%s)",
6062 bss->ifname, MAC2STR(addr), ret, strerror(-ret));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07006063
6064 if (drv->rtnl_sk)
Sunil Ravic0f5d412024-09-11 22:12:49 +00006065 rtnl_neigh_delete_fdb_entry(bss, addr, false);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07006066
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006067 if (ret == -ENOENT)
6068 return 0;
6069 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006070}
6071
6072
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006073void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006074{
6075 struct nl_msg *msg;
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07006076 struct wpa_driver_nl80211_data *drv2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006077
6078 wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
6079
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006080 /* stop listening for EAPOL on this interface */
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07006081 dl_list_for_each(drv2, &drv->global->interfaces,
6082 struct wpa_driver_nl80211_data, list)
Dmitry Shmidt9c175262016-03-03 10:20:07 -08006083 {
6084 del_ifidx(drv2, ifidx, IFIDX_ANY);
6085 /* Remove all bridges learned for this iface */
6086 del_ifidx(drv2, IFIDX_ANY, ifidx);
6087 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006088
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006089 msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006090 if (send_and_recv_cmd(drv, msg) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006091 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006092 wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
6093}
6094
6095
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07006096const char * nl80211_iftype_str(enum nl80211_iftype mode)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006097{
6098 switch (mode) {
6099 case NL80211_IFTYPE_ADHOC:
6100 return "ADHOC";
6101 case NL80211_IFTYPE_STATION:
6102 return "STATION";
6103 case NL80211_IFTYPE_AP:
6104 return "AP";
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07006105 case NL80211_IFTYPE_AP_VLAN:
6106 return "AP_VLAN";
6107 case NL80211_IFTYPE_WDS:
6108 return "WDS";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006109 case NL80211_IFTYPE_MONITOR:
6110 return "MONITOR";
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07006111 case NL80211_IFTYPE_MESH_POINT:
6112 return "MESH_POINT";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006113 case NL80211_IFTYPE_P2P_CLIENT:
6114 return "P2P_CLIENT";
6115 case NL80211_IFTYPE_P2P_GO:
6116 return "P2P_GO";
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006117 case NL80211_IFTYPE_P2P_DEVICE:
6118 return "P2P_DEVICE";
Hai Shalom4fbc08f2020-05-18 12:37:00 -07006119 case NL80211_IFTYPE_OCB:
6120 return "OCB";
6121 case NL80211_IFTYPE_NAN:
6122 return "NAN";
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006123 default:
6124 return "unknown";
6125 }
6126}
6127
6128
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006129static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
6130 const char *ifname,
6131 enum nl80211_iftype iftype,
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006132 const u8 *addr, int wds,
6133 int (*handler)(struct nl_msg *, void *),
6134 void *arg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006135{
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07006136 struct nl_msg *msg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006137 int ifidx;
6138 int ret = -ENOBUFS;
6139
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006140 wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
6141 iftype, nl80211_iftype_str(iftype));
6142
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006143 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_NEW_INTERFACE);
6144 if (!msg ||
6145 nla_put_string(msg, NL80211_ATTR_IFNAME, ifname) ||
6146 nla_put_u32(msg, NL80211_ATTR_IFTYPE, iftype))
6147 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006148
6149 if (iftype == NL80211_IFTYPE_MONITOR) {
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07006150 struct nlattr *flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006151
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07006152 flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006153 if (!flags ||
6154 nla_put_flag(msg, NL80211_MNTR_FLAG_COOK_FRAMES))
6155 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006156
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07006157 nla_nest_end(msg, flags);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006158 } else if (wds) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006159 if (nla_put_u8(msg, NL80211_ATTR_4ADDR, wds))
6160 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006161 }
6162
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07006163 /*
6164 * Tell cfg80211 that the interface belongs to the socket that created
6165 * it, and the interface should be deleted when the socket is closed.
6166 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006167 if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
6168 goto fail;
Dmitry Shmidtb58836e2014-04-29 14:35:56 -07006169
Hai Shalom60840252021-02-19 19:02:11 -08006170 if ((addr && iftype == NL80211_IFTYPE_P2P_DEVICE) &&
6171 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
6172 goto fail;
6173
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006174 ret = send_and_recv_resp(drv, msg, handler, arg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006175 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006176 if (ret) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006177 fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006178 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006179 wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
6180 ifname, ret, strerror(-ret));
6181 return ret;
6182 }
6183
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006184 if (iftype == NL80211_IFTYPE_P2P_DEVICE)
6185 return 0;
6186
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006187 ifidx = if_nametoindex(ifname);
6188 wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
6189 ifname, ifidx);
6190
6191 if (ifidx <= 0)
6192 return -1;
6193
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07006194 /*
6195 * Some virtual interfaces need to process EAPOL packets and events on
6196 * the parent interface. This is used mainly with hostapd.
6197 */
6198 if (drv->hostapd ||
6199 iftype == NL80211_IFTYPE_AP_VLAN ||
6200 iftype == NL80211_IFTYPE_WDS ||
6201 iftype == NL80211_IFTYPE_MONITOR) {
6202 /* start listening for EAPOL on this interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08006203 add_ifidx(drv, ifidx, IFIDX_ANY);
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07006204 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006205
6206 if (addr && iftype != NL80211_IFTYPE_MONITOR &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006207 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006208 nl80211_remove_iface(drv, ifidx);
6209 return -1;
6210 }
6211
6212 return ifidx;
6213}
6214
6215
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006216int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
6217 const char *ifname, enum nl80211_iftype iftype,
6218 const u8 *addr, int wds,
6219 int (*handler)(struct nl_msg *, void *),
6220 void *arg, int use_existing)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006221{
6222 int ret;
6223
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006224 ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
6225 arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006226
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006227 /* if error occurred and interface exists already */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006228 if (ret == -ENFILE && if_nametoindex(ifname)) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006229 if (use_existing) {
6230 wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s",
6231 ifname);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07006232 if (addr && iftype != NL80211_IFTYPE_MONITOR &&
6233 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
6234 addr) < 0 &&
6235 (linux_set_iface_flags(drv->global->ioctl_sock,
6236 ifname, 0) < 0 ||
6237 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
6238 addr) < 0 ||
6239 linux_set_iface_flags(drv->global->ioctl_sock,
6240 ifname, 1) < 0))
6241 return -1;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006242 return -ENFILE;
6243 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006244 wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
6245
6246 /* Try to remove the interface that was already there. */
6247 nl80211_remove_iface(drv, if_nametoindex(ifname));
6248
6249 /* Try to create the interface again */
6250 ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
Dmitry Shmidt34af3062013-07-11 10:46:32 -07006251 wds, handler, arg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006252 }
6253
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006254 if (ret >= 0 && is_p2p_net_interface(iftype)) {
6255 wpa_printf(MSG_DEBUG,
6256 "nl80211: Interface %s created for P2P - disable 11b rates",
6257 ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006258 nl80211_disable_11b_rates(drv, ret, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006259 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006260
6261 return ret;
6262}
6263
6264
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006265static int nl80211_setup_ap(struct i802_bss *bss)
6266{
6267 struct wpa_driver_nl80211_data *drv = bss->drv;
6268
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006269 wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d use_monitor=%d",
6270 bss->ifname, drv->device_ap_sme, drv->use_monitor);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006271
6272 /*
6273 * Disable Probe Request reporting unless we need it in this way for
6274 * devices that include the AP SME, in the other case (unless using
6275 * monitor iface) we'll get it through the nl_mgmt socket instead.
6276 */
6277 if (!drv->device_ap_sme)
6278 wpa_driver_nl80211_probe_req_report(bss, 0);
6279
6280 if (!drv->device_ap_sme && !drv->use_monitor)
6281 if (nl80211_mgmt_subscribe_ap(bss))
6282 return -1;
6283
6284 if (drv->device_ap_sme && !drv->use_monitor)
6285 if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
Dmitry Shmidt849734c2016-05-27 09:59:01 -07006286 wpa_printf(MSG_DEBUG,
6287 "nl80211: Failed to subscribe for mgmt frames from SME driver - trying to run without it");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006288
6289 if (!drv->device_ap_sme && drv->use_monitor &&
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07006290 nl80211_create_monitor_interface(drv) &&
6291 !drv->device_ap_sme)
Dmitry Shmidt04949592012-07-19 12:16:46 -07006292 return -1;
6293
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006294 if (drv->device_ap_sme &&
6295 wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
6296 wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
6297 "Probe Request frame reporting in AP mode");
6298 /* Try to survive without this */
6299 }
6300
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006301 return 0;
6302}
6303
6304
6305static void nl80211_teardown_ap(struct i802_bss *bss)
6306{
6307 struct wpa_driver_nl80211_data *drv = bss->drv;
6308
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006309 wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d use_monitor=%d",
6310 bss->ifname, drv->device_ap_sme, drv->use_monitor);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006311 if (drv->device_ap_sme) {
6312 wpa_driver_nl80211_probe_req_report(bss, 0);
6313 if (!drv->use_monitor)
6314 nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
6315 } else if (drv->use_monitor)
6316 nl80211_remove_monitor_interface(drv);
6317 else
6318 nl80211_mgmt_unsubscribe(bss, "AP teardown");
6319
Paul Stewart092955c2017-02-06 09:13:09 -08006320 nl80211_put_wiphy_data_ap(bss);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006321 if (bss->flink)
6322 bss->flink->beacon_set = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006323}
6324
6325
Hai Shalomfdcde762020-04-02 11:19:20 -07006326static int nl80211_tx_control_port(void *priv, const u8 *dest,
6327 u16 proto, const u8 *buf, size_t len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006328 int no_encrypt, int link_id)
Hai Shalomfdcde762020-04-02 11:19:20 -07006329{
Hai Shalom899fcc72020-10-19 14:38:18 -07006330 struct nl80211_ack_ext_arg ext_arg;
Hai Shalomfdcde762020-04-02 11:19:20 -07006331 struct i802_bss *bss = priv;
6332 struct nl_msg *msg;
Hai Shalom899fcc72020-10-19 14:38:18 -07006333 u64 cookie = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07006334 int ret;
6335
6336 wpa_printf(MSG_DEBUG,
6337 "nl80211: Send over control port dest=" MACSTR
6338 " proto=0x%04x len=%u no_encrypt=%d",
6339 MAC2STR(dest), proto, (unsigned int) len, no_encrypt);
6340
6341 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CONTROL_PORT_FRAME);
6342 if (!msg ||
6343 nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
6344 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dest) ||
6345 nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
6346 (no_encrypt &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006347 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)) ||
6348 (link_id != NL80211_DRV_LINK_ID_NA &&
6349 nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id))) {
Hai Shalomfdcde762020-04-02 11:19:20 -07006350 nlmsg_free(msg);
6351 return -ENOBUFS;
6352 }
6353
Hai Shalom899fcc72020-10-19 14:38:18 -07006354 os_memset(&ext_arg, 0, sizeof(struct nl80211_ack_ext_arg));
6355 ext_arg.ext_data = &cookie;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006356 ret = send_and_recv(bss->drv->global, bss->drv->global->nl, msg,
6357 NULL, NULL, ack_handler_cookie, &ext_arg, NULL);
Hai Shalom899fcc72020-10-19 14:38:18 -07006358 if (ret) {
Hai Shalomfdcde762020-04-02 11:19:20 -07006359 wpa_printf(MSG_DEBUG,
6360 "nl80211: tx_control_port failed: ret=%d (%s)",
6361 ret, strerror(-ret));
Hai Shalom899fcc72020-10-19 14:38:18 -07006362 } else {
6363 struct wpa_driver_nl80211_data *drv = bss->drv;
6364
6365 wpa_printf(MSG_DEBUG,
6366 "nl80211: tx_control_port cookie=0x%llx",
6367 (long long unsigned int) cookie);
6368 drv->eapol_tx_cookie = cookie;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006369 drv->eapol_tx_link_id = link_id;
Hai Shalom899fcc72020-10-19 14:38:18 -07006370 }
Hai Shalomfdcde762020-04-02 11:19:20 -07006371
6372 return ret;
6373}
6374
6375
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006376static int nl80211_send_eapol_data(struct i802_bss *bss,
6377 const u8 *addr, const u8 *data,
6378 size_t data_len)
6379{
6380 struct sockaddr_ll ll;
6381 int ret;
6382
6383 if (bss->drv->eapol_tx_sock < 0) {
6384 wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
6385 return -1;
6386 }
6387
6388 os_memset(&ll, 0, sizeof(ll));
6389 ll.sll_family = AF_PACKET;
6390 ll.sll_ifindex = bss->ifindex;
6391 ll.sll_protocol = htons(ETH_P_PAE);
6392 ll.sll_halen = ETH_ALEN;
6393 os_memcpy(ll.sll_addr, addr, ETH_ALEN);
6394 ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
6395 (struct sockaddr *) &ll, sizeof(ll));
6396 if (ret < 0)
6397 wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
6398 strerror(errno));
6399
6400 return ret;
6401}
6402
6403
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006404static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
6405
6406static int wpa_driver_nl80211_hapd_send_eapol(
6407 void *priv, const u8 *addr, const u8 *data,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006408 size_t data_len, int encrypt, const u8 *own_addr, u32 flags,
6409 int link_id)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006410{
6411 struct i802_bss *bss = priv;
6412 struct wpa_driver_nl80211_data *drv = bss->drv;
6413 struct ieee80211_hdr *hdr;
6414 size_t len;
6415 u8 *pos;
6416 int res;
6417 int qos = flags & WPA_STA_WMM;
Dmitry Shmidt641185e2013-11-06 15:17:13 -08006418
Hai Shalomb755a2a2020-04-23 21:49:02 -07006419 /* For now, disable EAPOL TX over control port in AP mode by default
6420 * since it does not provide TX status notifications. */
6421 if (drv->control_port_ap &&
6422 (drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT))
Hai Shalomfdcde762020-04-02 11:19:20 -07006423 return nl80211_tx_control_port(bss, addr, ETH_P_EAPOL,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006424 data, data_len, !encrypt,
6425 link_id);
Hai Shalomfdcde762020-04-02 11:19:20 -07006426
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006427 if (drv->device_ap_sme || !drv->use_monitor)
6428 return nl80211_send_eapol_data(bss, addr, data, data_len);
6429
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006430 len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
6431 data_len;
6432 hdr = os_zalloc(len);
6433 if (hdr == NULL) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07006434 wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)",
6435 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006436 return -1;
6437 }
6438
6439 hdr->frame_control =
6440 IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
6441 hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
6442 if (encrypt)
6443 hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
6444 if (qos) {
6445 hdr->frame_control |=
6446 host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
6447 }
6448
6449 memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
6450 memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
6451 memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
6452 pos = (u8 *) (hdr + 1);
6453
6454 if (qos) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006455 /* Set highest priority in QoS header */
6456 pos[0] = 7;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006457 pos[1] = 0;
6458 pos += 2;
6459 }
6460
6461 memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
6462 pos += sizeof(rfc1042_header);
6463 WPA_PUT_BE16(pos, ETH_P_PAE);
6464 pos += 2;
6465 memcpy(pos, data, data_len);
6466
Hai Shalomfdcde762020-04-02 11:19:20 -07006467 res = nl80211_send_monitor(drv, hdr, len, encrypt, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006468 if (res < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07006469 wpa_printf(MSG_ERROR,
6470 "hapd_send_eapol - packet len: %lu - failed",
6471 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006472 }
6473 os_free(hdr);
6474
6475 return res;
6476}
6477
6478
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006479static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006480 unsigned int total_flags,
6481 unsigned int flags_or,
6482 unsigned int flags_and)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006483{
6484 struct i802_bss *bss = priv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07006485 struct nl_msg *msg;
6486 struct nlattr *flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006487 struct nl80211_sta_flag_update upd;
6488
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07006489 wpa_printf(MSG_DEBUG, "nl80211: Set STA flags - ifname=%s addr=" MACSTR
6490 " total_flags=0x%x flags_or=0x%x flags_and=0x%x authorized=%d",
6491 bss->ifname, MAC2STR(addr), total_flags, flags_or, flags_and,
6492 !!(total_flags & WPA_STA_AUTHORIZED));
6493
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006494 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
6495 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
6496 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006497
6498 /*
6499 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
6500 * can be removed eventually.
6501 */
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07006502 flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006503 if (!flags ||
6504 ((total_flags & WPA_STA_AUTHORIZED) &&
6505 nla_put_flag(msg, NL80211_STA_FLAG_AUTHORIZED)) ||
6506 ((total_flags & WPA_STA_WMM) &&
6507 nla_put_flag(msg, NL80211_STA_FLAG_WME)) ||
6508 ((total_flags & WPA_STA_SHORT_PREAMBLE) &&
6509 nla_put_flag(msg, NL80211_STA_FLAG_SHORT_PREAMBLE)) ||
6510 ((total_flags & WPA_STA_MFP) &&
6511 nla_put_flag(msg, NL80211_STA_FLAG_MFP)) ||
6512 ((total_flags & WPA_STA_TDLS_PEER) &&
6513 nla_put_flag(msg, NL80211_STA_FLAG_TDLS_PEER)))
6514 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006515
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07006516 nla_nest_end(msg, flags);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006517
6518 os_memset(&upd, 0, sizeof(upd));
6519 upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
6520 upd.set = sta_flags_nl80211(flags_or);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006521 if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
6522 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006523
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006524 return send_and_recv_cmd(bss->drv, msg);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006525fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006526 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006527 return -ENOBUFS;
6528}
6529
6530
Hai Shalom81f62d82019-07-22 12:10:00 -07006531static int driver_nl80211_sta_set_airtime_weight(void *priv, const u8 *addr,
6532 unsigned int weight)
6533{
6534 struct i802_bss *bss = priv;
6535 struct nl_msg *msg;
Hai Shalomc1a21442022-02-04 13:43:00 -08006536 int ret;
Hai Shalom81f62d82019-07-22 12:10:00 -07006537
6538 wpa_printf(MSG_DEBUG,
6539 "nl80211: Set STA airtime weight - ifname=%s addr=" MACSTR
6540 " weight=%u", bss->ifname, MAC2STR(addr), weight);
6541
6542 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
6543 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
6544 nla_put_u16(msg, NL80211_ATTR_AIRTIME_WEIGHT, weight))
6545 goto fail;
6546
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006547 ret = send_and_recv_cmd(bss->drv, msg);
Hai Shalomc1a21442022-02-04 13:43:00 -08006548 if (ret) {
6549 wpa_printf(MSG_DEBUG,
6550 "nl80211: SET_STATION[AIRTIME_WEIGHT] failed: ret=%d (%s)",
6551 ret, strerror(-ret));
6552 }
6553 return ret;
Hai Shalom81f62d82019-07-22 12:10:00 -07006554fail:
6555 nlmsg_free(msg);
6556 return -ENOBUFS;
6557}
6558
6559
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006560static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
6561 struct wpa_driver_associate_params *params)
6562{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006563 enum nl80211_iftype nlmode, old_mode;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006564
6565 if (params->p2p) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006566 wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
6567 "group (GO)");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006568 nlmode = NL80211_IFTYPE_P2P_GO;
6569 } else
6570 nlmode = NL80211_IFTYPE_AP;
6571
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006572 old_mode = drv->nlmode;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006573 if (wpa_driver_nl80211_set_mode(drv->first_bss, nlmode)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006574 nl80211_remove_monitor_interface(drv);
6575 return -1;
6576 }
6577
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08006578 if (params->freq.freq &&
6579 nl80211_set_channel(drv->first_bss, &params->freq, 0)) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006580 if (old_mode != nlmode)
Dmitry Shmidtcce06662013-11-04 18:44:24 -08006581 wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006582 nl80211_remove_monitor_interface(drv);
6583 return -1;
6584 }
6585
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006586 return 0;
6587}
6588
6589
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006590static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
6591 int reset_mode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006592{
6593 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006594 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006595
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006596 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006597 ret = send_and_recv(drv->global, drv->first_bss->nl_connect, msg, NULL,
6598 NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006599 if (ret) {
6600 wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
6601 "(%s)", ret, strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006602 } else {
6603 wpa_printf(MSG_DEBUG,
6604 "nl80211: Leave IBSS request sent successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006605 }
6606
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006607 if (reset_mode &&
6608 wpa_driver_nl80211_set_mode(drv->first_bss,
Dmitry Shmidt56052862013-10-04 10:23:25 -07006609 NL80211_IFTYPE_STATION)) {
6610 wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
6611 "station mode");
6612 }
6613
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006614 return ret;
6615}
6616
6617
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006618static int nl80211_ht_vht_overrides(struct nl_msg *msg,
6619 struct wpa_driver_associate_params *params)
6620{
6621 if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
6622 return -1;
6623
6624 if (params->htcaps && params->htcaps_mask) {
6625 int sz = sizeof(struct ieee80211_ht_capabilities);
6626 wpa_hexdump(MSG_DEBUG, " * htcaps", params->htcaps, sz);
6627 wpa_hexdump(MSG_DEBUG, " * htcaps_mask",
6628 params->htcaps_mask, sz);
6629 if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
6630 params->htcaps) ||
6631 nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
6632 params->htcaps_mask))
6633 return -1;
6634 }
6635
6636#ifdef CONFIG_VHT_OVERRIDES
6637 if (params->disable_vht) {
6638 wpa_printf(MSG_DEBUG, " * VHT disabled");
6639 if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
6640 return -1;
6641 }
6642
6643 if (params->vhtcaps && params->vhtcaps_mask) {
6644 int sz = sizeof(struct ieee80211_vht_capabilities);
6645 wpa_hexdump(MSG_DEBUG, " * vhtcaps", params->vhtcaps, sz);
6646 wpa_hexdump(MSG_DEBUG, " * vhtcaps_mask",
6647 params->vhtcaps_mask, sz);
6648 if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
6649 params->vhtcaps) ||
6650 nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
6651 params->vhtcaps_mask))
6652 return -1;
6653 }
6654#endif /* CONFIG_VHT_OVERRIDES */
6655
Hai Shalomc1a21442022-02-04 13:43:00 -08006656#ifdef CONFIG_HE_OVERRIDES
6657 if (params->disable_he) {
6658 wpa_printf(MSG_DEBUG, " * HE disabled");
6659 if (nla_put_flag(msg, NL80211_ATTR_DISABLE_HE))
6660 return -1;
6661 }
6662#endif /* CONFIG_HE_OVERRIDES */
6663
Sunil Ravi77d572f2023-01-17 23:58:31 +00006664 if (params->disable_eht) {
6665 wpa_printf(MSG_DEBUG, " * EHT disabled");
6666 if (nla_put_flag(msg, NL80211_ATTR_DISABLE_EHT))
6667 return -1;
6668 }
6669
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006670 return 0;
6671}
6672
6673
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006674static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
6675 struct wpa_driver_associate_params *params)
6676{
6677 struct nl_msg *msg;
6678 int ret = -1;
6679 int count = 0;
6680
6681 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
6682
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006683 if (wpa_driver_nl80211_set_mode_ibss(drv->first_bss, &params->freq)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006684 wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
6685 "IBSS mode");
6686 return -1;
6687 }
6688
6689retry:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006690 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_IBSS)) ||
6691 params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
6692 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006693
Hai Shalom74f70d42019-02-11 14:42:39 -08006694 wpa_printf(MSG_DEBUG, " * SSID=%s",
6695 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006696 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
6697 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006698 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6699 drv->ssid_len = params->ssid_len;
6700
Dmitry Shmidtff787d52015-01-12 13:01:47 -08006701 if (nl80211_put_freq_params(msg, &params->freq) < 0 ||
6702 nl80211_put_beacon_int(msg, params->beacon_int))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006703 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006704
6705 ret = nl80211_set_conn_keys(params, msg);
6706 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006707 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006708
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006709 if (params->bssid && params->fixed_bssid) {
6710 wpa_printf(MSG_DEBUG, " * BSSID=" MACSTR,
6711 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006712 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
6713 goto fail;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006714 }
6715
Dmitry Shmidt7f656022015-02-25 14:36:37 -08006716 if (params->fixed_freq) {
6717 wpa_printf(MSG_DEBUG, " * fixed_freq");
6718 if (nla_put_flag(msg, NL80211_ATTR_FREQ_FIXED))
6719 goto fail;
6720 }
6721
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006722 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
6723 params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
6724 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00006725 params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
6726 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA384) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006727 wpa_printf(MSG_DEBUG, " * control port");
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006728 if (nl80211_put_control_port(drv, msg))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006729 goto fail;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006730 }
6731
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006732 if (params->wpa_ie) {
6733 wpa_hexdump(MSG_DEBUG,
6734 " * Extra IEs for Beacon/Probe Response frames",
6735 params->wpa_ie, params->wpa_ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006736 if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
6737 params->wpa_ie))
6738 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006739 }
6740
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08006741 ret = nl80211_ht_vht_overrides(msg, params);
6742 if (ret < 0)
6743 goto fail;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08006744
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006745 if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
6746 goto fail;
6747 ret = send_and_recv(drv->global, drv->first_bss->nl_connect, msg, NULL,
6748 NULL, NULL, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006749 msg = NULL;
6750 if (ret) {
6751 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
6752 ret, strerror(-ret));
6753 count++;
6754 if (ret == -EALREADY && count == 1) {
6755 wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
6756 "forced leave");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006757 nl80211_leave_ibss(drv, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006758 nlmsg_free(msg);
6759 goto retry;
6760 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006761 } else {
6762 wpa_printf(MSG_DEBUG,
6763 "nl80211: Join IBSS request sent successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006764 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006765
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006766fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006767 nlmsg_free(msg);
6768 return ret;
6769}
6770
6771
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006772static int nl80211_put_fils_connect_params(struct wpa_driver_nl80211_data *drv,
6773 struct wpa_driver_associate_params *params,
6774 struct nl_msg *msg)
6775{
6776 if (params->fils_erp_username_len) {
6777 wpa_hexdump_ascii(MSG_DEBUG, " * FILS ERP EMSKname/username",
6778 params->fils_erp_username,
6779 params->fils_erp_username_len);
6780 if (nla_put(msg, NL80211_ATTR_FILS_ERP_USERNAME,
6781 params->fils_erp_username_len,
6782 params->fils_erp_username))
6783 return -1;
6784 }
6785
6786 if (params->fils_erp_realm_len) {
6787 wpa_hexdump_ascii(MSG_DEBUG, " * FILS ERP Realm",
6788 params->fils_erp_realm,
6789 params->fils_erp_realm_len);
6790 if (nla_put(msg, NL80211_ATTR_FILS_ERP_REALM,
6791 params->fils_erp_realm_len, params->fils_erp_realm))
6792 return -1;
6793 }
6794
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006795 if (params->fils_erp_rrk_len) {
Vinita S. Maloo3a5b4412020-05-19 17:43:22 +05306796 wpa_printf(MSG_DEBUG, " * FILS ERP next seq %u",
6797 params->fils_erp_next_seq_num);
6798 if (nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
6799 params->fils_erp_next_seq_num))
6800 return -1;
6801
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006802 wpa_printf(MSG_DEBUG, " * FILS ERP rRK (len=%lu)",
6803 (unsigned long) params->fils_erp_rrk_len);
6804 if (nla_put(msg, NL80211_ATTR_FILS_ERP_RRK,
6805 params->fils_erp_rrk_len, params->fils_erp_rrk))
6806 return -1;
6807 }
6808
6809 return 0;
6810}
6811
6812
Sunil Ravi89eba102022-09-13 21:04:37 -07006813static unsigned int num_bits_set(u32 val)
6814{
6815 unsigned int c;
6816
6817 for (c = 0; val; c++)
6818 val &= val - 1;
6819
6820 return c;
6821}
6822
6823
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006824static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
6825 struct wpa_driver_associate_params *params,
6826 struct nl_msg *msg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006827{
Sunil Ravi77d572f2023-01-17 23:58:31 +00006828 if (params->mld_params.mld_addr && params->mld_params.valid_links > 0) {
6829 struct wpa_driver_mld_params *mld_params = &params->mld_params;
6830 struct nlattr *links, *attr;
Sunil Ravi77d572f2023-01-17 23:58:31 +00006831 u8 link_id;
6832
6833 wpa_printf(MSG_DEBUG, " * MLD: MLD addr=" MACSTR,
6834 MAC2STR(mld_params->mld_addr));
6835
6836 if (nla_put(msg, NL80211_ATTR_MLD_ADDR, ETH_ALEN,
6837 mld_params->mld_addr) ||
6838 nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID,
6839 mld_params->assoc_link_id))
6840 return -1;
6841
6842 links = nla_nest_start(msg, NL80211_ATTR_MLO_LINKS);
6843 if (!links)
6844 return -1;
6845
Sunil Ravi99c035e2024-07-12 01:42:03 +00006846 for_each_link(mld_params->valid_links, link_id) {
6847 attr = nla_nest_start(msg, 0);
Sunil Ravi77d572f2023-01-17 23:58:31 +00006848 if (!attr)
6849 return -1;
6850
6851 if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID,
6852 link_id) ||
6853 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
6854 mld_params->mld_links[link_id].bssid) ||
6855 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
6856 mld_params->mld_links[link_id].freq) ||
Sunil Ravi99c035e2024-07-12 01:42:03 +00006857 (mld_params->mld_links[link_id].disabled &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006858 nla_put_flag(msg,
6859 NL80211_ATTR_MLO_LINK_DISABLED)) ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00006860 (mld_params->mld_links[link_id].ies &&
Sunil Ravi99c035e2024-07-12 01:42:03 +00006861 mld_params->mld_links[link_id].ies_len &&
Sunil Ravi77d572f2023-01-17 23:58:31 +00006862 nla_put(msg, NL80211_ATTR_IE,
6863 mld_params->mld_links[link_id].ies_len,
6864 mld_params->mld_links[link_id].ies)))
6865 return -1;
6866
6867 os_memcpy(drv->sta_mlo_info.links[link_id].bssid,
6868 mld_params->mld_links[link_id].bssid,
6869 ETH_ALEN);
6870 nla_nest_end(msg, attr);
Sunil Ravi77d572f2023-01-17 23:58:31 +00006871 }
6872
6873 nla_nest_end(msg, links);
6874
6875 os_memcpy(drv->sta_mlo_info.ap_mld_addr,
6876 params->mld_params.mld_addr, ETH_ALEN);
6877 drv->sta_mlo_info.assoc_link_id = mld_params->assoc_link_id;
6878 drv->sta_mlo_info.req_links = mld_params->valid_links;
6879 }
6880
Paul Stewart092955c2017-02-06 09:13:09 -08006881 if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
6882 return -1;
6883
Sunil Ravi77d572f2023-01-17 23:58:31 +00006884 if (params->bssid && !params->mld_params.mld_addr) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006885 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
6886 MAC2STR(params->bssid));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006887 if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
6888 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006889 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006890
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006891 if (params->bssid_hint) {
6892 wpa_printf(MSG_DEBUG, " * bssid_hint=" MACSTR,
6893 MAC2STR(params->bssid_hint));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006894 if (nla_put(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
6895 params->bssid_hint))
6896 return -1;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006897 }
6898
Sunil Ravi77d572f2023-01-17 23:58:31 +00006899 if (params->freq.freq && !params->mld_params.mld_addr) {
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006900 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq.freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006901 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
6902 params->freq.freq))
6903 return -1;
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07006904 drv->assoc_freq = params->freq.freq;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07006905 } else
6906 drv->assoc_freq = 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006907
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006908 if (params->freq_hint) {
6909 wpa_printf(MSG_DEBUG, " * freq_hint=%d", params->freq_hint);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006910 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_HINT,
6911 params->freq_hint))
6912 return -1;
Dmitry Shmidt96be6222014-02-13 10:16:51 -08006913 }
6914
Hai Shalomc3565922019-10-28 11:58:20 -07006915 if (params->freq.edmg.channels && params->freq.edmg.bw_config) {
6916 wpa_printf(MSG_DEBUG,
6917 " * EDMG configuration: channels=0x%x bw_config=%d",
6918 params->freq.edmg.channels,
6919 params->freq.edmg.bw_config);
6920 if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
6921 params->freq.edmg.channels) ||
6922 nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
6923 params->freq.edmg.bw_config))
6924 return -1;
6925 }
6926
Dmitry Shmidt04949592012-07-19 12:16:46 -07006927 if (params->bg_scan_period >= 0) {
6928 wpa_printf(MSG_DEBUG, " * bg scan period=%d",
6929 params->bg_scan_period);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006930 if (nla_put_u16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
6931 params->bg_scan_period))
6932 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07006933 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006934
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006935 if (params->ssid) {
Hai Shalom74f70d42019-02-11 14:42:39 -08006936 wpa_printf(MSG_DEBUG, " * SSID=%s",
6937 wpa_ssid_txt(params->ssid, params->ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006938 if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
6939 params->ssid))
6940 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006941 if (params->ssid_len > sizeof(drv->ssid))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006942 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006943 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6944 drv->ssid_len = params->ssid_len;
6945 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006946
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006947 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006948 if (params->wpa_ie &&
6949 nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie))
6950 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006951
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006952 if (params->wpa_proto) {
6953 enum nl80211_wpa_versions ver = 0;
6954
6955 if (params->wpa_proto & WPA_PROTO_WPA)
6956 ver |= NL80211_WPA_VERSION_1;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006957 if (params->wpa_proto & WPA_PROTO_RSN) {
6958#if !defined(CONFIG_DRIVER_NL80211_BRCM) && !defined(CONFIG_DRIVER_NL80211_SYNA)
6959 /*
6960 * NL80211_ATTR_SAE_PASSWORD is related and was added
6961 * at the same time as NL80211_WPA_VERSION_3.
6962 */
6963 if (nl80211_attr_supported(drv,
6964 NL80211_ATTR_SAE_PASSWORD) &&
6965 wpa_key_mgmt_sae(params->key_mgmt_suite))
6966 ver |= NL80211_WPA_VERSION_3;
6967 else
6968#endif
6969 ver |= NL80211_WPA_VERSION_2;
6970 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006971
6972 wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006973 if (nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
6974 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006975 }
6976
6977 if (params->pairwise_suite != WPA_CIPHER_NONE) {
6978 u32 cipher = wpa_cipher_to_cipher_suite(params->pairwise_suite);
6979 wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006980 if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
6981 cipher))
6982 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006983 }
6984
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08006985 if (params->group_suite == WPA_CIPHER_GTK_NOT_USED &&
6986 !(drv->capa.enc & WPA_DRIVER_CAPA_ENC_GTK_NOT_USED)) {
6987 /*
6988 * This is likely to work even though many drivers do not
6989 * advertise support for operations without GTK.
6990 */
6991 wpa_printf(MSG_DEBUG, " * skip group cipher configuration for GTK_NOT_USED due to missing driver support advertisement");
6992 } else if (params->group_suite != WPA_CIPHER_NONE) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006993 u32 cipher = wpa_cipher_to_cipher_suite(params->group_suite);
6994 wpa_printf(MSG_DEBUG, " * group=0x%x", cipher);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006995 if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher))
6996 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006997 }
6998
6999 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
7000 params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
7001 params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X ||
7002 params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
Dmitry Shmidt15907092014-03-25 10:42:57 -07007003 params->key_mgmt_suite == WPA_KEY_MGMT_CCKM ||
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07007004 params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
7005 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007006 params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
Hai Shalom021b0b52019-04-10 11:17:58 -07007007 params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
Sunil Ravi89eba102022-09-13 21:04:37 -07007008 params->key_mgmt_suite == WPA_KEY_MGMT_SAE_EXT_KEY ||
Hai Shalom021b0b52019-04-10 11:17:58 -07007009 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE ||
Sunil Ravi89eba102022-09-13 21:04:37 -07007010 params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE_EXT_KEY ||
Dmitry Shmidt807291d2015-01-27 13:40:23 -08007011 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007012 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ||
Hai Shalom021b0b52019-04-10 11:17:58 -07007013 params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007014 params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA256 ||
7015 params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA384 ||
7016 params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA256 ||
Roshan Pius3a1667e2018-07-03 15:17:14 -07007017 params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384 ||
7018 params->key_mgmt_suite == WPA_KEY_MGMT_OWE ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007019 params->key_mgmt_suite == WPA_KEY_MGMT_DPP ||
7020 params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA384) {
Sunil Ravi89eba102022-09-13 21:04:37 -07007021 u32 *mgmt;
7022 unsigned int akm_count = 1, i;
7023
7024 /*
7025 * Make sure the driver has capability to handle default AKM in
7026 * key_mgmt_suite plus allowed AKMs in allowed_key_mgmts.
7027 */
7028 if (drv->capa.max_num_akms <=
7029 num_bits_set(params->allowed_key_mgmts)) {
7030 wpa_printf(MSG_INFO,
7031 "nl80211: Not enough support for the allowed AKMs (max_num_akms=%u <= num_bits_set=%u)",
7032 drv->capa.max_num_akms,
7033 num_bits_set(params->allowed_key_mgmts));
7034 return -1;
7035 }
7036
7037 mgmt = os_malloc(sizeof(u32) * drv->capa.max_num_akms);
7038 if (!mgmt)
7039 return -1;
7040
7041 mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007042
7043 switch (params->key_mgmt_suite) {
7044 case WPA_KEY_MGMT_CCKM:
Sunil Ravi89eba102022-09-13 21:04:37 -07007045 mgmt[0] = RSN_AUTH_KEY_MGMT_CCKM;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007046 break;
7047 case WPA_KEY_MGMT_IEEE8021X:
Sunil Ravi89eba102022-09-13 21:04:37 -07007048 mgmt[0] = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007049 break;
7050 case WPA_KEY_MGMT_FT_IEEE8021X:
Sunil Ravi89eba102022-09-13 21:04:37 -07007051 mgmt[0] = RSN_AUTH_KEY_MGMT_FT_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007052 break;
7053 case WPA_KEY_MGMT_FT_PSK:
Sunil Ravi89eba102022-09-13 21:04:37 -07007054 mgmt[0] = RSN_AUTH_KEY_MGMT_FT_PSK;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007055 break;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07007056 case WPA_KEY_MGMT_IEEE8021X_SHA256:
Sunil Ravi89eba102022-09-13 21:04:37 -07007057 mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07007058 break;
7059 case WPA_KEY_MGMT_PSK_SHA256:
Sunil Ravi89eba102022-09-13 21:04:37 -07007060 mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_SHA256;
Dmitry Shmidt3c57b3f2014-05-22 15:13:07 -07007061 break;
Dmitry Shmidt15907092014-03-25 10:42:57 -07007062 case WPA_KEY_MGMT_OSEN:
Sunil Ravi89eba102022-09-13 21:04:37 -07007063 mgmt[0] = RSN_AUTH_KEY_MGMT_OSEN;
Dmitry Shmidt15907092014-03-25 10:42:57 -07007064 break;
Hai Shalom021b0b52019-04-10 11:17:58 -07007065 case WPA_KEY_MGMT_SAE:
Sunil Ravi89eba102022-09-13 21:04:37 -07007066 mgmt[0] = RSN_AUTH_KEY_MGMT_SAE;
7067 break;
7068 case WPA_KEY_MGMT_SAE_EXT_KEY:
7069 mgmt[0] = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY;
Hai Shalom021b0b52019-04-10 11:17:58 -07007070 break;
7071 case WPA_KEY_MGMT_FT_SAE:
Sunil Ravi89eba102022-09-13 21:04:37 -07007072 mgmt[0] = RSN_AUTH_KEY_MGMT_FT_SAE;
7073 break;
7074 case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
7075 mgmt[0] = RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY;
Hai Shalom021b0b52019-04-10 11:17:58 -07007076 break;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007077 case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
Sunil Ravi89eba102022-09-13 21:04:37 -07007078 mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007079 break;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08007080 case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
Sunil Ravi89eba102022-09-13 21:04:37 -07007081 mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08007082 break;
Hai Shalom021b0b52019-04-10 11:17:58 -07007083 case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
Sunil Ravi89eba102022-09-13 21:04:37 -07007084 mgmt[0] = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
Hai Shalom021b0b52019-04-10 11:17:58 -07007085 break;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007086 case WPA_KEY_MGMT_FILS_SHA256:
Sunil Ravi89eba102022-09-13 21:04:37 -07007087 mgmt[0] = RSN_AUTH_KEY_MGMT_FILS_SHA256;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007088 break;
7089 case WPA_KEY_MGMT_FILS_SHA384:
Sunil Ravi89eba102022-09-13 21:04:37 -07007090 mgmt[0] = RSN_AUTH_KEY_MGMT_FILS_SHA384;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007091 break;
7092 case WPA_KEY_MGMT_FT_FILS_SHA256:
Sunil Ravi89eba102022-09-13 21:04:37 -07007093 mgmt[0] = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007094 break;
7095 case WPA_KEY_MGMT_FT_FILS_SHA384:
Sunil Ravi89eba102022-09-13 21:04:37 -07007096 mgmt[0] = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007097 break;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007098 case WPA_KEY_MGMT_OWE:
Sunil Ravi89eba102022-09-13 21:04:37 -07007099 mgmt[0] = RSN_AUTH_KEY_MGMT_OWE;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007100 break;
7101 case WPA_KEY_MGMT_DPP:
Sunil Ravi89eba102022-09-13 21:04:37 -07007102 mgmt[0] = RSN_AUTH_KEY_MGMT_DPP;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007103 break;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007104 case WPA_KEY_MGMT_IEEE8021X_SHA384:
7105 mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SHA384;
7106 break;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007107 case WPA_KEY_MGMT_PSK:
7108 default:
Sunil Ravi89eba102022-09-13 21:04:37 -07007109 mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007110 break;
7111 }
Sunil Ravi89eba102022-09-13 21:04:37 -07007112
7113 if (drv->capa.max_num_akms > 1) {
7114 akm_count += wpa_key_mgmt_to_suites(
7115 params->allowed_key_mgmts, &mgmt[1],
7116 drv->capa.max_num_akms - 1);
7117 }
7118
7119 for (i = 0; i < akm_count; i++)
7120 wpa_printf(MSG_DEBUG, " * akm[%d]=0x%x", i, mgmt[i]);
7121
7122 if (nla_put(msg, NL80211_ATTR_AKM_SUITES,
7123 akm_count * sizeof(u32), mgmt)) {
7124 os_free(mgmt);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007125 return -1;
Sunil Ravi89eba102022-09-13 21:04:37 -07007126 }
7127
7128 os_free(mgmt);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007129 }
7130
Isaac Chiou6ce580d2024-04-24 17:07:24 +08007131#if (defined(CONFIG_DRIVER_NL80211_BRCM) && !defined(WIFI_BRCM_OPEN_SOURCE_MULTI_AKM)) || \
7132 defined(CONFIG_DRIVER_NL80211_SYNA)
Vinayak Yadawad14709082022-03-17 14:25:11 +05307133 if (IS_CROSS_AKM_ROAM_KEY_MGMT(params->key_mgmt_suite)) {
7134 int num_suites;
7135 u32 suites[NL80211_MAX_NR_AKM_SUITES];
7136
7137 wpa_printf(MSG_INFO, "nl80211: key_mgmt_suites=0x%x",
7138 params->key_mgmt_suite);
7139 num_suites = wpa_cross_akm_key_mgmt_to_suites(params->key_mgmt_suite,
7140 suites, ARRAY_SIZE(suites));
7141 if (num_suites &&
7142 nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32), suites)) {
7143 wpa_printf(MSG_ERROR, "Updating multi akm_suite failed");
7144 return -1;
7145 }
7146 }
Isaac Chiou6ce580d2024-04-24 17:07:24 +08007147#endif /* (CONFIG_DRIVER_NL80211_BRCM && !WIFI_BRCM_OPEN_SOURCE_MULTI_AKM) ||
7148 * CONFIG_DRIVER_NL80211_SYNA */
Hai Shalomc3565922019-10-28 11:58:20 -07007149 if (params->req_handshake_offload &&
Hai Shalom74f70d42019-02-11 14:42:39 -08007150 (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) {
7151 wpa_printf(MSG_DEBUG, " * WANT_1X_4WAY_HS");
7152 if (nla_put_flag(msg, NL80211_ATTR_WANT_1X_4WAY_HS))
7153 return -1;
7154 }
7155
Roshan Pius3a1667e2018-07-03 15:17:14 -07007156 /* Add PSK in case of 4-way handshake offload */
7157 if (params->psk &&
Hai Shalom74f70d42019-02-11 14:42:39 -08007158 (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07007159 wpa_hexdump_key(MSG_DEBUG, " * PSK", params->psk, 32);
7160 if (nla_put(msg, NL80211_ATTR_PMK, 32, params->psk))
7161 return -1;
7162 }
7163
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007164 if (nl80211_put_control_port(drv, msg))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007165 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007166
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07007167 if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
7168 (params->pairwise_suite == WPA_CIPHER_NONE ||
7169 params->pairwise_suite == WPA_CIPHER_WEP104 ||
7170 params->pairwise_suite == WPA_CIPHER_WEP40) &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007171 nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
Dmitry Shmidtd13095b2016-08-22 14:02:19 -07007172 return -1;
7173
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007174 if (params->rrm_used) {
7175 u32 drv_rrm_flags = drv->capa.rrm_flags;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07007176 if ((!((drv_rrm_flags &
7177 WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) &&
7178 (drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) &&
7179 !(drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007180 nla_put_flag(msg, NL80211_ATTR_USE_RRM))
7181 return -1;
7182 }
7183
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007184 if (nl80211_ht_vht_overrides(msg, params) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007185 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007186
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007187 if (params->p2p)
7188 wpa_printf(MSG_DEBUG, " * P2P group");
7189
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08007190 if (params->pbss) {
7191 wpa_printf(MSG_DEBUG, " * PBSS");
7192 if (nla_put_flag(msg, NL80211_ATTR_PBSS))
7193 return -1;
7194 }
7195
Dmitry Shmidte4663042016-04-04 10:07:49 -07007196 drv->connect_reassoc = 0;
7197 if (params->prev_bssid) {
7198 wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR,
7199 MAC2STR(params->prev_bssid));
7200 if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
7201 params->prev_bssid))
7202 return -1;
7203 drv->connect_reassoc = 1;
7204 }
7205
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007206 if ((params->auth_alg & WPA_AUTH_ALG_FILS) &&
7207 nl80211_put_fils_connect_params(drv, params, msg) != 0)
7208 return -1;
7209
Sunil Ravi89eba102022-09-13 21:04:37 -07007210 if ((wpa_key_mgmt_sae(params->key_mgmt_suite) ||
7211 wpa_key_mgmt_sae(params->allowed_key_mgmts)) &&
Roshan Pius3a1667e2018-07-03 15:17:14 -07007212 (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
7213 nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
7214 return -1;
7215
Sunil Ravi036cec52023-03-29 11:35:17 -07007216 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
7217 nla_put_flag(msg, NL80211_ATTR_MLO_SUPPORT))
7218 return -1;
7219
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007220 return 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007221}
7222
7223
Sunil Ravic0f5d412024-09-11 22:12:49 +00007224#ifdef CONFIG_DRIVER_NL80211_QCA
7225static void connect_ext_feature_set(u8 *features,
7226 enum qca_wlan_connect_ext_features idx)
7227{
7228 u8 *idx_byte = &features[idx / 8];
7229
7230 *idx_byte |= BIT(idx % 8);
7231}
7232#endif /* CONFIG_DRIVER_NL80211_QCA */
7233
7234
7235static int nl80211_connect_ext(struct wpa_driver_nl80211_data *drv,
7236 struct wpa_driver_associate_params *params)
7237{
7238#ifdef CONFIG_DRIVER_NL80211_QCA
7239 struct nl_msg *msg;
7240 struct nlattr *attr;
7241 u8 features[(NUM_QCA_CONNECT_EXT_FEATURES + 7) / 8] = {};
7242
7243 if (!drv->connect_ext_vendor_cmd_avail)
7244 return -1;
7245
7246 wpa_printf(MSG_DEBUG, "nl80211: Connect_ext (ifindex=%d)",
7247 drv->ifindex);
7248
7249 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
7250 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
7251 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
7252 QCA_NL80211_VENDOR_SUBCMD_CONNECT_EXT))
7253 goto fail;
7254
7255 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
7256 if (!attr)
7257 goto fail;
7258
7259 if (params->rsn_overriding) {
7260 wpa_printf(MSG_DEBUG, "- RSN overriding");
7261 connect_ext_feature_set(features, QCA_CONNECT_EXT_FEATURE_RSNO);
7262 }
7263
7264 if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_FEATURES,
7265 sizeof(features), features))
7266 goto fail;
7267
7268 nla_nest_end(msg, attr);
7269
7270 return send_and_recv_cmd(drv, msg);
7271fail:
7272 nlmsg_free(msg);
7273#endif /* CONFIG_DRIVER_NL80211_QCA */
7274 return -1;
7275}
7276
7277
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007278static int wpa_driver_nl80211_try_connect(
7279 struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007280 struct wpa_driver_associate_params *params,
Hai Shalomc1a21442022-02-04 13:43:00 -08007281 struct i802_bss *bss)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007282{
7283 struct nl_msg *msg;
7284 enum nl80211_auth_type type;
7285 int ret;
7286 int algs;
7287
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007288#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007289 if (params->req_key_mgmt_offload && params->psk &&
Sunil Ravi89eba102022-09-13 21:04:37 -07007290 (wpa_key_mgmt_wpa_psk_no_sae(params->key_mgmt_suite) ||
7291 wpa_key_mgmt_wpa_psk_no_sae(params->allowed_key_mgmts))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007292 wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK");
7293 ret = issue_key_mgmt_set_key(drv, params->psk, 32);
7294 if (ret)
7295 return ret;
7296 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08007297#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007298
Sunil Ravic0f5d412024-09-11 22:12:49 +00007299 nl80211_connect_ext(drv, params);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007300 wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
7301 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_CONNECT);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007302 if (!msg)
7303 return -1;
7304
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007305 ret = nl80211_connect_common(drv, params, msg);
7306 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007307 goto fail;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007308
Roshan Pius3a1667e2018-07-03 15:17:14 -07007309 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
7310 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
7311 goto fail;
7312
7313 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_OPTIONAL &&
7314 (drv->capa.flags & WPA_DRIVER_FLAGS_MFP_OPTIONAL) &&
7315 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_OPTIONAL))
7316 goto fail;
7317
Hai Shalom60840252021-02-19 19:02:11 -08007318#ifdef CONFIG_SAE
Sunil Ravi89eba102022-09-13 21:04:37 -07007319 if ((wpa_key_mgmt_sae(params->key_mgmt_suite) ||
7320 wpa_key_mgmt_sae(params->allowed_key_mgmts)) &&
Hai Shalom60840252021-02-19 19:02:11 -08007321 nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
7322 goto fail;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007323
7324 /* Add SAE password in case of SAE authentication offload */
7325 if ((params->sae_password || params->passphrase) &&
7326 (drv->capa.flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA)) {
7327 const char *password;
7328 size_t pwd_len;
7329
7330 if (params->sae_password && params->sae_password_id) {
7331 wpa_printf(MSG_INFO,
7332 "nl80211: Use of SAE password identifiers not supported with driver-based SAE");
7333 goto fail;
7334 }
7335
7336 password = params->sae_password;
7337 if (!password)
7338 password = params->passphrase;
7339 pwd_len = os_strlen(password);
7340 wpa_printf(MSG_DEBUG, " * SAE password");
7341 if (nla_put(msg, NL80211_ATTR_SAE_PASSWORD, pwd_len, password))
7342 goto fail;
7343 }
Hai Shalom60840252021-02-19 19:02:11 -08007344#endif /* CONFIG_SAE */
7345
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007346 algs = 0;
7347 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
7348 algs++;
7349 if (params->auth_alg & WPA_AUTH_ALG_SHARED)
7350 algs++;
7351 if (params->auth_alg & WPA_AUTH_ALG_LEAP)
7352 algs++;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007353 if (params->auth_alg & WPA_AUTH_ALG_FILS)
7354 algs++;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007355 if (params->auth_alg & WPA_AUTH_ALG_FT)
7356 algs++;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007357 if (params->auth_alg & WPA_AUTH_ALG_SAE)
7358 algs++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007359 if (algs > 1) {
7360 wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic "
7361 "selection");
7362 goto skip_auth_type;
7363 }
7364
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007365 type = get_nl_auth_type(params->auth_alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007366 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007367 if (type == NL80211_AUTHTYPE_MAX ||
7368 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007369 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007370
7371skip_auth_type:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007372 ret = nl80211_set_conn_keys(params, msg);
7373 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007374 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007375
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007376 if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
7377 goto fail;
7378 ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL,
7379 NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007380 msg = NULL;
7381 if (ret) {
7382 wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
7383 "(%s)", ret, strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007384 } else {
Hai Shalom60840252021-02-19 19:02:11 -08007385#ifdef CONFIG_DRIVER_NL80211_QCA
7386 drv->roam_indication_done = false;
7387#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007388 wpa_printf(MSG_DEBUG,
7389 "nl80211: Connect request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007390 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007391
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007392fail:
Hai Shalom74f70d42019-02-11 14:42:39 -08007393 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007394 nlmsg_free(msg);
7395 return ret;
7396
7397}
7398
7399
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08007400static int wpa_driver_nl80211_connect(
7401 struct wpa_driver_nl80211_data *drv,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007402 struct wpa_driver_associate_params *params,
Hai Shalomc1a21442022-02-04 13:43:00 -08007403 struct i802_bss *bss)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08007404{
Jithu Jancea7c60b42014-12-03 18:54:40 +05307405 int ret;
7406
7407 /* Store the connection attempted bssid for future use */
7408 if (params->bssid)
7409 os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
7410 else
7411 os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
7412
Hai Shalomc1a21442022-02-04 13:43:00 -08007413 ret = wpa_driver_nl80211_try_connect(drv, params, bss);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08007414 if (ret == -EALREADY) {
7415 /*
7416 * cfg80211 does not currently accept new connections if
7417 * we are already connected. As a workaround, force
7418 * disconnection and try again.
7419 */
7420 wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
7421 "disconnecting before reassociation "
7422 "attempt");
7423 if (wpa_driver_nl80211_disconnect(
Hai Shalomc1a21442022-02-04 13:43:00 -08007424 drv, WLAN_REASON_PREV_AUTH_NOT_VALID, bss))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08007425 return -1;
Hai Shalomc1a21442022-02-04 13:43:00 -08007426 ret = wpa_driver_nl80211_try_connect(drv, params, bss);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08007427 }
7428 return ret;
7429}
7430
7431
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007432static int wpa_driver_nl80211_associate(
7433 void *priv, struct wpa_driver_associate_params *params)
7434{
7435 struct i802_bss *bss = priv;
7436 struct wpa_driver_nl80211_data *drv = bss->drv;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007437 struct nl80211_err_info err_info;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007438 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007439 struct nl_msg *msg;
7440
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007441 nl80211_unmask_11b_rates(bss);
7442
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007443 if (params->mode == IEEE80211_MODE_AP)
7444 return wpa_driver_nl80211_ap(drv, params);
7445
7446 if (params->mode == IEEE80211_MODE_IBSS)
7447 return wpa_driver_nl80211_ibss(drv, params);
7448
7449 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007450 enum nl80211_iftype nlmode = params->p2p ?
7451 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
7452
7453 if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007454 return -1;
Hai Shalom74f70d42019-02-11 14:42:39 -08007455
Hai Shalomc1a21442022-02-04 13:43:00 -08007456 return wpa_driver_nl80211_connect(drv, params, bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007457 }
7458
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07007459 nl80211_mark_disconnected(drv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007460
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007461 wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
7462 drv->ifindex);
7463 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ASSOCIATE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007464 if (!msg)
7465 return -1;
7466
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007467 ret = nl80211_connect_common(drv, params, msg);
7468 if (ret)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007469 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007470
Roshan Pius3a1667e2018-07-03 15:17:14 -07007471 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
7472 nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
7473 goto fail;
7474
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08007475 if (params->fils_kek) {
7476 wpa_printf(MSG_DEBUG, " * FILS KEK (len=%u)",
7477 (unsigned int) params->fils_kek_len);
7478 if (nla_put(msg, NL80211_ATTR_FILS_KEK, params->fils_kek_len,
7479 params->fils_kek))
7480 goto fail;
7481 }
7482 if (params->fils_nonces) {
7483 wpa_hexdump(MSG_DEBUG, " * FILS nonces (for AAD)",
7484 params->fils_nonces,
7485 params->fils_nonces_len);
7486 if (nla_put(msg, NL80211_ATTR_FILS_NONCES,
7487 params->fils_nonces_len, params->fils_nonces))
7488 goto fail;
7489 }
7490
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007491 if (!TEST_FAIL_TAG("assoc")) {
7492 if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
7493 goto fail;
7494 ret = send_and_recv(drv->global, drv->first_bss->nl_connect,
7495 msg, NULL, NULL, NULL, NULL, &err_info);
7496 msg = NULL;
7497 } else {
7498 int i;
7499
7500 /* Error and force TEST_FAIL checking for each link */
7501 ret = -EINVAL;
Sunil Ravi99c035e2024-07-12 01:42:03 +00007502 for_each_link(params->mld_params.valid_links, i) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007503 if (TEST_FAIL_TAG("link"))
7504 err_info.link_id = i;
7505 }
7506 }
7507
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007508 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007509 wpa_dbg(drv->ctx, MSG_DEBUG,
7510 "nl80211: MLME command failed (assoc): ret=%d (%s)",
7511 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007512 nl80211_dump_scan(drv);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007513
7514 /* Mark failed link within params */
7515 if (err_info.link_id >= 0) {
7516 if (err_info.link_id >= MAX_NUM_MLD_LINKS ||
7517 !(params->mld_params.valid_links &
7518 BIT(err_info.link_id))) {
7519 wpa_printf(MSG_DEBUG,
7520 "nl80211: Invalid errorred link_id %d",
7521 err_info.link_id);
7522 goto fail;
7523 }
7524 params->mld_params.mld_links[err_info.link_id].error =
7525 ret;
7526 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007527 } else {
7528 wpa_printf(MSG_DEBUG,
7529 "nl80211: Association request send successfully");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007530 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007531
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007532fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007533 nlmsg_free(msg);
7534 return ret;
7535}
7536
7537
7538static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007539 int ifindex, enum nl80211_iftype mode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007540{
7541 struct nl_msg *msg;
7542 int ret = -ENOBUFS;
7543
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007544 wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
7545 ifindex, mode, nl80211_iftype_str(mode));
7546
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007547 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
7548 if (!msg || nla_put_u32(msg, NL80211_ATTR_IFTYPE, mode))
7549 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007550
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007551 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007552 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007553 if (!ret)
7554 return 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007555fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007556 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007557 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
7558 " %d (%s)", ifindex, mode, ret, strerror(-ret));
7559 return ret;
7560}
7561
7562
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007563static int wpa_driver_nl80211_set_mode_impl(
7564 struct i802_bss *bss,
7565 enum nl80211_iftype nlmode,
7566 struct hostapd_freq_params *desired_freq_params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007567{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007568 struct wpa_driver_nl80211_data *drv = bss->drv;
7569 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007570 int i;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007571 int was_ap = is_ap_interface(drv->nlmode);
7572 int res;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007573 int mode_switch_res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007574
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07007575 if (TEST_FAIL())
7576 return -1;
7577
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007578 mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
7579 if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))
7580 mode_switch_res = 0;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007581
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007582 if (mode_switch_res == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007583 drv->nlmode = nlmode;
7584 ret = 0;
7585 goto done;
7586 }
7587
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007588 if (mode_switch_res == -ENODEV)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007589 return -1;
7590
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007591 if (nlmode == drv->nlmode) {
7592 wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
7593 "requested mode - ignore error");
7594 ret = 0;
7595 goto done; /* Already in the requested mode */
7596 }
7597
7598 /* mac80211 doesn't allow mode changes while the device is up, so
7599 * take the device down, try to set the mode again, and bring the
7600 * device back up.
7601 */
7602 wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
7603 "interface down");
7604 for (i = 0; i < 10; i++) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007605 res = i802_set_iface_flags(bss, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007606 if (res == -EACCES || res == -ENODEV)
7607 break;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007608 if (res != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007609 wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
7610 "interface down");
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007611 os_sleep(0, 100000);
7612 continue;
7613 }
7614
7615 /*
7616 * Setting the mode will fail for some drivers if the phy is
7617 * on a frequency that the mode is disallowed in.
7618 */
7619 if (desired_freq_params) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007620 res = nl80211_set_channel(bss, desired_freq_params, 0);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007621 if (res) {
7622 wpa_printf(MSG_DEBUG,
7623 "nl80211: Failed to set frequency on interface");
7624 }
7625 }
7626
Hai Shalom4fbc08f2020-05-18 12:37:00 -07007627 if (i == 0 && was_ap && !is_ap_interface(nlmode) &&
7628 bss->brname[0] &&
7629 (bss->added_if_into_bridge || bss->already_in_bridge)) {
7630 wpa_printf(MSG_DEBUG,
7631 "nl80211: Remove AP interface %s temporarily from the bridge %s to allow its mode to be set to STATION",
7632 bss->ifname, bss->brname);
7633 if (linux_br_del_if(drv->global->ioctl_sock,
7634 bss->brname, bss->ifname) < 0)
7635 wpa_printf(MSG_INFO,
7636 "nl80211: Failed to remove interface %s from bridge %s: %s",
7637 bss->ifname, bss->brname,
7638 strerror(errno));
7639 }
7640
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007641 /* Try to set the mode again while the interface is down */
7642 mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
7643 if (mode_switch_res == -EBUSY) {
7644 wpa_printf(MSG_DEBUG,
7645 "nl80211: Delaying mode set while interface going down");
7646 os_sleep(0, 100000);
7647 continue;
7648 }
7649 ret = mode_switch_res;
7650 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007651 }
7652
7653 if (!ret) {
7654 wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
7655 "interface is down");
7656 drv->nlmode = nlmode;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007657 drv->ignore_if_down_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007658 }
7659
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007660 /* Bring the interface back up */
7661 res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
7662 if (res != 0) {
7663 wpa_printf(MSG_DEBUG,
7664 "nl80211: Failed to set interface up after switching mode");
7665 ret = -1;
7666 }
7667
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007668done:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007669 if (ret) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007670 wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
7671 "from %d failed", nlmode, drv->nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007672 return ret;
7673 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007674
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007675 if (is_p2p_net_interface(nlmode)) {
7676 wpa_printf(MSG_DEBUG,
7677 "nl80211: Interface %s mode change to P2P - disable 11b rates",
7678 bss->ifname);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007679 nl80211_disable_11b_rates(drv, drv->ifindex, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007680 } else if (drv->disabled_11b_rates) {
7681 wpa_printf(MSG_DEBUG,
7682 "nl80211: Interface %s mode changed to non-P2P - re-enable 11b rates",
7683 bss->ifname);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007684 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007685 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007686
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007687 if (is_ap_interface(nlmode)) {
7688 nl80211_mgmt_unsubscribe(bss, "start AP");
7689 /* Setup additional AP mode functionality if needed */
7690 if (nl80211_setup_ap(bss))
7691 return -1;
7692 } else if (was_ap) {
7693 /* Remove additional AP mode functionality */
7694 nl80211_teardown_ap(bss);
7695 } else {
7696 nl80211_mgmt_unsubscribe(bss, "mode change");
7697 }
7698
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007699 if (is_mesh_interface(nlmode) &&
7700 nl80211_mgmt_subscribe_mesh(bss))
7701 return -1;
7702
Dmitry Shmidt04949592012-07-19 12:16:46 -07007703 if (!bss->in_deinit && !is_ap_interface(nlmode) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007704 !is_mesh_interface(nlmode) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007705 nl80211_mgmt_subscribe_non_ap(bss) < 0)
7706 wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
7707 "frame processing - ignore for now");
7708
7709 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007710}
7711
7712
Hai Shalom4fbc08f2020-05-18 12:37:00 -07007713void nl80211_restore_ap_mode(struct i802_bss *bss)
7714{
7715 struct wpa_driver_nl80211_data *drv = bss->drv;
7716 int was_ap = is_ap_interface(drv->nlmode);
leslc3979c32021-03-29 22:34:02 +08007717 int br_ifindex;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07007718
7719 wpa_driver_nl80211_set_mode(bss, drv->ap_scan_as_station);
7720 if (!was_ap && is_ap_interface(drv->ap_scan_as_station) &&
7721 bss->brname[0] &&
7722 (bss->added_if_into_bridge || bss->already_in_bridge)) {
7723 wpa_printf(MSG_DEBUG,
7724 "nl80211: Add AP interface %s back into the bridge %s",
7725 bss->ifname, bss->brname);
7726 if (linux_br_add_if(drv->global->ioctl_sock, bss->brname,
7727 bss->ifname) < 0) {
7728 wpa_printf(MSG_WARNING,
7729 "nl80211: Failed to add interface %s into bridge %s: %s",
7730 bss->ifname, bss->brname, strerror(errno));
7731 }
leslc3979c32021-03-29 22:34:02 +08007732 br_ifindex = if_nametoindex(bss->brname);
7733 add_ifidx(drv, br_ifindex, drv->ifindex);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07007734 }
7735 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
7736}
7737
7738
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007739int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
7740 enum nl80211_iftype nlmode)
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007741{
7742 return wpa_driver_nl80211_set_mode_impl(bss, nlmode, NULL);
7743}
7744
7745
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07007746static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
7747 struct hostapd_freq_params *freq)
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007748{
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007749 return wpa_driver_nl80211_set_mode_impl(bss, NL80211_IFTYPE_ADHOC,
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -07007750 freq);
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07007751}
7752
7753
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007754static int wpa_driver_nl80211_get_capa(void *priv,
7755 struct wpa_driver_capa *capa)
7756{
7757 struct i802_bss *bss = priv;
7758 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07007759
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007760 if (!drv->has_capability)
7761 return -1;
7762 os_memcpy(capa, &drv->capa, sizeof(*capa));
Dmitry Shmidt444d5672013-04-01 13:08:44 -07007763 if (drv->extended_capa && drv->extended_capa_mask) {
7764 capa->extended_capa = drv->extended_capa;
7765 capa->extended_capa_mask = drv->extended_capa_mask;
7766 capa->extended_capa_len = drv->extended_capa_len;
7767 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07007768
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007769 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007770}
7771
7772
7773static int wpa_driver_nl80211_set_operstate(void *priv, int state)
7774{
7775 struct i802_bss *bss = priv;
7776 struct wpa_driver_nl80211_data *drv = bss->drv;
7777
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007778 wpa_printf(MSG_DEBUG, "nl80211: Set %s operstate %d->%d (%s)",
7779 bss->ifname, drv->operstate, state,
7780 state ? "UP" : "DORMANT");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007781 drv->operstate = state;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007782 return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007783 state ? IF_OPER_UP : IF_OPER_DORMANT);
7784}
7785
7786
7787static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
7788{
7789 struct i802_bss *bss = priv;
7790 struct wpa_driver_nl80211_data *drv = bss->drv;
7791 struct nl_msg *msg;
7792 struct nl80211_sta_flag_update upd;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007793 int ret;
Sunil Ravi89eba102022-09-13 21:04:37 -07007794 const u8 *connected_addr = drv->sta_mlo_info.valid_links ?
7795 drv->sta_mlo_info.ap_mld_addr : drv->bssid;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007796
Sunil Ravi89eba102022-09-13 21:04:37 -07007797 if (!drv->associated && is_zero_ether_addr(connected_addr) &&
7798 !authorized) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007799 wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated");
7800 return 0;
7801 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007802
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07007803 wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
Sunil Ravi89eba102022-09-13 21:04:37 -07007804 MACSTR, authorized ? "" : "un", MAC2STR(connected_addr));
Dmitry Shmidt8bae4132013-06-06 11:25:10 -07007805
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007806 os_memset(&upd, 0, sizeof(upd));
7807 upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
7808 if (authorized)
7809 upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007810
7811 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
Sunil Ravi89eba102022-09-13 21:04:37 -07007812 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, connected_addr) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007813 nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd)) {
7814 nlmsg_free(msg);
7815 return -ENOBUFS;
7816 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007817
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007818 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007819 if (!ret)
7820 return 0;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007821 wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)",
7822 ret, strerror(-ret));
7823 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007824}
7825
7826
Jouni Malinen75ecf522011-06-27 15:19:46 -07007827/* Set kernel driver on given frequency (MHz) */
7828static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007829{
Jouni Malinen75ecf522011-06-27 15:19:46 -07007830 struct i802_bss *bss = priv;
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07007831 return nl80211_set_channel(bss, freq, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007832}
7833
7834
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007835static inline int min_int(int a, int b)
7836{
7837 if (a < b)
7838 return a;
7839 return b;
7840}
7841
7842
7843static int get_key_handler(struct nl_msg *msg, void *arg)
7844{
7845 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7846 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7847
7848 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7849 genlmsg_attrlen(gnlh, 0), NULL);
7850
7851 /*
7852 * TODO: validate the key index and mac address!
7853 * Otherwise, there's a race condition as soon as
7854 * the kernel starts sending key notifications.
7855 */
7856
7857 if (tb[NL80211_ATTR_KEY_SEQ])
7858 memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
7859 min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
Hai Shalom021b0b52019-04-10 11:17:58 -07007860 nl80211_nlmsg_clear(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007861 return NL_SKIP;
7862}
7863
7864
7865static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007866 int idx, int link_id, u8 *seq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007867{
7868 struct i802_bss *bss = priv;
7869 struct wpa_driver_nl80211_data *drv = bss->drv;
7870 struct nl_msg *msg;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007871 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007872
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007873 msg = nl80211_ifindex_msg(drv, if_nametoindex(iface), 0,
7874 NL80211_CMD_GET_KEY);
7875 if (!msg ||
7876 (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007877 (link_id != NL80211_DRV_LINK_ID_NA &&
7878 nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007879 nla_put_u8(msg, NL80211_ATTR_KEY_IDX, idx)) {
7880 nlmsg_free(msg);
7881 return -ENOBUFS;
7882 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007883
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007884 os_memset(seq, 0, 6);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007885 res = send_and_recv_resp(drv, msg, get_key_handler, seq);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007886 if (res) {
7887 wpa_printf(MSG_DEBUG,
7888 "nl80211: Failed to get current TX sequence for a key (link_id=%d idx=%d): %d (%s)",
7889 link_id, idx, res, strerror(-res));
7890 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007891
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007892 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007893}
7894
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007895
7896static int i802_set_rts(void *priv, int rts)
7897{
7898 struct i802_bss *bss = priv;
7899 struct wpa_driver_nl80211_data *drv = bss->drv;
7900 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007901 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007902 u32 val;
7903
Hai Shalom021b0b52019-04-10 11:17:58 -07007904 if (rts >= 2347 || rts == -1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007905 val = (u32) -1;
7906 else
7907 val = rts;
7908
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007909 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
7910 nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val)) {
7911 nlmsg_free(msg);
7912 return -ENOBUFS;
7913 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007914
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007915 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007916 if (!ret)
7917 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007918 wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
7919 "%d (%s)", rts, ret, strerror(-ret));
7920 return ret;
7921}
7922
7923
7924static int i802_set_frag(void *priv, int frag)
7925{
7926 struct i802_bss *bss = priv;
7927 struct wpa_driver_nl80211_data *drv = bss->drv;
7928 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007929 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007930 u32 val;
7931
Hai Shalom021b0b52019-04-10 11:17:58 -07007932 if (frag >= 2346 || frag == -1)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007933 val = (u32) -1;
7934 else
7935 val = frag;
7936
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007937 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
7938 nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val)) {
7939 nlmsg_free(msg);
7940 return -ENOBUFS;
7941 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007942
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007943 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007944 if (!ret)
7945 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007946 wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
7947 "%d: %d (%s)", frag, ret, strerror(-ret));
7948 return ret;
7949}
7950
7951
Sunil Ravi7f769292024-07-23 22:21:32 +00007952static int i802_flush(void *priv, int link_id)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007953{
7954 struct i802_bss *bss = priv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007955 struct nl_msg *msg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007956 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007957
Sunil Ravi7f769292024-07-23 22:21:32 +00007958 if (link_id == NL80211_DRV_LINK_ID_NA)
7959 wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
7960 bss->ifname);
7961 else
7962 wpa_printf(MSG_DEBUG,
7963 "nl80211: flush -> DEL_STATION %s (with link %d)",
7964 bss->ifname, link_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007965
7966 /*
7967 * XXX: FIX! this needs to flush all VLANs too
7968 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08007969 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
Sunil Ravi7f769292024-07-23 22:21:32 +00007970 if (link_id >= 0 && (bss->valid_links & BIT(link_id)) &&
7971 nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id))
7972 goto fail;
7973
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007974 res = send_and_recv_cmd(bss->drv, msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007975 if (res) {
7976 wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
7977 "(%s)", res, strerror(-res));
7978 }
7979 return res;
Sunil Ravi7f769292024-07-23 22:21:32 +00007980fail:
7981 nlmsg_free(msg);
7982 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007983}
7984
7985
Hai Shalom81f62d82019-07-22 12:10:00 -07007986static void get_sta_tid_stats(struct hostap_sta_driver_data *data,
7987 struct nlattr *attr)
7988{
7989 struct nlattr *tid_stats[NL80211_TID_STATS_MAX + 1], *tidattr;
7990 struct nlattr *txq_stats[NL80211_TXQ_STATS_MAX + 1];
7991 static struct nla_policy txq_stats_policy[NL80211_TXQ_STATS_MAX + 1] = {
7992 [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 },
7993 [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 },
7994 };
7995 int rem;
7996
7997 nla_for_each_nested(tidattr, attr, rem) {
7998 if (nla_parse_nested(tid_stats, NL80211_TID_STATS_MAX,
7999 tidattr, NULL) != 0 ||
8000 !tid_stats[NL80211_TID_STATS_TXQ_STATS] ||
8001 nla_parse_nested(txq_stats, NL80211_TXQ_STATS_MAX,
8002 tid_stats[NL80211_TID_STATS_TXQ_STATS],
8003 txq_stats_policy) != 0)
8004 continue;
8005 /* sum the backlogs over all TIDs for station */
8006 if (txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES])
8007 data->backlog_bytes += nla_get_u32(
8008 txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES]);
8009 if (txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS])
8010 data->backlog_bytes += nla_get_u32(
8011 txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS]);
8012 }
8013}
8014
8015
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008016static int get_sta_handler(struct nl_msg *msg, void *arg)
8017{
8018 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8019 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8020 struct hostap_sta_driver_data *data = arg;
8021 struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
8022 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
8023 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
8024 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
8025 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
Sunil Ravi77d572f2023-01-17 23:58:31 +00008026 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008027 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
8028 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
Sunil Ravi77d572f2023-01-17 23:58:31 +00008029 [NL80211_STA_INFO_TX_RETRIES] = { .type = NLA_U32 },
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03008030 [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
Sunil Ravi77d572f2023-01-17 23:58:31 +00008031 [NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
8032 [NL80211_STA_INFO_CONNECTED_TIME] = { .type = NLA_U32 },
8033 [NL80211_STA_INFO_BEACON_LOSS] = { .type = NLA_U32 },
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08008034 [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
8035 [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
Sunil Ravi77d572f2023-01-17 23:58:31 +00008036 [NL80211_STA_INFO_EXPECTED_THROUGHPUT] = { .type = NLA_U32 },
8037 [NL80211_STA_INFO_RX_DROP_MISC] = { .type = NLA_U64 },
8038 [NL80211_STA_INFO_BEACON_RX] = { .type = NLA_U64 },
8039 [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8},
Hai Shalom81f62d82019-07-22 12:10:00 -07008040 [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 },
Sunil Ravi77d572f2023-01-17 23:58:31 +00008041 [NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 },
8042 [NL80211_STA_INFO_ACK_SIGNAL_AVG] = { .type = NLA_S8 },
8043 [NL80211_STA_INFO_RX_MPDUS] = { .type = NLA_U32 },
8044 [NL80211_STA_INFO_FCS_ERROR_COUNT] = { .type = NLA_U32 },
Hai Shalom81f62d82019-07-22 12:10:00 -07008045 [NL80211_STA_INFO_TX_DURATION] = { .type = NLA_U64 },
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008046 };
8047 struct nlattr *rate[NL80211_RATE_INFO_MAX + 1];
8048 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
8049 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
8050 [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 },
8051 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
8052 [NL80211_RATE_INFO_VHT_MCS] = { .type = NLA_U8 },
8053 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
8054 [NL80211_RATE_INFO_VHT_NSS] = { .type = NLA_U8 },
Sunil Ravi77d572f2023-01-17 23:58:31 +00008055 [NL80211_RATE_INFO_HE_MCS] = { .type = NLA_U8 },
8056 [NL80211_RATE_INFO_HE_NSS] = { .type = NLA_U8 },
Sunil Ravi036cec52023-03-29 11:35:17 -07008057 [NL80211_RATE_INFO_HE_GI] = { .type = NLA_U8 },
8058 [NL80211_RATE_INFO_HE_DCM] = { .type = NLA_U8 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008059 };
8060
8061 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8062 genlmsg_attrlen(gnlh, 0), NULL);
8063
8064 /*
8065 * TODO: validate the interface and mac address!
8066 * Otherwise, there's a race condition as soon as
8067 * the kernel starts sending station notifications.
8068 */
8069
8070 if (!tb[NL80211_ATTR_STA_INFO]) {
8071 wpa_printf(MSG_DEBUG, "sta stats missing!");
8072 return NL_SKIP;
8073 }
8074 if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
8075 tb[NL80211_ATTR_STA_INFO],
8076 stats_policy)) {
8077 wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
8078 return NL_SKIP;
8079 }
8080
8081 if (stats[NL80211_STA_INFO_INACTIVE_TIME])
8082 data->inactive_msec =
8083 nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08008084 /* For backwards compatibility, fetch the 32-bit counters first. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008085 if (stats[NL80211_STA_INFO_RX_BYTES])
8086 data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
8087 if (stats[NL80211_STA_INFO_TX_BYTES])
8088 data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08008089 if (stats[NL80211_STA_INFO_RX_BYTES64] &&
8090 stats[NL80211_STA_INFO_TX_BYTES64]) {
8091 /*
8092 * The driver supports 64-bit counters, so use them to override
8093 * the 32-bit values.
8094 */
8095 data->rx_bytes =
8096 nla_get_u64(stats[NL80211_STA_INFO_RX_BYTES64]);
8097 data->tx_bytes =
8098 nla_get_u64(stats[NL80211_STA_INFO_TX_BYTES64]);
8099 data->bytes_64bit = 1;
8100 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00008101 if (stats[NL80211_STA_INFO_SIGNAL])
8102 data->signal = (s8) nla_get_u8(stats[NL80211_STA_INFO_SIGNAL]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008103 if (stats[NL80211_STA_INFO_RX_PACKETS])
8104 data->rx_packets =
8105 nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
8106 if (stats[NL80211_STA_INFO_TX_PACKETS])
8107 data->tx_packets =
8108 nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008109 if (stats[NL80211_STA_INFO_TX_RETRIES])
8110 data->tx_retry_count =
8111 nla_get_u32(stats[NL80211_STA_INFO_TX_RETRIES]);
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03008112 if (stats[NL80211_STA_INFO_TX_FAILED])
8113 data->tx_retry_failed =
8114 nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008115 if (stats[NL80211_STA_INFO_SIGNAL_AVG])
8116 data->avg_signal =
8117 (s8) nla_get_u8(stats[NL80211_STA_INFO_SIGNAL_AVG]);
Hai Shalomc1a21442022-02-04 13:43:00 -08008118 if (stats[NL80211_STA_INFO_CONNECTED_TIME]) {
8119 data->connected_sec =
8120 nla_get_u32(stats[NL80211_STA_INFO_CONNECTED_TIME]);
8121 data->flags |= STA_DRV_DATA_CONN_TIME;
8122 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00008123 if (stats[NL80211_STA_INFO_BEACON_LOSS])
8124 data->beacon_loss_count =
8125 nla_get_u32(stats[NL80211_STA_INFO_BEACON_LOSS]);
8126 if (stats[NL80211_STA_INFO_EXPECTED_THROUGHPUT])
8127 data->expected_throughput =
8128 nla_get_u32(stats[NL80211_STA_INFO_EXPECTED_THROUGHPUT]);
8129 if (stats[NL80211_STA_INFO_RX_DROP_MISC])
8130 data->rx_drop_misc =
8131 nla_get_u64(stats[NL80211_STA_INFO_RX_DROP_MISC]);
8132 if (stats[NL80211_STA_INFO_BEACON_RX])
8133 data->beacons_count =
8134 nla_get_u64(stats[NL80211_STA_INFO_BEACON_RX]);
8135 if (stats[NL80211_STA_INFO_BEACON_SIGNAL_AVG])
8136 data->avg_beacon_signal =
8137 (s8) nla_get_u8(stats[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
8138 if (stats[NL80211_STA_INFO_RX_DURATION])
8139 data->rx_airtime =
8140 nla_get_u64(stats[NL80211_STA_INFO_RX_DURATION]);
8141 if (stats[NL80211_STA_INFO_ACK_SIGNAL]) {
8142 data->last_ack_rssi =
8143 nla_get_u8(stats[NL80211_STA_INFO_ACK_SIGNAL]);
8144 data->flags |= STA_DRV_DATA_LAST_ACK_RSSI;
8145 }
8146 if (stats[NL80211_STA_INFO_ACK_SIGNAL_AVG])
8147 data->avg_ack_signal =
8148 nla_get_s8(stats[NL80211_STA_INFO_ACK_SIGNAL_AVG]);
8149 if (stats[NL80211_STA_INFO_RX_MPDUS])
8150 data->rx_mpdus = nla_get_u32(stats[NL80211_STA_INFO_RX_MPDUS]);
8151 if (stats[NL80211_STA_INFO_FCS_ERROR_COUNT])
8152 data->fcs_error_count =
8153 nla_get_u32(stats[NL80211_STA_INFO_FCS_ERROR_COUNT]);
8154 if (stats[NL80211_STA_INFO_TX_DURATION])
8155 data->tx_airtime =
8156 nla_get_u64(stats[NL80211_STA_INFO_TX_DURATION]);
Hai Shalomc1a21442022-02-04 13:43:00 -08008157
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008158 if (stats[NL80211_STA_INFO_TX_BITRATE] &&
8159 nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
8160 stats[NL80211_STA_INFO_TX_BITRATE],
8161 rate_policy) == 0) {
8162 if (rate[NL80211_RATE_INFO_BITRATE32])
8163 data->current_tx_rate =
8164 nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
8165 else if (rate[NL80211_RATE_INFO_BITRATE])
8166 data->current_tx_rate =
8167 nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
8168
Sunil Ravi77d572f2023-01-17 23:58:31 +00008169 /* Convert from 100 kbps to kbps; it's a more convenient unit.
8170 * It's also safe up until ~1Tbps. */
8171 data->current_tx_rate = data->current_tx_rate * 100;
8172
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008173 if (rate[NL80211_RATE_INFO_MCS]) {
8174 data->tx_mcs = nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
8175 data->flags |= STA_DRV_DATA_TX_MCS;
8176 }
8177 if (rate[NL80211_RATE_INFO_VHT_MCS]) {
8178 data->tx_vhtmcs =
8179 nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
8180 data->flags |= STA_DRV_DATA_TX_VHT_MCS;
8181 }
Sunil Ravi036cec52023-03-29 11:35:17 -07008182 if (rate[NL80211_RATE_INFO_SHORT_GI]) {
8183 data->tx_guard_interval = GUARD_INTERVAL_0_4;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008184 data->flags |= STA_DRV_DATA_TX_SHORT_GI;
Sunil Ravi036cec52023-03-29 11:35:17 -07008185 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008186 if (rate[NL80211_RATE_INFO_VHT_NSS]) {
8187 data->tx_vht_nss =
8188 nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
8189 data->flags |= STA_DRV_DATA_TX_VHT_NSS;
8190 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00008191 if (rate[NL80211_RATE_INFO_HE_MCS]) {
8192 data->tx_hemcs =
8193 nla_get_u8(rate[NL80211_RATE_INFO_HE_MCS]);
8194 data->flags |= STA_DRV_DATA_TX_HE_MCS;
8195 }
8196 if (rate[NL80211_RATE_INFO_HE_NSS]) {
8197 data->tx_he_nss =
8198 nla_get_u8(rate[NL80211_RATE_INFO_HE_NSS]);
8199 data->flags |= STA_DRV_DATA_TX_HE_NSS;
8200 }
Sunil Ravi036cec52023-03-29 11:35:17 -07008201 if (rate[NL80211_RATE_INFO_HE_GI]) {
8202 switch (nla_get_u8(rate[NL80211_RATE_INFO_HE_GI])) {
8203 case NL80211_RATE_INFO_HE_GI_0_8:
8204 data->tx_guard_interval = GUARD_INTERVAL_0_8;
8205 break;
8206 case NL80211_RATE_INFO_HE_GI_1_6:
8207 data->tx_guard_interval = GUARD_INTERVAL_1_6;
8208 break;
8209 case NL80211_RATE_INFO_HE_GI_3_2:
8210 data->tx_guard_interval = GUARD_INTERVAL_3_2;
8211 break;
8212 }
8213 data->flags |= STA_DRV_DATA_TX_HE_GI;
8214 }
8215 if (rate[NL80211_RATE_INFO_HE_DCM]) {
8216 data->tx_dcm =
8217 nla_get_u8(rate[NL80211_RATE_INFO_HE_DCM]);
8218 data->flags |= STA_DRV_DATA_TX_HE_DCM;
8219 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008220 }
8221
8222 if (stats[NL80211_STA_INFO_RX_BITRATE] &&
8223 nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
8224 stats[NL80211_STA_INFO_RX_BITRATE],
8225 rate_policy) == 0) {
8226 if (rate[NL80211_RATE_INFO_BITRATE32])
8227 data->current_rx_rate =
8228 nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
8229 else if (rate[NL80211_RATE_INFO_BITRATE])
8230 data->current_rx_rate =
8231 nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
8232
Sunil Ravi77d572f2023-01-17 23:58:31 +00008233 /* Convert from 100 kbps to kbps; it's a more convenient unit.
8234 * It's also safe up until ~1Tbps. */
8235 data->current_rx_rate = data->current_rx_rate * 100;
8236
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008237 if (rate[NL80211_RATE_INFO_MCS]) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00008238 data->rx_mcs = nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008239 data->flags |= STA_DRV_DATA_RX_MCS;
8240 }
8241 if (rate[NL80211_RATE_INFO_VHT_MCS]) {
8242 data->rx_vhtmcs =
8243 nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
8244 data->flags |= STA_DRV_DATA_RX_VHT_MCS;
8245 }
Sunil Ravi036cec52023-03-29 11:35:17 -07008246 if (rate[NL80211_RATE_INFO_SHORT_GI]) {
8247 data->rx_guard_interval = GUARD_INTERVAL_0_4;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008248 data->flags |= STA_DRV_DATA_RX_SHORT_GI;
Sunil Ravi036cec52023-03-29 11:35:17 -07008249 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008250 if (rate[NL80211_RATE_INFO_VHT_NSS]) {
8251 data->rx_vht_nss =
8252 nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
8253 data->flags |= STA_DRV_DATA_RX_VHT_NSS;
8254 }
Sunil Ravi77d572f2023-01-17 23:58:31 +00008255 if (rate[NL80211_RATE_INFO_HE_MCS]) {
8256 data->rx_hemcs =
8257 nla_get_u8(rate[NL80211_RATE_INFO_HE_MCS]);
8258 data->flags |= STA_DRV_DATA_RX_HE_MCS;
8259 }
8260 if (rate[NL80211_RATE_INFO_HE_NSS]) {
8261 data->rx_he_nss =
8262 nla_get_u8(rate[NL80211_RATE_INFO_HE_NSS]);
8263 data->flags |= STA_DRV_DATA_RX_HE_NSS;
8264 }
Sunil Ravi036cec52023-03-29 11:35:17 -07008265 if (rate[NL80211_RATE_INFO_HE_GI]) {
8266 switch (nla_get_u8(rate[NL80211_RATE_INFO_HE_GI])) {
8267 case NL80211_RATE_INFO_HE_GI_0_8:
8268 data->rx_guard_interval = GUARD_INTERVAL_0_8;
8269 break;
8270 case NL80211_RATE_INFO_HE_GI_1_6:
8271 data->rx_guard_interval = GUARD_INTERVAL_1_6;
8272 break;
8273 case NL80211_RATE_INFO_HE_GI_3_2:
8274 data->rx_guard_interval = GUARD_INTERVAL_3_2;
8275 break;
8276 }
8277 data->flags |= STA_DRV_DATA_RX_HE_GI;
8278 }
8279 if (rate[NL80211_RATE_INFO_HE_DCM]) {
8280 data->rx_dcm =
8281 nla_get_u8(rate[NL80211_RATE_INFO_HE_DCM]);
8282 data->flags |= STA_DRV_DATA_RX_HE_DCM;
8283 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008284 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008285
Hai Shalom81f62d82019-07-22 12:10:00 -07008286 if (stats[NL80211_STA_INFO_TID_STATS])
8287 get_sta_tid_stats(data, stats[NL80211_STA_INFO_TID_STATS]);
8288
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008289 return NL_SKIP;
8290}
8291
Sunil Ravi77d572f2023-01-17 23:58:31 +00008292
8293int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
8294 const u8 *bssid,
8295 struct hostap_sta_driver_data *data)
8296{
8297 struct nl_msg *msg;
8298
8299 data->signal = -WPA_INVALID_NOISE;
8300 data->current_tx_rate = 0;
8301
8302 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
8303 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) {
8304 nlmsg_free(msg);
8305 return -ENOBUFS;
8306 }
8307
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008308 return send_and_recv_resp(drv, msg, get_sta_handler, data);
Sunil Ravi77d572f2023-01-17 23:58:31 +00008309}
8310
8311
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008312static int i802_read_sta_data(struct i802_bss *bss,
8313 struct hostap_sta_driver_data *data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008314 const u8 *addr)
8315{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008316 struct nl_msg *msg;
8317
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008318 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_STATION)) ||
8319 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
8320 nlmsg_free(msg);
8321 return -ENOBUFS;
8322 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008323
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008324 return send_and_recv_resp(bss->drv, msg, get_sta_handler, data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008325}
8326
8327
8328static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008329 int cw_min, int cw_max, int burst_time,
8330 int link_id)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008331{
8332 struct i802_bss *bss = priv;
8333 struct wpa_driver_nl80211_data *drv = bss->drv;
8334 struct nl_msg *msg;
8335 struct nlattr *txq, *params;
Hai Shalom74f70d42019-02-11 14:42:39 -08008336 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008337
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008338 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008339 if (!msg)
8340 return -1;
8341
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008342 txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
8343 if (!txq)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008344 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008345
8346 /* We are only sending parameters for a single TXQ at a time */
8347 params = nla_nest_start(msg, 1);
8348 if (!params)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008349 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008350
8351 switch (queue) {
8352 case 0:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008353 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO))
8354 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008355 break;
8356 case 1:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008357 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI))
8358 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008359 break;
8360 case 2:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008361 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE))
8362 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008363 break;
8364 case 3:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008365 if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK))
8366 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008367 break;
8368 }
8369 /* Burst time is configured in units of 0.1 msec and TXOP parameter in
8370 * 32 usec, so need to convert the value here. */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008371 if (nla_put_u16(msg, NL80211_TXQ_ATTR_TXOP,
8372 (burst_time * 100 + 16) / 32) ||
8373 nla_put_u16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min) ||
8374 nla_put_u16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max) ||
8375 nla_put_u8(msg, NL80211_TXQ_ATTR_AIFS, aifs))
8376 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008377
8378 nla_nest_end(msg, params);
8379
8380 nla_nest_end(msg, txq);
8381
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008382 if (link_id != NL80211_DRV_LINK_ID_NA &&
8383 nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id))
8384 goto fail;
8385
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008386 res = send_and_recv_cmd(drv, msg);
Hai Shalom74f70d42019-02-11 14:42:39 -08008387 wpa_printf(MSG_DEBUG,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008388 "nl80211: link=%d: TX queue param set: queue=%d aifs=%d cw_min=%d cw_max=%d burst_time=%d --> res=%d",
8389 link_id, queue, aifs, cw_min, cw_max, burst_time, res);
Hai Shalom74f70d42019-02-11 14:42:39 -08008390 if (res == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008391 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008392 msg = NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008393fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008394 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008395 return -1;
8396}
8397
8398
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008399static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008400 const char *ifname, int vlan_id, int link_id)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008401{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008402 struct wpa_driver_nl80211_data *drv = bss->drv;
8403 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008404 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008405
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008406 wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
8407 ", ifname=%s[%d], vlan_id=%d)",
8408 bss->ifname, if_nametoindex(bss->ifname),
8409 MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008410 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
8411 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
Hai Shalom899fcc72020-10-19 14:38:18 -07008412 (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) &&
Hai Shalomfdcde762020-04-02 11:19:20 -07008413 nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008414 (link_id != NL80211_DRV_LINK_ID_NA &&
8415 nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008416 nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
8417 nlmsg_free(msg);
8418 return -ENOBUFS;
8419 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008420
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008421 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008422 if (ret < 0) {
8423 wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
8424 MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
8425 MAC2STR(addr), ifname, vlan_id, ret,
8426 strerror(-ret));
8427 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008428 return ret;
8429}
8430
8431
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008432static int i802_get_inact_sec(void *priv, const u8 *addr)
8433{
8434 struct hostap_sta_driver_data data;
8435 int ret;
8436
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08008437 os_memset(&data, 0, sizeof(data));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008438 data.inactive_msec = (unsigned long) -1;
8439 ret = i802_read_sta_data(priv, &data, addr);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08008440 if (ret == -ENOENT)
8441 return -ENOENT;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008442 if (ret || data.inactive_msec == (unsigned long) -1)
8443 return -1;
8444 return data.inactive_msec / 1000;
8445}
8446
8447
8448static int i802_sta_clear_stats(void *priv, const u8 *addr)
8449{
8450#if 0
8451 /* TODO */
8452#endif
8453 return 0;
8454}
8455
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008456
8457static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008458 u16 reason, int link_id)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008459{
8460 struct i802_bss *bss = priv;
Dmitry Shmidt04949592012-07-19 12:16:46 -07008461 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008462 struct ieee80211_mgmt mgmt;
Dmitry Shmidt29333592017-01-09 12:27:11 -08008463 u8 channel;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008464 struct i802_link *link = nl80211_get_link(bss, link_id);
Dmitry Shmidt29333592017-01-09 12:27:11 -08008465
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008466 if (ieee80211_freq_to_chan(link->freq, &channel) ==
Dmitry Shmidt29333592017-01-09 12:27:11 -08008467 HOSTAPD_MODE_IEEE80211AD) {
8468 /* Deauthentication is not used in DMG/IEEE 802.11ad;
8469 * disassociate the STA instead. */
8470 return i802_sta_disassoc(priv, own_addr, addr, reason);
8471 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008472
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008473 if (is_mesh_interface(drv->nlmode))
8474 return -1;
8475
Dmitry Shmidt04949592012-07-19 12:16:46 -07008476 if (drv->device_ap_sme)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008477 return wpa_driver_nl80211_sta_remove(bss, addr, 1, reason);
Dmitry Shmidt04949592012-07-19 12:16:46 -07008478
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008479 memset(&mgmt, 0, sizeof(mgmt));
8480 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
8481 WLAN_FC_STYPE_DEAUTH);
8482 memcpy(mgmt.da, addr, ETH_ALEN);
8483 memcpy(mgmt.sa, own_addr, ETH_ALEN);
8484 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
8485 mgmt.u.deauth.reason_code = host_to_le16(reason);
8486 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
8487 IEEE80211_HDRLEN +
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008488 sizeof(mgmt.u.deauth), 0, 0, 0, 0,
Sunil Ravi7f769292024-07-23 22:21:32 +00008489 0, NULL, 0, 0, link_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008490}
8491
8492
8493static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -07008494 u16 reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008495{
8496 struct i802_bss *bss = priv;
Dmitry Shmidt04949592012-07-19 12:16:46 -07008497 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008498 struct ieee80211_mgmt mgmt;
8499
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008500 if (is_mesh_interface(drv->nlmode))
8501 return -1;
8502
Dmitry Shmidt04949592012-07-19 12:16:46 -07008503 if (drv->device_ap_sme)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008504 return wpa_driver_nl80211_sta_remove(bss, addr, 0, reason);
Dmitry Shmidt04949592012-07-19 12:16:46 -07008505
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008506 memset(&mgmt, 0, sizeof(mgmt));
8507 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
8508 WLAN_FC_STYPE_DISASSOC);
8509 memcpy(mgmt.da, addr, ETH_ALEN);
8510 memcpy(mgmt.sa, own_addr, ETH_ALEN);
8511 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
8512 mgmt.u.disassoc.reason_code = host_to_le16(reason);
8513 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
8514 IEEE80211_HDRLEN +
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008515 sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008516 0, NULL, 0, 0, -1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008517}
8518
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008519
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008520static void dump_ifidx(struct wpa_driver_nl80211_data *drv)
8521{
8522 char buf[200], *pos, *end;
8523 int i, res;
8524
8525 pos = buf;
8526 end = pos + sizeof(buf);
8527
8528 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07008529 if (!drv->if_indices[i].ifindex)
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008530 continue;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008531 res = os_snprintf(pos, end - pos, " %d(%d)",
Hai Shalom81f62d82019-07-22 12:10:00 -07008532 drv->if_indices[i].ifindex,
8533 drv->if_indices[i].reason);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008534 if (os_snprintf_error(end - pos, res))
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008535 break;
8536 pos += res;
8537 }
8538 *pos = '\0';
8539
8540 wpa_printf(MSG_DEBUG, "nl80211: if_indices[%d]:%s",
8541 drv->num_if_indices, buf);
8542}
8543
8544
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008545static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
8546 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008547{
8548 int i;
Hai Shalom81f62d82019-07-22 12:10:00 -07008549 struct drv_nl80211_if_info *old;
Jouni Malinen75ecf522011-06-27 15:19:46 -07008550
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008551 wpa_printf(MSG_DEBUG,
8552 "nl80211: Add own interface ifindex %d (ifidx_reason %d)",
8553 ifidx, ifidx_reason);
8554 if (have_ifidx(drv, ifidx, ifidx_reason)) {
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008555 wpa_printf(MSG_DEBUG, "nl80211: ifindex %d already in the list",
8556 ifidx);
8557 return;
8558 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07008559 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07008560 if (drv->if_indices[i].ifindex == 0) {
8561 drv->if_indices[i].ifindex = ifidx;
8562 drv->if_indices[i].reason = ifidx_reason;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008563 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008564 return;
8565 }
8566 }
8567
8568 if (drv->if_indices != drv->default_if_indices)
8569 old = drv->if_indices;
8570 else
8571 old = NULL;
8572
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008573 drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
Hai Shalom81f62d82019-07-22 12:10:00 -07008574 sizeof(*old));
Jouni Malinen75ecf522011-06-27 15:19:46 -07008575 if (!drv->if_indices) {
8576 if (!old)
8577 drv->if_indices = drv->default_if_indices;
8578 else
8579 drv->if_indices = old;
8580 wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
8581 "interfaces");
8582 wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
8583 return;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008584 }
8585 if (!old)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008586 os_memcpy(drv->if_indices, drv->default_if_indices,
8587 sizeof(drv->default_if_indices));
Hai Shalom81f62d82019-07-22 12:10:00 -07008588 drv->if_indices[drv->num_if_indices].ifindex = ifidx;
8589 drv->if_indices[drv->num_if_indices].reason = ifidx_reason;
Jouni Malinen75ecf522011-06-27 15:19:46 -07008590 drv->num_if_indices++;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008591 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008592}
8593
8594
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008595static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
8596 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008597{
8598 int i;
8599
8600 for (i = 0; i < drv->num_if_indices; i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07008601 if ((drv->if_indices[i].ifindex == ifidx ||
8602 ifidx == IFIDX_ANY) &&
8603 (drv->if_indices[i].reason == ifidx_reason ||
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008604 ifidx_reason == IFIDX_ANY)) {
Hai Shalom81f62d82019-07-22 12:10:00 -07008605 drv->if_indices[i].ifindex = 0;
8606 drv->if_indices[i].reason = 0;
Jouni Malinen75ecf522011-06-27 15:19:46 -07008607 break;
8608 }
8609 }
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07008610 dump_ifidx(drv);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008611}
8612
8613
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008614static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
8615 int ifidx_reason)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008616{
8617 int i;
8618
8619 for (i = 0; i < drv->num_if_indices; i++)
Hai Shalom81f62d82019-07-22 12:10:00 -07008620 if (drv->if_indices[i].ifindex == ifidx &&
8621 (drv->if_indices[i].reason == ifidx_reason ||
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008622 ifidx_reason == IFIDX_ANY))
Jouni Malinen75ecf522011-06-27 15:19:46 -07008623 return 1;
8624
8625 return 0;
8626}
8627
8628
8629static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
Dmitry Shmidt7832adb2014-04-29 10:53:02 -07008630 const char *bridge_ifname, char *ifname_wds)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008631{
8632 struct i802_bss *bss = priv;
8633 struct wpa_driver_nl80211_data *drv = bss->drv;
8634 char name[IFNAMSIZ + 1];
Roshan Pius3a1667e2018-07-03 15:17:14 -07008635 union wpa_event_data event;
Sunil Ravic0f5d412024-09-11 22:12:49 +00008636 bool add_br = false;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08008637 int ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -07008638
Hai Shalom39ba6fc2019-01-22 12:40:38 -08008639 ret = os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
8640 if (ret >= (int) sizeof(name))
8641 wpa_printf(MSG_WARNING,
8642 "nl80211: WDS interface name was truncated");
8643 else if (ret < 0)
8644 return ret;
8645
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07008646 if (ifname_wds)
8647 os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
8648
Jouni Malinen75ecf522011-06-27 15:19:46 -07008649 wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
8650 " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
8651 if (val) {
8652 if (!if_nametoindex(name)) {
8653 if (nl80211_create_iface(drv, name,
8654 NL80211_IFTYPE_AP_VLAN,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008655 bss->addr, 1, NULL, NULL, 0) <
8656 0)
Jouni Malinen75ecf522011-06-27 15:19:46 -07008657 return -1;
Sunil Ravic0f5d412024-09-11 22:12:49 +00008658
8659 if (bridge_ifname)
8660 add_br = true;
Roshan Pius3a1667e2018-07-03 15:17:14 -07008661
8662 os_memset(&event, 0, sizeof(event));
8663 event.wds_sta_interface.sta_addr = addr;
8664 event.wds_sta_interface.ifname = name;
8665 event.wds_sta_interface.istatus = INTERFACE_ADDED;
Hai Shalomce48b4a2018-09-05 11:41:35 -07008666 wpa_supplicant_event(bss->ctx,
Roshan Pius3a1667e2018-07-03 15:17:14 -07008667 EVENT_WDS_STA_INTERFACE_STATUS,
8668 &event);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008669 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008670 if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
8671 wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
8672 "interface %s up", name);
8673 }
Sunil Ravic0f5d412024-09-11 22:12:49 +00008674
8675 if (add_br &&
8676 linux_br_add_if(drv->global->ioctl_sock,
8677 bridge_ifname, name) < 0)
8678 return -1;
8679
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008680 return i802_set_sta_vlan(priv, addr, name, 0,
8681 NL80211_DRV_LINK_ID_NA);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008682 } else {
Hai Shalom74f70d42019-02-11 14:42:39 -08008683 if (bridge_ifname &&
8684 linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
8685 name) < 0)
8686 wpa_printf(MSG_INFO,
8687 "nl80211: Failed to remove interface %s from bridge %s: %s",
8688 name, bridge_ifname, strerror(errno));
Dmitry Shmidtaa532512012-09-24 10:35:31 -07008689
Sunil Ravi2a14cf12023-11-21 00:54:38 +00008690 i802_set_sta_vlan(priv, addr, bss->ifname, 0,
8691 NL80211_DRV_LINK_ID_NA);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08008692 nl80211_remove_iface(drv, if_nametoindex(name));
Roshan Pius3a1667e2018-07-03 15:17:14 -07008693 os_memset(&event, 0, sizeof(event));
8694 event.wds_sta_interface.sta_addr = addr;
8695 event.wds_sta_interface.ifname = name;
8696 event.wds_sta_interface.istatus = INTERFACE_REMOVED;
Hai Shalomce48b4a2018-09-05 11:41:35 -07008697 wpa_supplicant_event(bss->ctx, EVENT_WDS_STA_INTERFACE_STATUS,
Roshan Pius3a1667e2018-07-03 15:17:14 -07008698 &event);
Dmitry Shmidta38abf92014-03-06 13:38:44 -08008699 return 0;
Jouni Malinen75ecf522011-06-27 15:19:46 -07008700 }
8701}
8702
8703
8704static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
8705{
8706 struct wpa_driver_nl80211_data *drv = eloop_ctx;
8707 struct sockaddr_ll lladdr;
8708 unsigned char buf[3000];
8709 int len;
8710 socklen_t fromlen = sizeof(lladdr);
8711
8712 len = recvfrom(sock, buf, sizeof(buf), 0,
8713 (struct sockaddr *)&lladdr, &fromlen);
8714 if (len < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008715 wpa_printf(MSG_ERROR, "nl80211: EAPOL recv failed: %s",
8716 strerror(errno));
Jouni Malinen75ecf522011-06-27 15:19:46 -07008717 return;
8718 }
8719
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008720 if (have_ifidx(drv, lladdr.sll_ifindex, IFIDX_ANY))
Jouni Malinen75ecf522011-06-27 15:19:46 -07008721 drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
8722}
8723
8724
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008725static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
8726 struct i802_bss *bss,
8727 const char *brname, const char *ifname)
8728{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008729 int br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008730 char in_br[IFNAMSIZ];
8731
8732 os_strlcpy(bss->brname, brname, IFNAMSIZ);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008733 br_ifindex = if_nametoindex(brname);
8734 if (br_ifindex == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008735 /*
8736 * Bridge was configured, but the bridge device does
8737 * not exist. Try to add it now.
8738 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008739 if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008740 wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
8741 "bridge interface %s: %s",
8742 brname, strerror(errno));
8743 return -1;
8744 }
8745 bss->added_bridge = 1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008746 br_ifindex = if_nametoindex(brname);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008747 add_ifidx(drv, br_ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008748 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008749 bss->br_ifindex = br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008750
8751 if (linux_br_get(in_br, ifname) == 0) {
Hai Shalomc9e41a12018-07-31 14:41:42 -07008752 if (os_strcmp(in_br, brname) == 0) {
8753 bss->already_in_bridge = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008754 return 0; /* already in the bridge */
Hai Shalomc9e41a12018-07-31 14:41:42 -07008755 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008756
8757 wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
8758 "bridge %s", ifname, in_br);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008759 if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
8760 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008761 wpa_printf(MSG_ERROR, "nl80211: Failed to "
8762 "remove interface %s from bridge "
8763 "%s: %s",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07008764 ifname, in_br, strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008765 return -1;
8766 }
8767 }
8768
8769 wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
8770 ifname, brname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008771 if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008772 wpa_printf(MSG_WARNING,
8773 "nl80211: Failed to add interface %s into bridge %s: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008774 ifname, brname, strerror(errno));
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08008775 /* Try to continue without the interface being in a bridge. This
8776 * may be needed for some cases, e.g., with Open vSwitch, where
8777 * an external component will need to handle bridge
8778 * configuration. */
8779 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008780 }
8781 bss->added_if_into_bridge = 1;
8782
8783 return 0;
8784}
8785
8786
8787static void *i802_init(struct hostapd_data *hapd,
8788 struct wpa_init_params *params)
8789{
8790 struct wpa_driver_nl80211_data *drv;
8791 struct i802_bss *bss;
8792 size_t i;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008793 char master_ifname[IFNAMSIZ];
8794 int ifindex, br_ifindex = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008795 int br_added = 0;
8796
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08008797 bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
8798 params->global_priv, 1,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008799 params->bssid, params->driver_params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008800 if (bss == NULL)
8801 return NULL;
8802
8803 drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008804
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008805 if (linux_br_get(master_ifname, params->ifname) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008806 wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008807 params->ifname, master_ifname);
8808 br_ifindex = if_nametoindex(master_ifname);
8809 os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
8810 } else if ((params->num_bridge == 0 || !params->bridge[0]) &&
8811 linux_master_get(master_ifname, params->ifname) == 0) {
8812 wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in master %s",
8813 params->ifname, master_ifname);
8814 /* start listening for EAPOL on the master interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008815 add_ifidx(drv, if_nametoindex(master_ifname), drv->ifindex);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08008816
8817 /* check if master itself is under bridge */
8818 if (linux_br_get(master_ifname, master_ifname) == 0) {
8819 wpa_printf(MSG_DEBUG, "nl80211: which is in bridge %s",
8820 master_ifname);
8821 br_ifindex = if_nametoindex(master_ifname);
8822 os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
8823 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008824 } else {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008825 master_ifname[0] = '\0';
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008826 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008827
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008828 bss->br_ifindex = br_ifindex;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008829
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008830 for (i = 0; i < params->num_bridge; i++) {
8831 if (params->bridge[i]) {
8832 ifindex = if_nametoindex(params->bridge[i]);
8833 if (ifindex)
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008834 add_ifidx(drv, ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008835 if (ifindex == br_ifindex)
8836 br_added = 1;
8837 }
8838 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008839
8840 /* start listening for EAPOL on the default AP interface */
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008841 add_ifidx(drv, drv->ifindex, IFIDX_ANY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008842
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008843 if (params->num_bridge && params->bridge[0]) {
8844 if (i802_check_bridge(drv, bss, params->bridge[0],
8845 params->ifname) < 0)
8846 goto failed;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008847 if (os_strcmp(params->bridge[0], master_ifname) != 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008848 br_added = 1;
8849 }
8850
8851 if (!br_added && br_ifindex &&
8852 (params->num_bridge == 0 || !params->bridge[0]))
Dmitry Shmidt9c175262016-03-03 10:20:07 -08008853 add_ifidx(drv, br_ifindex, drv->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008854
Hai Shalomc9e41a12018-07-31 14:41:42 -07008855 if (bss->added_if_into_bridge || bss->already_in_bridge) {
Hai Shalomfdcde762020-04-02 11:19:20 -07008856 int err;
8857
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07008858 drv->rtnl_sk = nl_socket_alloc();
8859 if (drv->rtnl_sk == NULL) {
8860 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
8861 goto failed;
8862 }
8863
Hai Shalomfdcde762020-04-02 11:19:20 -07008864 err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE);
8865 if (err) {
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07008866 wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -07008867 nl_geterror(err));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07008868 goto failed;
8869 }
8870 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07008871
Hai Shalomb755a2a2020-04-23 21:49:02 -07008872 if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) {
8873 wpa_printf(MSG_DEBUG,
8874 "nl80211: Do not open EAPOL RX socket - using control port for RX");
8875 goto skip_eapol_sock;
8876 }
8877
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008878 drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
8879 if (drv->eapol_sock < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008880 wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
8881 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008882 goto failed;
8883 }
8884
8885 if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
8886 {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07008887 wpa_printf(MSG_INFO, "nl80211: Could not register read socket for eapol");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008888 goto failed;
8889 }
Hai Shalomb755a2a2020-04-23 21:49:02 -07008890skip_eapol_sock:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008891
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008892 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
8893 params->own_addr))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008894 goto failed;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07008895 os_memcpy(drv->perm_addr, params->own_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008896
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008897 memcpy(bss->addr, params->own_addr, ETH_ALEN);
8898
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008899 return bss;
8900
8901failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008902 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008903 return NULL;
8904}
8905
8906
8907static void i802_deinit(void *priv)
8908{
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008909 struct i802_bss *bss = priv;
8910 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008911}
8912
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008913
8914static enum nl80211_iftype wpa_driver_nl80211_if_type(
8915 enum wpa_driver_if_type type)
8916{
8917 switch (type) {
8918 case WPA_IF_STATION:
8919 return NL80211_IFTYPE_STATION;
8920 case WPA_IF_P2P_CLIENT:
8921 case WPA_IF_P2P_GROUP:
8922 return NL80211_IFTYPE_P2P_CLIENT;
8923 case WPA_IF_AP_VLAN:
8924 return NL80211_IFTYPE_AP_VLAN;
8925 case WPA_IF_AP_BSS:
8926 return NL80211_IFTYPE_AP;
8927 case WPA_IF_P2P_GO:
8928 return NL80211_IFTYPE_P2P_GO;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008929 case WPA_IF_P2P_DEVICE:
8930 return NL80211_IFTYPE_P2P_DEVICE;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008931 case WPA_IF_MESH:
8932 return NL80211_IFTYPE_MESH_POINT;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08008933 default:
8934 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008935 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008936}
8937
8938
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008939static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
8940{
8941 struct wpa_driver_nl80211_data *drv;
8942 dl_list_for_each(drv, &global->interfaces,
8943 struct wpa_driver_nl80211_data, list) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00008944 if (ether_addr_equal(addr, drv->first_bss->addr))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008945 return 1;
8946 }
8947 return 0;
8948}
8949
8950
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008951static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008952{
8953 unsigned int idx;
8954
8955 if (!drv->global)
8956 return -1;
8957
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008958 os_memcpy(new_addr, drv->first_bss->addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008959 for (idx = 0; idx < 64; idx++) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08008960 new_addr[0] = drv->first_bss->addr[0] | 0x02;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008961 new_addr[0] ^= idx << 2;
8962 if (!nl80211_addr_in_use(drv->global, new_addr))
8963 break;
8964 }
8965 if (idx == 64)
8966 return -1;
8967
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08008968 wpa_printf(MSG_DEBUG, "nl80211: Assigned new virtual interface address "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008969 MACSTR, MAC2STR(new_addr));
8970
8971 return 0;
8972}
8973
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008974
Dmitry Shmidt34af3062013-07-11 10:46:32 -07008975struct wdev_info {
8976 u64 wdev_id;
8977 int wdev_id_set;
8978 u8 macaddr[ETH_ALEN];
8979};
8980
8981static int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
8982{
8983 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8984 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8985 struct wdev_info *wi = arg;
8986
8987 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8988 genlmsg_attrlen(gnlh, 0), NULL);
8989 if (tb[NL80211_ATTR_WDEV]) {
8990 wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
8991 wi->wdev_id_set = 1;
8992 }
8993
8994 if (tb[NL80211_ATTR_MAC])
8995 os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
8996 ETH_ALEN);
8997
8998 return NL_SKIP;
8999}
9000
9001
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009002static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
9003 const char *ifname, const u8 *addr,
9004 void *bss_ctx, void **drv_priv,
9005 char *force_ifname, u8 *if_addr,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009006 const char *bridge, int use_existing,
9007 int setup_ap)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009008{
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009009 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009010 struct i802_bss *bss = priv;
9011 struct wpa_driver_nl80211_data *drv = bss->drv;
9012 int ifidx;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009013 int added = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009014
9015 if (addr)
9016 os_memcpy(if_addr, addr, ETH_ALEN);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009017 nlmode = wpa_driver_nl80211_if_type(type);
9018 if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
9019 struct wdev_info p2pdev_info;
9020
9021 os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
9022 ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
9023 0, nl80211_wdev_handler,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009024 &p2pdev_info, use_existing);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009025 if (!p2pdev_info.wdev_id_set || ifidx != 0) {
9026 wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
9027 ifname);
9028 return -1;
9029 }
9030
9031 drv->global->if_add_wdevid = p2pdev_info.wdev_id;
9032 drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
Mir Ali8a8f1002020-10-06 22:41:40 +05309033 if (!is_zero_ether_addr(p2pdev_info.macaddr)) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009034 os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
Mir Ali8a8f1002020-10-06 22:41:40 +05309035 os_memcpy(drv->global->p2p_perm_addr, p2pdev_info.macaddr, ETH_ALEN);
9036 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009037 wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
9038 ifname,
9039 (long long unsigned int) p2pdev_info.wdev_id);
9040 } else {
9041 ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009042 0, NULL, NULL, use_existing);
9043 if (use_existing && ifidx == -ENFILE) {
9044 added = 0;
9045 ifidx = if_nametoindex(ifname);
9046 } else if (ifidx < 0) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009047 return -1;
9048 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009049 }
9050
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009051 if (!addr) {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07009052 if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009053 os_memcpy(if_addr, bss->addr, ETH_ALEN);
9054 else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07009055 ifname, if_addr) < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009056 if (added)
9057 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009058 return -1;
9059 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009060 }
9061
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009062 if (!addr &&
9063 (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07009064 type == WPA_IF_P2P_GO || type == WPA_IF_MESH ||
Sunil Ravi77d572f2023-01-17 23:58:31 +00009065 type == WPA_IF_STATION || type == WPA_IF_AP_BSS)) {
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07009066 /* Enforce unique address */
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009067 u8 new_addr[ETH_ALEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009068
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009069 if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009070 new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07009071 if (added)
9072 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009073 return -1;
9074 }
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009075 if (nl80211_addr_in_use(drv->global, new_addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009076 wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07009077 "for interface %s type %d", ifname, type);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009078 if (nl80211_vif_addr(drv, new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07009079 if (added)
9080 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009081 return -1;
9082 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009083 if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009084 new_addr) < 0) {
Dmitry Shmidt71757432014-06-02 13:50:35 -07009085 if (added)
9086 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009087 return -1;
9088 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009089 }
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07009090 os_memcpy(if_addr, new_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009091 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009092
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009093 if (type == WPA_IF_AP_BSS && setup_ap) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07009094 struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
Sunil Ravi036cec52023-03-29 11:35:17 -07009095
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07009096 if (new_bss == NULL) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009097 if (added)
9098 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07009099 return -1;
9100 }
9101
9102 if (bridge &&
9103 i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
9104 wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
9105 "interface %s to a bridge %s",
9106 ifname, bridge);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009107 if (added)
9108 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07009109 os_free(new_bss);
9110 return -1;
9111 }
9112
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009113 if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
9114 {
Dmitry Shmidt71757432014-06-02 13:50:35 -07009115 if (added)
9116 nl80211_remove_iface(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009117 os_free(new_bss);
9118 return -1;
9119 }
9120 os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009121 os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009122 new_bss->ifindex = ifidx;
9123 new_bss->drv = drv;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009124 new_bss->next = drv->first_bss->next;
Sunil Ravi036cec52023-03-29 11:35:17 -07009125 new_bss->flink = &new_bss->links[0];
Sunil Ravi99c035e2024-07-12 01:42:03 +00009126 new_bss->valid_links = 0;
Sunil Ravi036cec52023-03-29 11:35:17 -07009127 os_memcpy(new_bss->flink->addr, new_bss->addr, ETH_ALEN);
9128
9129 new_bss->flink->freq = drv->first_bss->flink->freq;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08009130 new_bss->ctx = bss_ctx;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009131 new_bss->added_if = added;
9132 drv->first_bss->next = new_bss;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009133 if (drv_priv)
9134 *drv_priv = new_bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009135 nl80211_init_bss(new_bss);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009136
9137 /* Subscribe management frames for this WPA_IF_AP_BSS */
9138 if (nl80211_setup_ap(new_bss))
9139 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009140 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009141
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009142 if (drv->global)
9143 drv->global->if_add_ifindex = ifidx;
9144
Dmitry Shmidt43cb5782014-06-16 16:23:22 -07009145 /*
9146 * Some virtual interfaces need to process EAPOL packets and events on
9147 * the parent interface. This is used mainly with hostapd.
9148 */
9149 if (ifidx > 0 &&
9150 (drv->hostapd ||
9151 nlmode == NL80211_IFTYPE_AP_VLAN ||
9152 nlmode == NL80211_IFTYPE_WDS ||
9153 nlmode == NL80211_IFTYPE_MONITOR))
Dmitry Shmidt9c175262016-03-03 10:20:07 -08009154 add_ifidx(drv, ifidx, IFIDX_ANY);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07009155
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009156 return 0;
9157}
9158
9159
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009160static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009161 enum wpa_driver_if_type type,
9162 const char *ifname)
9163{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009164 struct wpa_driver_nl80211_data *drv = bss->drv;
9165 int ifindex = if_nametoindex(ifname);
9166
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009167 wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
9168 __func__, type, ifname, ifindex, bss->added_if);
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08009169 if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
Dmitry Shmidt051af732013-10-22 13:52:46 -07009170 nl80211_remove_iface(drv, ifindex);
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07009171 else if (ifindex > 0 && !bss->added_if) {
9172 struct wpa_driver_nl80211_data *drv2;
9173 dl_list_for_each(drv2, &drv->global->interfaces,
Dmitry Shmidt9c175262016-03-03 10:20:07 -08009174 struct wpa_driver_nl80211_data, list) {
9175 del_ifidx(drv2, ifindex, IFIDX_ANY);
9176 del_ifidx(drv2, IFIDX_ANY, ifindex);
9177 }
Dmitry Shmidt76cd2cc2014-05-27 12:56:04 -07009178 }
Dmitry Shmidtaa532512012-09-24 10:35:31 -07009179
Dmitry Shmidtaa532512012-09-24 10:35:31 -07009180 if (type != WPA_IF_AP_BSS)
9181 return 0;
9182
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009183 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009184 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
9185 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009186 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
9187 "interface %s from bridge %s: %s",
9188 bss->ifname, bss->brname, strerror(errno));
9189 }
9190 if (bss->added_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009191 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009192 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
9193 "bridge %s: %s",
9194 bss->brname, strerror(errno));
9195 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009196
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009197 if (bss != drv->first_bss) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009198 struct i802_bss *tbss;
9199
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009200 wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it");
9201 for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009202 if (tbss->next == bss) {
9203 tbss->next = bss->next;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009204 /* Unsubscribe management frames */
9205 nl80211_teardown_ap(bss);
Sunil Ravi99c035e2024-07-12 01:42:03 +00009206 nl80211_remove_links(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009207 nl80211_destroy_bss(bss);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07009208 if (!bss->added_if)
9209 i802_set_iface_flags(bss, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009210 os_free(bss);
9211 bss = NULL;
9212 break;
9213 }
9214 }
9215 if (bss)
9216 wpa_printf(MSG_INFO, "nl80211: %s - could not find "
9217 "BSS %p in the list", __func__, bss);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009218 } else {
9219 wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
9220 nl80211_teardown_ap(bss);
Sunil Ravi99c035e2024-07-12 01:42:03 +00009221 nl80211_remove_links(bss);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009222 if (!bss->added_if && !drv->first_bss->next)
Sunil Ravi036cec52023-03-29 11:35:17 -07009223 wpa_driver_nl80211_del_beacon_all(bss);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009224 nl80211_destroy_bss(bss);
9225 if (!bss->added_if)
9226 i802_set_iface_flags(bss, 0);
9227 if (drv->first_bss->next) {
9228 drv->first_bss = drv->first_bss->next;
9229 drv->ctx = drv->first_bss->ctx;
Sunil Ravi99c035e2024-07-12 01:42:03 +00009230 drv->ifindex = drv->first_bss->ifindex;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08009231 os_free(bss);
9232 } else {
9233 wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
9234 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009235 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009236
9237 return 0;
9238}
9239
9240
9241static int cookie_handler(struct nl_msg *msg, void *arg)
9242{
9243 struct nlattr *tb[NL80211_ATTR_MAX + 1];
9244 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
9245 u64 *cookie = arg;
9246 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
9247 genlmsg_attrlen(gnlh, 0), NULL);
9248 if (tb[NL80211_ATTR_COOKIE])
9249 *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
9250 return NL_SKIP;
9251}
9252
9253
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009254static int nl80211_send_frame_cmd(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009255 unsigned int freq, unsigned int wait,
9256 const u8 *buf, size_t buf_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07009257 int save_cookie, int no_cck, int no_ack,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009258 int offchanok, const u16 *csa_offs,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009259 size_t csa_offs_len, int link_id)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009260{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009261 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009262 struct nl_msg *msg;
9263 u64 cookie;
9264 int ret = -1;
9265
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07009266 wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
Dmitry Shmidt04949592012-07-19 12:16:46 -07009267 "no_ack=%d offchanok=%d",
9268 freq, wait, no_cck, no_ack, offchanok);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07009269 wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009270
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009271 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME)) ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009272 ((link_id != NL80211_DRV_LINK_ID_NA) &&
9273 nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009274 (freq && nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
9275 (wait && nla_put_u32(msg, NL80211_ATTR_DURATION, wait)) ||
9276 (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
9277 drv->test_use_roc_tx) &&
9278 nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) ||
9279 (no_cck && nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) ||
9280 (no_ack && nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK)) ||
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009281 (csa_offs && nla_put(msg, NL80211_ATTR_CSA_C_OFFSETS_TX,
9282 csa_offs_len * sizeof(u16), csa_offs)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009283 nla_put(msg, NL80211_ATTR_FRAME, buf_len, buf))
9284 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009285
9286 cookie = 0;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009287 ret = send_and_recv_resp(drv, msg, cookie_handler, &cookie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009288 msg = NULL;
9289 if (ret) {
9290 wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07009291 "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
9292 freq, wait);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009293 } else {
9294 wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
9295 "cookie 0x%llx", no_ack ? " (no ACK)" : "",
9296 (long long unsigned int) cookie);
9297
Hai Shalomfdcde762020-04-02 11:19:20 -07009298 if (save_cookie)
9299 drv->send_frame_cookie = no_ack ? (u64) -1 : cookie;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009300
Sunil Ravia04bd252022-05-02 22:54:18 -07009301 if (!wait) {
9302 /* There is no need to store this cookie since there
9303 * is no wait that could be canceled later. */
9304 goto fail;
9305 }
Hai Shalomfdcde762020-04-02 11:19:20 -07009306 if (drv->num_send_frame_cookies == MAX_SEND_FRAME_COOKIES) {
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009307 wpa_printf(MSG_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07009308 "nl80211: Drop oldest pending send frame cookie 0x%llx",
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009309 (long long unsigned int)
Hai Shalomfdcde762020-04-02 11:19:20 -07009310 drv->send_frame_cookies[0]);
9311 os_memmove(&drv->send_frame_cookies[0],
9312 &drv->send_frame_cookies[1],
9313 (MAX_SEND_FRAME_COOKIES - 1) *
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009314 sizeof(u64));
Hai Shalomfdcde762020-04-02 11:19:20 -07009315 drv->num_send_frame_cookies--;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009316 }
Hai Shalomfdcde762020-04-02 11:19:20 -07009317 drv->send_frame_cookies[drv->num_send_frame_cookies] = cookie;
9318 drv->num_send_frame_cookies++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009319 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009320
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009321fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009322 nlmsg_free(msg);
9323 return ret;
9324}
9325
9326
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009327static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
9328 unsigned int freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009329 unsigned int wait_time,
9330 const u8 *dst, const u8 *src,
9331 const u8 *bssid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009332 const u8 *data, size_t data_len,
9333 int no_cck)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009334{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009335 struct wpa_driver_nl80211_data *drv = bss->drv;
9336 int ret = -1;
9337 u8 *buf;
9338 struct ieee80211_hdr *hdr;
Hai Shalomfdcde762020-04-02 11:19:20 -07009339 int offchanok = 1;
9340
Sunil Ravi036cec52023-03-29 11:35:17 -07009341 if (is_ap_interface(drv->nlmode) && (int) freq == bss->flink->freq &&
9342 bss->flink->beacon_set)
Hai Shalomfdcde762020-04-02 11:19:20 -07009343 offchanok = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009344
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009345 if (!freq && is_sta_interface(drv->nlmode))
9346 offchanok = 0;
9347
9348 wpa_printf(MSG_DEBUG,
9349 "nl80211: Send Action frame (ifindex=%d, freq=%u MHz wait=%d ms no_cck=%d offchanok=%d dst="
9350 MACSTR " src=" MACSTR " bssid=" MACSTR ")",
9351 drv->ifindex, freq, wait_time, no_cck, offchanok,
9352 MAC2STR(dst), MAC2STR(src), MAC2STR(bssid));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009353
9354 buf = os_zalloc(24 + data_len);
9355 if (buf == NULL)
9356 return ret;
9357 os_memcpy(buf + 24, data, data_len);
9358 hdr = (struct ieee80211_hdr *) buf;
9359 hdr->frame_control =
9360 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
9361 os_memcpy(hdr->addr1, dst, ETH_ALEN);
9362 os_memcpy(hdr->addr2, src, ETH_ALEN);
9363 os_memcpy(hdr->addr3, bssid, ETH_ALEN);
9364
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009365 if (!ether_addr_equal(bss->addr, src)) {
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08009366 wpa_printf(MSG_DEBUG, "nl80211: Use random TA " MACSTR,
9367 MAC2STR(src));
9368 os_memcpy(bss->rand_addr, src, ETH_ALEN);
9369 } else {
9370 os_memset(bss->rand_addr, 0, ETH_ALEN);
9371 }
9372
Hai Shalom60840252021-02-19 19:02:11 -08009373#ifdef CONFIG_MESH
9374 if (is_mesh_interface(drv->nlmode)) {
9375 struct hostapd_hw_modes *modes;
9376 u16 num_modes, flags;
9377 u8 dfs_domain;
9378 int i;
9379
9380 modes = nl80211_get_hw_feature_data(bss, &num_modes,
9381 &flags, &dfs_domain);
9382 if (dfs_domain != HOSTAPD_DFS_REGION_ETSI &&
Sunil Ravi036cec52023-03-29 11:35:17 -07009383 ieee80211_is_dfs(bss->flink->freq, modes, num_modes))
Hai Shalom60840252021-02-19 19:02:11 -08009384 offchanok = 0;
9385 if (modes) {
9386 for (i = 0; i < num_modes; i++) {
9387 os_free(modes[i].channels);
9388 os_free(modes[i].rates);
9389 }
9390 os_free(modes);
9391 }
9392 }
9393#endif /* CONFIG_MESH */
9394
Dmitry Shmidt56052862013-10-04 10:23:25 -07009395 if (is_ap_interface(drv->nlmode) &&
9396 (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
Sunil Ravi036cec52023-03-29 11:35:17 -07009397 (int) freq == bss->flink->freq || drv->device_ap_sme ||
Dmitry Shmidt56052862013-10-04 10:23:25 -07009398 !drv->use_monitor))
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009399 ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07009400 0, freq, no_cck, offchanok,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00009401 wait_time, NULL, 0, 0, -1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009402 else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009403 ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009404 24 + data_len, 1, no_cck, 0,
9405 offchanok, NULL, 0,
9406 NL80211_DRV_LINK_ID_NA);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009407
9408 os_free(buf);
9409 return ret;
9410}
9411
9412
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009413static void nl80211_frame_wait_cancel(struct i802_bss *bss, u64 cookie)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009414{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009415 struct wpa_driver_nl80211_data *drv = bss->drv;
9416 struct nl_msg *msg;
9417 int ret;
9418
Dmitry Shmidt2f3b8de2013-03-01 09:32:50 -08009419 wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009420 (long long unsigned int) cookie);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009421 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME_WAIT_CANCEL)) ||
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009422 nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009423 nlmsg_free(msg);
9424 return;
9425 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009426
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009427 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009428 if (ret)
9429 wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
9430 "(%s)", ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009431}
9432
9433
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009434static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
9435{
9436 struct i802_bss *bss = priv;
9437 struct wpa_driver_nl80211_data *drv = bss->drv;
9438 unsigned int i;
9439 u64 cookie;
9440
9441 /* Cancel the last pending TX cookie */
Sunil Ravia04bd252022-05-02 22:54:18 -07009442 if (drv->send_frame_cookie != (u64) -1)
9443 nl80211_frame_wait_cancel(bss, drv->send_frame_cookie);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009444
9445 /*
9446 * Cancel the other pending TX cookies, if any. This is needed since
9447 * the driver may keep a list of all pending offchannel TX operations
9448 * and free up the radio only once they have expired or cancelled.
9449 */
Hai Shalomfdcde762020-04-02 11:19:20 -07009450 for (i = drv->num_send_frame_cookies; i > 0; i--) {
9451 cookie = drv->send_frame_cookies[i - 1];
9452 if (cookie != drv->send_frame_cookie)
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009453 nl80211_frame_wait_cancel(bss, cookie);
9454 }
Hai Shalomfdcde762020-04-02 11:19:20 -07009455 drv->num_send_frame_cookies = 0;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009456}
9457
9458
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009459static int nl80211_put_any_link_id(struct nl_msg *msg,
9460 struct driver_sta_mlo_info *mlo,
9461 int freq)
9462{
9463 int i;
9464 int link_id = -1;
9465 int any_valid_link_id = -1;
9466
9467 if (!mlo->valid_links)
9468 return 0;
9469
9470 /* First try to pick a link that uses the same band */
Sunil Ravi99c035e2024-07-12 01:42:03 +00009471 for_each_link(mlo->valid_links, i) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009472 if (any_valid_link_id == -1)
9473 any_valid_link_id = i;
9474
9475 if (is_same_band(freq, mlo->links[i].freq)) {
9476 link_id = i;
9477 break;
9478 }
9479 }
9480
9481 /* Use any valid link ID if no band match was found */
9482 if (link_id == -1)
9483 link_id = any_valid_link_id;
9484
9485 if (link_id == -1) {
9486 wpa_printf(MSG_INFO,
9487 "nl80211: No valid Link ID found for freq %u", freq);
9488 return 0;
9489 }
9490
9491 wpa_printf(MSG_DEBUG, "nl80211: Add Link ID %d", link_id);
9492 return nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id);
9493}
9494
9495
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009496static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
9497 unsigned int duration)
9498{
9499 struct i802_bss *bss = priv;
9500 struct wpa_driver_nl80211_data *drv = bss->drv;
9501 struct nl_msg *msg;
9502 int ret;
9503 u64 cookie;
9504
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009505 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REMAIN_ON_CHANNEL)) ||
9506 nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009507 nla_put_u32(msg, NL80211_ATTR_DURATION, duration) ||
9508 nl80211_put_any_link_id(msg, &drv->sta_mlo_info, freq)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009509 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009510 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009511 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009512
9513 cookie = 0;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009514 ret = send_and_recv_resp(drv, msg, cookie_handler, &cookie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009515 if (ret == 0) {
9516 wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
9517 "0x%llx for freq=%u MHz duration=%u",
9518 (long long unsigned int) cookie, freq, duration);
9519 drv->remain_on_chan_cookie = cookie;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009520 drv->pending_remain_on_chan = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009521 return 0;
9522 }
9523 wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
9524 "(freq=%d duration=%u): %d (%s)",
9525 freq, duration, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009526 return -1;
9527}
9528
9529
9530static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
9531{
9532 struct i802_bss *bss = priv;
9533 struct wpa_driver_nl80211_data *drv = bss->drv;
9534 struct nl_msg *msg;
9535 int ret;
9536
9537 if (!drv->pending_remain_on_chan) {
9538 wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
9539 "to cancel");
9540 return -1;
9541 }
9542
9543 wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
9544 "0x%llx",
9545 (long long unsigned int) drv->remain_on_chan_cookie);
9546
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009547 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
9548 if (!msg ||
9549 nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie)) {
9550 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009551 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009552 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009553
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009554 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009555 if (ret == 0)
9556 return 0;
9557 wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
9558 "%d (%s)", ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009559 return -1;
9560}
9561
9562
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009563static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009564{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009565 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07009566
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009567 if (!report) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009568 if (bss->nl_preq && drv->device_ap_sme &&
Dmitry Shmidt03658832014-08-13 11:03:49 -07009569 is_ap_interface(drv->nlmode) && !bss->in_deinit &&
9570 !bss->static_ap) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009571 /*
9572 * Do not disable Probe Request reporting that was
9573 * enabled in nl80211_setup_ap().
9574 */
9575 wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
9576 "Probe Request reporting nl_preq=%p while "
9577 "in AP mode", bss->nl_preq);
9578 } else if (bss->nl_preq) {
9579 wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
9580 "reporting nl_preq=%p", bss->nl_preq);
Roshan Pius3a1667e2018-07-03 15:17:14 -07009581 nl80211_destroy_eloop_handle(&bss->nl_preq, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009582 }
9583 return 0;
9584 }
9585
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009586 if (bss->nl_preq) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009587 wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009588 "already on! nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009589 return 0;
9590 }
9591
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009592 bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
9593 if (bss->nl_preq == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009594 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009595 wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
9596 "reporting nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009597
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009598 if (nl80211_register_frame(bss, bss->nl_preq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009599 (WLAN_FC_TYPE_MGMT << 2) |
9600 (WLAN_FC_STYPE_PROBE_REQ << 4),
Hai Shalome21d4e82020-04-29 16:34:06 -07009601 NULL, 0, false) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009602 goto out_err;
Dmitry Shmidt497c1d52011-07-21 15:19:46 -07009603
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07009604 nl80211_register_eloop_read(&bss->nl_preq,
9605 wpa_driver_nl80211_event_receive,
Roshan Pius3a1667e2018-07-03 15:17:14 -07009606 bss->nl_cb, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009607
9608 return 0;
9609
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009610 out_err:
9611 nl_destroy_handles(&bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009612 return -1;
9613}
9614
9615
9616static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
9617 int ifindex, int disabled)
9618{
9619 struct nl_msg *msg;
9620 struct nlattr *bands, *band;
9621 int ret;
9622
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009623 wpa_printf(MSG_DEBUG,
9624 "nl80211: NL80211_CMD_SET_TX_BITRATE_MASK (ifindex=%d %s)",
9625 ifindex, disabled ? "NL80211_TXRATE_LEGACY=OFDM-only" :
9626 "no NL80211_TXRATE_LEGACY constraint");
9627
9628 msg = nl80211_ifindex_msg(drv, ifindex, 0,
9629 NL80211_CMD_SET_TX_BITRATE_MASK);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009630 if (!msg)
9631 return -1;
9632
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009633 bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
9634 if (!bands)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009635 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009636
9637 /*
9638 * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
9639 * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
9640 * rates. All 5 GHz rates are left enabled.
9641 */
9642 band = nla_nest_start(msg, NL80211_BAND_2GHZ);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009643 if (!band ||
9644 (disabled && nla_put(msg, NL80211_TXRATE_LEGACY, 8,
9645 "\x0c\x12\x18\x24\x30\x48\x60\x6c")))
9646 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009647 nla_nest_end(msg, band);
9648
9649 nla_nest_end(msg, bands);
9650
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009651 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009652 if (ret) {
9653 wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
9654 "(%s)", ret, strerror(-ret));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07009655 } else
9656 drv->disabled_11b_rates = disabled;
9657
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009658 return ret;
9659
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009660fail:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009661 nlmsg_free(msg);
9662 return -1;
9663}
9664
9665
Sunil Ravic0f5d412024-09-11 22:12:49 +00009666int nl80211_remove_link(struct i802_bss *bss, int link_id)
Sunil Raviaf399a82024-05-05 20:56:55 +00009667{
Sunil Ravi88611412024-06-28 17:34:56 +00009668 struct wpa_driver_nl80211_data *drv = bss->drv;
Sunil Ravi99c035e2024-07-12 01:42:03 +00009669 struct i802_link *link;
Sunil Ravi88611412024-06-28 17:34:56 +00009670 struct nl_msg *msg;
Sunil Ravi99c035e2024-07-12 01:42:03 +00009671 size_t i;
9672 int ret;
Sunil Ravic0f5d412024-09-11 22:12:49 +00009673 u8 link_addr[ETH_ALEN];
Sunil Ravi99c035e2024-07-12 01:42:03 +00009674
9675 wpa_printf(MSG_DEBUG, "nl80211: Remove link (ifindex=%d link_id=%u)",
9676 bss->ifindex, link_id);
9677
9678 if (!(bss->valid_links & BIT(link_id))) {
9679 wpa_printf(MSG_DEBUG,
9680 "nl80211: MLD: remove link: Link not found");
9681 return -1;
9682 }
9683
9684 link = &bss->links[link_id];
9685
9686 wpa_driver_nl80211_del_beacon(bss, link_id);
9687
Sunil Ravic0f5d412024-09-11 22:12:49 +00009688 os_memcpy(link_addr, link->addr, ETH_ALEN);
Sunil Ravi99c035e2024-07-12 01:42:03 +00009689 /* First remove the link locally */
9690 bss->valid_links &= ~BIT(link_id);
9691 os_memset(link->addr, 0, ETH_ALEN);
9692
9693 /* Choose new deflink if we are removing that link */
9694 if (bss->flink == link) {
9695 for_each_link_default(bss->valid_links, i, 0) {
9696 bss->flink = &bss->links[i];
9697 break;
9698 }
9699 }
9700
9701 /* If this was the last link, reset default link */
9702 if (!bss->valid_links) {
9703 /* TODO: Does keeping freq/bandwidth make sense? */
9704 if (bss->flink != link)
9705 os_memcpy(bss->flink, link, sizeof(*link));
9706
9707 os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN);
9708 }
9709
9710 /* Remove the link from the kernel */
9711 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_REMOVE_LINK);
9712 if (!msg ||
9713 nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) {
9714 nlmsg_free(msg);
9715 wpa_printf(MSG_ERROR,
9716 "nl80211: remove link (%d) failed", link_id);
9717 return -1;
9718 }
9719
9720 ret = send_and_recv_cmd(drv, msg);
9721 if (ret)
9722 wpa_printf(MSG_ERROR,
9723 "nl80211: remove link (%d) failed. ret=%d (%s)",
9724 link_id, ret, strerror(-ret));
9725
Sunil Ravic0f5d412024-09-11 22:12:49 +00009726 if (drv->rtnl_sk)
9727 rtnl_neigh_delete_fdb_entry(bss, link_addr, true);
9728
Sunil Ravi99c035e2024-07-12 01:42:03 +00009729 return ret;
9730}
9731
9732
9733static void nl80211_remove_links(struct i802_bss *bss)
9734{
Sunil Ravi036cec52023-03-29 11:35:17 -07009735 int ret;
9736 u8 link_id;
9737
Sunil Ravi99c035e2024-07-12 01:42:03 +00009738 for_each_link(bss->valid_links, link_id) {
9739 ret = nl80211_remove_link(bss, link_id);
9740 if (ret)
9741 break;
Sunil Ravi88611412024-06-28 17:34:56 +00009742 }
Sunil Ravi99c035e2024-07-12 01:42:03 +00009743
9744 if (bss->flink)
9745 os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN);
Sunil Ravi036cec52023-03-29 11:35:17 -07009746}
9747
9748
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009749static int wpa_driver_nl80211_deinit_ap(void *priv)
9750{
9751 struct i802_bss *bss = priv;
9752 struct wpa_driver_nl80211_data *drv = bss->drv;
Sunil Ravi036cec52023-03-29 11:35:17 -07009753
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009754 if (!is_ap_interface(drv->nlmode))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009755 return -1;
Sunil Ravi036cec52023-03-29 11:35:17 -07009756
9757 /* Stop beaconing */
Sunil Ravi99c035e2024-07-12 01:42:03 +00009758 wpa_driver_nl80211_del_beacon(bss, NL80211_DRV_LINK_ID_NA);
Sunil Ravi036cec52023-03-29 11:35:17 -07009759
9760 nl80211_remove_links(bss);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009761
9762 /*
9763 * If the P2P GO interface was dynamically added, then it is
9764 * possible that the interface change to station is not possible.
9765 */
9766 if (drv->nlmode == NL80211_IFTYPE_P2P_GO && bss->if_dynamic)
9767 return 0;
9768
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009769 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009770}
9771
9772
Sunil Ravi99c035e2024-07-12 01:42:03 +00009773static int wpa_driver_nl80211_stop_ap(void *priv, int link_id)
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009774{
9775 struct i802_bss *bss = priv;
9776 struct wpa_driver_nl80211_data *drv = bss->drv;
Sunil Ravi036cec52023-03-29 11:35:17 -07009777
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009778 if (!is_ap_interface(drv->nlmode))
9779 return -1;
Sunil Ravi036cec52023-03-29 11:35:17 -07009780
Sunil Ravi99c035e2024-07-12 01:42:03 +00009781 if (link_id == -1) {
9782 wpa_driver_nl80211_del_beacon_all(bss);
9783 return 0;
9784 }
Sunil Ravi036cec52023-03-29 11:35:17 -07009785
Sunil Ravi99c035e2024-07-12 01:42:03 +00009786 if (nl80211_link_valid(bss->valid_links, link_id)) {
9787 wpa_driver_nl80211_del_beacon(bss, link_id);
9788 return 0;
9789 }
9790
9791 return -1;
Dmitry Shmidtea69e842013-05-13 14:52:28 -07009792}
9793
9794
Dmitry Shmidt04949592012-07-19 12:16:46 -07009795static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
9796{
9797 struct i802_bss *bss = priv;
9798 struct wpa_driver_nl80211_data *drv = bss->drv;
9799 if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
9800 return -1;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07009801
9802 /*
9803 * If the P2P Client interface was dynamically added, then it is
9804 * possible that the interface change to station is not possible.
9805 */
9806 if (bss->if_dynamic)
9807 return 0;
9808
Dmitry Shmidt04949592012-07-19 12:16:46 -07009809 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
9810}
9811
9812
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009813static void wpa_driver_nl80211_resume(void *priv)
9814{
9815 struct i802_bss *bss = priv;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009816 enum nl80211_iftype nlmode = nl80211_get_ifmode(bss);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009817
9818 if (i802_set_iface_flags(bss, 1))
9819 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event");
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08009820
9821 if (is_p2p_net_interface(nlmode))
9822 nl80211_disable_11b_rates(bss->drv, bss->drv->ifindex, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009823}
9824
9825
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009826static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
9827{
9828 struct i802_bss *bss = priv;
9829 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07009830 struct nl_msg *msg;
9831 struct nlattr *cqm;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009832
9833 wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
9834 "hysteresis=%d", threshold, hysteresis);
9835
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009836 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_CQM)) ||
9837 !(cqm = nla_nest_start(msg, NL80211_ATTR_CQM)) ||
9838 nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold) ||
9839 nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis)) {
9840 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009841 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009842 }
Dmitry Shmidt8da800a2013-04-24 12:57:01 -07009843 nla_nest_end(msg, cqm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009844
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009845 return send_and_recv_cmd(drv, msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009846}
9847
9848
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009849static int get_channel_width(struct nl_msg *msg, void *arg)
9850{
9851 struct nlattr *tb[NL80211_ATTR_MAX + 1];
9852 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
9853 struct wpa_signal_info *sig_change = arg;
9854
9855 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
9856 genlmsg_attrlen(gnlh, 0), NULL);
9857
9858 sig_change->center_frq1 = -1;
9859 sig_change->center_frq2 = -1;
9860 sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
9861
9862 if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
9863 sig_change->chanwidth = convert2width(
9864 nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
9865 if (tb[NL80211_ATTR_CENTER_FREQ1])
9866 sig_change->center_frq1 =
9867 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
9868 if (tb[NL80211_ATTR_CENTER_FREQ2])
9869 sig_change->center_frq2 =
9870 nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
9871 }
9872
9873 return NL_SKIP;
9874}
9875
9876
9877static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
9878 struct wpa_signal_info *sig)
9879{
9880 struct nl_msg *msg;
9881
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08009882 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009883 return send_and_recv_resp(drv, msg, get_channel_width, sig);
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009884}
9885
9886
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009887static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
9888{
9889 struct i802_bss *bss = priv;
9890 struct wpa_driver_nl80211_data *drv = bss->drv;
9891 int res;
9892
9893 os_memset(si, 0, sizeof(*si));
Sunil Ravi77d572f2023-01-17 23:58:31 +00009894 res = nl80211_get_link_signal(drv, drv->bssid, &si->data);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009895 if (res) {
9896 if (drv->nlmode != NL80211_IFTYPE_ADHOC &&
9897 drv->nlmode != NL80211_IFTYPE_MESH_POINT)
9898 return res;
Sunil Ravi77d572f2023-01-17 23:58:31 +00009899 si->data.signal = 0;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08009900 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009901
Dmitry Shmidt34af3062013-07-11 10:46:32 -07009902 res = nl80211_get_channel_width(drv, si);
9903 if (res != 0)
9904 return res;
9905
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009906 return nl80211_get_link_noise(drv, si);
9907}
9908
9909
Sunil Ravi89eba102022-09-13 21:04:37 -07009910static int get_links_noise(struct nl_msg *msg, void *arg)
9911{
9912 struct nlattr *tb[NL80211_ATTR_MAX + 1];
9913 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
9914 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
9915 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
9916 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
9917 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
9918 };
9919 struct wpa_mlo_signal_info *mlo_sig = arg;
9920 int i;
9921
9922 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
9923 genlmsg_attrlen(gnlh, 0), NULL);
9924
9925 if (!tb[NL80211_ATTR_SURVEY_INFO]) {
9926 wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
9927 return NL_SKIP;
9928 }
9929
9930 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
9931 tb[NL80211_ATTR_SURVEY_INFO],
9932 survey_policy)) {
9933 wpa_printf(MSG_DEBUG,
9934 "nl80211: Failed to parse nested attributes");
9935 return NL_SKIP;
9936 }
9937
9938 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
9939 return NL_SKIP;
9940
9941 if (!sinfo[NL80211_SURVEY_INFO_NOISE])
9942 return NL_SKIP;
9943
Sunil Ravi99c035e2024-07-12 01:42:03 +00009944 for_each_link(mlo_sig->valid_links, i) {
Sunil Ravi89eba102022-09-13 21:04:37 -07009945 if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
9946 mlo_sig->links[i].frequency)
9947 continue;
9948
9949 mlo_sig->links[i].current_noise =
9950 (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
9951 break;
9952 }
9953
9954 return NL_SKIP;
9955}
9956
9957
9958static int nl80211_get_links_noise(struct wpa_driver_nl80211_data *drv,
9959 struct wpa_mlo_signal_info *mlo_sig)
9960{
9961 struct nl_msg *msg;
9962
9963 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00009964 return send_and_recv_resp(drv, msg, get_links_noise, mlo_sig);
Sunil Ravi89eba102022-09-13 21:04:37 -07009965}
9966
9967
9968static int get_links_channel_width(struct nl_msg *msg, void *arg)
9969{
9970 struct nlattr *tb[NL80211_ATTR_MAX + 1];
9971 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
9972 struct wpa_mlo_signal_info *mlo_sig = arg;
9973 struct nlattr *link;
9974 int rem_links;
9975
9976 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
9977 genlmsg_attrlen(gnlh, 0), NULL);
9978
9979 if (!tb[NL80211_ATTR_MLO_LINKS])
9980 return NL_SKIP;
9981
9982 nla_for_each_nested(link, tb[NL80211_ATTR_MLO_LINKS], rem_links) {
9983 struct nlattr *tb2[NL80211_ATTR_MAX + 1];
9984 int link_id;
9985
9986 nla_parse(tb2, NL80211_ATTR_MAX, nla_data(link), nla_len(link),
9987 NULL);
9988
9989 if (!tb2[NL80211_ATTR_MLO_LINK_ID])
9990 continue;
9991
9992 link_id = nla_get_u8(tb2[NL80211_ATTR_MLO_LINK_ID]);
9993 if (link_id >= MAX_NUM_MLD_LINKS)
9994 continue;
9995
9996 if (!tb2[NL80211_ATTR_CHANNEL_WIDTH])
9997 continue;
9998 mlo_sig->links[link_id].chanwidth = convert2width(
9999 nla_get_u32(tb2[NL80211_ATTR_CHANNEL_WIDTH]));
10000 if (tb2[NL80211_ATTR_CENTER_FREQ1])
10001 mlo_sig->links[link_id].center_frq1 =
10002 nla_get_u32(tb2[NL80211_ATTR_CENTER_FREQ1]);
10003 if (tb2[NL80211_ATTR_CENTER_FREQ2])
10004 mlo_sig->links[link_id].center_frq2 =
10005 nla_get_u32(tb2[NL80211_ATTR_CENTER_FREQ2]);
10006 }
10007
10008 return NL_SKIP;
10009}
10010
10011
10012static int nl80211_get_links_channel_width(struct wpa_driver_nl80211_data *drv,
10013 struct wpa_mlo_signal_info *mlo_sig)
10014{
10015 struct nl_msg *msg;
10016
10017 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
Sunil Ravib0ac25f2024-07-12 01:42:03 +000010018 return send_and_recv_resp(drv, msg, get_links_channel_width, mlo_sig);
Sunil Ravi89eba102022-09-13 21:04:37 -070010019}
10020
10021
10022static int nl80211_mlo_signal_poll(void *priv,
10023 struct wpa_mlo_signal_info *mlo_si)
10024{
10025 struct i802_bss *bss = priv;
10026 struct wpa_driver_nl80211_data *drv = bss->drv;
10027 int res;
10028 int i;
10029
10030 if (drv->nlmode != NL80211_IFTYPE_STATION ||
10031 !drv->sta_mlo_info.valid_links)
10032 return -1;
10033
10034 os_memset(mlo_si, 0, sizeof(*mlo_si));
10035 mlo_si->valid_links = drv->sta_mlo_info.valid_links;
10036
Sunil Ravi99c035e2024-07-12 01:42:03 +000010037 for_each_link(mlo_si->valid_links, i) {
Sunil Ravi89eba102022-09-13 21:04:37 -070010038 res = nl80211_get_link_signal(drv,
10039 drv->sta_mlo_info.links[i].bssid,
Sunil Ravi77d572f2023-01-17 23:58:31 +000010040 &mlo_si->links[i].data);
Sunil Ravi89eba102022-09-13 21:04:37 -070010041 if (res != 0)
10042 return res;
10043
10044 mlo_si->links[i].center_frq1 = -1;
10045 mlo_si->links[i].center_frq2 = -1;
10046 mlo_si->links[i].chanwidth = CHAN_WIDTH_UNKNOWN;
10047 mlo_si->links[i].current_noise = WPA_INVALID_NOISE;
10048 mlo_si->links[i].frequency = drv->sta_mlo_info.links[i].freq;
10049 }
10050
10051 res = nl80211_get_links_channel_width(drv, mlo_si);
10052 if (res != 0)
10053 return res;
10054
10055 return nl80211_get_links_noise(drv, mlo_si);
10056}
10057
10058
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010059static int nl80211_set_param(void *priv, const char *param)
10060{
Dmitry Shmidtaca489e2016-09-28 15:44:14 -070010061 struct i802_bss *bss = priv;
10062 struct wpa_driver_nl80211_data *drv = bss->drv;
10063
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010064 if (param == NULL)
10065 return 0;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -080010066 wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010067
10068#ifdef CONFIG_P2P
10069 if (os_strstr(param, "use_p2p_group_interface=1")) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010070 wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
10071 "interface");
10072 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
10073 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
10074 }
10075#endif /* CONFIG_P2P */
10076
Dmitry Shmidtaca489e2016-09-28 15:44:14 -070010077 if (os_strstr(param, "use_monitor=1"))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010078 drv->use_monitor = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010079
10080 if (os_strstr(param, "force_connect_cmd=1")) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010081 drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME;
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070010082 drv->force_connect_cmd = 1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080010083 }
10084
Dmitry Shmidtaca489e2016-09-28 15:44:14 -070010085 if (os_strstr(param, "force_bss_selection=1"))
10086 drv->capa.flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
10087
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -080010088 if (os_strstr(param, "no_offchannel_tx=1")) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -080010089 drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
10090 drv->test_use_roc_tx = 1;
10091 }
10092
Hai Shalomb755a2a2020-04-23 21:49:02 -070010093 if (os_strstr(param, "control_port=0")) {
Hai Shalomfdcde762020-04-02 11:19:20 -070010094 drv->capa.flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
Hai Shalom899fcc72020-10-19 14:38:18 -070010095 drv->capa.flags2 &= ~(WPA_DRIVER_FLAGS2_CONTROL_PORT_RX |
10096 WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS);
10097 drv->control_port_ap = 0;
Hai Shalomb755a2a2020-04-23 21:49:02 -070010098 }
10099
10100 if (os_strstr(param, "control_port_ap=1"))
10101 drv->control_port_ap = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -070010102
Hai Shalom899fcc72020-10-19 14:38:18 -070010103 if (os_strstr(param, "control_port_ap=0")) {
10104 drv->capa.flags2 &= ~WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS;
10105 drv->control_port_ap = 0;
10106 }
10107
Hai Shalomfdcde762020-04-02 11:19:20 -070010108 if (os_strstr(param, "full_ap_client_state=0"))
10109 drv->capa.flags &= ~WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
10110
Hai Shalom899fcc72020-10-19 14:38:18 -070010111 if (os_strstr(param, "no_rrm=1")) {
10112 drv->no_rrm = 1;
10113
10114 if (!bss->in_deinit && !is_ap_interface(drv->nlmode) &&
10115 !is_mesh_interface(drv->nlmode)) {
10116 nl80211_mgmt_unsubscribe(bss, "no_rrm=1");
10117 if (nl80211_mgmt_subscribe_non_ap(bss) < 0)
10118 wpa_printf(MSG_DEBUG,
10119 "nl80211: Failed to re-register Action frame processing - ignore for now");
10120 }
10121 }
10122
Sunil Ravi640215c2023-06-28 23:08:09 +000010123 if (os_strstr(param, "secure_ltf=1")) {
10124 drv->capa.flags2 |= WPA_DRIVER_FLAGS2_SEC_LTF_STA |
10125 WPA_DRIVER_FLAGS2_SEC_LTF_AP;
10126 }
10127
Sunil Ravi7f769292024-07-23 22:21:32 +000010128 if (os_strstr(param, "rsn_override_in_driver=1"))
10129 drv->capa.flags2 |= WPA_DRIVER_FLAGS2_RSN_OVERRIDE_STA;
10130
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010131 return 0;
10132}
10133
10134
Dmitry Shmidte4663042016-04-04 10:07:49 -070010135static void * nl80211_global_init(void *ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010136{
10137 struct nl80211_global *global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010138 struct netlink_config *cfg;
Sunil Ravib0ac25f2024-07-12 01:42:03 +000010139 struct utsname name;
10140
10141 if (uname(&name) == 0) {
10142 wpa_printf(MSG_DEBUG, "nl80211: Kernel version: %s %s (%s; %s)",
10143 name.sysname, name.release,
10144 name.version, name.machine);
10145 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010146
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010147 global = os_zalloc(sizeof(*global));
10148 if (global == NULL)
10149 return NULL;
Dmitry Shmidte4663042016-04-04 10:07:49 -070010150 global->ctx = ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010151 global->ioctl_sock = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010152 dl_list_init(&global->interfaces);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010153 global->if_add_ifindex = -1;
10154
10155 cfg = os_zalloc(sizeof(*cfg));
10156 if (cfg == NULL)
10157 goto err;
10158
10159 cfg->ctx = global;
10160 cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
10161 cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
10162 global->netlink = netlink_init(cfg);
10163 if (global->netlink == NULL) {
10164 os_free(cfg);
10165 goto err;
10166 }
10167
10168 if (wpa_driver_nl80211_init_nl_global(global) < 0)
10169 goto err;
10170
10171 global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
10172 if (global->ioctl_sock < 0) {
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -070010173 wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s",
10174 strerror(errno));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010175 goto err;
10176 }
10177
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010178 return global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010179
10180err:
10181 nl80211_global_deinit(global);
10182 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010183}
10184
10185
10186static void nl80211_global_deinit(void *priv)
10187{
10188 struct nl80211_global *global = priv;
10189 if (global == NULL)
10190 return;
10191 if (!dl_list_empty(&global->interfaces)) {
10192 wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at "
10193 "nl80211_global_deinit",
10194 dl_list_len(&global->interfaces));
10195 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010196
10197 if (global->netlink)
10198 netlink_deinit(global->netlink);
10199
10200 nl_destroy_handles(&global->nl);
10201
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -070010202 if (global->nl_event)
Roshan Pius3a1667e2018-07-03 15:17:14 -070010203 nl80211_destroy_eloop_handle(&global->nl_event, 0);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010204
10205 nl_cb_put(global->nl_cb);
10206
10207 if (global->ioctl_sock >= 0)
10208 close(global->ioctl_sock);
10209
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010210 os_free(global);
10211}
10212
10213
10214static const char * nl80211_get_radio_name(void *priv)
10215{
10216 struct i802_bss *bss = priv;
10217 struct wpa_driver_nl80211_data *drv = bss->drv;
10218 return drv->phyname;
10219}
10220
10221
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010222static int nl80211_pmkid(struct i802_bss *bss, int cmd,
Sunil Ravi77d572f2023-01-17 23:58:31 +000010223 struct wpa_pmkid_params *params, bool skip_pmk)
Jouni Malinen75ecf522011-06-27 15:19:46 -070010224{
10225 struct nl_msg *msg;
Sunil Ravi77d572f2023-01-17 23:58:31 +000010226
10227 if (cmd == NL80211_CMD_SET_PMKSA)
10228 wpa_printf(MSG_DEBUG,
10229 "nl80211: NL80211_CMD_SET_PMKSA with skip_pmk=%s pmk_len=%zu",
10230 skip_pmk ? "true" : "false", params->pmk_len);
Jouni Malinen75ecf522011-06-27 15:19:46 -070010231
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010232 if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010233 (params->pmkid &&
10234 nla_put(msg, NL80211_ATTR_PMKID, 16, params->pmkid)) ||
10235 (params->bssid &&
10236 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid)) ||
10237 (params->ssid_len &&
10238 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
10239 (params->fils_cache_id &&
10240 nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2,
10241 params->fils_cache_id)) ||
Hai Shalomfdcde762020-04-02 11:19:20 -070010242 (params->pmk_lifetime &&
10243 nla_put_u32(msg, NL80211_ATTR_PMK_LIFETIME,
10244 params->pmk_lifetime)) ||
10245 (params->pmk_reauth_threshold &&
10246 nla_put_u8(msg, NL80211_ATTR_PMK_REAUTH_THRESHOLD,
10247 params->pmk_reauth_threshold)) ||
Hai Shalom021b0b52019-04-10 11:17:58 -070010248 (cmd != NL80211_CMD_DEL_PMKSA &&
Sunil Ravi77d572f2023-01-17 23:58:31 +000010249 params->pmk_len && !skip_pmk &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010250 nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
Hai Shalom74f70d42019-02-11 14:42:39 -080010251 nl80211_nlmsg_clear(msg);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010252 nlmsg_free(msg);
10253 return -ENOBUFS;
10254 }
Jouni Malinen75ecf522011-06-27 15:19:46 -070010255
Sunil Ravib0ac25f2024-07-12 01:42:03 +000010256 return send_and_recv_cmd(bss->drv, msg);
Jouni Malinen75ecf522011-06-27 15:19:46 -070010257}
10258
10259
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010260static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params)
Jouni Malinen75ecf522011-06-27 15:19:46 -070010261{
10262 struct i802_bss *bss = priv;
Sunil Ravi77d572f2023-01-17 23:58:31 +000010263 const size_t PMK_MAX_LEN = 64; /* current cfg80211 limit */
10264 const size_t LEGACY_PMK_MAX_LEN = 48; /* old cfg80211 limit */
10265 bool skip_pmk = params->pmk_len > PMK_MAX_LEN;
Roshan Pius3a1667e2018-07-03 15:17:14 -070010266 int ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010267
10268 if (params->bssid)
10269 wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR,
10270 MAC2STR(params->bssid));
10271 else if (params->fils_cache_id && params->ssid_len) {
10272 wpa_printf(MSG_DEBUG,
10273 "nl80211: Add PMKSA for cache id %02x%02x SSID %s",
10274 params->fils_cache_id[0], params->fils_cache_id[1],
10275 wpa_ssid_txt(params->ssid, params->ssid_len));
10276 }
10277
Sunil Ravi77d572f2023-01-17 23:58:31 +000010278 ret = nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params, skip_pmk);
10279 /*
10280 * Try again by skipping PMK if the first attempt failed with ERANGE
10281 * error, PMK was not skipped, and PMK length is greater than the
10282 * legacy kernel maximum allowed limit.
10283 */
10284 if (ret == -ERANGE && !skip_pmk &&
10285 params->pmk_len > LEGACY_PMK_MAX_LEN)
10286 ret = nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params, true);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010287 if (ret < 0) {
10288 wpa_printf(MSG_DEBUG,
10289 "nl80211: NL80211_CMD_SET_PMKSA failed: %d (%s)",
10290 ret, strerror(-ret));
10291 }
10292
10293 return ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -070010294}
10295
10296
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010297static int nl80211_remove_pmkid(void *priv, struct wpa_pmkid_params *params)
Jouni Malinen75ecf522011-06-27 15:19:46 -070010298{
10299 struct i802_bss *bss = priv;
Roshan Pius3a1667e2018-07-03 15:17:14 -070010300 int ret;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010301
10302 if (params->bssid)
10303 wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
10304 MAC2STR(params->bssid));
10305 else if (params->fils_cache_id && params->ssid_len) {
10306 wpa_printf(MSG_DEBUG,
10307 "nl80211: Delete PMKSA for cache id %02x%02x SSID %s",
10308 params->fils_cache_id[0], params->fils_cache_id[1],
10309 wpa_ssid_txt(params->ssid, params->ssid_len));
10310 }
10311
Sunil Ravi77d572f2023-01-17 23:58:31 +000010312 ret = nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params, true);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010313 if (ret < 0) {
10314 wpa_printf(MSG_DEBUG,
10315 "nl80211: NL80211_CMD_DEL_PMKSA failed: %d (%s)",
10316 ret, strerror(-ret));
10317 }
10318
10319 return ret;
Jouni Malinen75ecf522011-06-27 15:19:46 -070010320}
10321
10322
10323static int nl80211_flush_pmkid(void *priv)
10324{
10325 struct i802_bss *bss = priv;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010326 struct nl_msg *msg;
10327
Jouni Malinen75ecf522011-06-27 15:19:46 -070010328 wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010329 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_FLUSH_PMKSA);
10330 if (!msg)
10331 return -ENOBUFS;
Sunil Ravib0ac25f2024-07-12 01:42:03 +000010332 return send_and_recv_cmd(bss->drv, msg);
Jouni Malinen75ecf522011-06-27 15:19:46 -070010333}
10334
10335
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010336static void clean_survey_results(struct survey_results *survey_results)
10337{
10338 struct freq_survey *survey, *tmp;
10339
10340 if (dl_list_empty(&survey_results->survey_list))
10341 return;
10342
10343 dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
10344 struct freq_survey, list) {
10345 dl_list_del(&survey->list);
10346 os_free(survey);
10347 }
10348}
10349
10350
10351static void add_survey(struct nlattr **sinfo, u32 ifidx,
10352 struct dl_list *survey_list)
10353{
10354 struct freq_survey *survey;
10355
10356 survey = os_zalloc(sizeof(struct freq_survey));
10357 if (!survey)
10358 return;
10359
10360 survey->ifidx = ifidx;
10361 survey->freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
10362 survey->filled = 0;
10363
10364 if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
10365 survey->nf = (int8_t)
10366 nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
10367 survey->filled |= SURVEY_HAS_NF;
10368 }
10369
10370 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) {
10371 survey->channel_time =
10372 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
10373 survey->filled |= SURVEY_HAS_CHAN_TIME;
10374 }
10375
10376 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
10377 survey->channel_time_busy =
10378 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
10379 survey->filled |= SURVEY_HAS_CHAN_TIME_BUSY;
10380 }
10381
10382 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) {
10383 survey->channel_time_rx =
10384 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]);
10385 survey->filled |= SURVEY_HAS_CHAN_TIME_RX;
10386 }
10387
10388 if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) {
10389 survey->channel_time_tx =
10390 nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]);
10391 survey->filled |= SURVEY_HAS_CHAN_TIME_TX;
10392 }
10393
10394 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)",
10395 survey->freq,
10396 survey->nf,
10397 (unsigned long int) survey->channel_time,
10398 (unsigned long int) survey->channel_time_busy,
10399 (unsigned long int) survey->channel_time_tx,
10400 (unsigned long int) survey->channel_time_rx,
10401 survey->filled);
10402
10403 dl_list_add_tail(survey_list, &survey->list);
10404}
10405
10406
10407static int check_survey_ok(struct nlattr **sinfo, u32 surveyed_freq,
10408 unsigned int freq_filter)
10409{
10410 if (!freq_filter)
10411 return 1;
10412
10413 return freq_filter == surveyed_freq;
10414}
10415
10416
10417static int survey_handler(struct nl_msg *msg, void *arg)
10418{
10419 struct nlattr *tb[NL80211_ATTR_MAX + 1];
10420 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
10421 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
10422 struct survey_results *survey_results;
10423 u32 surveyed_freq = 0;
10424 u32 ifidx;
10425
10426 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
10427 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
10428 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
10429 };
10430
10431 survey_results = (struct survey_results *) arg;
10432
10433 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
10434 genlmsg_attrlen(gnlh, 0), NULL);
10435
Dmitry Shmidt97672262014-02-03 13:02:54 -080010436 if (!tb[NL80211_ATTR_IFINDEX])
10437 return NL_SKIP;
10438
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010439 ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
10440
10441 if (!tb[NL80211_ATTR_SURVEY_INFO])
10442 return NL_SKIP;
10443
10444 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
10445 tb[NL80211_ATTR_SURVEY_INFO],
10446 survey_policy))
10447 return NL_SKIP;
10448
10449 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) {
10450 wpa_printf(MSG_ERROR, "nl80211: Invalid survey data");
10451 return NL_SKIP;
10452 }
10453
10454 surveyed_freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
10455
10456 if (!check_survey_ok(sinfo, surveyed_freq,
10457 survey_results->freq_filter))
10458 return NL_SKIP;
10459
10460 if (survey_results->freq_filter &&
10461 survey_results->freq_filter != surveyed_freq) {
10462 wpa_printf(MSG_EXCESSIVE, "nl80211: Ignoring survey data for freq %d MHz",
10463 surveyed_freq);
10464 return NL_SKIP;
10465 }
10466
10467 add_survey(sinfo, ifidx, &survey_results->survey_list);
10468
10469 return NL_SKIP;
10470}
10471
10472
10473static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
10474{
10475 struct i802_bss *bss = priv;
10476 struct wpa_driver_nl80211_data *drv = bss->drv;
10477 struct nl_msg *msg;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010478 int err;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010479 union wpa_event_data data;
10480 struct survey_results *survey_results;
Sunil Ravic0f5d412024-09-11 22:12:49 +000010481 void *ctx = (bss->scan_link && bss->scan_link->ctx) ?
10482 bss->scan_link->ctx : bss->ctx;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010483
10484 os_memset(&data, 0, sizeof(data));
10485 survey_results = &data.survey_results;
10486
10487 dl_list_init(&survey_results->survey_list);
10488
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010489 msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010490 if (!msg)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010491 return -ENOBUFS;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010492
10493 if (freq)
10494 data.survey_results.freq_filter = freq;
10495
10496 do {
10497 wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
Sunil Ravib0ac25f2024-07-12 01:42:03 +000010498 err = send_and_recv_resp(drv, msg, survey_handler,
10499 survey_results);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010500 } while (err > 0);
10501
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010502 if (err)
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010503 wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010504 else
Sunil Ravic0f5d412024-09-11 22:12:49 +000010505 wpa_supplicant_event(ctx, EVENT_SURVEY, &data);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010506
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010507 clean_survey_results(survey_results);
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070010508 return err;
10509}
10510
10511
Dmitry Shmidt807291d2015-01-27 13:40:23 -080010512static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
10513 const u8 *kck, size_t kck_len,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010514 const u8 *replay_ctr)
10515{
10516 struct i802_bss *bss = priv;
10517 struct wpa_driver_nl80211_data *drv = bss->drv;
10518 struct nlattr *replay_nested;
10519 struct nl_msg *msg;
Dmitry Shmidtff787d52015-01-12 13:01:47 -080010520 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010521
Dmitry Shmidtff787d52015-01-12 13:01:47 -080010522 if (!drv->set_rekey_offload)
10523 return;
10524
10525 wpa_printf(MSG_DEBUG, "nl80211: Set rekey offload");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010526 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
10527 !(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
Dmitry Shmidt807291d2015-01-27 13:40:23 -080010528 nla_put(msg, NL80211_REKEY_DATA_KEK, kek_len, kek) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070010529 (kck_len && nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010530 nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
10531 replay_ctr)) {
10532 nl80211_nlmsg_clear(msg);
10533 nlmsg_free(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010534 return;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010535 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010536
10537 nla_nest_end(msg, replay_nested);
10538
Sunil Ravib0ac25f2024-07-12 01:42:03 +000010539 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidtff787d52015-01-12 13:01:47 -080010540 if (ret == -EOPNOTSUPP) {
10541 wpa_printf(MSG_DEBUG,
10542 "nl80211: Driver does not support rekey offload");
10543 drv->set_rekey_offload = 0;
10544 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010545}
10546
10547
10548static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
10549 const u8 *addr, int qos)
10550{
10551 /* send data frame to poll STA and check whether
10552 * this frame is ACKed */
10553 struct {
10554 struct ieee80211_hdr hdr;
10555 u16 qos_ctl;
10556 } STRUCT_PACKED nulldata;
10557 size_t size;
10558
10559 /* Send data frame to poll STA and check whether this frame is ACKed */
10560
10561 os_memset(&nulldata, 0, sizeof(nulldata));
10562
10563 if (qos) {
10564 nulldata.hdr.frame_control =
10565 IEEE80211_FC(WLAN_FC_TYPE_DATA,
10566 WLAN_FC_STYPE_QOS_NULL);
10567 size = sizeof(nulldata);
10568 } else {
10569 nulldata.hdr.frame_control =
10570 IEEE80211_FC(WLAN_FC_TYPE_DATA,
10571 WLAN_FC_STYPE_NULLFUNC);
10572 size = sizeof(struct ieee80211_hdr);
10573 }
10574
10575 nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
10576 os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
10577 os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
10578 os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
10579
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080010580 if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
Sunil Ravi2a14cf12023-11-21 00:54:38 +000010581 0, 0, NULL, 0, 0, -1) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010582 wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
10583 "send poll frame");
10584}
10585
10586static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
10587 int qos)
10588{
10589 struct i802_bss *bss = priv;
10590 struct wpa_driver_nl80211_data *drv = bss->drv;
10591 struct nl_msg *msg;
Hai Shalom5f92bc92019-04-18 11:54:11 -070010592 u64 cookie;
Dmitry Shmidt7f656022015-02-25 14:36:37 -080010593 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010594
10595 if (!drv->poll_command_supported) {
10596 nl80211_send_null_frame(bss, own_addr, addr, qos);
10597 return;
10598 }
10599
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010600 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_PROBE_CLIENT)) ||
10601 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
10602 nlmsg_free(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010603 return;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010604 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010605
Sunil Ravib0ac25f2024-07-12 01:42:03 +000010606 ret = send_and_recv_resp(drv, msg, cookie_handler, &cookie);
Dmitry Shmidt7f656022015-02-25 14:36:37 -080010607 if (ret < 0) {
10608 wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
10609 MACSTR " failed: ret=%d (%s)",
10610 MAC2STR(addr), ret, strerror(-ret));
Hai Shalom5f92bc92019-04-18 11:54:11 -070010611 } else {
10612 wpa_printf(MSG_DEBUG,
10613 "nl80211: Client probe request addr=" MACSTR
10614 " cookie=%llu", MAC2STR(addr),
10615 (long long unsigned int) cookie);
Dmitry Shmidt7f656022015-02-25 14:36:37 -080010616 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010617}
10618
10619
10620static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
10621{
10622 struct nl_msg *msg;
Roshan Pius3a1667e2018-07-03 15:17:14 -070010623 int ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010624
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010625 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
10626 nla_put_u32(msg, NL80211_ATTR_PS_STATE,
10627 enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED)) {
10628 nlmsg_free(msg);
10629 return -ENOBUFS;
10630 }
Roshan Pius3a1667e2018-07-03 15:17:14 -070010631
Sunil Ravib0ac25f2024-07-12 01:42:03 +000010632 ret = send_and_recv_cmd(bss->drv, msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -070010633 if (ret < 0) {
10634 wpa_printf(MSG_DEBUG,
10635 "nl80211: Setting PS state %s failed: %d (%s)",
10636 enabled ? "enabled" : "disabled",
10637 ret, strerror(-ret));
10638 }
10639 return ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010640}
10641
10642
10643static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
10644 int ctwindow)
10645{
10646 struct i802_bss *bss = priv;
10647
10648 wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
10649 "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
10650
Dmitry Shmidt292b0c32013-11-22 12:54:42 -080010651 if (opp_ps != -1 || ctwindow != -1) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080010652#ifdef ANDROID_P2P
10653 wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
Dmitry Shmidt292b0c32013-11-22 12:54:42 -080010654#else /* ANDROID_P2P */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010655 return -1; /* Not yet supported */
Dmitry Shmidt292b0c32013-11-22 12:54:42 -080010656#endif /* ANDROID_P2P */
10657 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010658
10659 if (legacy_ps == -1)
10660 return 0;
10661 if (legacy_ps != 0 && legacy_ps != 1)
10662 return -1; /* Not yet supported */
10663
10664 return nl80211_set_power_save(bss, legacy_ps);
10665}
10666
10667
Dmitry Shmidt051af732013-10-22 13:52:46 -070010668static int nl80211_start_radar_detection(void *priv,
10669 struct hostapd_freq_params *freq)
Dmitry Shmidtea69e842013-05-13 14:52:28 -070010670{
10671 struct i802_bss *bss = priv;
10672 struct wpa_driver_nl80211_data *drv = bss->drv;
10673 struct nl_msg *msg;
10674 int ret;
10675
Hai Shalom81f62d82019-07-22 12:10:00 -070010676 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)",
10677 freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
Dmitry Shmidt051af732013-10-22 13:52:46 -070010678 freq->bandwidth, freq->center_freq1, freq->center_freq2);
10679
Dmitry Shmidtea69e842013-05-13 14:52:28 -070010680 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
10681 wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
10682 "detection");
10683 return -1;
10684 }
10685
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010686 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_RADAR_DETECT)) ||
10687 nl80211_put_freq_params(msg, freq) < 0) {
10688 nlmsg_free(msg);
Dmitry Shmidtea69e842013-05-13 14:52:28 -070010689 return -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010690 }
Dmitry Shmidtea69e842013-05-13 14:52:28 -070010691
Sunil Ravib0ac25f2024-07-12 01:42:03 +000010692 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidtea69e842013-05-13 14:52:28 -070010693 if (ret == 0)
10694 return 0;
10695 wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
10696 "%d (%s)", ret, strerror(-ret));
Dmitry Shmidtea69e842013-05-13 14:52:28 -070010697 return -1;
10698}
10699
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010700#ifdef CONFIG_TDLS
10701
Hai Shalomc1a21442022-02-04 13:43:00 -080010702static int nl80211_add_peer_capab(struct nl_msg *msg,
10703 enum tdls_peer_capability capa)
10704{
10705 u32 peer_capab = 0;
10706
10707 if (!capa)
10708 return 0;
10709
10710 if (capa & TDLS_PEER_HT)
10711 peer_capab |= NL80211_TDLS_PEER_HT;
10712 if (capa & TDLS_PEER_VHT)
10713 peer_capab |= NL80211_TDLS_PEER_VHT;
10714 if (capa & TDLS_PEER_WMM)
10715 peer_capab |= NL80211_TDLS_PEER_WMM;
10716 if (capa & TDLS_PEER_HE)
10717 peer_capab |= NL80211_TDLS_PEER_HE;
10718
10719 return nla_put_u32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY,
10720 peer_capab);
10721}
10722
10723
Sunil Ravi2a14cf12023-11-21 00:54:38 +000010724static int
10725nl80211_tdls_set_discovery_resp_link(struct wpa_driver_nl80211_data *drv,
10726 int link_id)
10727{
10728#ifdef CONFIG_DRIVER_NL80211_QCA
10729 struct nl_msg *msg;
10730 struct nlattr *params;
10731
10732 wpa_printf(MSG_DEBUG, "nl80211: TDLS Discovery Response Tx link ID %u",
10733 link_id);
10734
10735 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
10736 nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) ||
10737 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
10738 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
10739 QCA_NL80211_VENDOR_SUBCMD_TDLS_DISC_RSP_EXT) ||
10740 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
10741 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_TX_LINK,
10742 link_id)) {
10743 wpa_printf(MSG_ERROR,
10744 "%s: err in adding vendor_cmd and vendor_data",
10745 __func__);
10746 nlmsg_free(msg);
10747 return -1;
10748 }
10749 nla_nest_end(msg, params);
10750
Sunil Ravib0ac25f2024-07-12 01:42:03 +000010751 return send_and_recv_cmd(drv, msg);
Sunil Ravi2a14cf12023-11-21 00:54:38 +000010752#else /* CONFIG_DRIVER_NL80211_QCA */
10753 wpa_printf(MSG_ERROR,
10754 "nl80211: Setting TX link for TDLS Discovery Response not supported");
10755 return -1;
10756#endif /* CONFIG_DRIVER_NL80211_QCA */
10757}
10758
10759
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010760static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
10761 u8 dialog_token, u16 status_code,
Dmitry Shmidt9ead16e2014-10-07 13:15:23 -070010762 u32 peer_capab, int initiator, const u8 *buf,
Sunil Ravi2a14cf12023-11-21 00:54:38 +000010763 size_t len, int link_id)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010764{
10765 struct i802_bss *bss = priv;
10766 struct wpa_driver_nl80211_data *drv = bss->drv;
10767 struct nl_msg *msg;
10768
10769 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
10770 return -EOPNOTSUPP;
10771
10772 if (!dst)
10773 return -EINVAL;
10774
Sunil Ravi2a14cf12023-11-21 00:54:38 +000010775 if (link_id >= 0 &&
10776 nl80211_tdls_set_discovery_resp_link(drv, link_id) < 0)
10777 return -EOPNOTSUPP;
10778
Sunil Ravi7f769292024-07-23 22:21:32 +000010779 if (link_id < 0 && drv->sta_mlo_info.valid_links)
10780 link_id = drv->sta_mlo_info.assoc_link_id;
10781
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010782 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_MGMT)) ||
10783 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
10784 nla_put_u8(msg, NL80211_ATTR_TDLS_ACTION, action_code) ||
10785 nla_put_u8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token) ||
Hai Shalomc1a21442022-02-04 13:43:00 -080010786 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status_code) ||
Sunil Ravi7f769292024-07-23 22:21:32 +000010787 (link_id >= 0 &&
10788 nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) ||
Hai Shalomc1a21442022-02-04 13:43:00 -080010789 nl80211_add_peer_capab(msg, peer_capab) ||
10790 (initiator && nla_put_flag(msg, NL80211_ATTR_TDLS_INITIATOR)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010791 nla_put(msg, NL80211_ATTR_IE, len, buf))
10792 goto fail;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010793
Sunil Ravib0ac25f2024-07-12 01:42:03 +000010794 return send_and_recv_cmd(drv, msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010795
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010796fail:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010797 nlmsg_free(msg);
10798 return -ENOBUFS;
10799}
10800
10801
10802static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
10803{
10804 struct i802_bss *bss = priv;
10805 struct wpa_driver_nl80211_data *drv = bss->drv;
10806 struct nl_msg *msg;
10807 enum nl80211_tdls_operation nl80211_oper;
Paul Stewart092955c2017-02-06 09:13:09 -080010808 int res;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010809
10810 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
10811 return -EOPNOTSUPP;
10812
10813 switch (oper) {
10814 case TDLS_DISCOVERY_REQ:
10815 nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
10816 break;
10817 case TDLS_SETUP:
10818 nl80211_oper = NL80211_TDLS_SETUP;
10819 break;
10820 case TDLS_TEARDOWN:
10821 nl80211_oper = NL80211_TDLS_TEARDOWN;
10822 break;
10823 case TDLS_ENABLE_LINK:
10824 nl80211_oper = NL80211_TDLS_ENABLE_LINK;
10825 break;
10826 case TDLS_DISABLE_LINK:
10827 nl80211_oper = NL80211_TDLS_DISABLE_LINK;
10828 break;
10829 case TDLS_ENABLE:
10830 return 0;
10831 case TDLS_DISABLE:
10832 return 0;
10833 default:
10834 return -EINVAL;
10835 }
10836
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010837 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_OPER)) ||
10838 nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper) ||
10839 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) {
10840 nlmsg_free(msg);
10841 return -ENOBUFS;
10842 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010843
Sunil Ravib0ac25f2024-07-12 01:42:03 +000010844 res = send_and_recv_cmd(drv, msg);
Paul Stewart092955c2017-02-06 09:13:09 -080010845 wpa_printf(MSG_DEBUG, "nl80211: TDLS_OPER: oper=%d mac=" MACSTR
10846 " --> res=%d (%s)", nl80211_oper, MAC2STR(peer), res,
10847 strerror(-res));
10848 return res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010849}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010850
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010851
10852static int
10853nl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
10854 const struct hostapd_freq_params *params)
10855{
10856 struct i802_bss *bss = priv;
10857 struct wpa_driver_nl80211_data *drv = bss->drv;
10858 struct nl_msg *msg;
10859 int ret = -ENOBUFS;
10860
10861 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
10862 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
10863 return -EOPNOTSUPP;
10864
10865 wpa_printf(MSG_DEBUG, "nl80211: Enable TDLS channel switch " MACSTR
10866 " oper_class=%u freq=%u",
10867 MAC2STR(addr), oper_class, params->freq);
10868 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CHANNEL_SWITCH);
10869 if (!msg ||
10870 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
10871 nla_put_u8(msg, NL80211_ATTR_OPER_CLASS, oper_class) ||
10872 (ret = nl80211_put_freq_params(msg, params))) {
10873 nlmsg_free(msg);
10874 wpa_printf(MSG_DEBUG, "nl80211: Could not build TDLS chan switch");
10875 return ret;
10876 }
10877
Sunil Ravib0ac25f2024-07-12 01:42:03 +000010878 return send_and_recv_cmd(drv, msg);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080010879}
10880
10881
10882static int
10883nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
10884{
10885 struct i802_bss *bss = priv;
10886 struct wpa_driver_nl80211_data *drv = bss->drv;
10887 struct nl_msg *msg;
10888
10889 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
10890 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
10891 return -EOPNOTSUPP;
10892
10893 wpa_printf(MSG_DEBUG, "nl80211: Disable TDLS channel switch " MACSTR,
10894 MAC2STR(addr));
10895 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH);
10896 if (!msg ||
10897 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
10898 nlmsg_free(msg);
10899 wpa_printf(MSG_DEBUG,
10900 "nl80211: Could not build TDLS cancel chan switch");
10901 return -ENOBUFS;
10902 }
10903
Sunil Ravib0ac25f2024-07-12 01:42:03 +000010904 return send_and_recv_cmd(drv, msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080010905}
10906
10907#endif /* CONFIG TDLS */
10908
10909
Hai Shalomfdcde762020-04-02 11:19:20 -070010910static int driver_nl80211_set_key(void *priv,
10911 struct wpa_driver_set_key_params *params)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080010912{
10913 struct i802_bss *bss = priv;
Hai Shalomfdcde762020-04-02 11:19:20 -070010914
10915 return wpa_driver_nl80211_set_key(bss, params);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080010916}
10917
10918
10919static int driver_nl80211_scan2(void *priv,
10920 struct wpa_driver_scan_params *params)
10921{
10922 struct i802_bss *bss = priv;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080010923#ifdef CONFIG_DRIVER_NL80211_QCA
10924 struct wpa_driver_nl80211_data *drv = bss->drv;
10925
10926 /*
10927 * Do a vendor specific scan if possible. If only_new_results is
10928 * set, do a normal scan since a kernel (cfg80211) BSS cache flush
10929 * cannot be achieved through a vendor scan. The below condition may
10930 * need to be modified if new scan flags are added in the future whose
10931 * functionality can only be achieved through a normal scan.
10932 */
10933 if (drv->scan_vendor_cmd_avail && !params->only_new_results)
10934 return wpa_driver_nl80211_vendor_scan(bss, params);
10935#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080010936 return wpa_driver_nl80211_scan(bss, params);
10937}
10938
10939
10940static int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -070010941 u16 reason_code)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080010942{
10943 struct i802_bss *bss = priv;
10944 return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
10945}
10946
10947
10948static int driver_nl80211_authenticate(void *priv,
10949 struct wpa_driver_auth_params *params)
10950{
10951 struct i802_bss *bss = priv;
10952 return wpa_driver_nl80211_authenticate(bss, params);
10953}
10954
10955
10956static void driver_nl80211_deinit(void *priv)
10957{
10958 struct i802_bss *bss = priv;
10959 wpa_driver_nl80211_deinit(bss);
10960}
10961
10962
10963static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
10964 const char *ifname)
10965{
10966 struct i802_bss *bss = priv;
10967 return wpa_driver_nl80211_if_remove(bss, type, ifname);
10968}
10969
10970
Sunil Ravi99c035e2024-07-12 01:42:03 +000010971#ifdef CONFIG_IEEE80211BE
10972
10973static int driver_nl80211_link_remove(void *priv, enum wpa_driver_if_type type,
10974 const char *ifname, u8 link_id)
10975{
10976 struct i802_bss *bss = priv;
10977 struct wpa_driver_nl80211_data *drv = bss->drv;
Sunil Ravic0f5d412024-09-11 22:12:49 +000010978 int ret;
Sunil Ravi99c035e2024-07-12 01:42:03 +000010979
10980 if (type != WPA_IF_AP_BSS ||
10981 !nl80211_link_valid(bss->valid_links, link_id))
10982 return -1;
10983
10984 wpa_printf(MSG_DEBUG,
10985 "nl80211: Teardown AP(%s) link %d (type=%d ifname=%s links=0x%x)",
10986 bss->ifname, link_id, type, ifname, bss->valid_links);
10987
10988 nl80211_remove_link(bss, link_id);
10989
10990 bss->ctx = bss->flink->ctx;
10991
Sunil Ravi7f769292024-07-23 22:21:32 +000010992 if (drv->first_bss == bss && bss->valid_links)
Sunil Ravi99c035e2024-07-12 01:42:03 +000010993 drv->ctx = bss->ctx;
10994
10995 if (!bss->valid_links) {
10996 wpa_printf(MSG_DEBUG,
10997 "nl80211: No more links remaining, so remove interface");
Sunil Ravic0f5d412024-09-11 22:12:49 +000010998 ret = wpa_driver_nl80211_if_remove(bss, type, ifname);
10999 if (ret)
11000 return ret;
11001
11002 /* Notify that the MLD interface is removed */
11003 wpa_supplicant_event(bss->ctx, EVENT_MLD_INTERFACE_FREED, NULL);
Sunil Ravi99c035e2024-07-12 01:42:03 +000011004 }
11005
11006 return 0;
11007}
11008
11009
Sunil Ravic0f5d412024-09-11 22:12:49 +000011010static bool nl80211_is_drv_shared(void *priv, int link_id)
Sunil Ravi99c035e2024-07-12 01:42:03 +000011011{
11012 struct i802_bss *bss = priv;
11013 struct wpa_driver_nl80211_data *drv = bss->drv;
Sunil Ravic0f5d412024-09-11 22:12:49 +000011014 unsigned int num_bss = 0, num_links = 0;
11015 bool self = false;
11016 u8 i;
Sunil Ravi99c035e2024-07-12 01:42:03 +000011017
11018 /* If any other BSS exist, someone else is using this since at this
11019 * time, we would have removed all BSSs created by this driver and only
11020 * this BSS should be remaining if the driver is not shared by anyone.
11021 */
11022 for (bss = drv->first_bss; bss; bss = bss->next) {
11023 num_bss++;
11024 if (num_bss > 1)
11025 return true;
11026 }
11027
11028 /* This is the only BSS present */
11029 bss = priv;
11030
Sunil Ravic0f5d412024-09-11 22:12:49 +000011031 for_each_link(bss->valid_links, i) {
11032 num_links++;
11033 if (i == link_id)
11034 self = true;
11035 }
11036
11037 /* More than one links means some one is still sharing */
11038 if (num_links > 1)
11039 return true;
11040
11041 /* Even if only one link is there, it should match the given
11042 * link ID to assert that no one else is sharing. */
11043 if (num_links == 1 && self)
Sunil Ravi99c035e2024-07-12 01:42:03 +000011044 return false;
11045
Sunil Ravic0f5d412024-09-11 22:12:49 +000011046 /* No links are active means no one is sharing */
11047 if (num_links == 0)
Sunil Ravi99c035e2024-07-12 01:42:03 +000011048 return false;
11049
11050 return true;
11051}
11052
11053#endif /* CONFIG_IEEE80211BE */
11054
11055
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011056static int driver_nl80211_send_mlme(void *priv, const u8 *data,
Dmitry Shmidta3dc3092015-06-23 11:21:28 -070011057 size_t data_len, int noack,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011058 unsigned int freq,
Hai Shalomfdcde762020-04-02 11:19:20 -070011059 const u16 *csa_offs, size_t csa_offs_len,
Sunil Ravi2a14cf12023-11-21 00:54:38 +000011060 int no_encrypt, unsigned int wait,
11061 int link_id)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011062{
11063 struct i802_bss *bss = priv;
11064 return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
Hai Shalomfdcde762020-04-02 11:19:20 -070011065 freq, 0, 0, wait, csa_offs,
Sunil Ravi2a14cf12023-11-21 00:54:38 +000011066 csa_offs_len, no_encrypt, link_id);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011067}
11068
11069
11070static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
11071{
11072 struct i802_bss *bss = priv;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011073 return wpa_driver_nl80211_sta_remove(bss, addr, -1, 0);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011074}
11075
11076
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011077static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
Sunil Ravi2a14cf12023-11-21 00:54:38 +000011078 const char *ifname, int vlan_id,
11079 int link_id)
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011080{
11081 struct i802_bss *bss = priv;
Sunil Ravi2a14cf12023-11-21 00:54:38 +000011082 return i802_set_sta_vlan(bss, addr, ifname, vlan_id, link_id);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011083}
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011084
11085
11086static int driver_nl80211_read_sta_data(void *priv,
11087 struct hostap_sta_driver_data *data,
11088 const u8 *addr)
11089{
11090 struct i802_bss *bss = priv;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -080011091
11092 os_memset(data, 0, sizeof(*data));
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080011093 return i802_read_sta_data(bss, data, addr);
11094}
11095
11096
11097static int driver_nl80211_send_action(void *priv, unsigned int freq,
11098 unsigned int wait_time,
11099 const u8 *dst, const u8 *src,
11100 const u8 *bssid,
11101 const u8 *data, size_t data_len,
11102 int no_cck)
11103{
11104 struct i802_bss *bss = priv;
11105 return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
11106 bssid, data, data_len, no_cck);
11107}
11108
11109
11110static int driver_nl80211_probe_req_report(void *priv, int report)
11111{
11112 struct i802_bss *bss = priv;
11113 return wpa_driver_nl80211_probe_req_report(bss, report);
11114}
11115
11116
Dmitry Shmidt700a1372013-03-15 14:14:44 -070011117static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
11118 const u8 *ies, size_t ies_len)
11119{
11120 int ret;
11121 struct nl_msg *msg;
11122 struct i802_bss *bss = priv;
11123 struct wpa_driver_nl80211_data *drv = bss->drv;
11124 u16 mdid = WPA_GET_LE16(md);
11125
Dmitry Shmidt700a1372013-03-15 14:14:44 -070011126 wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011127 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_FT_IES)) ||
11128 nla_put(msg, NL80211_ATTR_IE, ies_len, ies) ||
11129 nla_put_u16(msg, NL80211_ATTR_MDID, mdid)) {
11130 nlmsg_free(msg);
11131 return -ENOBUFS;
11132 }
Dmitry Shmidt700a1372013-03-15 14:14:44 -070011133
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011134 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt700a1372013-03-15 14:14:44 -070011135 if (ret) {
11136 wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
11137 "err=%d (%s)", ret, strerror(-ret));
11138 }
11139
11140 return ret;
Dmitry Shmidt700a1372013-03-15 14:14:44 -070011141}
11142
11143
Hai Shalom81f62d82019-07-22 12:10:00 -070011144static int nl80211_update_dh_ie(void *priv, const u8 *peer_mac,
11145 u16 reason_code, const u8 *ie, size_t ie_len)
11146{
11147 int ret;
11148 struct nl_msg *msg;
11149 struct i802_bss *bss = priv;
11150 struct wpa_driver_nl80211_data *drv = bss->drv;
11151
11152 wpa_printf(MSG_DEBUG, "nl80211: Updating DH IE peer: " MACSTR
11153 " reason %u", MAC2STR(peer_mac), reason_code);
11154 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UPDATE_OWE_INFO)) ||
11155 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer_mac) ||
11156 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, reason_code) ||
11157 (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie))) {
11158 nlmsg_free(msg);
11159 return -ENOBUFS;
11160 }
11161
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011162 ret = send_and_recv_cmd(drv, msg);
Hai Shalom81f62d82019-07-22 12:10:00 -070011163 if (ret) {
11164 wpa_printf(MSG_DEBUG,
11165 "nl80211: update_dh_ie failed err=%d (%s)",
11166 ret, strerror(-ret));
11167 }
11168
11169 return ret;
11170}
11171
11172
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -070011173static const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
Dmitry Shmidt34af3062013-07-11 10:46:32 -070011174{
11175 struct i802_bss *bss = priv;
11176 struct wpa_driver_nl80211_data *drv = bss->drv;
11177
11178 if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
11179 return NULL;
11180
11181 return bss->addr;
11182}
11183
11184
Dmitry Shmidt56052862013-10-04 10:23:25 -070011185static const char * scan_state_str(enum scan_states scan_state)
11186{
11187 switch (scan_state) {
11188 case NO_SCAN:
11189 return "NO_SCAN";
11190 case SCAN_REQUESTED:
11191 return "SCAN_REQUESTED";
11192 case SCAN_STARTED:
11193 return "SCAN_STARTED";
11194 case SCAN_COMPLETED:
11195 return "SCAN_COMPLETED";
11196 case SCAN_ABORTED:
11197 return "SCAN_ABORTED";
11198 case SCHED_SCAN_STARTED:
11199 return "SCHED_SCAN_STARTED";
11200 case SCHED_SCAN_STOPPED:
11201 return "SCHED_SCAN_STOPPED";
11202 case SCHED_SCAN_RESULTS:
11203 return "SCHED_SCAN_RESULTS";
11204 }
11205
11206 return "??";
11207}
11208
11209
11210static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
11211{
11212 struct i802_bss *bss = priv;
11213 struct wpa_driver_nl80211_data *drv = bss->drv;
11214 int res;
11215 char *pos, *end;
Hai Shalom74f70d42019-02-11 14:42:39 -080011216 struct nl_msg *msg;
11217 char alpha2[3] = { 0, 0, 0 };
Dmitry Shmidt56052862013-10-04 10:23:25 -070011218
11219 pos = buf;
11220 end = buf + buflen;
11221
11222 res = os_snprintf(pos, end - pos,
11223 "ifindex=%d\n"
11224 "ifname=%s\n"
11225 "brname=%s\n"
11226 "addr=" MACSTR "\n"
11227 "freq=%d\n"
Hai Shalomc9e41a12018-07-31 14:41:42 -070011228 "%s%s%s%s%s%s",
Dmitry Shmidt56052862013-10-04 10:23:25 -070011229 bss->ifindex,
11230 bss->ifname,
11231 bss->brname,
11232 MAC2STR(bss->addr),
Sunil Ravi036cec52023-03-29 11:35:17 -070011233 bss->flink->freq,
11234 bss->flink->beacon_set ? "beacon_set=1\n" : "",
Dmitry Shmidt56052862013-10-04 10:23:25 -070011235 bss->added_if_into_bridge ?
11236 "added_if_into_bridge=1\n" : "",
Hai Shalomc9e41a12018-07-31 14:41:42 -070011237 bss->already_in_bridge ? "already_in_bridge=1\n" : "",
Dmitry Shmidt56052862013-10-04 10:23:25 -070011238 bss->added_bridge ? "added_bridge=1\n" : "",
11239 bss->in_deinit ? "in_deinit=1\n" : "",
11240 bss->if_dynamic ? "if_dynamic=1\n" : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011241 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -070011242 return pos - buf;
11243 pos += res;
11244
11245 if (bss->wdev_id_set) {
11246 res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
11247 (unsigned long long) bss->wdev_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011248 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -070011249 return pos - buf;
11250 pos += res;
11251 }
11252
11253 res = os_snprintf(pos, end - pos,
11254 "phyname=%s\n"
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070011255 "perm_addr=" MACSTR "\n"
Dmitry Shmidt56052862013-10-04 10:23:25 -070011256 "drv_ifindex=%d\n"
11257 "operstate=%d\n"
11258 "scan_state=%s\n"
11259 "auth_bssid=" MACSTR "\n"
11260 "auth_attempt_bssid=" MACSTR "\n"
11261 "bssid=" MACSTR "\n"
11262 "prev_bssid=" MACSTR "\n"
11263 "associated=%d\n"
11264 "assoc_freq=%u\n"
11265 "monitor_sock=%d\n"
11266 "monitor_ifidx=%d\n"
11267 "monitor_refcount=%d\n"
11268 "last_mgmt_freq=%u\n"
11269 "eapol_tx_sock=%d\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011270 "%s%s%s%s%s%s%s%s%s%s%s%s%s",
Dmitry Shmidt56052862013-10-04 10:23:25 -070011271 drv->phyname,
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070011272 MAC2STR(drv->perm_addr),
Dmitry Shmidt56052862013-10-04 10:23:25 -070011273 drv->ifindex,
11274 drv->operstate,
11275 scan_state_str(drv->scan_state),
11276 MAC2STR(drv->auth_bssid),
11277 MAC2STR(drv->auth_attempt_bssid),
11278 MAC2STR(drv->bssid),
11279 MAC2STR(drv->prev_bssid),
11280 drv->associated,
11281 drv->assoc_freq,
11282 drv->monitor_sock,
11283 drv->monitor_ifidx,
11284 drv->monitor_refcount,
11285 drv->last_mgmt_freq,
11286 drv->eapol_tx_sock,
11287 drv->ignore_if_down_event ?
11288 "ignore_if_down_event=1\n" : "",
11289 drv->scan_complete_events ?
11290 "scan_complete_events=1\n" : "",
11291 drv->disabled_11b_rates ?
11292 "disabled_11b_rates=1\n" : "",
11293 drv->pending_remain_on_chan ?
11294 "pending_remain_on_chan=1\n" : "",
11295 drv->in_interface_list ? "in_interface_list=1\n" : "",
11296 drv->device_ap_sme ? "device_ap_sme=1\n" : "",
11297 drv->poll_command_supported ?
11298 "poll_command_supported=1\n" : "",
11299 drv->data_tx_status ? "data_tx_status=1\n" : "",
11300 drv->scan_for_auth ? "scan_for_auth=1\n" : "",
11301 drv->retry_auth ? "retry_auth=1\n" : "",
11302 drv->use_monitor ? "use_monitor=1\n" : "",
11303 drv->ignore_next_local_disconnect ?
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011304 "ignore_next_local_disconnect\n" : "",
Dmitry Shmidt7dba0e52014-04-14 10:49:15 -070011305 drv->ignore_next_local_deauth ?
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011306 "ignore_next_local_deauth\n" : "");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011307 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -070011308 return pos - buf;
11309 pos += res;
11310
Sunil Ravi89eba102022-09-13 21:04:37 -070011311 if (drv->sta_mlo_info.valid_links) {
11312 int i;
11313 struct driver_sta_mlo_info *mlo = &drv->sta_mlo_info;
11314
11315 res = os_snprintf(pos, end - pos,
Sunil Ravi640215c2023-06-28 23:08:09 +000011316 "ap_mld_addr=" MACSTR "\n"
11317 "default_map=%d\n",
11318 MAC2STR(mlo->ap_mld_addr),
11319 mlo->default_map);
Sunil Ravi89eba102022-09-13 21:04:37 -070011320 if (os_snprintf_error(end - pos, res))
11321 return pos - buf;
11322 pos += res;
11323
Sunil Ravi99c035e2024-07-12 01:42:03 +000011324 for_each_link(mlo->valid_links, i) {
Sunil Ravi89eba102022-09-13 21:04:37 -070011325 res = os_snprintf(pos, end - pos,
11326 "link_addr[%u]=" MACSTR "\n"
11327 "link_bssid[%u]=" MACSTR "\n"
11328 "link_freq[%u]=%u\n",
11329 i, MAC2STR(mlo->links[i].addr),
11330 i, MAC2STR(mlo->links[i].bssid),
11331 i, mlo->links[i].freq);
11332 if (os_snprintf_error(end - pos, res))
11333 return pos - buf;
11334 pos += res;
Sunil Ravi640215c2023-06-28 23:08:09 +000011335
11336 if (!mlo->default_map) {
11337 res = os_snprintf(
11338 pos, end - pos,
11339 "uplink_map[%u]=%x\n"
11340 "downlink_map[%u]=%x\n",
11341 i, mlo->links[i].t2lmap.uplink,
11342 i, mlo->links[i].t2lmap.downlink);
11343 if (os_snprintf_error(end - pos, res))
11344 return pos - buf;
11345 pos += res;
11346 }
Sunil Ravi89eba102022-09-13 21:04:37 -070011347 }
11348 }
11349
Dmitry Shmidt56052862013-10-04 10:23:25 -070011350 if (drv->has_capability) {
11351 res = os_snprintf(pos, end - pos,
11352 "capa.key_mgmt=0x%x\n"
11353 "capa.enc=0x%x\n"
11354 "capa.auth=0x%x\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011355 "capa.flags=0x%llx\n"
Sunil Ravi2a14cf12023-11-21 00:54:38 +000011356 "capa.flags2=0x%llx\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011357 "capa.rrm_flags=0x%x\n"
Dmitry Shmidt56052862013-10-04 10:23:25 -070011358 "capa.max_scan_ssids=%d\n"
11359 "capa.max_sched_scan_ssids=%d\n"
11360 "capa.sched_scan_supported=%d\n"
11361 "capa.max_match_sets=%d\n"
11362 "capa.max_remain_on_chan=%u\n"
11363 "capa.max_stations=%u\n"
11364 "capa.probe_resp_offloads=0x%x\n"
11365 "capa.max_acl_mac_addrs=%u\n"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011366 "capa.num_multichan_concurrent=%u\n"
11367 "capa.mac_addr_rand_sched_scan_supported=%d\n"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011368 "capa.mac_addr_rand_scan_supported=%d\n"
11369 "capa.conc_capab=%u\n"
11370 "capa.max_conc_chan_2_4=%u\n"
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080011371 "capa.max_conc_chan_5_0=%u\n"
11372 "capa.max_sched_scan_plans=%u\n"
11373 "capa.max_sched_scan_plan_interval=%u\n"
Sunil Ravi77d572f2023-01-17 23:58:31 +000011374 "capa.max_sched_scan_plan_iterations=%u\n"
11375 "capa.mbssid_max_interfaces=%u\n"
11376 "capa.ema_max_periodicity=%u\n",
Dmitry Shmidt56052862013-10-04 10:23:25 -070011377 drv->capa.key_mgmt,
11378 drv->capa.enc,
11379 drv->capa.auth,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011380 (unsigned long long) drv->capa.flags,
Sunil Ravi2a14cf12023-11-21 00:54:38 +000011381 (unsigned long long) drv->capa.flags2,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011382 drv->capa.rrm_flags,
Dmitry Shmidt56052862013-10-04 10:23:25 -070011383 drv->capa.max_scan_ssids,
11384 drv->capa.max_sched_scan_ssids,
11385 drv->capa.sched_scan_supported,
11386 drv->capa.max_match_sets,
11387 drv->capa.max_remain_on_chan,
11388 drv->capa.max_stations,
11389 drv->capa.probe_resp_offloads,
11390 drv->capa.max_acl_mac_addrs,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011391 drv->capa.num_multichan_concurrent,
11392 drv->capa.mac_addr_rand_sched_scan_supported,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011393 drv->capa.mac_addr_rand_scan_supported,
11394 drv->capa.conc_capab,
11395 drv->capa.max_conc_chan_2_4,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080011396 drv->capa.max_conc_chan_5_0,
11397 drv->capa.max_sched_scan_plans,
11398 drv->capa.max_sched_scan_plan_interval,
Sunil Ravi77d572f2023-01-17 23:58:31 +000011399 drv->capa.max_sched_scan_plan_iterations,
11400 drv->capa.mbssid_max_interfaces,
11401 drv->capa.ema_max_periodicity);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011402 if (os_snprintf_error(end - pos, res))
Dmitry Shmidt56052862013-10-04 10:23:25 -070011403 return pos - buf;
11404 pos += res;
11405 }
11406
Hai Shalom74f70d42019-02-11 14:42:39 -080011407 msg = nlmsg_alloc();
11408 if (msg &&
11409 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG) &&
11410 nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx) == 0) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011411 if (send_and_recv_resp(drv, msg, nl80211_get_country,
11412 alpha2) == 0 &&
Hai Shalom74f70d42019-02-11 14:42:39 -080011413 alpha2[0]) {
11414 res = os_snprintf(pos, end - pos, "country=%s\n",
11415 alpha2);
11416 if (os_snprintf_error(end - pos, res))
11417 return pos - buf;
11418 pos += res;
11419 }
11420 } else {
11421 nlmsg_free(msg);
11422 }
11423
Dmitry Shmidt56052862013-10-04 10:23:25 -070011424 return pos - buf;
11425}
11426
11427
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011428static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
11429{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011430 if ((settings->head &&
11431 nla_put(msg, NL80211_ATTR_BEACON_HEAD,
11432 settings->head_len, settings->head)) ||
11433 (settings->tail &&
11434 nla_put(msg, NL80211_ATTR_BEACON_TAIL,
11435 settings->tail_len, settings->tail)) ||
11436 (settings->beacon_ies &&
11437 nla_put(msg, NL80211_ATTR_IE,
11438 settings->beacon_ies_len, settings->beacon_ies)) ||
11439 (settings->proberesp_ies &&
11440 nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
11441 settings->proberesp_ies_len, settings->proberesp_ies)) ||
11442 (settings->assocresp_ies &&
11443 nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
11444 settings->assocresp_ies_len, settings->assocresp_ies)) ||
11445 (settings->probe_resp &&
11446 nla_put(msg, NL80211_ATTR_PROBE_RESP,
11447 settings->probe_resp_len, settings->probe_resp)))
11448 return -ENOBUFS;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011449
11450 return 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011451}
11452
11453
11454static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
11455{
11456 struct nl_msg *msg;
11457 struct i802_bss *bss = priv;
11458 struct wpa_driver_nl80211_data *drv = bss->drv;
11459 struct nlattr *beacon_csa;
11460 int ret = -ENOBUFS;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011461 int csa_off_len = 0;
11462 int i;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011463
Hai Shalomc1a21442022-02-04 13:43:00 -080011464 wpa_printf(MSG_DEBUG,
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011465 "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d channel=%d sec_channel_offset=%d width=%d cf1=%d cf2=%d puncturing_bitmap=0x%04x link_id=%d%s%s%s)",
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011466 settings->cs_count, settings->block_tx,
Hai Shalomc1a21442022-02-04 13:43:00 -080011467 settings->freq_params.freq,
11468 settings->freq_params.channel,
11469 settings->freq_params.sec_channel_offset,
11470 settings->freq_params.bandwidth,
Dmitry Shmidt04f534e2013-12-09 15:50:16 -080011471 settings->freq_params.center_freq1,
Hai Shalomc1a21442022-02-04 13:43:00 -080011472 settings->freq_params.center_freq2,
Sunil Ravi036cec52023-03-29 11:35:17 -070011473 settings->punct_bitmap,
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011474 settings->link_id,
Hai Shalomc1a21442022-02-04 13:43:00 -080011475 settings->freq_params.ht_enabled ? " ht" : "",
11476 settings->freq_params.vht_enabled ? " vht" : "",
11477 settings->freq_params.he_enabled ? " he" : "");
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011478
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080011479 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_AP_CSA)) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011480 wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
11481 return -EOPNOTSUPP;
11482 }
11483
Roshan Pius3a1667e2018-07-03 15:17:14 -070011484 if (drv->nlmode != NL80211_IFTYPE_AP &&
11485 drv->nlmode != NL80211_IFTYPE_P2P_GO &&
11486 drv->nlmode != NL80211_IFTYPE_MESH_POINT)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011487 return -EOPNOTSUPP;
11488
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011489 /*
11490 * Remove empty counters, assuming Probe Response and Beacon frame
11491 * counters match. This implementation assumes that there are only two
11492 * counters.
11493 */
11494 if (settings->counter_offset_beacon[0] &&
11495 !settings->counter_offset_beacon[1]) {
11496 csa_off_len = 1;
11497 } else if (settings->counter_offset_beacon[1] &&
11498 !settings->counter_offset_beacon[0]) {
11499 csa_off_len = 1;
11500 settings->counter_offset_beacon[0] =
11501 settings->counter_offset_beacon[1];
11502 settings->counter_offset_presp[0] =
11503 settings->counter_offset_presp[1];
11504 } else if (settings->counter_offset_beacon[1] &&
11505 settings->counter_offset_beacon[0]) {
11506 csa_off_len = 2;
11507 } else {
11508 wpa_printf(MSG_ERROR, "nl80211: No CSA counters provided");
11509 return -EINVAL;
11510 }
11511
11512 /* Check CSA counters validity */
11513 if (drv->capa.max_csa_counters &&
11514 csa_off_len > drv->capa.max_csa_counters) {
11515 wpa_printf(MSG_ERROR,
11516 "nl80211: Too many CSA counters provided");
11517 return -EINVAL;
11518 }
11519
11520 if (!settings->beacon_csa.tail)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011521 return -EINVAL;
11522
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011523 for (i = 0; i < csa_off_len; i++) {
11524 u16 csa_c_off_bcn = settings->counter_offset_beacon[i];
11525 u16 csa_c_off_presp = settings->counter_offset_presp[i];
11526
11527 if ((settings->beacon_csa.tail_len <= csa_c_off_bcn) ||
11528 (settings->beacon_csa.tail[csa_c_off_bcn] !=
11529 settings->cs_count))
11530 return -EINVAL;
11531
11532 if (settings->beacon_csa.probe_resp &&
11533 ((settings->beacon_csa.probe_resp_len <=
11534 csa_c_off_presp) ||
11535 (settings->beacon_csa.probe_resp[csa_c_off_presp] !=
11536 settings->cs_count)))
11537 return -EINVAL;
11538 }
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011539
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011540 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CHANNEL_SWITCH)) ||
11541 nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT,
11542 settings->cs_count) ||
11543 (ret = nl80211_put_freq_params(msg, &settings->freq_params)) ||
11544 (settings->block_tx &&
Sunil Ravi036cec52023-03-29 11:35:17 -070011545 nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)) ||
11546 (settings->punct_bitmap &&
11547 nla_put_u32(msg, NL80211_ATTR_PUNCT_BITMAP,
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011548 settings->punct_bitmap)) ||
11549 (settings->link_id != NL80211_DRV_LINK_ID_NA &&
11550 nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, settings->link_id)))
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011551 goto error;
11552
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011553 /* beacon_after params */
11554 ret = set_beacon_data(msg, &settings->beacon_after);
11555 if (ret)
11556 goto error;
11557
11558 /* beacon_csa params */
11559 beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
11560 if (!beacon_csa)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011561 goto fail;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011562
11563 ret = set_beacon_data(msg, &settings->beacon_csa);
11564 if (ret)
11565 goto error;
11566
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011567 if (nla_put(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
11568 csa_off_len * sizeof(u16),
11569 settings->counter_offset_beacon) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011570 (settings->beacon_csa.probe_resp &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080011571 nla_put(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
11572 csa_off_len * sizeof(u16),
11573 settings->counter_offset_presp)))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011574 goto fail;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011575
11576 nla_nest_end(msg, beacon_csa);
Sunil Ravi7f769292024-07-23 22:21:32 +000011577
11578#ifdef CONFIG_IEEE80211AX
11579 if (settings->ubpr.unsol_bcast_probe_resp_interval &&
11580 nl80211_unsol_bcast_probe_resp(bss, msg, &settings->ubpr) < 0)
11581 goto fail;
11582#endif /* CONFIG_IEEE80211AX */
11583
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011584 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011585 if (ret) {
11586 wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
11587 ret, strerror(-ret));
11588 }
11589 return ret;
11590
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011591fail:
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080011592 ret = -ENOBUFS;
11593error:
11594 nlmsg_free(msg);
11595 wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request");
11596 return ret;
11597}
11598
11599
Sunil Ravia04bd252022-05-02 22:54:18 -070011600#ifdef CONFIG_IEEE80211AX
11601static int nl80211_switch_color(void *priv, struct cca_settings *settings)
11602{
11603 struct i802_bss *bss = priv;
11604 struct wpa_driver_nl80211_data *drv = bss->drv;
11605 struct nlattr *beacon_cca;
11606 struct nl_msg *msg;
11607 int ret = -ENOBUFS;
11608
11609 wpa_printf(MSG_DEBUG,
11610 "nl80211: Color change request (cca_count=%u color=%d)",
11611 settings->cca_count, settings->cca_color);
11612
11613 if (drv->nlmode != NL80211_IFTYPE_AP)
11614 return -EOPNOTSUPP;
11615
11616 if (!settings->beacon_cca.tail)
11617 return -EINVAL;
11618
11619 if (settings->beacon_cca.tail_len <= settings->counter_offset_beacon ||
11620 settings->beacon_cca.tail[settings->counter_offset_beacon] !=
11621 settings->cca_count)
11622 return -EINVAL;
11623
11624 if (settings->beacon_cca.probe_resp &&
11625 (settings->beacon_cca.probe_resp_len <=
11626 settings->counter_offset_presp ||
11627 settings->beacon_cca.probe_resp[settings->counter_offset_presp] !=
11628 settings->cca_count))
11629 return -EINVAL;
11630
11631 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_COLOR_CHANGE_REQUEST);
11632 if (!msg ||
11633 nla_put_u8(msg, NL80211_ATTR_COLOR_CHANGE_COUNT,
11634 settings->cca_count) ||
11635 nla_put_u8(msg, NL80211_ATTR_COLOR_CHANGE_COLOR,
11636 settings->cca_color))
11637 goto error;
11638
11639 /* beacon_after params */
11640 ret = set_beacon_data(msg, &settings->beacon_after);
11641 if (ret)
11642 goto error;
11643
11644 /* beacon_csa params */
11645 beacon_cca = nla_nest_start(msg, NL80211_ATTR_COLOR_CHANGE_ELEMS);
11646 if (!beacon_cca) {
11647 ret = -ENOBUFS;
11648 goto error;
11649 }
11650
11651 ret = set_beacon_data(msg, &settings->beacon_cca);
11652 if (ret)
11653 goto error;
11654
11655 if (nla_put_u16(msg, NL80211_ATTR_CNTDWN_OFFS_BEACON,
11656 settings->counter_offset_beacon) ||
11657 (settings->beacon_cca.probe_resp &&
11658 nla_put_u16(msg, NL80211_ATTR_CNTDWN_OFFS_PRESP,
11659 settings->counter_offset_presp))) {
11660 ret = -ENOBUFS;
11661 goto error;
11662 }
11663
11664 nla_nest_end(msg, beacon_cca);
Sunil Ravi7f769292024-07-23 22:21:32 +000011665
11666 if (settings->ubpr.unsol_bcast_probe_resp_interval &&
11667 nl80211_unsol_bcast_probe_resp(bss, msg, &settings->ubpr) < 0) {
11668 ret = -ENOBUFS;
11669 goto error;
11670 }
11671
11672#ifdef CONFIG_IEEE80211BE
11673 if (nl80211_link_valid(bss->valid_links, settings->link_id)) {
11674 wpa_printf(MSG_DEBUG,
11675 "nl80211: Color change request on link_id=%d",
11676 settings->link_id);
11677
11678 if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID,
11679 settings->link_id)) {
11680 nlmsg_free(msg);
11681 return -1;
11682 }
11683 }
11684#endif /* CONFIG_IEEE80211BE */
11685
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011686 ret = send_and_recv_cmd(drv, msg);
Sunil Ravia04bd252022-05-02 22:54:18 -070011687 if (ret) {
11688 wpa_printf(MSG_DEBUG,
11689 "nl80211: switch_color failed err=%d (%s)",
11690 ret, strerror(-ret));
11691 }
11692 return ret;
11693
11694error:
11695 nlmsg_free(msg);
11696 wpa_printf(MSG_DEBUG, "nl80211: Could not build color switch request");
11697 return ret;
11698}
11699#endif /* CONFIG_IEEE80211AX */
11700
11701
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011702static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr,
11703 u8 user_priority, u16 admitted_time)
11704{
11705 struct i802_bss *bss = priv;
11706 struct wpa_driver_nl80211_data *drv = bss->drv;
11707 struct nl_msg *msg;
11708 int ret;
11709
11710 wpa_printf(MSG_DEBUG,
11711 "nl80211: add_ts request: tsid=%u admitted_time=%u up=%d",
11712 tsid, admitted_time, user_priority);
11713
11714 if (!is_sta_interface(drv->nlmode))
11715 return -ENOTSUP;
11716
11717 msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ADD_TX_TS);
11718 if (!msg ||
11719 nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
11720 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
11721 nla_put_u8(msg, NL80211_ATTR_USER_PRIO, user_priority) ||
11722 nla_put_u16(msg, NL80211_ATTR_ADMITTED_TIME, admitted_time)) {
11723 nlmsg_free(msg);
11724 return -ENOBUFS;
11725 }
11726
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011727 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011728 if (ret)
11729 wpa_printf(MSG_DEBUG, "nl80211: add_ts failed err=%d (%s)",
11730 ret, strerror(-ret));
11731 return ret;
11732}
11733
11734
11735static int nl80211_del_ts(void *priv, u8 tsid, const u8 *addr)
11736{
11737 struct i802_bss *bss = priv;
11738 struct wpa_driver_nl80211_data *drv = bss->drv;
11739 struct nl_msg *msg;
11740 int ret;
11741
11742 wpa_printf(MSG_DEBUG, "nl80211: del_ts request: tsid=%u", tsid);
11743
11744 if (!is_sta_interface(drv->nlmode))
11745 return -ENOTSUP;
11746
11747 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_TX_TS)) ||
11748 nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
11749 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
11750 nlmsg_free(msg);
11751 return -ENOBUFS;
11752 }
11753
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011754 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011755 if (ret)
11756 wpa_printf(MSG_DEBUG, "nl80211: del_ts failed err=%d (%s)",
11757 ret, strerror(-ret));
11758 return ret;
11759}
11760
11761
Dmitry Shmidta38abf92014-03-06 13:38:44 -080011762#ifdef CONFIG_TESTING_OPTIONS
11763static int cmd_reply_handler(struct nl_msg *msg, void *arg)
11764{
11765 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
11766 struct wpabuf *buf = arg;
11767
11768 if (!buf)
11769 return NL_SKIP;
11770
11771 if ((size_t) genlmsg_attrlen(gnlh, 0) > wpabuf_tailroom(buf)) {
11772 wpa_printf(MSG_INFO, "nl80211: insufficient buffer space for reply");
11773 return NL_SKIP;
11774 }
11775
11776 wpabuf_put_data(buf, genlmsg_attrdata(gnlh, 0),
11777 genlmsg_attrlen(gnlh, 0));
11778
11779 return NL_SKIP;
11780}
11781#endif /* CONFIG_TESTING_OPTIONS */
11782
11783
11784static int vendor_reply_handler(struct nl_msg *msg, void *arg)
11785{
11786 struct nlattr *tb[NL80211_ATTR_MAX + 1];
11787 struct nlattr *nl_vendor_reply, *nl;
11788 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
11789 struct wpabuf *buf = arg;
11790 int rem;
11791
11792 if (!buf)
11793 return NL_SKIP;
11794
11795 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
11796 genlmsg_attrlen(gnlh, 0), NULL);
11797 nl_vendor_reply = tb[NL80211_ATTR_VENDOR_DATA];
11798
11799 if (!nl_vendor_reply)
11800 return NL_SKIP;
11801
11802 if ((size_t) nla_len(nl_vendor_reply) > wpabuf_tailroom(buf)) {
11803 wpa_printf(MSG_INFO, "nl80211: Vendor command: insufficient buffer space for reply");
11804 return NL_SKIP;
11805 }
11806
11807 nla_for_each_nested(nl, nl_vendor_reply, rem) {
11808 wpabuf_put_data(buf, nla_data(nl), nla_len(nl));
11809 }
11810
11811 return NL_SKIP;
11812}
11813
11814
Hai Shalom60840252021-02-19 19:02:11 -080011815static bool is_cmd_with_nested_attrs(unsigned int vendor_id,
11816 unsigned int subcmd)
11817{
11818 if (vendor_id != OUI_QCA)
11819 return true;
11820
11821 switch (subcmd) {
11822 case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
11823 case QCA_NL80211_VENDOR_SUBCMD_STATS_EXT:
11824 case QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI:
11825 case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY:
11826 case QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS:
11827 case QCA_NL80211_VENDOR_SUBCMD_NAN:
11828 return false;
11829 default:
11830 return true;
11831 }
11832}
11833
11834
Dmitry Shmidta38abf92014-03-06 13:38:44 -080011835static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
11836 unsigned int subcmd, const u8 *data,
Hai Shalom60840252021-02-19 19:02:11 -080011837 size_t data_len, enum nested_attr nested_attr,
11838 struct wpabuf *buf)
Dmitry Shmidta38abf92014-03-06 13:38:44 -080011839{
11840 struct i802_bss *bss = priv;
11841 struct wpa_driver_nl80211_data *drv = bss->drv;
11842 struct nl_msg *msg;
Hai Shalom60840252021-02-19 19:02:11 -080011843 int ret, nla_flag;
Dmitry Shmidta38abf92014-03-06 13:38:44 -080011844
Dmitry Shmidta38abf92014-03-06 13:38:44 -080011845#ifdef CONFIG_TESTING_OPTIONS
11846 if (vendor_id == 0xffffffff) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011847 msg = nlmsg_alloc();
11848 if (!msg)
11849 return -ENOMEM;
11850
Dmitry Shmidta38abf92014-03-06 13:38:44 -080011851 nl80211_cmd(drv, msg, 0, subcmd);
11852 if (nlmsg_append(msg, (void *) data, data_len, NLMSG_ALIGNTO) <
11853 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011854 goto fail;
Hai Shalomb755a2a2020-04-23 21:49:02 -070011855 /* This test vendor_cmd can be used with nl80211 commands that
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011856 * need the connect nl_sock, so use the variant that takes in
11857 * bss->nl_connect as the handle. */
11858 ret = send_and_recv(drv->global, bss->nl_connect, msg,
11859 cmd_reply_handler, buf, NULL, NULL, NULL);
Dmitry Shmidta38abf92014-03-06 13:38:44 -080011860 if (ret)
11861 wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
11862 ret);
11863 return ret;
11864 }
11865#endif /* CONFIG_TESTING_OPTIONS */
11866
Hai Shalom60840252021-02-19 19:02:11 -080011867 if (nested_attr == NESTED_ATTR_USED)
11868 nla_flag = NLA_F_NESTED;
11869 else if (nested_attr == NESTED_ATTR_UNSPECIFIED &&
11870 is_cmd_with_nested_attrs(vendor_id, subcmd))
11871 nla_flag = NLA_F_NESTED;
11872 else
11873 nla_flag = 0;
11874
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011875 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
11876 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, vendor_id) ||
11877 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd) ||
11878 (data &&
Hai Shalom60840252021-02-19 19:02:11 -080011879 nla_put(msg, nla_flag | NL80211_ATTR_VENDOR_DATA,
11880 data_len, data)))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011881 goto fail;
Dmitry Shmidta38abf92014-03-06 13:38:44 -080011882
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011883 ret = send_and_recv_resp(drv, msg, vendor_reply_handler, buf);
Dmitry Shmidta38abf92014-03-06 13:38:44 -080011884 if (ret)
11885 wpa_printf(MSG_DEBUG, "nl80211: vendor command failed err=%d",
11886 ret);
11887 return ret;
11888
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011889fail:
Dmitry Shmidta38abf92014-03-06 13:38:44 -080011890 nlmsg_free(msg);
11891 return -ENOBUFS;
11892}
11893
11894
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080011895static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
11896 u8 qos_map_set_len)
11897{
11898 struct i802_bss *bss = priv;
11899 struct wpa_driver_nl80211_data *drv = bss->drv;
11900 struct nl_msg *msg;
11901 int ret;
11902
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080011903 wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
11904 qos_map_set, qos_map_set_len);
11905
Sunil Ravi2a14cf12023-11-21 00:54:38 +000011906 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_QOS_MAP)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011907 nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) {
11908 nlmsg_free(msg);
11909 return -ENOBUFS;
11910 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080011911
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011912 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080011913 if (ret)
11914 wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
11915
11916 return ret;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080011917}
11918
11919
Hai Shalomfdcde762020-04-02 11:19:20 -070011920static int get_wowlan_handler(struct nl_msg *msg, void *arg)
11921{
11922 struct nlattr *tb[NL80211_ATTR_MAX + 1];
11923 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
11924 int *wowlan_enabled = arg;
11925
11926 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
11927 genlmsg_attrlen(gnlh, 0), NULL);
11928
11929 *wowlan_enabled = !!tb[NL80211_ATTR_WOWLAN_TRIGGERS];
11930
11931 return NL_SKIP;
11932}
11933
11934
11935static int nl80211_get_wowlan(void *priv)
11936{
11937 struct i802_bss *bss = priv;
11938 struct wpa_driver_nl80211_data *drv = bss->drv;
11939 struct nl_msg *msg;
11940 int wowlan_enabled;
11941 int ret;
11942
11943 wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status");
11944
11945 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_WOWLAN);
11946
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011947 ret = send_and_recv_resp(drv, msg, get_wowlan_handler, &wowlan_enabled);
Hai Shalomfdcde762020-04-02 11:19:20 -070011948 if (ret) {
11949 wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status failed");
11950 return 0;
11951 }
11952
11953 wpa_printf(MSG_DEBUG, "nl80211: wowlan is %s",
11954 wowlan_enabled ? "enabled" : "disabled");
11955
11956 return wowlan_enabled;
11957}
11958
11959
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070011960static int nl80211_set_wowlan(void *priv,
11961 const struct wowlan_triggers *triggers)
11962{
11963 struct i802_bss *bss = priv;
11964 struct wpa_driver_nl80211_data *drv = bss->drv;
11965 struct nl_msg *msg;
11966 struct nlattr *wowlan_triggers;
11967 int ret;
11968
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070011969 wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
11970
Dmitry Shmidta3dc3092015-06-23 11:21:28 -070011971 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_WOWLAN)) ||
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080011972 !(wowlan_triggers = nla_nest_start(msg,
11973 NL80211_ATTR_WOWLAN_TRIGGERS)) ||
11974 (triggers->any &&
11975 nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
11976 (triggers->disconnect &&
11977 nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
11978 (triggers->magic_pkt &&
11979 nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
11980 (triggers->gtk_rekey_failure &&
11981 nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
11982 (triggers->eap_identity_req &&
11983 nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
11984 (triggers->four_way_handshake &&
11985 nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
11986 (triggers->rfkill_release &&
11987 nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) {
11988 nlmsg_free(msg);
11989 return -ENOBUFS;
11990 }
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070011991
11992 nla_nest_end(msg, wowlan_triggers);
11993
Sunil Ravib0ac25f2024-07-12 01:42:03 +000011994 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070011995 if (ret)
11996 wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
11997
11998 return ret;
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070011999}
12000
12001
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012002#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070012003static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
12004{
12005 struct i802_bss *bss = priv;
12006 struct wpa_driver_nl80211_data *drv = bss->drv;
12007 struct nl_msg *msg;
12008 struct nlattr *params;
12009
12010 wpa_printf(MSG_DEBUG, "nl80211: Roaming policy: allowed=%d", allowed);
12011
12012 if (!drv->roaming_vendor_cmd_avail) {
12013 wpa_printf(MSG_DEBUG,
12014 "nl80211: Ignore roaming policy change since driver does not provide command for setting it");
12015 return -1;
12016 }
12017
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012018 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
12019 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
12020 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
12021 QCA_NL80211_VENDOR_SUBCMD_ROAMING) ||
12022 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
12023 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
12024 allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
12025 QCA_ROAMING_NOT_ALLOWED) ||
12026 (bssid &&
12027 nla_put(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid))) {
12028 nlmsg_free(msg);
12029 return -1;
12030 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070012031 nla_nest_end(msg, params);
12032
Sunil Ravib0ac25f2024-07-12 01:42:03 +000012033 return send_and_recv_cmd(drv, msg);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070012034}
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012035
12036
Roshan Pius3a1667e2018-07-03 15:17:14 -070012037static int nl80211_disable_fils(void *priv, int disable)
12038{
12039 struct i802_bss *bss = priv;
12040 struct wpa_driver_nl80211_data *drv = bss->drv;
12041 struct nl_msg *msg;
12042 struct nlattr *params;
12043
12044 wpa_printf(MSG_DEBUG, "nl80211: Disable FILS=%d", disable);
12045
12046 if (!drv->set_wifi_conf_vendor_cmd_avail)
12047 return -1;
12048
12049 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
12050 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
12051 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
12052 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION) ||
12053 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
12054 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS,
12055 disable)) {
12056 nlmsg_free(msg);
12057 return -1;
12058 }
12059 nla_nest_end(msg, params);
12060
Sunil Ravib0ac25f2024-07-12 01:42:03 +000012061 return send_and_recv_cmd(drv, msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -070012062}
12063
12064
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012065/* Reserved QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID value for wpa_supplicant */
12066#define WPA_SUPPLICANT_CLIENT_ID 1
12067
Hai Shalom899fcc72020-10-19 14:38:18 -070012068static int nl80211_set_bssid_tmp_disallow(void *priv, unsigned int num_bssid,
12069 const u8 *bssid)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012070{
12071 struct i802_bss *bss = priv;
12072 struct wpa_driver_nl80211_data *drv = bss->drv;
12073 struct nl_msg *msg;
12074 struct nlattr *params, *nlbssids, *attr;
12075 unsigned int i;
12076
Hai Shalom899fcc72020-10-19 14:38:18 -070012077 wpa_printf(MSG_DEBUG,
12078 "nl80211: Set temporarily disallowed BSSIDs (num=%u)",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012079 num_bssid);
12080
12081 if (!drv->roam_vendor_cmd_avail)
12082 return -1;
12083
12084 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
12085 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
12086 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
12087 QCA_NL80211_VENDOR_SUBCMD_ROAM) ||
12088 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
12089 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
Hai Shalomc3565922019-10-28 11:58:20 -070012090 QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID) ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012091 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID,
12092 WPA_SUPPLICANT_CLIENT_ID) ||
12093 nla_put_u32(msg,
12094 QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID,
12095 num_bssid))
12096 goto fail;
12097
12098 nlbssids = nla_nest_start(
12099 msg, QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS);
12100 if (!nlbssids)
12101 goto fail;
12102
12103 for (i = 0; i < num_bssid; i++) {
12104 attr = nla_nest_start(msg, i);
12105 if (!attr)
12106 goto fail;
12107 if (nla_put(msg,
12108 QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID,
12109 ETH_ALEN, &bssid[i * ETH_ALEN]))
12110 goto fail;
12111 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%u]: " MACSTR, i,
12112 MAC2STR(&bssid[i * ETH_ALEN]));
12113 nla_nest_end(msg, attr);
12114 }
12115 nla_nest_end(msg, nlbssids);
12116 nla_nest_end(msg, params);
12117
Sunil Ravib0ac25f2024-07-12 01:42:03 +000012118 return send_and_recv_cmd(drv, msg);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012119
12120fail:
12121 nlmsg_free(msg);
12122 return -1;
12123}
12124
Hai Shalomc3565922019-10-28 11:58:20 -070012125
12126static int nl80211_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
12127{
12128 struct i802_bss *bss = priv;
12129 struct wpa_driver_nl80211_data *drv = bss->drv;
12130 struct nl_msg *msg;
12131 struct nlattr *params;
12132
12133 if (!drv->add_sta_node_vendor_cmd_avail)
12134 return -EOPNOTSUPP;
12135
12136 wpa_printf(MSG_DEBUG, "nl80211: Add STA node");
12137
12138 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
12139 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
12140 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
12141 QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE) ||
12142 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
12143 (addr &&
12144 nla_put(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_MAC_ADDR, ETH_ALEN,
12145 addr)) ||
12146 nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO,
12147 auth_alg)) {
12148 nlmsg_free(msg);
12149 wpa_printf(MSG_ERROR,
12150 "%s: err in adding vendor_cmd and vendor_data",
12151 __func__);
12152 return -1;
12153 }
12154 nla_nest_end(msg, params);
12155
Sunil Ravib0ac25f2024-07-12 01:42:03 +000012156 return send_and_recv_cmd(drv, msg);
Hai Shalomc3565922019-10-28 11:58:20 -070012157}
12158
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012159#endif /* CONFIG_DRIVER_NL80211_QCA */
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070012160
12161
12162static int nl80211_set_mac_addr(void *priv, const u8 *addr)
12163{
12164 struct i802_bss *bss = priv;
12165 struct wpa_driver_nl80211_data *drv = bss->drv;
12166 int new_addr = addr != NULL;
Andy Kuoaba17c12022-04-14 16:05:31 +080012167#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Mir Ali8a8f1002020-10-06 22:41:40 +053012168 struct nl_msg *msg;
12169 struct nlattr *params;
12170 int ret;
Andy Kuoaba17c12022-04-14 16:05:31 +080012171#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
Mir Ali8a8f1002020-10-06 22:41:40 +053012172 wpa_printf(MSG_DEBUG, "Enter: %s", __FUNCTION__);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070012173
Dmitry Shmidt849734c2016-05-27 09:59:01 -070012174 if (TEST_FAIL())
12175 return -1;
Mir Ali8a8f1002020-10-06 22:41:40 +053012176 if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
Andy Kuoaba17c12022-04-14 16:05:31 +080012177#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Mir Ali8a8f1002020-10-06 22:41:40 +053012178 if (!addr ) {
12179 addr = drv->global->p2p_perm_addr;
12180 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -070012181
Mir Ali8a8f1002020-10-06 22:41:40 +053012182 if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
12183 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
12184 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
Hai Shalomc1a21442022-02-04 13:43:00 -080012185 BRCM_VENDOR_SCMD_SET_MAC) ||
Mir Ali8a8f1002020-10-06 22:41:40 +053012186 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
12187 nla_put(msg, BRCM_ATTR_DRIVER_MAC_ADDR, ETH_ALEN, addr)) {
12188 wpa_printf(MSG_ERROR, "failed to put p2p randmac");
12189 nl80211_nlmsg_clear(msg);
12190 nlmsg_free(msg);
12191 return -ENOBUFS;
12192 }
12193 nla_nest_end(msg, params);
12194
Sunil Ravib0ac25f2024-07-12 01:42:03 +000012195 ret = send_and_recv_cmd(drv, msg);
Mir Ali8a8f1002020-10-06 22:41:40 +053012196 if (ret) {
12197 wpa_printf(MSG_ERROR, "nl80211: p2p set macaddr failed: ret=%d (%s)",
12198 ret, strerror(-ret));
12199 }
12200 memcpy(bss->addr, addr, ETH_ALEN);
12201 return ret;
12202#else
12203 return -ENOTSUP;
Andy Kuoaba17c12022-04-14 16:05:31 +080012204#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
Mir Ali8a8f1002020-10-06 22:41:40 +053012205 }
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070012206 if (!addr)
12207 addr = drv->perm_addr;
12208
12209 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) < 0)
12210 return -1;
12211
12212 if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, addr) < 0)
12213 {
12214 wpa_printf(MSG_DEBUG,
Mir Ali8a8f1002020-10-06 22:41:40 +053012215 "nl80211: failed to set_mac_addr for %s to " MACSTR,
12216 bss->ifname, MAC2STR(addr));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070012217 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
Mir Ali8a8f1002020-10-06 22:41:40 +053012218 1) < 0) {
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070012219 wpa_printf(MSG_DEBUG,
Mir Ali8a8f1002020-10-06 22:41:40 +053012220 "nl80211: Could not restore interface UP after failed set_mac_addr");
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070012221 }
12222 return -1;
12223 }
12224
12225 wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR,
Sunil Ravi2a14cf12023-11-21 00:54:38 +000012226 bss->ifname, MAC2STR(addr));
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070012227 drv->addr_changed = new_addr;
Sunil Ravi77d572f2023-01-17 23:58:31 +000012228 os_memcpy(bss->prev_addr, bss->addr, ETH_ALEN);
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070012229 os_memcpy(bss->addr, addr, ETH_ALEN);
12230
Hsiu-Chang Chen289286d2024-01-24 18:00:43 +080012231 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0)
12232 {
12233 wpa_printf(MSG_DEBUG,
12234 "nl80211: Could not restore interface UP after set_mac_addr");
12235 }
12236
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070012237 return 0;
12238}
12239
12240
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012241#ifdef CONFIG_MESH
12242
12243static int wpa_driver_nl80211_init_mesh(void *priv)
12244{
12245 if (wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_MESH_POINT)) {
12246 wpa_printf(MSG_INFO,
12247 "nl80211: Failed to set interface into mesh mode");
12248 return -1;
12249 }
12250 return 0;
12251}
12252
12253
Dmitry Shmidtff787d52015-01-12 13:01:47 -080012254static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id,
12255 size_t mesh_id_len)
12256{
12257 if (mesh_id) {
Hai Shalom74f70d42019-02-11 14:42:39 -080012258 wpa_printf(MSG_DEBUG, " * Mesh ID (SSID)=%s",
12259 wpa_ssid_txt(mesh_id, mesh_id_len));
Dmitry Shmidtff787d52015-01-12 13:01:47 -080012260 return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
12261 }
12262
12263 return 0;
12264}
12265
12266
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070012267static int nl80211_put_mesh_config(struct nl_msg *msg,
12268 struct wpa_driver_mesh_bss_params *params)
12269{
12270 struct nlattr *container;
12271
12272 container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
12273 if (!container)
12274 return -1;
12275
12276 if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
Roshan Pius3a1667e2018-07-03 15:17:14 -070012277 nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
12278 params->auto_plinks)) ||
Hai Shalomc1a21442022-02-04 13:43:00 -080012279 ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_FORWARDING) &&
12280 nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
12281 params->forwarding)) ||
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070012282 ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) &&
12283 nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012284 params->max_peer_links)) ||
12285 ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD) &&
12286 nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
12287 params->rssi_threshold)))
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070012288 return -1;
12289
12290 /*
12291 * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
12292 * the timer could disconnect stations even in that case.
12293 */
12294 if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT) &&
12295 nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
12296 params->peer_link_timeout)) {
12297 wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
12298 return -1;
12299 }
12300
12301 if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE) &&
12302 nla_put_u16(msg, NL80211_MESHCONF_HT_OPMODE, params->ht_opmode)) {
12303 wpa_printf(MSG_ERROR, "nl80211: Failed to set HT_OP_MODE");
12304 return -1;
12305 }
12306
12307 nla_nest_end(msg, container);
12308
12309 return 0;
12310}
12311
12312
Dmitry Shmidt7f656022015-02-25 14:36:37 -080012313static int nl80211_join_mesh(struct i802_bss *bss,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012314 struct wpa_driver_mesh_join_params *params)
12315{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012316 struct wpa_driver_nl80211_data *drv = bss->drv;
12317 struct nl_msg *msg;
12318 struct nlattr *container;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -080012319 int ret = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012320
12321 wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
12322 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
Dmitry Shmidtff787d52015-01-12 13:01:47 -080012323 if (!msg ||
12324 nl80211_put_freq_params(msg, &params->freq) ||
12325 nl80211_put_basic_rates(msg, params->basic_rates) ||
12326 nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) ||
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070012327 nl80211_put_beacon_int(msg, params->beacon_int) ||
12328 nl80211_put_dtim_period(msg, params->dtim_period))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012329 goto fail;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012330
12331 wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags);
12332
Hai Shalom60840252021-02-19 19:02:11 -080012333 if (params->handle_dfs && nla_put_flag(msg, NL80211_ATTR_HANDLE_DFS))
12334 goto fail;
12335
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012336 container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
12337 if (!container)
12338 goto fail;
12339
12340 if (params->ies) {
12341 wpa_hexdump(MSG_DEBUG, " * IEs", params->ies, params->ie_len);
12342 if (nla_put(msg, NL80211_MESH_SETUP_IE, params->ie_len,
12343 params->ies))
12344 goto fail;
12345 }
12346 /* WPA_DRIVER_MESH_FLAG_OPEN_AUTH is treated as default by nl80211 */
12347 if (params->flags & WPA_DRIVER_MESH_FLAG_SAE_AUTH) {
12348 if (nla_put_u8(msg, NL80211_MESH_SETUP_AUTH_PROTOCOL, 0x1) ||
12349 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AUTH))
12350 goto fail;
12351 }
12352 if ((params->flags & WPA_DRIVER_MESH_FLAG_AMPE) &&
12353 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AMPE))
12354 goto fail;
12355 if ((params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) &&
12356 nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_MPM))
12357 goto fail;
12358 nla_nest_end(msg, container);
12359
Dmitry Shmidtd13095b2016-08-22 14:02:19 -070012360 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
12361 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT;
12362 params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS;
12363 if (nl80211_put_mesh_config(msg, &params->conf) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012364 goto fail;
12365
Sunil Ravib0ac25f2024-07-12 01:42:03 +000012366 if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
12367 return -1;
12368 ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL,
12369 NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012370 msg = NULL;
12371 if (ret) {
12372 wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
12373 ret, strerror(-ret));
12374 goto fail;
12375 }
12376 ret = 0;
Sunil Ravi036cec52023-03-29 11:35:17 -070012377 drv->assoc_freq = bss->flink->freq = params->freq.freq;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012378 wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
12379
12380fail:
12381 nlmsg_free(msg);
12382 return ret;
12383}
12384
12385
Dmitry Shmidt7f656022015-02-25 14:36:37 -080012386static int
12387wpa_driver_nl80211_join_mesh(void *priv,
12388 struct wpa_driver_mesh_join_params *params)
12389{
12390 struct i802_bss *bss = priv;
12391 int ret, timeout;
12392
12393 timeout = params->conf.peer_link_timeout;
12394
12395 /* Disable kernel inactivity timer */
12396 if (params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM)
12397 params->conf.peer_link_timeout = 0;
12398
12399 ret = nl80211_join_mesh(bss, params);
12400 if (ret == -EINVAL && params->conf.peer_link_timeout == 0) {
12401 wpa_printf(MSG_DEBUG,
12402 "nl80211: Mesh join retry for peer_link_timeout");
12403 /*
12404 * Old kernel does not support setting
12405 * NL80211_MESHCONF_PLINK_TIMEOUT to zero, so set 60 seconds
12406 * into future from peer_link_timeout.
12407 */
12408 params->conf.peer_link_timeout = timeout + 60;
12409 ret = nl80211_join_mesh(priv, params);
12410 }
12411
12412 params->conf.peer_link_timeout = timeout;
12413 return ret;
12414}
12415
12416
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012417static int wpa_driver_nl80211_leave_mesh(void *priv)
12418{
12419 struct i802_bss *bss = priv;
12420 struct wpa_driver_nl80211_data *drv = bss->drv;
12421 struct nl_msg *msg;
12422 int ret;
12423
12424 wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
12425 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
Sunil Ravib0ac25f2024-07-12 01:42:03 +000012426 ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL,
12427 NULL, NULL);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012428 if (ret) {
12429 wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
12430 ret, strerror(-ret));
12431 } else {
12432 wpa_printf(MSG_DEBUG,
12433 "nl80211: mesh leave request send successfully");
Sunil Ravi036cec52023-03-29 11:35:17 -070012434 drv->first_bss->flink->freq = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012435 }
12436
Hai Shalomc1a21442022-02-04 13:43:00 -080012437 if (drv->start_mode_sta &&
12438 wpa_driver_nl80211_set_mode(drv->first_bss,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012439 NL80211_IFTYPE_STATION)) {
12440 wpa_printf(MSG_INFO,
12441 "nl80211: Failed to set interface into station mode");
12442 }
12443 return ret;
12444}
12445
Hai Shalom81f62d82019-07-22 12:10:00 -070012446
12447static int nl80211_probe_mesh_link(void *priv, const u8 *addr, const u8 *eth,
12448 size_t len)
12449{
12450 struct i802_bss *bss = priv;
12451 struct wpa_driver_nl80211_data *drv = bss->drv;
12452 struct nl_msg *msg;
12453 int ret;
12454
12455 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_PROBE_MESH_LINK);
12456 if (!msg ||
12457 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
12458 nla_put(msg, NL80211_ATTR_FRAME, len, eth)) {
12459 nlmsg_free(msg);
12460 return -ENOBUFS;
12461 }
12462
Sunil Ravib0ac25f2024-07-12 01:42:03 +000012463 ret = send_and_recv_cmd(drv, msg);
Hai Shalom81f62d82019-07-22 12:10:00 -070012464 if (ret) {
12465 wpa_printf(MSG_DEBUG, "nl80211: mesh link probe to " MACSTR
12466 " failed: ret=%d (%s)",
12467 MAC2STR(addr), ret, strerror(-ret));
12468 } else {
12469 wpa_printf(MSG_DEBUG, "nl80211: Mesh link to " MACSTR
12470 " probed successfully", MAC2STR(addr));
12471 }
12472
12473 return ret;
12474}
12475
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012476#endif /* CONFIG_MESH */
12477
12478
12479static int wpa_driver_br_add_ip_neigh(void *priv, u8 version,
12480 const u8 *ipaddr, int prefixlen,
12481 const u8 *addr)
12482{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012483 struct i802_bss *bss = priv;
12484 struct wpa_driver_nl80211_data *drv = bss->drv;
Sunil Ravi99c035e2024-07-12 01:42:03 +000012485 struct ndmsg nhdr = {
12486 .ndm_state = NUD_PERMANENT,
12487 .ndm_ifindex = bss->br_ifindex,
12488 };
12489 struct nl_msg *msg;
12490 int addrsize;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012491 int res;
12492
12493 if (!ipaddr || prefixlen == 0 || !addr)
12494 return -EINVAL;
12495
12496 if (bss->br_ifindex == 0) {
12497 wpa_printf(MSG_DEBUG,
12498 "nl80211: bridge must be set before adding an ip neigh to it");
12499 return -1;
12500 }
12501
12502 if (!drv->rtnl_sk) {
12503 wpa_printf(MSG_DEBUG,
12504 "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
12505 return -1;
12506 }
12507
12508 if (version == 4) {
Sunil Ravi99c035e2024-07-12 01:42:03 +000012509 nhdr.ndm_family = AF_INET;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012510 addrsize = 4;
12511 } else if (version == 6) {
Sunil Ravi99c035e2024-07-12 01:42:03 +000012512 nhdr.ndm_family = AF_INET6;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012513 addrsize = 16;
12514 } else {
12515 return -EINVAL;
12516 }
12517
Sunil Ravi99c035e2024-07-12 01:42:03 +000012518 msg = nlmsg_alloc_simple(RTM_NEWNEIGH, NLM_F_CREATE);
12519 if (!msg)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012520 return -ENOMEM;
12521
Sunil Ravi99c035e2024-07-12 01:42:03 +000012522 res = -ENOMEM;
12523 if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0 ||
12524 nla_put(msg, NDA_DST, addrsize, (void *) ipaddr) ||
12525 nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *) addr))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012526 goto errout;
Sunil Ravi99c035e2024-07-12 01:42:03 +000012527
12528 res = nl_send_auto_complete(drv->rtnl_sk, msg);
12529 if (res < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012530 goto errout;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012531
Sunil Ravi99c035e2024-07-12 01:42:03 +000012532 res = nl_wait_for_ack(drv->rtnl_sk);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012533 if (res) {
12534 wpa_printf(MSG_DEBUG,
12535 "nl80211: Adding bridge ip neigh failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070012536 nl_geterror(res));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012537 }
12538errout:
Sunil Ravi99c035e2024-07-12 01:42:03 +000012539 nlmsg_free(msg);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012540 return res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012541}
12542
12543
12544static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version,
12545 const u8 *ipaddr)
12546{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012547 struct i802_bss *bss = priv;
12548 struct wpa_driver_nl80211_data *drv = bss->drv;
Sunil Ravi99c035e2024-07-12 01:42:03 +000012549 struct ndmsg nhdr = {
12550 .ndm_state = NUD_PERMANENT,
12551 .ndm_ifindex = bss->br_ifindex,
12552 };
12553 struct nl_msg *msg;
12554 int addrsize;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012555 int res;
12556
12557 if (!ipaddr)
12558 return -EINVAL;
12559
12560 if (version == 4) {
Sunil Ravi99c035e2024-07-12 01:42:03 +000012561 nhdr.ndm_family = AF_INET;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012562 addrsize = 4;
12563 } else if (version == 6) {
Sunil Ravi99c035e2024-07-12 01:42:03 +000012564 nhdr.ndm_family = AF_INET6;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012565 addrsize = 16;
12566 } else {
12567 return -EINVAL;
12568 }
12569
12570 if (bss->br_ifindex == 0) {
12571 wpa_printf(MSG_DEBUG,
12572 "nl80211: bridge must be set to delete an ip neigh");
12573 return -1;
12574 }
12575
12576 if (!drv->rtnl_sk) {
12577 wpa_printf(MSG_DEBUG,
12578 "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
12579 return -1;
12580 }
12581
Sunil Ravi99c035e2024-07-12 01:42:03 +000012582 msg = nlmsg_alloc_simple(RTM_DELNEIGH, NLM_F_CREATE);
12583 if (!msg)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012584 return -ENOMEM;
12585
Sunil Ravi99c035e2024-07-12 01:42:03 +000012586 res = -ENOMEM;
12587 if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0 ||
12588 nla_put(msg, NDA_DST, addrsize, (void *) ipaddr))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012589 goto errout;
Sunil Ravi99c035e2024-07-12 01:42:03 +000012590
12591 res = nl_send_auto_complete(drv->rtnl_sk, msg);
12592 if (res < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012593 goto errout;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012594
Sunil Ravi99c035e2024-07-12 01:42:03 +000012595 res = nl_wait_for_ack(drv->rtnl_sk);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012596 if (res) {
12597 wpa_printf(MSG_DEBUG,
12598 "nl80211: Deleting bridge ip neigh failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070012599 nl_geterror(res));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012600 }
12601errout:
Sunil Ravi99c035e2024-07-12 01:42:03 +000012602 nlmsg_free(msg);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012603 return res;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012604}
12605
12606
12607static int linux_write_system_file(const char *path, unsigned int val)
12608{
12609 char buf[50];
12610 int fd, len;
12611
12612 len = os_snprintf(buf, sizeof(buf), "%u\n", val);
12613 if (os_snprintf_error(sizeof(buf), len))
12614 return -1;
12615
12616 fd = open(path, O_WRONLY);
12617 if (fd < 0)
12618 return -1;
12619
12620 if (write(fd, buf, len) < 0) {
12621 wpa_printf(MSG_DEBUG,
12622 "nl80211: Failed to write Linux system file: %s with the value of %d",
12623 path, val);
12624 close(fd);
12625 return -1;
12626 }
12627 close(fd);
12628
12629 return 0;
12630}
12631
12632
12633static const char * drv_br_port_attr_str(enum drv_br_port_attr attr)
12634{
12635 switch (attr) {
12636 case DRV_BR_PORT_ATTR_PROXYARP:
Dmitry Shmidt4dd28dc2015-03-10 11:21:43 -070012637 return "proxyarp_wifi";
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012638 case DRV_BR_PORT_ATTR_HAIRPIN_MODE:
12639 return "hairpin_mode";
Sunil Ravi036cec52023-03-29 11:35:17 -070012640 case DRV_BR_PORT_ATTR_MCAST2UCAST:
12641 return "multicast_to_unicast";
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012642 }
12643
12644 return NULL;
12645}
12646
12647
12648static int wpa_driver_br_port_set_attr(void *priv, enum drv_br_port_attr attr,
12649 unsigned int val)
12650{
12651 struct i802_bss *bss = priv;
12652 char path[128];
12653 const char *attr_txt;
12654
12655 attr_txt = drv_br_port_attr_str(attr);
12656 if (attr_txt == NULL)
12657 return -EINVAL;
12658
12659 os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/%s",
12660 bss->ifname, attr_txt);
12661
12662 if (linux_write_system_file(path, val))
12663 return -1;
12664
12665 return 0;
12666}
12667
12668
12669static const char * drv_br_net_param_str(enum drv_br_net_param param)
12670{
12671 switch (param) {
12672 case DRV_BR_NET_PARAM_GARP_ACCEPT:
12673 return "arp_accept";
Dmitry Shmidt83474442015-04-15 13:47:09 -070012674 default:
12675 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012676 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012677}
12678
12679
12680static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
12681 unsigned int val)
12682{
12683 struct i802_bss *bss = priv;
12684 char path[128];
12685 const char *param_txt;
12686 int ip_version = 4;
12687
Dmitry Shmidt83474442015-04-15 13:47:09 -070012688 if (param == DRV_BR_MULTICAST_SNOOPING) {
12689 os_snprintf(path, sizeof(path),
12690 "/sys/devices/virtual/net/%s/bridge/multicast_snooping",
12691 bss->brname);
12692 goto set_val;
12693 }
12694
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012695 param_txt = drv_br_net_param_str(param);
12696 if (param_txt == NULL)
12697 return -EINVAL;
12698
12699 switch (param) {
12700 case DRV_BR_NET_PARAM_GARP_ACCEPT:
12701 ip_version = 4;
12702 break;
12703 default:
12704 return -EINVAL;
12705 }
12706
12707 os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
12708 ip_version, bss->brname, param_txt);
12709
Dmitry Shmidt83474442015-04-15 13:47:09 -070012710set_val:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012711 if (linux_write_system_file(path, val))
12712 return -1;
12713
12714 return 0;
12715}
12716
12717
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012718#ifdef CONFIG_DRIVER_NL80211_QCA
12719
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012720static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
12721{
12722 switch (hw_mode) {
12723 case HOSTAPD_MODE_IEEE80211B:
12724 return QCA_ACS_MODE_IEEE80211B;
12725 case HOSTAPD_MODE_IEEE80211G:
12726 return QCA_ACS_MODE_IEEE80211G;
12727 case HOSTAPD_MODE_IEEE80211A:
12728 return QCA_ACS_MODE_IEEE80211A;
12729 case HOSTAPD_MODE_IEEE80211AD:
12730 return QCA_ACS_MODE_IEEE80211AD;
Dmitry Shmidtb1e52102015-05-29 12:36:29 -070012731 case HOSTAPD_MODE_IEEE80211ANY:
12732 return QCA_ACS_MODE_IEEE80211ANY;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012733 default:
12734 return -1;
12735 }
12736}
12737
12738
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080012739static int add_acs_ch_list(struct nl_msg *msg, const int *freq_list)
12740{
12741 int num_channels = 0, num_freqs;
12742 u8 *ch_list;
12743 enum hostapd_hw_mode hw_mode;
12744 int ret = 0;
12745 int i;
12746
12747 if (!freq_list)
12748 return 0;
12749
12750 num_freqs = int_array_len(freq_list);
12751 ch_list = os_malloc(sizeof(u8) * num_freqs);
12752 if (!ch_list)
12753 return -1;
12754
12755 for (i = 0; i < num_freqs; i++) {
12756 const int freq = freq_list[i];
12757
12758 if (freq == 0)
12759 break;
12760 /* Send 2.4 GHz and 5 GHz channels with
12761 * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST to maintain backwards
12762 * compatibility.
12763 */
12764 if (!(freq >= 2412 && freq <= 2484) &&
Hai Shalomc1a21442022-02-04 13:43:00 -080012765 !(freq >= 5180 && freq <= 5900) &&
12766 !(freq >= 5945 && freq <= 7115))
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080012767 continue;
12768 hw_mode = ieee80211_freq_to_chan(freq, &ch_list[num_channels]);
12769 if (hw_mode != NUM_HOSTAPD_MODES)
12770 num_channels++;
12771 }
12772
12773 if (num_channels)
12774 ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
12775 num_channels, ch_list);
12776
12777 os_free(ch_list);
12778 return ret;
12779}
12780
12781
Sunil Ravic0f5d412024-09-11 22:12:49 +000012782static int add_freq_list(struct nl_msg *msg, int attr, const int *freq_list)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012783{
12784 int i, len, ret;
12785 u32 *freqs;
12786
12787 if (!freq_list)
12788 return 0;
12789 len = int_array_len(freq_list);
12790 freqs = os_malloc(sizeof(u32) * len);
12791 if (!freqs)
12792 return -1;
12793 for (i = 0; i < len; i++)
12794 freqs[i] = freq_list[i];
Sunil Ravic0f5d412024-09-11 22:12:49 +000012795 ret = nla_put(msg, attr, sizeof(u32) * len, freqs);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012796 os_free(freqs);
12797 return ret;
12798}
12799
12800
Hai Shalomc1a21442022-02-04 13:43:00 -080012801static int nl80211_qca_do_acs(struct wpa_driver_nl80211_data *drv,
12802 struct drv_acs_params *params)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012803{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012804 struct nl_msg *msg;
12805 struct nlattr *data;
12806 int ret;
12807 int mode;
12808
12809 mode = hw_mode_to_qca_acs(params->hw_mode);
12810 if (mode < 0)
12811 return -1;
12812
12813 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
12814 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
12815 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
12816 QCA_NL80211_VENDOR_SUBCMD_DO_ACS) ||
12817 !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
12818 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, mode) ||
12819 (params->ht_enabled &&
12820 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
12821 (params->ht40_enabled &&
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070012822 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) ||
12823 (params->vht_enabled &&
12824 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
Sunil Ravia04bd252022-05-02 22:54:18 -070012825 (params->eht_enabled &&
12826 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED)) ||
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070012827 nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
12828 params->ch_width) ||
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080012829 add_acs_ch_list(msg, params->freq_list) ||
Sunil Ravic0f5d412024-09-11 22:12:49 +000012830 add_freq_list(msg, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
12831 params->freq_list) ||
Hai Shalomfdcde762020-04-02 11:19:20 -070012832 (params->edmg_enabled &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +000012833 nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED)) ||
12834 (params->link_id != NL80211_DRV_LINK_ID_NA &&
12835 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_ACS_LINK_ID,
12836 params->link_id))) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012837 nlmsg_free(msg);
12838 return -ENOBUFS;
12839 }
12840 nla_nest_end(msg, data);
12841
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070012842 wpa_printf(MSG_DEBUG,
Sunil Ravib0ac25f2024-07-12 01:42:03 +000012843 "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d EHT: %d BW: %d EDMG: %d, link_id: %d",
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070012844 params->hw_mode, params->ht_enabled, params->ht40_enabled,
Sunil Ravia04bd252022-05-02 22:54:18 -070012845 params->vht_enabled, params->eht_enabled, params->ch_width,
Sunil Ravib0ac25f2024-07-12 01:42:03 +000012846 params->edmg_enabled, params->link_id);
Dmitry Shmidtdda10c22015-03-24 16:05:01 -070012847
Sunil Ravib0ac25f2024-07-12 01:42:03 +000012848 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012849 if (ret) {
12850 wpa_printf(MSG_DEBUG,
12851 "nl80211: Failed to invoke driver ACS function: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070012852 strerror(-ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080012853 }
12854 return ret;
12855}
12856
12857
Hai Shalom60840252021-02-19 19:02:11 -080012858static int nl80211_set_band(void *priv, u32 band_mask)
Ravi Joshie6ccb162015-07-16 17:45:41 -070012859{
12860 struct i802_bss *bss = priv;
12861 struct wpa_driver_nl80211_data *drv = bss->drv;
12862 struct nl_msg *msg;
12863 struct nlattr *data;
12864 int ret;
Hai Shalom60840252021-02-19 19:02:11 -080012865 enum qca_set_band qca_band_value;
12866 u32 qca_band_mask = QCA_SETBAND_AUTO;
Ravi Joshie6ccb162015-07-16 17:45:41 -070012867
Hai Shalom60840252021-02-19 19:02:11 -080012868 if (!drv->setband_vendor_cmd_avail ||
12869 (band_mask > (WPA_SETBAND_2G | WPA_SETBAND_5G | WPA_SETBAND_6G)))
Ravi Joshie6ccb162015-07-16 17:45:41 -070012870 return -1;
12871
Hai Shalom60840252021-02-19 19:02:11 -080012872 if (band_mask & WPA_SETBAND_5G)
12873 qca_band_mask |= QCA_SETBAND_5G;
12874 if (band_mask & WPA_SETBAND_2G)
12875 qca_band_mask |= QCA_SETBAND_2G;
12876 if (band_mask & WPA_SETBAND_6G)
12877 qca_band_mask |= QCA_SETBAND_6G;
12878
12879 /*
12880 * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE is a legacy interface hence make
12881 * it suite to its values (AUTO/5G/2G) for backwards compatibility.
12882 */
12883 qca_band_value = ((qca_band_mask & QCA_SETBAND_5G) &&
12884 (qca_band_mask & QCA_SETBAND_2G)) ?
12885 QCA_SETBAND_AUTO :
12886 qca_band_mask & ~QCA_SETBAND_6G;
12887
12888 wpa_printf(MSG_DEBUG,
12889 "nl80211: QCA_BAND_MASK = 0x%x, QCA_BAND_VALUE = %d",
12890 qca_band_mask, qca_band_value);
Ravi Joshie6ccb162015-07-16 17:45:41 -070012891
12892 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
12893 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
12894 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
12895 QCA_NL80211_VENDOR_SUBCMD_SETBAND) ||
12896 !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
Hai Shalom60840252021-02-19 19:02:11 -080012897 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE,
12898 qca_band_value) ||
12899 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_MASK,
12900 qca_band_mask)) {
Ravi Joshie6ccb162015-07-16 17:45:41 -070012901 nlmsg_free(msg);
12902 return -ENOBUFS;
12903 }
12904 nla_nest_end(msg, data);
12905
Sunil Ravib0ac25f2024-07-12 01:42:03 +000012906 ret = send_and_recv_cmd(drv, msg);
Ravi Joshie6ccb162015-07-16 17:45:41 -070012907 if (ret) {
12908 wpa_printf(MSG_DEBUG,
12909 "nl80211: Driver setband function failed: %s",
Hai Shalomfdcde762020-04-02 11:19:20 -070012910 strerror(-ret));
Ravi Joshie6ccb162015-07-16 17:45:41 -070012911 }
12912 return ret;
12913}
12914
12915
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012916struct nl80211_pcl {
12917 unsigned int num;
Sunil8cd6f4d2022-06-28 18:40:46 +000012918 struct weighted_pcl *freq_list;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012919};
12920
Sunil8cd6f4d2022-06-28 18:40:46 +000012921static void get_pcl_attr_values(struct weighted_pcl *wpcl, struct nlattr *nl[])
12922{
12923 if (nl[QCA_WLAN_VENDOR_ATTR_PCL_FREQ])
12924 wpcl->freq = nla_get_u32(nl[QCA_WLAN_VENDOR_ATTR_PCL_FREQ]);
12925 if (nl[QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT])
12926 wpcl->weight = nla_get_u8(nl[QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT]);
12927 if (nl[QCA_WLAN_VENDOR_ATTR_PCL_FLAG]) {
12928 u32 flags = nla_get_u32(nl[QCA_WLAN_VENDOR_ATTR_PCL_FLAG]);
12929
12930 wpcl->flag = 0;
12931 if (flags & BIT(0))
12932 wpcl->flag |= WEIGHTED_PCL_GO;
12933 if (flags & BIT(1))
12934 wpcl->flag |= WEIGHTED_PCL_CLI;
12935 if (flags & BIT(2))
12936 wpcl->flag |= WEIGHTED_PCL_MUST_CONSIDER;
12937 if (flags & BIT(3))
12938 wpcl->flag |= WEIGHTED_PCL_EXCLUDE;
12939 } else {
12940 wpcl->flag = WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI;
12941 }
12942}
12943
12944
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012945static int preferred_freq_info_handler(struct nl_msg *msg, void *arg)
12946{
12947 struct nlattr *tb[NL80211_ATTR_MAX + 1];
12948 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
12949 struct nl80211_pcl *param = arg;
12950 struct nlattr *nl_vend, *attr;
12951 enum qca_iface_type iface_type;
12952 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
Sunil8cd6f4d2022-06-28 18:40:46 +000012953 struct nlattr *nl_pcl[QCA_WLAN_VENDOR_ATTR_PCL_MAX + 1];
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080012954 unsigned int num, max_num;
12955 u32 *freqs;
12956
12957 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
12958 genlmsg_attrlen(gnlh, 0), NULL);
12959
12960 nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
12961 if (!nl_vend)
12962 return NL_SKIP;
12963
12964 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
12965 nla_data(nl_vend), nla_len(nl_vend), NULL);
12966
12967 attr = tb_vendor[
12968 QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE];
12969 if (!attr) {
12970 wpa_printf(MSG_ERROR, "nl80211: iface_type couldn't be found");
12971 param->num = 0;
12972 return NL_SKIP;
12973 }
12974
12975 iface_type = (enum qca_iface_type) nla_get_u32(attr);
12976 wpa_printf(MSG_DEBUG, "nl80211: Driver returned iface_type=%d",
12977 iface_type);
12978
Sunil8cd6f4d2022-06-28 18:40:46 +000012979 attr = tb_vendor[
12980 QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_WEIGHED_PCL];
12981 if (attr) {
12982 int rem;
12983 struct nlattr *wpcl = attr;
12984 unsigned int i;
12985
12986 num = 0;
12987 nla_for_each_nested(attr, wpcl, rem) {
12988 if (num == param->num)
12989 break; /* not enough room for all entries */
12990 if (nla_parse(nl_pcl, QCA_WLAN_VENDOR_ATTR_PCL_MAX,
12991 nla_data(attr), nla_len(attr), NULL)) {
12992 wpa_printf(MSG_ERROR,
12993 "nl80211: Failed to parse PCL info");
12994 param->num = 0;
12995 return NL_SKIP;
12996 }
12997 get_pcl_attr_values(&param->freq_list[num], nl_pcl);
12998 num++;
12999 }
13000 param->num = num;
13001
13002 /* Sort frequencies based on their weight */
13003 for (i = 0; i < num; i++) {
13004 unsigned int j;
13005
13006 for (j = i + 1; j < num; j++) {
13007 if (param->freq_list[i].weight <
13008 param->freq_list[j].weight) {
13009 struct weighted_pcl tmp;
13010
13011 tmp = param->freq_list[i];
13012 param->freq_list[i] =
13013 param->freq_list[j];
13014 param->freq_list[j] = tmp;
13015 }
13016 }
13017 }
13018 } else if (tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST]) {
13019 wpa_printf(MSG_DEBUG,
13020 "nl80211: Driver does not provide weighted PCL; use the non-weighted variant");
13021 attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST];
13022 /*
13023 * param->num has the maximum number of entries for which there
13024 * is room in the freq_list provided by the caller.
13025 */
13026 freqs = nla_data(attr);
13027 max_num = nla_len(attr) / sizeof(u32);
13028 if (max_num > param->num)
13029 max_num = param->num;
13030 for (num = 0; num < max_num; num++) {
13031 param->freq_list[num].freq = freqs[num];
13032 param->freq_list[num].flag =
13033 WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI;
13034 }
13035 param->num = num;
13036 } else {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080013037 wpa_printf(MSG_ERROR,
13038 "nl80211: preferred_freq_list couldn't be found");
13039 param->num = 0;
13040 return NL_SKIP;
13041 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080013042 return NL_SKIP;
13043}
13044
13045
13046static int nl80211_get_pref_freq_list(void *priv,
13047 enum wpa_driver_if_type if_type,
13048 unsigned int *num,
Sunil8cd6f4d2022-06-28 18:40:46 +000013049 struct weighted_pcl *freq_list)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080013050{
13051 struct i802_bss *bss = priv;
13052 struct wpa_driver_nl80211_data *drv = bss->drv;
13053 struct nl_msg *msg;
13054 int ret;
13055 unsigned int i;
13056 struct nlattr *params;
13057 struct nl80211_pcl param;
13058 enum qca_iface_type iface_type;
13059
13060 if (!drv->get_pref_freq_list)
13061 return -1;
13062
13063 switch (if_type) {
13064 case WPA_IF_STATION:
13065 iface_type = QCA_IFACE_TYPE_STA;
13066 break;
13067 case WPA_IF_AP_BSS:
13068 iface_type = QCA_IFACE_TYPE_AP;
13069 break;
13070 case WPA_IF_P2P_GO:
13071 iface_type = QCA_IFACE_TYPE_P2P_GO;
13072 break;
13073 case WPA_IF_P2P_CLIENT:
13074 iface_type = QCA_IFACE_TYPE_P2P_CLIENT;
13075 break;
13076 case WPA_IF_IBSS:
13077 iface_type = QCA_IFACE_TYPE_IBSS;
13078 break;
13079 case WPA_IF_TDLS:
13080 iface_type = QCA_IFACE_TYPE_TDLS;
13081 break;
13082 default:
13083 return -1;
13084 }
13085
13086 param.num = *num;
13087 param.freq_list = freq_list;
13088
13089 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
13090 nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) ||
13091 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13092 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13093 QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST) ||
13094 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
13095 nla_put_u32(msg,
13096 QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE,
13097 iface_type)) {
13098 wpa_printf(MSG_ERROR,
13099 "%s: err in adding vendor_cmd and vendor_data",
13100 __func__);
13101 nlmsg_free(msg);
13102 return -1;
13103 }
13104 nla_nest_end(msg, params);
13105
Sunil8cd6f4d2022-06-28 18:40:46 +000013106 if (freq_list)
13107 os_memset(freq_list, 0, *num * sizeof(struct weighted_pcl));
Sunil Ravib0ac25f2024-07-12 01:42:03 +000013108 ret = send_and_recv_resp(drv, msg, preferred_freq_info_handler, &param);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080013109 if (ret) {
13110 wpa_printf(MSG_ERROR,
Sunil Ravib0ac25f2024-07-12 01:42:03 +000013111 "%s: err in send_and_recv_resp", __func__);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080013112 return ret;
13113 }
13114
13115 *num = param.num;
13116
13117 for (i = 0; i < *num; i++) {
Sunil8cd6f4d2022-06-28 18:40:46 +000013118 wpa_printf(MSG_DEBUG,
13119 "nl80211: preferred_channel_list[%d]=%d[%d]:0x%x",
13120 i, freq_list[i].freq, freq_list[i].weight,
13121 freq_list[i].flag);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080013122 }
13123
13124 return 0;
13125}
13126
13127
13128static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq)
13129{
13130 struct i802_bss *bss = priv;
13131 struct wpa_driver_nl80211_data *drv = bss->drv;
13132 struct nl_msg *msg;
13133 int ret;
13134 struct nlattr *params;
13135
13136 if (!drv->set_prob_oper_freq)
13137 return -1;
13138
13139 wpa_printf(MSG_DEBUG,
13140 "nl80211: Set P2P probable operating freq %u for ifindex %d",
13141 freq, bss->ifindex);
13142
13143 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
13144 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13145 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13146 QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL) ||
13147 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
13148 nla_put_u32(msg,
13149 QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE,
13150 QCA_IFACE_TYPE_P2P_CLIENT) ||
13151 nla_put_u32(msg,
13152 QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ,
13153 freq)) {
13154 wpa_printf(MSG_ERROR,
13155 "%s: err in adding vendor_cmd and vendor_data",
13156 __func__);
13157 nlmsg_free(msg);
13158 return -1;
13159 }
13160 nla_nest_end(msg, params);
13161
Sunil Ravib0ac25f2024-07-12 01:42:03 +000013162 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080013163 msg = NULL;
13164 if (ret) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +000013165 wpa_printf(MSG_ERROR, "%s: err in send_and_recv_cmd",
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080013166 __func__);
13167 return ret;
13168 }
13169 nlmsg_free(msg);
13170 return 0;
13171}
13172
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070013173
13174static int nl80211_p2p_lo_start(void *priv, unsigned int freq,
13175 unsigned int period, unsigned int interval,
13176 unsigned int count, const u8 *device_types,
13177 size_t dev_types_len,
13178 const u8 *ies, size_t ies_len)
13179{
13180 struct i802_bss *bss = priv;
13181 struct wpa_driver_nl80211_data *drv = bss->drv;
13182 struct nl_msg *msg;
13183 struct nlattr *container;
13184 int ret;
13185
13186 wpa_printf(MSG_DEBUG,
13187 "nl80211: Start P2P Listen offload: freq=%u, period=%u, interval=%u, count=%u",
13188 freq, period, interval, count);
13189
13190 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
13191 return -1;
13192
13193 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
13194 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13195 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13196 QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START))
13197 goto fail;
13198
13199 container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
13200 if (!container)
13201 goto fail;
13202
13203 if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL,
13204 freq) ||
13205 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD,
13206 period) ||
13207 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL,
13208 interval) ||
13209 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT,
13210 count) ||
13211 nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES,
13212 dev_types_len, device_types) ||
13213 nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE,
13214 ies_len, ies))
13215 goto fail;
13216
13217 nla_nest_end(msg, container);
Sunil Ravib0ac25f2024-07-12 01:42:03 +000013218 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070013219 msg = NULL;
13220 if (ret) {
13221 wpa_printf(MSG_DEBUG,
13222 "nl80211: Failed to send P2P Listen offload vendor command");
13223 goto fail;
13224 }
13225
13226 return 0;
13227
13228fail:
13229 nlmsg_free(msg);
13230 return -1;
13231}
13232
13233
13234static int nl80211_p2p_lo_stop(void *priv)
13235{
13236 struct i802_bss *bss = priv;
13237 struct wpa_driver_nl80211_data *drv = bss->drv;
13238 struct nl_msg *msg;
13239
13240 wpa_printf(MSG_DEBUG, "nl80211: Stop P2P Listen offload");
13241
13242 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
13243 return -1;
13244
13245 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
13246 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13247 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13248 QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP)) {
13249 nlmsg_free(msg);
13250 return -1;
13251 }
13252
Sunil Ravib0ac25f2024-07-12 01:42:03 +000013253 return send_and_recv_cmd(drv, msg);
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070013254}
13255
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080013256
13257static int nl80211_set_tdls_mode(void *priv, int tdls_external_control)
13258{
13259 struct i802_bss *bss = priv;
13260 struct wpa_driver_nl80211_data *drv = bss->drv;
13261 struct nl_msg *msg;
13262 struct nlattr *params;
13263 int ret;
13264 u32 tdls_mode;
13265
13266 wpa_printf(MSG_DEBUG,
13267 "nl80211: Set TDKS mode: tdls_external_control=%d",
13268 tdls_external_control);
13269
13270 if (tdls_external_control == 1)
13271 tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT |
13272 QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL;
13273 else
13274 tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT;
13275
13276 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
13277 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13278 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13279 QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS))
13280 goto fail;
13281
13282 params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
13283 if (!params)
13284 goto fail;
13285
13286 if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE,
13287 tdls_mode))
13288 goto fail;
13289
13290 nla_nest_end(msg, params);
13291
Sunil Ravib0ac25f2024-07-12 01:42:03 +000013292 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080013293 msg = NULL;
13294 if (ret) {
13295 wpa_printf(MSG_ERROR,
13296 "nl80211: Set TDLS mode failed: ret=%d (%s)",
13297 ret, strerror(-ret));
13298 goto fail;
13299 }
13300 return 0;
13301fail:
13302 nlmsg_free(msg);
13303 return -1;
13304}
13305
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070013306
13307#ifdef CONFIG_MBO
13308
13309static enum mbo_transition_reject_reason
13310nl80211_mbo_reject_reason_mapping(enum qca_wlan_btm_candidate_status status)
13311{
13312 switch (status) {
13313 case QCA_STATUS_REJECT_EXCESSIVE_FRAME_LOSS_EXPECTED:
13314 return MBO_TRANSITION_REJECT_REASON_FRAME_LOSS;
13315 case QCA_STATUS_REJECT_EXCESSIVE_DELAY_EXPECTED:
13316 return MBO_TRANSITION_REJECT_REASON_DELAY;
13317 case QCA_STATUS_REJECT_INSUFFICIENT_QOS_CAPACITY:
13318 return MBO_TRANSITION_REJECT_REASON_QOS_CAPACITY;
13319 case QCA_STATUS_REJECT_LOW_RSSI:
13320 return MBO_TRANSITION_REJECT_REASON_RSSI;
13321 case QCA_STATUS_REJECT_HIGH_INTERFERENCE:
13322 return MBO_TRANSITION_REJECT_REASON_INTERFERENCE;
13323 case QCA_STATUS_REJECT_UNKNOWN:
13324 default:
13325 return MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
13326 }
13327}
13328
13329
13330static void nl80211_parse_btm_candidate_info(struct candidate_list *candidate,
13331 struct nlattr *tb[], int num)
13332{
13333 enum qca_wlan_btm_candidate_status status;
13334 char buf[50];
13335
13336 os_memcpy(candidate->bssid,
13337 nla_data(tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]),
13338 ETH_ALEN);
13339
13340 status = nla_get_u32(
13341 tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS]);
13342 candidate->is_accept = status == QCA_STATUS_ACCEPT;
13343 candidate->reject_reason = nl80211_mbo_reject_reason_mapping(status);
13344
13345 if (candidate->is_accept)
13346 os_snprintf(buf, sizeof(buf), "Accepted");
13347 else
13348 os_snprintf(buf, sizeof(buf),
13349 "Rejected, Reject_reason: %d",
13350 candidate->reject_reason);
13351 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%d]: " MACSTR " %s",
13352 num, MAC2STR(candidate->bssid), buf);
13353}
13354
13355
13356static int
13357nl80211_get_bss_transition_status_handler(struct nl_msg *msg, void *arg)
13358{
13359 struct wpa_bss_candidate_info *info = arg;
13360 struct candidate_list *candidate = info->candidates;
13361 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
13362 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
13363 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1];
13364 static struct nla_policy policy[
13365 QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1] = {
13366 [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] = {
13367 .minlen = ETH_ALEN
13368 },
13369 [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS] = {
13370 .type = NLA_U32,
13371 },
13372 };
13373 struct nlattr *attr;
13374 int rem;
13375 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
13376 u8 num;
13377
13378 num = info->num; /* number of candidates sent to driver */
13379 info->num = 0;
13380 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
13381 genlmsg_attrlen(gnlh, 0), NULL);
13382
13383 if (!tb_msg[NL80211_ATTR_VENDOR_DATA] ||
13384 nla_parse_nested(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
13385 tb_msg[NL80211_ATTR_VENDOR_DATA], NULL) ||
13386 !tb_vendor[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO])
13387 return NL_SKIP;
13388
13389 wpa_printf(MSG_DEBUG,
13390 "nl80211: WNM Candidate list received from driver");
13391 nla_for_each_nested(attr,
13392 tb_vendor[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO],
13393 rem) {
13394 if (info->num >= num ||
13395 nla_parse_nested(
13396 tb, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX,
13397 attr, policy) ||
13398 !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] ||
13399 !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS])
13400 break;
13401
13402 nl80211_parse_btm_candidate_info(candidate, tb, info->num);
13403
13404 candidate++;
13405 info->num++;
13406 }
13407
13408 return NL_SKIP;
13409}
13410
13411
13412static struct wpa_bss_candidate_info *
13413nl80211_get_bss_transition_status(void *priv, struct wpa_bss_trans_info *params)
13414{
13415 struct i802_bss *bss = priv;
13416 struct wpa_driver_nl80211_data *drv = bss->drv;
13417 struct nl_msg *msg;
13418 struct nlattr *attr, *attr1, *attr2;
13419 struct wpa_bss_candidate_info *info;
13420 u8 i;
13421 int ret;
13422 u8 *pos;
13423
13424 if (!drv->fetch_bss_trans_status)
13425 return NULL;
13426
13427 info = os_zalloc(sizeof(*info));
13428 if (!info)
13429 return NULL;
13430 /* Allocate memory for number of candidates sent to driver */
13431 info->candidates = os_calloc(params->n_candidates,
13432 sizeof(*info->candidates));
13433 if (!info->candidates) {
13434 os_free(info);
13435 return NULL;
13436 }
13437
13438 /* Copy the number of candidates being sent to driver. This is used in
13439 * nl80211_get_bss_transition_status_handler() to limit the number of
13440 * candidates that can be populated in info->candidates and will be
13441 * later overwritten with the actual number of candidates received from
13442 * the driver.
13443 */
13444 info->num = params->n_candidates;
13445
13446 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
13447 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13448 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13449 QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS))
13450 goto fail;
13451
13452 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
13453 if (!attr)
13454 goto fail;
13455
13456 if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON,
13457 params->mbo_transition_reason))
13458 goto fail;
13459
13460 attr1 = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO);
13461 if (!attr1)
13462 goto fail;
13463
13464 wpa_printf(MSG_DEBUG,
13465 "nl80211: WNM Candidate list info sending to driver: mbo_transition_reason: %d n_candidates: %d",
13466 params->mbo_transition_reason, params->n_candidates);
13467 pos = params->bssid;
13468 for (i = 0; i < params->n_candidates; i++) {
13469 wpa_printf(MSG_DEBUG, "nl80211: BSSID[%d]: " MACSTR, i,
13470 MAC2STR(pos));
13471 attr2 = nla_nest_start(msg, i);
13472 if (!attr2 ||
13473 nla_put(msg, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID,
13474 ETH_ALEN, pos))
13475 goto fail;
13476 pos += ETH_ALEN;
13477 nla_nest_end(msg, attr2);
13478 }
13479
13480 nla_nest_end(msg, attr1);
13481 nla_nest_end(msg, attr);
13482
Sunil Ravib0ac25f2024-07-12 01:42:03 +000013483 ret = send_and_recv_resp(drv, msg,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070013484 nl80211_get_bss_transition_status_handler,
Sunil Ravib0ac25f2024-07-12 01:42:03 +000013485 info);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070013486 msg = NULL;
13487 if (ret) {
13488 wpa_printf(MSG_ERROR,
13489 "nl80211: WNM Get BSS transition status failed: ret=%d (%s)",
13490 ret, strerror(-ret));
13491 goto fail;
13492 }
13493 return info;
13494
13495fail:
13496 nlmsg_free(msg);
13497 os_free(info->candidates);
13498 os_free(info);
13499 return NULL;
13500}
13501
13502
13503/**
13504 * nl80211_ignore_assoc_disallow - Configure driver to ignore assoc_disallow
13505 * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
13506 * @ignore_assoc_disallow: 0 to not ignore, 1 to ignore
13507 * Returns: 0 on success, -1 on failure
13508 */
13509static int nl80211_ignore_assoc_disallow(void *priv, int ignore_disallow)
13510{
13511 struct i802_bss *bss = priv;
13512 struct wpa_driver_nl80211_data *drv = bss->drv;
13513 struct nl_msg *msg;
13514 struct nlattr *attr;
13515 int ret = -1;
13516
13517 if (!drv->set_wifi_conf_vendor_cmd_avail)
13518 return -1;
13519
13520 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
13521 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13522 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13523 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION))
13524 goto fail;
13525
13526 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
13527 if (!attr)
13528 goto fail;
13529
13530 wpa_printf(MSG_DEBUG, "nl80211: Set ignore_assoc_disallow %d",
13531 ignore_disallow);
13532 if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED,
13533 ignore_disallow))
13534 goto fail;
13535
13536 nla_nest_end(msg, attr);
13537
Sunil Ravib0ac25f2024-07-12 01:42:03 +000013538 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070013539 msg = NULL;
13540 if (ret) {
13541 wpa_printf(MSG_ERROR,
13542 "nl80211: Set ignore_assoc_disallow failed: ret=%d (%s)",
13543 ret, strerror(-ret));
13544 goto fail;
13545 }
13546
13547fail:
13548 nlmsg_free(msg);
13549 return ret;
13550}
13551
13552#endif /* CONFIG_MBO */
13553
Sunil Ravi89eba102022-09-13 21:04:37 -070013554
13555#ifdef CONFIG_PASN
13556
13557static int nl80211_send_pasn_resp(void *priv, struct pasn_auth *params)
13558{
13559 unsigned int i;
13560 struct i802_bss *bss = priv;
13561 struct nl_msg *msg = NULL;
13562 struct nlattr *nlpeers, *attr, *attr1;
13563 struct wpa_driver_nl80211_data *drv = bss->drv;
13564
13565 wpa_dbg(drv->ctx, MSG_DEBUG,
13566 "nl80211: PASN authentication response for %d entries",
13567 params->num_peers);
13568 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
13569 if (!msg ||
13570 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13571 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13572 QCA_NL80211_VENDOR_SUBCMD_PASN))
13573 goto fail;
13574
13575 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
13576 if (!attr)
13577 goto fail;
13578
13579 nlpeers = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEERS);
13580 if (!nlpeers)
13581 goto fail;
13582
13583 for (i = 0; i < params->num_peers; i++) {
13584 attr1 = nla_nest_start(msg, i);
13585 if (!attr1 ||
13586 nla_put(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR,
13587 ETH_ALEN, params->peer[i].own_addr) ||
13588 nla_put(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR,
13589 ETH_ALEN, params->peer[i].peer_addr))
13590 goto fail;
13591
Sunil Ravi77d572f2023-01-17 23:58:31 +000013592 if (params->peer[i].status == 0 &&
13593 nla_put_flag(msg,
13594 QCA_WLAN_VENDOR_ATTR_PASN_PEER_STATUS_SUCCESS))
13595 goto fail;
Sunil Ravi89eba102022-09-13 21:04:37 -070013596
13597 wpa_printf(MSG_DEBUG,
13598 "nl80211: Own address[%u]: " MACSTR
13599 " Peer address[%u]: " MACSTR " Status: %s",
13600 i, MAC2STR(params->peer[i].own_addr), i,
13601 MAC2STR(params->peer[i].peer_addr),
13602 params->peer[i].status ? "Fail" : "Success");
13603 nla_nest_end(msg, attr1);
13604 }
13605
13606 nla_nest_end(msg, nlpeers);
13607 nla_nest_end(msg, attr);
13608
Sunil Ravib0ac25f2024-07-12 01:42:03 +000013609 return send_and_recv_cmd(drv, msg);
Sunil Ravi89eba102022-09-13 21:04:37 -070013610
13611fail:
13612 nlmsg_free(msg);
13613 return -1;
13614}
13615
13616
13617static u32 wpa_ltf_keyseed_len_to_sha_type(size_t len)
13618{
13619 if (len == SHA384_MAC_LEN)
13620 return QCA_WLAN_VENDOR_SHA_384;
13621 if (len == SHA256_MAC_LEN)
13622 return QCA_WLAN_VENDOR_SHA_256;
13623
13624 wpa_printf(MSG_ERROR, "nl80211: Unexpected LTF keyseed len %zu", len);
13625 return (u32) -1;
13626}
13627
13628
13629static int nl80211_set_secure_ranging_ctx(void *priv,
13630 struct secure_ranging_params *params)
13631{
13632 int ret;
13633 u32 suite;
13634 struct nlattr *attr;
13635 struct nl_msg *msg = NULL;
13636 struct i802_bss *bss = priv;
13637 struct wpa_driver_nl80211_data *drv = bss->drv;
13638
13639 /* Configure secure ranging context only to the drivers that support it.
13640 */
13641 if (!drv->secure_ranging_ctx_vendor_cmd_avail)
13642 return 0;
13643
13644 if (!params->peer_addr || !params->own_addr)
13645 return -1;
13646
13647 wpa_dbg(drv->ctx, MSG_DEBUG,
13648 "nl80211: Secure ranging context for " MACSTR,
13649 MAC2STR(params->peer_addr));
13650
13651 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
13652 if (!msg ||
13653 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13654 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13655 QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT))
13656 goto fail;
13657
13658 attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
13659 if (!attr)
13660 goto fail;
13661
13662 if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR,
13663 ETH_ALEN, params->peer_addr) ||
13664 nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR,
13665 ETH_ALEN, params->own_addr) ||
13666 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION,
13667 params->action))
13668 goto fail;
13669
13670 if (params->cipher) {
13671 suite = wpa_cipher_to_cipher_suite(params->cipher);
13672 if (!suite ||
13673 nla_put_u32(msg,
13674 QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER,
13675 suite))
13676 goto fail;
13677 }
13678
13679 if (params->tk_len && params->tk) {
13680 if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK,
13681 params->tk_len, params->tk))
13682 goto fail;
13683 wpa_hexdump_key(MSG_DEBUG, "nl80211: TK",
13684 params->tk, params->tk_len);
13685 }
13686
13687 if (params->ltf_keyseed_len && params->ltf_keyseed) {
13688 u32 sha_type = wpa_ltf_keyseed_len_to_sha_type(
13689 params->ltf_keyseed_len);
13690
13691 if (sha_type == (u32) -1 ||
13692 nla_put_u32(
13693 msg,
13694 QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE,
13695 sha_type) ||
13696 nla_put(msg,
13697 QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED,
13698 params->ltf_keyseed_len, params->ltf_keyseed))
13699 goto fail;
13700 wpa_hexdump_key(MSG_DEBUG, "nl80211: LTF keyseed",
13701 params->ltf_keyseed, params->ltf_keyseed_len);
13702 }
13703 nla_nest_end(msg, attr);
13704
Sunil Ravib0ac25f2024-07-12 01:42:03 +000013705 ret = send_and_recv_cmd(drv, msg);
Sunil Ravi89eba102022-09-13 21:04:37 -070013706 if (ret)
13707 wpa_printf(MSG_DEBUG,
13708 "nl80211: Set secure ranging context failed: ret=%d (%s)",
13709 ret, strerror(-ret));
13710 return ret;
13711fail:
13712 nlmsg_free(msg);
13713 return -1;
13714}
13715
13716#endif /* CONFIG_PASN */
13717
Sunil Ravic0f5d412024-09-11 22:12:49 +000013718#ifdef CONFIG_NAN_USD
13719
13720static int nl80211_nan_flush(void *priv)
13721{
13722 struct i802_bss *bss = priv;
13723 struct wpa_driver_nl80211_data *drv = bss->drv;
13724 struct nl_msg *msg;
13725 struct nlattr *container;
13726 int ret;
13727
13728 wpa_printf(MSG_DEBUG, "nl80211: NAN USD flush");
13729
13730 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
13731 if (!msg ||
13732 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13733 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13734 QCA_NL80211_VENDOR_SUBCMD_USD))
13735 goto fail;
13736
13737 container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
13738 if (!container ||
13739 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE,
13740 QCA_WLAN_VENDOR_USD_OP_TYPE_FLUSH))
13741 goto fail;
13742
13743 nla_nest_end(msg, container);
13744
13745 ret = send_and_recv_cmd(drv, msg);
13746 if (ret) {
13747 wpa_printf(MSG_ERROR,
13748 "nl80211: Failed to send NAN USD flush");
13749 goto fail;
13750 }
13751 return 0;
13752
13753fail:
13754 nlmsg_free(msg);
13755 return -1;
13756}
13757
13758
13759static int nl80211_nan_publish(void *priv, const u8 *src, int publish_id,
13760 const char *service_name, const u8 *service_id,
13761 enum nan_service_protocol_type srv_proto_type,
13762 const struct wpabuf *ssi,
13763 const struct wpabuf *elems,
13764 struct nan_publish_params *params)
13765{
13766 struct i802_bss *bss = priv;
13767 struct wpa_driver_nl80211_data *drv = bss->drv;
13768 struct nl_msg *msg;
13769 struct nlattr *container, *attr;
13770 int ret;
13771
13772 wpa_printf(MSG_DEBUG,
13773 "nl80211: Start NAN USD publish: default freq=%u, ttl=%u",
13774 params->freq, params->ttl);
13775 wpa_hexdump_buf(MSG_MSGDUMP, "nl80211: USD elements", elems);
13776
13777 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
13778 if (!msg ||
13779 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13780 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13781 QCA_NL80211_VENDOR_SUBCMD_USD))
13782 goto fail;
13783
13784 container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
13785 if (!container)
13786 goto fail;
13787
13788 if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE,
13789 QCA_WLAN_VENDOR_USD_OP_TYPE_PUBLISH) ||
13790 nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_SRC_ADDR, ETH_ALEN, src) ||
13791 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_INSTANCE_ID, publish_id) ||
13792 nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_SERVICE_ID,
13793 NAN_SERVICE_ID_LEN, service_id) ||
13794 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_SERVICE_PROTOCOL_TYPE,
13795 srv_proto_type) ||
13796 nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_USD_TTL, params->ttl) ||
13797 nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_ELEMENT_CONTAINER,
13798 wpabuf_len(elems), wpabuf_head(elems)) ||
13799 (ssi && nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_SSI,
13800 wpabuf_len(ssi), wpabuf_head(ssi))))
13801 goto fail;
13802
13803 attr = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG);
13804 if (!attr)
13805 goto fail;
13806 if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_DEFAULT_FREQ,
13807 params->freq) ||
13808 add_freq_list(msg, QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_FREQ_LIST,
13809 params->freq_list))
13810 nla_nest_end(msg, attr);
13811
13812 nla_nest_end(msg, container);
13813 ret = send_and_recv_cmd(drv, msg);
13814 if (ret) {
13815 wpa_printf(MSG_ERROR,
13816 "nl80211: Failed to send NAN USD publish");
13817 goto fail;
13818 }
13819 return 0;
13820
13821fail:
13822 nlmsg_free(msg);
13823 return -1;
13824}
13825
13826
13827static int nl80211_nan_cancel_publish(void *priv, int publish_id)
13828{
13829 struct i802_bss *bss = priv;
13830 struct wpa_driver_nl80211_data *drv = bss->drv;
13831 struct nl_msg *msg;
13832 struct nlattr *container;
13833 int ret;
13834
13835 wpa_printf(MSG_DEBUG, "nl80211: NAN USD cancel publish");
13836
13837 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
13838 if (!msg ||
13839 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13840 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13841 QCA_NL80211_VENDOR_SUBCMD_USD))
13842 goto fail;
13843
13844 container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
13845 if (!container)
13846 goto fail;
13847
13848 if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE,
13849 QCA_WLAN_VENDOR_USD_OP_TYPE_CANCEL_PUBLISH) ||
13850 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_INSTANCE_ID,
13851 publish_id))
13852 goto fail;
13853
13854 nla_nest_end(msg, container);
13855
13856 ret = send_and_recv_cmd(drv, msg);
13857 if (ret) {
13858 wpa_printf(MSG_ERROR,
13859 "nl80211: Failed to send NAN USD cancel publish");
13860 goto fail;
13861 }
13862 return 0;
13863
13864fail:
13865 nlmsg_free(msg);
13866 return -1;
13867}
13868
13869
13870static int nl80211_nan_update_publish(void *priv, int publish_id,
13871 const struct wpabuf *ssi)
13872{
13873 struct i802_bss *bss = priv;
13874 struct wpa_driver_nl80211_data *drv = bss->drv;
13875 struct nl_msg *msg;
13876 struct nlattr *container;
13877 int ret;
13878
13879 wpa_printf(MSG_DEBUG, "nl80211: NAN USD update publish: id=%d",
13880 publish_id);
13881
13882 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
13883 if (!msg ||
13884 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13885 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13886 QCA_NL80211_VENDOR_SUBCMD_USD))
13887 goto fail;
13888
13889 container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
13890 if (!container)
13891 goto fail;
13892
13893 if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE,
13894 QCA_WLAN_VENDOR_USD_OP_TYPE_UPDATE_PUBLISH) ||
13895 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_INSTANCE_ID,
13896 publish_id) ||
13897 (ssi && nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_SSI,
13898 wpabuf_len(ssi), wpabuf_head(ssi))))
13899 goto fail;
13900
13901 nla_nest_end(msg, container);
13902 ret = send_and_recv_cmd(drv, msg);
13903 if (ret) {
13904 wpa_printf(MSG_ERROR,
13905 "nl80211: Failed to send NAN USD update publish");
13906 goto fail;
13907 }
13908 return 0;
13909
13910fail:
13911 nlmsg_free(msg);
13912 return -1;
13913}
13914
13915
13916static int nl80211_nan_subscribe(void *priv, const u8 *src, int subscribe_id,
13917 const char *service_name, const u8 *service_id,
13918 enum nan_service_protocol_type srv_proto_type,
13919 const struct wpabuf *ssi,
13920 const struct wpabuf *elems,
13921 struct nan_subscribe_params *params)
13922{
13923 struct i802_bss *bss = priv;
13924 struct wpa_driver_nl80211_data *drv = bss->drv;
13925 struct nl_msg *msg;
13926 struct nlattr *container, *attr;
13927 int ret;
13928
13929 wpa_printf(MSG_DEBUG,
13930 "nl80211: Start NAN USD subscribe: freq=%u, ttl=%u",
13931 params->freq, params->ttl);
13932 wpa_hexdump_buf(MSG_MSGDUMP, "nl80211: USD elements", elems);
13933
13934 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
13935 if (!msg ||
13936 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13937 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13938 QCA_NL80211_VENDOR_SUBCMD_USD))
13939 goto fail;
13940
13941 container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
13942 if (!container)
13943 goto fail;
13944
13945 if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE,
13946 QCA_WLAN_VENDOR_USD_OP_TYPE_SUBSCRIBE) ||
13947 nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_SRC_ADDR, ETH_ALEN, src) ||
13948 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_INSTANCE_ID,
13949 subscribe_id) ||
13950 nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_SERVICE_ID,
13951 NAN_SERVICE_ID_LEN, service_id) ||
13952 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_SERVICE_PROTOCOL_TYPE,
13953 srv_proto_type) ||
13954 nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_USD_TTL, params->ttl) ||
13955 nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_ELEMENT_CONTAINER,
13956 wpabuf_len(elems), wpabuf_head(elems)) ||
13957 (ssi && nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_SSI,
13958 wpabuf_len(ssi), wpabuf_head(ssi))))
13959 goto fail;
13960
13961 attr = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG);
13962 if (!attr ||
13963 nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_DEFAULT_FREQ,
13964 params->freq) ||
13965 add_freq_list(msg, QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_FREQ_LIST,
13966 params->freq_list))
13967 goto fail;
13968 nla_nest_end(msg, attr);
13969
13970 nla_nest_end(msg, container);
13971 ret = send_and_recv_cmd(drv, msg);
13972 if (ret) {
13973 wpa_printf(MSG_ERROR,
13974 "nl80211: Failed to send NAN USD subscribe");
13975 goto fail;
13976 }
13977 return 0;
13978
13979fail:
13980 nlmsg_free(msg);
13981 return -1;
13982}
13983
13984
13985static int nl80211_nan_cancel_subscribe(void *priv, int subscribe_id)
13986{
13987 struct i802_bss *bss = priv;
13988 struct wpa_driver_nl80211_data *drv = bss->drv;
13989 struct nl_msg *msg;
13990 struct nlattr *container;
13991 int ret;
13992
13993 wpa_printf(MSG_DEBUG, "nl80211: NAN USD cancel subscribe");
13994
13995 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
13996 if (!msg ||
13997 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
13998 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
13999 QCA_NL80211_VENDOR_SUBCMD_USD))
14000 goto fail;
14001
14002 container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
14003 if (!container ||
14004 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE,
14005 QCA_WLAN_VENDOR_USD_OP_TYPE_CANCEL_SUBSCRIBE) ||
14006 nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_INSTANCE_ID,
14007 subscribe_id))
14008 goto fail;
14009
14010 nla_nest_end(msg, container);
14011
14012 ret = send_and_recv_cmd(drv, msg);
14013 if (ret) {
14014 wpa_printf(MSG_ERROR,
14015 "nl80211: Failed to send NAN USD cancel subscribe");
14016 goto fail;
14017 }
14018 return 0;
14019
14020fail:
14021 nlmsg_free(msg);
14022 return -1;
14023}
14024
14025#endif /* CONFIG_NAN_USD */
14026
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080014027#endif /* CONFIG_DRIVER_NL80211_QCA */
14028
Sunil Ravib0ac25f2024-07-12 01:42:03 +000014029
14030#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
14031static int wpa_driver_do_broadcom_acs(struct wpa_driver_nl80211_data *drv,
14032 struct drv_acs_params *params)
14033{
14034 struct nl_msg *msg;
14035 struct nlattr *data;
14036 int freq_list_len;
14037 int ret = -1;
14038
14039 freq_list_len = int_array_len(params->freq_list);
14040 wpa_printf(MSG_DEBUG, "%s: freq_list_len=%d",
14041 __func__, freq_list_len);
14042
14043 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
14044 if (!msg ||
14045 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
14046 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
14047 BRCM_VENDOR_SCMD_ACS) ||
14048 !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
14049 nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HW_MODE, params->hw_mode) ||
14050 nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT_ENABLED,
14051 params->ht_enabled) ||
14052 nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED,
14053 params->ht40_enabled) ||
14054 nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED,
14055 params->vht_enabled) ||
14056 nla_put_u16(msg, BRCM_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width) ||
14057 (freq_list_len > 0 &&
14058 nla_put(msg, BRCM_VENDOR_ATTR_ACS_FREQ_LIST,
14059 sizeof(int) * freq_list_len, params->freq_list)))
14060 goto fail;
14061 nla_nest_end(msg, data);
14062
14063 wpa_printf(MSG_DEBUG,
14064 "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d",
14065 params->hw_mode, params->ht_enabled, params->ht40_enabled,
14066 params->vht_enabled, params->ch_width);
14067
14068 ret = send_and_recv_cmd(drv, msg);
14069 if (ret) {
14070 wpa_printf(MSG_ERROR,
14071 "nl80211: BRCM Failed to invoke driver ACS function: %s",
14072 strerror(errno));
14073 }
14074
14075 msg = NULL;
14076fail:
14077 nlmsg_free(msg);
14078 return ret;
14079}
14080#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
14081
14082
Hai Shalomc1a21442022-02-04 13:43:00 -080014083static int nl80211_do_acs(void *priv, struct drv_acs_params *params)
14084{
Andy Kuoaba17c12022-04-14 16:05:31 +080014085#if defined(CONFIG_DRIVER_NL80211_QCA) || defined(CONFIG_DRIVER_NL80211_BRCM) \
14086 || defined(CONFIG_DRIVER_NL80211_SYNA)
Hai Shalomc1a21442022-02-04 13:43:00 -080014087 struct i802_bss *bss = priv;
14088 struct wpa_driver_nl80211_data *drv = bss->drv;
Andy Kuoaba17c12022-04-14 16:05:31 +080014089#endif /* CONFIG_DRIVER_NL80211_QCA || CONFIG_DRIVER_NL80211_BRCM \
14090 || defined(CONFIG_DRIVER_NL80211_SYNA) */
Hai Shalomc1a21442022-02-04 13:43:00 -080014091
14092#ifdef CONFIG_DRIVER_NL80211_QCA
14093 if (drv->qca_do_acs)
14094 return nl80211_qca_do_acs(drv, params);
14095#endif /* CONFIG_DRIVER_NL80211_QCA */
14096
Andy Kuoaba17c12022-04-14 16:05:31 +080014097#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Hai Shalomc1a21442022-02-04 13:43:00 -080014098 if (drv->brcm_do_acs)
14099 return wpa_driver_do_broadcom_acs(drv, params);
Andy Kuoaba17c12022-04-14 16:05:31 +080014100#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
Hai Shalomc1a21442022-02-04 13:43:00 -080014101
14102 return -1;
14103}
14104
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080014105
Dmitry Shmidt849734c2016-05-27 09:59:01 -070014106static int nl80211_write_to_file(const char *name, unsigned int val)
14107{
14108 int fd, len;
14109 char tmp[128];
Hai Shalomc3565922019-10-28 11:58:20 -070014110 int ret = 0;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070014111
14112 fd = open(name, O_RDWR);
14113 if (fd < 0) {
Hai Shalomc3565922019-10-28 11:58:20 -070014114 int level;
14115 /*
14116 * Flags may not exist on older kernels, or while we're tearing
14117 * down a disappearing device.
14118 */
14119 if (errno == ENOENT) {
14120 ret = 0;
14121 level = MSG_DEBUG;
14122 } else {
14123 ret = -1;
14124 level = MSG_ERROR;
14125 }
14126 wpa_printf(level, "nl80211: Failed to open %s: %s",
Dmitry Shmidt849734c2016-05-27 09:59:01 -070014127 name, strerror(errno));
Hai Shalomc3565922019-10-28 11:58:20 -070014128 return ret;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070014129 }
14130
14131 len = os_snprintf(tmp, sizeof(tmp), "%u\n", val);
14132 len = write(fd, tmp, len);
Hai Shalomc3565922019-10-28 11:58:20 -070014133 if (len < 0) {
14134 ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070014135 wpa_printf(MSG_ERROR, "nl80211: Failed to write to %s: %s",
14136 name, strerror(errno));
Hai Shalomc3565922019-10-28 11:58:20 -070014137 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -070014138 close(fd);
14139
Hai Shalomc3565922019-10-28 11:58:20 -070014140 return ret;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070014141}
14142
14143
14144static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags)
14145{
14146 struct i802_bss *bss = priv;
14147 char path[128];
14148 int ret;
14149
Hai Shalom60840252021-02-19 19:02:11 -080014150 /* P2P-Device has no netdev that can (or should) be configured here */
14151 if (nl80211_get_ifmode(bss) == NL80211_IFTYPE_P2P_DEVICE)
14152 return 0;
14153
Dmitry Shmidt849734c2016-05-27 09:59:01 -070014154 wpa_printf(MSG_DEBUG, "nl80211: Data frame filter flags=0x%x",
14155 filter_flags);
14156
14157 /* Configure filtering of unicast frame encrypted using GTK */
14158 ret = os_snprintf(path, sizeof(path),
14159 "/proc/sys/net/ipv4/conf/%s/drop_unicast_in_l2_multicast",
14160 bss->ifname);
14161 if (os_snprintf_error(sizeof(path), ret))
14162 return -1;
14163
14164 ret = nl80211_write_to_file(path,
14165 !!(filter_flags &
14166 WPA_DATA_FRAME_FILTER_FLAG_GTK));
14167 if (ret) {
14168 wpa_printf(MSG_ERROR,
14169 "nl80211: Failed to set IPv4 unicast in multicast filter");
14170 return ret;
14171 }
14172
14173 os_snprintf(path, sizeof(path),
14174 "/proc/sys/net/ipv6/conf/%s/drop_unicast_in_l2_multicast",
14175 bss->ifname);
14176 ret = nl80211_write_to_file(path,
14177 !!(filter_flags &
14178 WPA_DATA_FRAME_FILTER_FLAG_GTK));
14179
14180 if (ret) {
14181 wpa_printf(MSG_ERROR,
14182 "nl80211: Failed to set IPv6 unicast in multicast filter");
14183 return ret;
14184 }
14185
14186 /* Configure filtering of unicast frame encrypted using GTK */
14187 os_snprintf(path, sizeof(path),
14188 "/proc/sys/net/ipv4/conf/%s/drop_gratuitous_arp",
14189 bss->ifname);
14190 ret = nl80211_write_to_file(path,
14191 !!(filter_flags &
14192 WPA_DATA_FRAME_FILTER_FLAG_ARP));
14193 if (ret) {
14194 wpa_printf(MSG_ERROR,
14195 "nl80211: Failed set gratuitous ARP filter");
14196 return ret;
14197 }
14198
14199 /* Configure filtering of IPv6 NA frames */
14200 os_snprintf(path, sizeof(path),
14201 "/proc/sys/net/ipv6/conf/%s/drop_unsolicited_na",
14202 bss->ifname);
14203 ret = nl80211_write_to_file(path,
14204 !!(filter_flags &
14205 WPA_DATA_FRAME_FILTER_FLAG_NA));
14206 if (ret) {
14207 wpa_printf(MSG_ERROR,
14208 "nl80211: Failed to set unsolicited NA filter");
14209 return ret;
14210 }
14211
14212 return 0;
14213}
14214
14215
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070014216static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type,
14217 const u8 **ext_capa, const u8 **ext_capa_mask,
14218 unsigned int *ext_capa_len)
14219{
14220 struct i802_bss *bss = priv;
14221 struct wpa_driver_nl80211_data *drv = bss->drv;
14222 enum nl80211_iftype nlmode;
14223 unsigned int i;
14224
14225 if (!ext_capa || !ext_capa_mask || !ext_capa_len)
14226 return -1;
14227
14228 nlmode = wpa_driver_nl80211_if_type(type);
14229
14230 /* By default, use the per-radio values */
14231 *ext_capa = drv->extended_capa;
14232 *ext_capa_mask = drv->extended_capa_mask;
14233 *ext_capa_len = drv->extended_capa_len;
14234
14235 /* Replace the default value if a per-interface type value exists */
Sunil Ravi2a14cf12023-11-21 00:54:38 +000014236 for (i = 0; i < drv->num_iface_capa; i++) {
14237 if (nlmode == drv->iface_capa[i].iftype) {
14238 *ext_capa = drv->iface_capa[i].ext_capa;
14239 *ext_capa_mask = drv->iface_capa[i].ext_capa_mask;
14240 *ext_capa_len = drv->iface_capa[i].ext_capa_len;
14241 break;
14242 }
14243 }
14244
14245 return 0;
14246}
14247
14248
14249static int nl80211_get_mld_capab(void *priv, enum wpa_driver_if_type type,
14250 u16 *eml_capa, u16 *mld_capa_and_ops)
14251{
14252 struct i802_bss *bss = priv;
14253 struct wpa_driver_nl80211_data *drv = bss->drv;
14254 enum nl80211_iftype nlmode;
14255 unsigned int i;
14256
14257 if (!eml_capa || !mld_capa_and_ops)
14258 return -1;
14259
14260 nlmode = wpa_driver_nl80211_if_type(type);
14261
14262 /* By default, set to zero */
14263 *eml_capa = 0;
14264 *mld_capa_and_ops = 0;
14265
14266 /* Replace the default value if a per-interface type value exists */
14267 for (i = 0; i < drv->num_iface_capa; i++) {
14268 if (nlmode == drv->iface_capa[i].iftype) {
14269 *eml_capa = drv->iface_capa[i].eml_capa;
14270 *mld_capa_and_ops =
14271 drv->iface_capa[i].mld_capa_and_ops;
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070014272 break;
14273 }
14274 }
14275
14276 return 0;
14277}
14278
14279
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070014280static int nl80211_update_connection_params(
14281 void *priv, struct wpa_driver_associate_params *params,
14282 enum wpa_drv_update_connect_params_mask mask)
14283{
14284 struct i802_bss *bss = priv;
14285 struct wpa_driver_nl80211_data *drv = bss->drv;
14286 struct nl_msg *msg;
14287 int ret = -1;
14288 enum nl80211_auth_type type;
14289
Hai Shalomc3565922019-10-28 11:58:20 -070014290 /* Update Connection Params is intended for drivers that implement
14291 * internal SME and expect these updated connection params from
14292 * wpa_supplicant. Do not send this request for the drivers using
14293 * SME from wpa_supplicant.
14294 */
14295 if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
14296 return 0;
14297
Vinayak Yadawade62409f2022-01-20 12:32:07 +053014298 /* Handle any connection param update here which might receive kernel handling in future */
Winnie Chen4138eec2022-11-10 16:32:53 +080014299#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Vinayak Yadawade62409f2022-01-20 12:32:07 +053014300 if (mask & WPA_DRV_UPDATE_TD_POLICY) {
14301 ret = nl80211_set_td_policy(priv, params->td_policy);
14302 if (ret) {
14303 wpa_dbg(drv->ctx, MSG_DEBUG,
14304 "nl80211: Update connect params command failed: ret=%d (%s)",
14305 ret, strerror(-ret));
14306 }
14307 return ret;
14308 }
Winnie Chen4138eec2022-11-10 16:32:53 +080014309#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
Vinayak Yadawade62409f2022-01-20 12:32:07 +053014310
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070014311 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_CONNECT_PARAMS);
14312 if (!msg)
14313 goto fail;
14314
14315 wpa_printf(MSG_DEBUG, "nl80211: Update connection params (ifindex=%d)",
14316 drv->ifindex);
14317
14318 if ((mask & WPA_DRV_UPDATE_ASSOC_IES) && params->wpa_ie) {
14319 if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
14320 params->wpa_ie))
14321 goto fail;
14322 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie,
14323 params->wpa_ie_len);
14324 }
14325
14326 if (mask & WPA_DRV_UPDATE_AUTH_TYPE) {
14327 type = get_nl_auth_type(params->auth_alg);
14328 if (type == NL80211_AUTHTYPE_MAX ||
14329 nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
14330 goto fail;
14331 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
14332 }
14333
14334 if ((mask & WPA_DRV_UPDATE_FILS_ERP_INFO) &&
14335 nl80211_put_fils_connect_params(drv, params, msg))
14336 goto fail;
14337
Sunil Ravib0ac25f2024-07-12 01:42:03 +000014338 ret = send_and_recv_cmd(drv, msg);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070014339 msg = NULL;
14340 if (ret)
14341 wpa_dbg(drv->ctx, MSG_DEBUG,
14342 "nl80211: Update connect params command failed: ret=%d (%s)",
14343 ret, strerror(-ret));
14344
14345fail:
14346 nlmsg_free(msg);
14347 return ret;
14348}
14349
14350
Roshan Pius3a1667e2018-07-03 15:17:14 -070014351static int nl80211_send_external_auth_status(void *priv,
14352 struct external_auth *params)
14353{
14354 struct i802_bss *bss = priv;
14355 struct wpa_driver_nl80211_data *drv = bss->drv;
14356 struct nl_msg *msg = NULL;
14357 int ret = -1;
14358
Hai Shalom5f92bc92019-04-18 11:54:11 -070014359 /* External auth command/status is intended for drivers that implement
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -080014360 * internal SME but want to offload authentication processing (e.g.,
14361 * SAE) to hostapd/wpa_supplicant. Do not send the status to drivers
Hai Shalom5f92bc92019-04-18 11:54:11 -070014362 * which do not support AP SME or use wpa_supplicant/hostapd SME.
14363 */
Hai Shalom81f62d82019-07-22 12:10:00 -070014364 if ((is_ap_interface(drv->nlmode) && !bss->drv->device_ap_sme) ||
Hai Shalom5f92bc92019-04-18 11:54:11 -070014365 (drv->capa.flags & WPA_DRIVER_FLAGS_SME))
14366 return -1;
14367
Roshan Pius3a1667e2018-07-03 15:17:14 -070014368 wpa_dbg(drv->ctx, MSG_DEBUG,
14369 "nl80211: External auth status: %u", params->status);
14370
14371 msg = nl80211_drv_msg(drv, 0, NL80211_CMD_EXTERNAL_AUTH);
14372 if (!msg ||
14373 nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, params->status) ||
Hai Shalom5f92bc92019-04-18 11:54:11 -070014374 (params->ssid && params->ssid_len &&
14375 nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
14376 (params->pmkid &&
14377 nla_put(msg, NL80211_ATTR_PMKID, PMKID_LEN, params->pmkid)) ||
14378 (params->bssid &&
14379 nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid)))
Roshan Pius3a1667e2018-07-03 15:17:14 -070014380 goto fail;
Sunil Ravib0ac25f2024-07-12 01:42:03 +000014381 ret = send_and_recv_cmd(drv, msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -070014382 msg = NULL;
14383 if (ret) {
14384 wpa_printf(MSG_DEBUG,
14385 "nl80211: External Auth status update failed: ret=%d (%s)",
14386 ret, strerror(-ret));
14387 goto fail;
14388 }
14389fail:
14390 nlmsg_free(msg);
14391 return ret;
14392}
14393
14394
Hai Shalom74f70d42019-02-11 14:42:39 -080014395static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname,
14396 int val)
14397{
14398 struct i802_bss *bss = priv;
14399 struct wpa_driver_nl80211_data *drv = bss->drv;
14400 struct nl_msg *msg;
14401 int ret = -ENOBUFS;
14402
14403 wpa_printf(MSG_DEBUG, "nl80211: %s 4addr mode (bridge_ifname: %s)",
14404 val ? "Enable" : "Disable", bridge_ifname);
14405
14406 msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
14407 if (!msg || nla_put_u8(msg, NL80211_ATTR_4ADDR, val))
14408 goto fail;
14409
14410 if (bridge_ifname[0] && bss->added_if_into_bridge && !val) {
14411 if (linux_br_del_if(drv->global->ioctl_sock,
14412 bridge_ifname, bss->ifname)) {
14413 wpa_printf(MSG_ERROR,
14414 "nl80211: Failed to remove interface %s from bridge %s",
14415 bss->ifname, bridge_ifname);
14416 return -1;
14417 }
14418 bss->added_if_into_bridge = 0;
14419 }
14420
Sunil Ravib0ac25f2024-07-12 01:42:03 +000014421 ret = send_and_recv_cmd(drv, msg);
Hai Shalom74f70d42019-02-11 14:42:39 -080014422 msg = NULL;
Hai Shalom60840252021-02-19 19:02:11 -080014423 if (ret && val && nl80211_get_4addr(bss) == 1) {
14424 wpa_printf(MSG_DEBUG,
14425 "nl80211: 4addr mode was already enabled");
14426 ret = 0;
14427 }
Hai Shalom74f70d42019-02-11 14:42:39 -080014428 if (!ret) {
14429 if (bridge_ifname[0] && val &&
14430 i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0)
14431 return -1;
14432 return 0;
14433 }
14434
14435fail:
14436 nlmsg_free(msg);
14437 wpa_printf(MSG_ERROR, "nl80211: Failed to enable/disable 4addr");
14438
14439 return ret;
14440}
14441
14442
Hai Shalome21d4e82020-04-29 16:34:06 -070014443#ifdef CONFIG_DPP
14444static int nl80211_dpp_listen(void *priv, bool enable)
14445{
14446 struct i802_bss *bss = priv;
14447 struct wpa_driver_nl80211_data *drv = bss->drv;
14448 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
14449 struct nl_sock *handle;
14450
14451 if (!drv->multicast_registrations || !bss->nl_mgmt)
14452 return 0; /* cannot do more than hope broadcast RX works */
14453
14454 wpa_printf(MSG_DEBUG,
14455 "nl80211: Update DPP Public Action frame registration (%s multicast RX)",
14456 enable ? "enable" : "disable");
14457 handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID);
14458 return nl80211_register_frame(bss, handle, type,
14459 (u8 *) "\x04\x09\x50\x6f\x9a\x1a", 6,
14460 enable);
14461}
14462#endif /* CONFIG_DPP */
14463
Winnie Chen4138eec2022-11-10 16:32:53 +080014464#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
Vinayak Yadawade62409f2022-01-20 12:32:07 +053014465static int nl80211_set_td_policy(void *priv, u32 td_policy)
14466{
14467 struct i802_bss *bss = priv;
14468 struct wpa_driver_nl80211_data *drv = bss->drv;
14469 struct nl_msg *msg;
14470 int ret;
14471 struct nlattr *params;
14472
14473 if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
14474 nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
14475 nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, BRCM_VENDOR_SCMD_SET_TD_POLICY) ||
14476 !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
14477 (nla_put_u32(msg, BRCM_ATTR_DRIVER_TD_POLICY, td_policy))) {
14478 nl80211_nlmsg_clear(msg);
14479 nlmsg_free(msg);
14480 return -ENOBUFS;
14481 }
14482 nla_nest_end(msg, params);
14483 wpa_printf(MSG_DEBUG, "nl80211: Transition Disable Policy %d\n", td_policy);
14484
Sunil Ravib0ac25f2024-07-12 01:42:03 +000014485 ret = send_and_recv_cmd(drv, msg);
Vinayak Yadawade62409f2022-01-20 12:32:07 +053014486 if (ret) {
14487 wpa_printf(MSG_DEBUG, "nl80211: Transition Disable setting failed: ret=%d (%s)",
14488 ret, strerror(-ret));
14489 }
14490
14491 return ret;
14492}
Winnie Chen4138eec2022-11-10 16:32:53 +080014493#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
Hai Shalome21d4e82020-04-29 16:34:06 -070014494
Sunil Ravi99c035e2024-07-12 01:42:03 +000014495static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr,
14496 void *bss_ctx)
Sunil Ravi036cec52023-03-29 11:35:17 -070014497{
14498 struct i802_bss *bss = priv;
14499 struct wpa_driver_nl80211_data *drv = bss->drv;
14500 struct nl_msg *msg;
Sunil Ravi036cec52023-03-29 11:35:17 -070014501 int ret;
14502
14503 wpa_printf(MSG_DEBUG, "nl80211: MLD: add link_id=%u, addr=" MACSTR,
14504 link_id, MAC2STR(addr));
14505
14506 if (drv->nlmode != NL80211_IFTYPE_AP) {
14507 wpa_printf(MSG_DEBUG,
14508 "nl80211: MLD: cannot add link to iftype=%u",
14509 drv->nlmode);
14510 return -EINVAL;
14511 }
14512
Sunil Ravi99c035e2024-07-12 01:42:03 +000014513 if (link_id >= MAX_NUM_MLD_LINKS) {
14514 wpa_printf(MSG_DEBUG,
14515 "nl80211: invalid link_id=%u", link_id);
Sunil Ravi036cec52023-03-29 11:35:17 -070014516 return -EINVAL;
14517 }
14518
Sunil Ravi99c035e2024-07-12 01:42:03 +000014519 if (bss->valid_links & BIT(link_id)) {
14520 wpa_printf(MSG_DEBUG,
14521 "nl80211: MLD: Link %u already set", link_id);
14522 return -EINVAL;
Sunil Ravi036cec52023-03-29 11:35:17 -070014523 }
14524
Sunil Ravi99c035e2024-07-12 01:42:03 +000014525 if (!bss->valid_links) {
14526 /* Becoming MLD, verify we were not beaconing */
Sunil Ravi036cec52023-03-29 11:35:17 -070014527 if (bss->flink->beacon_set) {
14528 wpa_printf(MSG_DEBUG, "nl80211: BSS already beaconing");
14529 return -EINVAL;
14530 }
Sunil Ravi036cec52023-03-29 11:35:17 -070014531 }
14532
Sunil Ravi7f769292024-07-23 22:21:32 +000014533 msg = nl80211_bss_msg(bss, 0, NL80211_CMD_ADD_LINK);
Sunil Ravi036cec52023-03-29 11:35:17 -070014534 if (!msg ||
14535 nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id) ||
14536 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
14537 nlmsg_free(msg);
14538 return -ENOBUFS;
14539 }
14540
Sunil Ravib0ac25f2024-07-12 01:42:03 +000014541 ret = send_and_recv_cmd(drv, msg);
Sunil Ravi036cec52023-03-29 11:35:17 -070014542 if (ret) {
14543 wpa_printf(MSG_DEBUG, "nl80211: add link failed. ret=%d (%s)",
14544 ret, strerror(-ret));
14545 return ret;
14546 }
14547
Sunil Ravi99c035e2024-07-12 01:42:03 +000014548 os_memcpy(bss->links[link_id].addr, addr, ETH_ALEN);
Sunil Ravi036cec52023-03-29 11:35:17 -070014549
Sunil Ravi99c035e2024-07-12 01:42:03 +000014550 /* The new link is the first one, make it the default */
14551 if (!bss->valid_links)
14552 bss->flink = &bss->links[link_id];
Sunil Ravi036cec52023-03-29 11:35:17 -070014553
Sunil Ravi99c035e2024-07-12 01:42:03 +000014554 bss->valid_links |= BIT(link_id);
14555 bss->links[link_id].ctx = bss_ctx;
14556
Sunil Ravi7f769292024-07-23 22:21:32 +000014557 wpa_printf(MSG_DEBUG, "nl80211: MLD: valid_links=0x%04x on %s",
14558 bss->valid_links, bss->ifname);
Sunil Ravic0f5d412024-09-11 22:12:49 +000014559
14560 if (drv->rtnl_sk)
14561 rtnl_neigh_add_fdb_entry(bss, addr, true);
14562
Sunil Ravi036cec52023-03-29 11:35:17 -070014563 return 0;
14564}
14565
14566
Sunil Ravi99c035e2024-07-12 01:42:03 +000014567#ifdef CONFIG_IEEE80211BE
14568static int wpa_driver_nl80211_link_sta_remove(void *priv, u8 link_id,
14569 const u8 *addr)
14570{
14571 struct i802_bss *bss = priv;
14572 struct wpa_driver_nl80211_data *drv = bss->drv;
14573 struct nl_msg *msg;
14574 int ret;
14575
14576 if (!(bss->valid_links & BIT(link_id)))
14577 return -ENOLINK;
14578
14579 if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_REMOVE_LINK_STA)) ||
14580 nla_put(msg, NL80211_ATTR_MLD_ADDR, ETH_ALEN, addr) ||
14581 nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) {
14582 nlmsg_free(msg);
14583 return -ENOBUFS;
14584 }
14585
14586 ret = send_and_recv_cmd(drv, msg);
14587 wpa_printf(MSG_DEBUG,
14588 "nl80211: link_sta_remove -> REMOVE_LINK_STA on link_id %u from MLD STA "
14589 MACSTR ", from %s --> %d (%s)",
14590 link_id, MAC2STR(addr), bss->ifname, ret, strerror(-ret));
14591
14592 return ret;
14593}
14594#endif /* CONFIG_IEEE80211BE */
14595
14596
Hai Shalomc1a21442022-02-04 13:43:00 -080014597#ifdef CONFIG_TESTING_OPTIONS
14598
14599static int testing_nl80211_register_frame(void *priv, u16 type,
14600 const u8 *match, size_t match_len,
14601 bool multicast)
14602{
14603 struct i802_bss *bss = priv;
14604 struct nl_sock *handle;
14605
14606 if (!bss->nl_mgmt)
14607 return -1;
14608 handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID);
14609 return nl80211_register_frame(bss, handle, type, match, match_len,
14610 multicast);
14611}
14612
14613
14614static int testing_nl80211_radio_disable(void *priv, int disabled)
14615{
14616 struct i802_bss *bss = priv;
14617 struct wpa_driver_nl80211_data *drv = bss->drv;
14618
14619 /* For now, this is supported only partially in station mode with
14620 * SME-in-wpa_supplicant case where the NL80211_ATTR_LOCAL_STATE_CHANGE
14621 * attribute can be used to avoid sending out the Deauthentication frame
14622 * to the currently associated AP. */
14623
14624 if (!disabled)
14625 return 0;
14626
14627 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
14628 return -1;
14629
14630 if (!drv->associated)
14631 return 0;
14632
14633 return wpa_driver_nl80211_mlme(drv, drv->bssid,
14634 NL80211_CMD_DEAUTHENTICATE,
14635 WLAN_REASON_PREV_AUTH_NOT_VALID, 1,
14636 drv->first_bss);
14637}
14638
14639#endif /* CONFIG_TESTING_OPTIONS */
14640
14641
Sunil Ravic0f5d412024-09-11 22:12:49 +000014642static struct hostapd_multi_hw_info *
14643wpa_driver_get_multi_hw_info(void *priv, unsigned int *num_multi_hws)
14644{
14645 struct i802_bss *bss = priv;
14646
14647 return nl80211_get_multi_hw_info(bss, num_multi_hws);
14648}
14649
14650
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014651const struct wpa_driver_ops wpa_driver_nl80211_ops = {
14652 .name = "nl80211",
14653 .desc = "Linux nl80211/cfg80211",
14654 .get_bssid = wpa_driver_nl80211_get_bssid,
14655 .get_ssid = wpa_driver_nl80211_get_ssid,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080014656 .set_key = driver_nl80211_set_key,
14657 .scan2 = driver_nl80211_scan2,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080014658 .sched_scan = wpa_driver_nl80211_sched_scan,
14659 .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
Sunil Ravi99c035e2024-07-12 01:42:03 +000014660 .get_scan_results = wpa_driver_nl80211_get_scan_results,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -080014661 .abort_scan = wpa_driver_nl80211_abort_scan,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080014662 .deauthenticate = driver_nl80211_deauthenticate,
14663 .authenticate = driver_nl80211_authenticate,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014664 .associate = wpa_driver_nl80211_associate,
14665 .global_init = nl80211_global_init,
14666 .global_deinit = nl80211_global_deinit,
14667 .init2 = wpa_driver_nl80211_init,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080014668 .deinit = driver_nl80211_deinit,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014669 .get_capa = wpa_driver_nl80211_get_capa,
14670 .set_operstate = wpa_driver_nl80211_set_operstate,
14671 .set_supp_port = wpa_driver_nl80211_set_supp_port,
14672 .set_country = wpa_driver_nl80211_set_country,
Dmitry Shmidtcce06662013-11-04 18:44:24 -080014673 .get_country = wpa_driver_nl80211_get_country,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080014674 .set_ap = wpa_driver_nl80211_set_ap,
Dmitry Shmidt8bae4132013-06-06 11:25:10 -070014675 .set_acl = wpa_driver_nl80211_set_acl,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014676 .if_add = wpa_driver_nl80211_if_add,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080014677 .if_remove = driver_nl80211_if_remove,
14678 .send_mlme = driver_nl80211_send_mlme,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080014679 .get_hw_feature_data = nl80211_get_hw_feature_data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014680 .sta_add = wpa_driver_nl80211_sta_add,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080014681 .sta_remove = driver_nl80211_sta_remove,
Hai Shalomfdcde762020-04-02 11:19:20 -070014682 .tx_control_port = nl80211_tx_control_port,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014683 .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
14684 .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
Hai Shalom81f62d82019-07-22 12:10:00 -070014685 .sta_set_airtime_weight = driver_nl80211_sta_set_airtime_weight,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014686 .hapd_init = i802_init,
14687 .hapd_deinit = i802_deinit,
Jouni Malinen75ecf522011-06-27 15:19:46 -070014688 .set_wds_sta = i802_set_wds_sta,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014689 .get_seqnum = i802_get_seqnum,
14690 .flush = i802_flush,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014691 .get_inact_sec = i802_get_inact_sec,
14692 .sta_clear_stats = i802_sta_clear_stats,
14693 .set_rts = i802_set_rts,
14694 .set_frag = i802_set_frag,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014695 .set_tx_queue_params = i802_set_tx_queue_params,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080014696 .set_sta_vlan = driver_nl80211_set_sta_vlan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014697 .sta_deauth = i802_sta_deauth,
14698 .sta_disassoc = i802_sta_disassoc,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080014699 .read_sta_data = driver_nl80211_read_sta_data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014700 .set_freq = i802_set_freq,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080014701 .send_action = driver_nl80211_send_action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014702 .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
14703 .remain_on_channel = wpa_driver_nl80211_remain_on_channel,
14704 .cancel_remain_on_channel =
14705 wpa_driver_nl80211_cancel_remain_on_channel,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -080014706 .probe_req_report = driver_nl80211_probe_req_report,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014707 .deinit_ap = wpa_driver_nl80211_deinit_ap,
Dmitry Shmidt04949592012-07-19 12:16:46 -070014708 .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014709 .resume = wpa_driver_nl80211_resume,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014710 .signal_monitor = nl80211_signal_monitor,
14711 .signal_poll = nl80211_signal_poll,
Sunil Ravi89eba102022-09-13 21:04:37 -070014712 .mlo_signal_poll = nl80211_mlo_signal_poll,
Hai Shalom74f70d42019-02-11 14:42:39 -080014713 .channel_info = nl80211_channel_info,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014714 .set_param = nl80211_set_param,
14715 .get_radio_name = nl80211_get_radio_name,
Jouni Malinen75ecf522011-06-27 15:19:46 -070014716 .add_pmkid = nl80211_add_pmkid,
14717 .remove_pmkid = nl80211_remove_pmkid,
14718 .flush_pmkid = nl80211_flush_pmkid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080014719 .set_rekey_info = nl80211_set_rekey_info,
14720 .poll_client = nl80211_poll_client,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080014721 .set_p2p_powersave = nl80211_set_p2p_powersave,
Dmitry Shmidtea69e842013-05-13 14:52:28 -070014722 .start_dfs_cac = nl80211_start_radar_detection,
14723 .stop_ap = wpa_driver_nl80211_stop_ap,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080014724#ifdef CONFIG_TDLS
14725 .send_tdls_mgmt = nl80211_send_tdls_mgmt,
14726 .tdls_oper = nl80211_tdls_oper,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080014727 .tdls_enable_channel_switch = nl80211_tdls_enable_channel_switch,
14728 .tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080014729#endif /* CONFIG_TDLS */
Dmitry Shmidt700a1372013-03-15 14:14:44 -070014730 .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
Hai Shalom81f62d82019-07-22 12:10:00 -070014731 .update_dh_ie = nl80211_update_dh_ie,
Dmitry Shmidt34af3062013-07-11 10:46:32 -070014732 .get_mac_addr = wpa_driver_nl80211_get_macaddr,
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -070014733 .get_survey = wpa_driver_nl80211_get_survey,
Dmitry Shmidt56052862013-10-04 10:23:25 -070014734 .status = wpa_driver_nl80211_status,
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -080014735 .switch_channel = nl80211_switch_channel,
Sunil Ravia04bd252022-05-02 22:54:18 -070014736#ifdef CONFIG_IEEE80211AX
14737 .switch_color = nl80211_switch_color,
14738#endif /* CONFIG_IEEE80211AX */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080014739#ifdef ANDROID_P2P
Dmitry Shmidt6e933c12011-09-27 12:29:26 -070014740 .set_noa = wpa_driver_set_p2p_noa,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080014741 .get_noa = wpa_driver_get_p2p_noa,
Dmitry Shmidt6e933c12011-09-27 12:29:26 -070014742 .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
Dmitry Shmidt292b0c32013-11-22 12:54:42 -080014743#endif /* ANDROID_P2P */
Dmitry Shmidt738a26e2011-07-07 14:22:14 -070014744#ifdef ANDROID
Dmitry Shmidt41712582015-06-29 11:02:15 -070014745#ifndef ANDROID_LIB_STUB
Dmitry Shmidt738a26e2011-07-07 14:22:14 -070014746 .driver_cmd = wpa_driver_nl80211_driver_cmd,
Dmitry Shmidt41712582015-06-29 11:02:15 -070014747#endif /* !ANDROID_LIB_STUB */
Dmitry Shmidt292b0c32013-11-22 12:54:42 -080014748#endif /* ANDROID */
Dmitry Shmidta38abf92014-03-06 13:38:44 -080014749 .vendor_cmd = nl80211_vendor_cmd,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080014750 .set_qos_map = nl80211_set_qos_map,
Hai Shalomfdcde762020-04-02 11:19:20 -070014751 .get_wowlan = nl80211_get_wowlan,
Dmitry Shmidtb58836e2014-04-29 14:35:56 -070014752 .set_wowlan = nl80211_set_wowlan,
Dmitry Shmidt661b4f72014-09-29 14:58:27 -070014753 .set_mac_addr = nl80211_set_mac_addr,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080014754#ifdef CONFIG_MESH
14755 .init_mesh = wpa_driver_nl80211_init_mesh,
14756 .join_mesh = wpa_driver_nl80211_join_mesh,
14757 .leave_mesh = wpa_driver_nl80211_leave_mesh,
Hai Shalom81f62d82019-07-22 12:10:00 -070014758 .probe_mesh_link = nl80211_probe_mesh_link,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080014759#endif /* CONFIG_MESH */
14760 .br_add_ip_neigh = wpa_driver_br_add_ip_neigh,
14761 .br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh,
14762 .br_port_set_attr = wpa_driver_br_port_set_attr,
14763 .br_set_net_param = wpa_driver_br_set_net_param,
14764 .add_tx_ts = nl80211_add_ts,
14765 .del_tx_ts = nl80211_del_ts,
Dmitry Shmidte4663042016-04-04 10:07:49 -070014766 .get_ifindex = nl80211_get_ifindex,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080014767#ifdef CONFIG_DRIVER_NL80211_QCA
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070014768 .roaming = nl80211_roaming,
Roshan Pius3a1667e2018-07-03 15:17:14 -070014769 .disable_fils = nl80211_disable_fils,
Ravi Joshie6ccb162015-07-16 17:45:41 -070014770 .set_band = nl80211_set_band,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080014771 .get_pref_freq_list = nl80211_get_pref_freq_list,
14772 .set_prob_oper_freq = nl80211_set_prob_oper_freq,
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -070014773 .p2p_lo_start = nl80211_p2p_lo_start,
14774 .p2p_lo_stop = nl80211_p2p_lo_stop,
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -070014775 .set_default_scan_ies = nl80211_set_default_scan_ies,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080014776 .set_tdls_mode = nl80211_set_tdls_mode,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070014777#ifdef CONFIG_MBO
14778 .get_bss_transition_status = nl80211_get_bss_transition_status,
14779 .ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
14780#endif /* CONFIG_MBO */
Hai Shalom899fcc72020-10-19 14:38:18 -070014781 .set_bssid_tmp_disallow = nl80211_set_bssid_tmp_disallow,
Hai Shalomc3565922019-10-28 11:58:20 -070014782 .add_sta_node = nl80211_add_sta_node,
Sunil Ravi89eba102022-09-13 21:04:37 -070014783#ifdef CONFIG_PASN
14784 .send_pasn_resp = nl80211_send_pasn_resp,
14785 .set_secure_ranging_ctx = nl80211_set_secure_ranging_ctx,
14786#endif /* CONFIG_PASN */
Sunil Ravic0f5d412024-09-11 22:12:49 +000014787#ifdef CONFIG_NAN_USD
14788 .nan_flush = nl80211_nan_flush,
14789 .nan_publish = nl80211_nan_publish,
14790 .nan_cancel_publish = nl80211_nan_cancel_publish,
14791 .nan_update_publish = nl80211_nan_update_publish,
14792 .nan_subscribe = nl80211_nan_subscribe,
14793 .nan_cancel_subscribe = nl80211_nan_cancel_subscribe,
14794#endif /* CONFIG_NAN_USD */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080014795#endif /* CONFIG_DRIVER_NL80211_QCA */
Hai Shalomc1a21442022-02-04 13:43:00 -080014796 .do_acs = nl80211_do_acs,
Dmitry Shmidt849734c2016-05-27 09:59:01 -070014797 .configure_data_frame_filters = nl80211_configure_data_frame_filters,
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -070014798 .get_ext_capab = nl80211_get_ext_capab,
Sunil Ravi2a14cf12023-11-21 00:54:38 +000014799 .get_mld_capab = nl80211_get_mld_capab,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070014800 .update_connect_params = nl80211_update_connection_params,
Roshan Pius3a1667e2018-07-03 15:17:14 -070014801 .send_external_auth_status = nl80211_send_external_auth_status,
Hai Shalom74f70d42019-02-11 14:42:39 -080014802 .set_4addr_mode = nl80211_set_4addr_mode,
Hai Shalome21d4e82020-04-29 16:34:06 -070014803#ifdef CONFIG_DPP
14804 .dpp_listen = nl80211_dpp_listen,
14805#endif /* CONFIG_DPP */
Sunil Ravi89eba102022-09-13 21:04:37 -070014806 .get_sta_mlo_info = nl80211_get_sta_mlo_info,
Sunil Ravi036cec52023-03-29 11:35:17 -070014807 .link_add = nl80211_link_add,
Sunil Ravi99c035e2024-07-12 01:42:03 +000014808#ifdef CONFIG_IEEE80211BE
14809 .link_remove = driver_nl80211_link_remove,
14810 .is_drv_shared = nl80211_is_drv_shared,
14811 .link_sta_remove = wpa_driver_nl80211_link_sta_remove,
14812#endif /* CONFIG_IEEE80211BE */
Hai Shalomc1a21442022-02-04 13:43:00 -080014813#ifdef CONFIG_TESTING_OPTIONS
14814 .register_frame = testing_nl80211_register_frame,
14815 .radio_disable = testing_nl80211_radio_disable,
14816#endif /* CONFIG_TESTING_OPTIONS */
Sunil Ravic0f5d412024-09-11 22:12:49 +000014817 .get_multi_hw_info = wpa_driver_get_multi_hw_info,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014818};