[PATCH 01/42] nl80211: Do a roundtrip to reset event supressions

Andrei Otcheretianski andrei.otcheretianski at intel.com
Mon Nov 20 15:51:15 PST 2023


From: Benjamin Berg <benjamin.berg at intel.com>

With nl80211 we need to supress the kernel generated event for any
disconnect and deauthenticate. This code is a bit fragile, as it
assumes that an event will happen. Commit b898b655824a ("nl80211: Do
not ignore disconnect event in case of !drv->associated") changed this
to only disconnect when the driver knows it is associated (apparently
required for P2P), however, deauthentication may also occur without
being associated yet.

Looking at the issue, what we are really interested in is whether the
event belongs to a disconnect/deauth command that we have send
ourselves. Any event happening after the disconnect/deauth completes
should not be suppressed (or after the next connect/auth as that would
be sufficient). We therefore need to know from the event stream
whether events were generated before or after disconnect/deauth
command completion.

To do so, send a simple command on the nl_event socket. As this will
be returned back to us in the correct order with regard to the events.
We can therefore use it to safely reset our internal
ignore_next_local_{deauth,disconnect} variables.

Signed-off-by: Benjamin Berg <benjamin.berg at intel.com>
---
 src/drivers/driver_nl80211.c       | 47 ++++++++++++++++++++++++++----
 src/drivers/driver_nl80211.h       |  5 ++--
 src/drivers/driver_nl80211_event.c | 23 +++++++++++++++
 3 files changed, 67 insertions(+), 8 deletions(-)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index ac63e64054..229c78a6d2 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -405,6 +405,41 @@ static void nl80211_nlmsg_clear(struct nl_msg *msg)
 }
 
 
+static int send_event_marker(struct wpa_driver_nl80211_data *drv)
+{
+	struct nl_sock *handle;
+	struct nl_msg *msg;
+	struct nlmsghdr *hdr;
+	int res = 0;
+	int err = -NLE_NOMEM;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		goto out;
+
+	/* We only care about the returned sequence number for matching. */
+	if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES))
+		goto out;
+
+	handle = (void *) (((intptr_t) drv->global->nl_event) ^
+			   ELOOP_SOCKET_INVALID);
+
+	err = nl_send_auto_complete(handle, msg);
+	if (err < 0)
+		goto out;
+
+	hdr = nlmsg_hdr(msg);
+	res = hdr->nlmsg_seq;
+
+out:
+	nlmsg_free(msg);
+	if (err)
+		wpa_printf(MSG_INFO, "nl80211: %s failed: %s",
+			   __func__, nl_geterror(err));
+	return res;
+}
+
+
 static int send_and_recv(struct nl80211_global *global,
 			 struct nl_sock *nl_handle, struct nl_msg *msg,
 			 int (*valid_handler)(struct nl_msg *, void *),
@@ -3736,7 +3771,6 @@ static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
 					 struct i802_bss *bss)
 {
 	int ret;
-	int drv_associated = drv->associated;
 
 	wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
 	nl80211_mark_disconnected(drv);
@@ -3747,7 +3781,8 @@ static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
 	 * For locally generated disconnect, supplicant already generates a
 	 * DEAUTH event, so ignore the event from NL80211.
 	 */
-	drv->ignore_next_local_disconnect = drv_associated && (ret == 0);
+	if (ret == 0)
+		drv->ignore_next_local_disconnect = send_event_marker(drv);
 
 	return ret;
 }
@@ -3758,7 +3793,6 @@ static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret;
-	int drv_associated = drv->associated;
 
 	if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
 		nl80211_mark_disconnected(drv);
@@ -3776,7 +3810,8 @@ static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
 	 * For locally generated deauthenticate, supplicant already generates a
 	 * DEAUTH event, so ignore the event from NL80211.
 	 */
-	drv->ignore_next_local_deauth = drv_associated && (ret == 0);
+	if (ret == 0)
+		drv->ignore_next_local_deauth = send_event_marker(drv);
 
 	return ret;
 }
@@ -10811,9 +10846,9 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
 			  drv->retry_auth ? "retry_auth=1\n" : "",
 			  drv->use_monitor ? "use_monitor=1\n" : "",
 			  drv->ignore_next_local_disconnect ?
-			  "ignore_next_local_disconnect=1\n" : "",
+			  "ignore_next_local_disconnect\n" : "",
 			  drv->ignore_next_local_deauth ?
-			  "ignore_next_local_deauth=1\n" : "");
+			  "ignore_next_local_deauth\n" : "");
 	if (os_snprintf_error(end - pos, res))
 		return pos - buf;
 	pos += res;
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index aee8c45124..d419739936 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -165,8 +165,6 @@ struct wpa_driver_nl80211_data {
 	unsigned int scan_for_auth:1;
 	unsigned int retry_auth:1;
 	unsigned int use_monitor:1;
-	unsigned int ignore_next_local_disconnect:1;
-	unsigned int ignore_next_local_deauth:1;
 	unsigned int hostapd:1;
 	unsigned int start_mode_sta:1;
 	unsigned int start_iface_up:1;
@@ -203,6 +201,9 @@ struct wpa_driver_nl80211_data {
 	unsigned int puncturing:1;
 	unsigned int qca_ap_allowed_freqs:1;
 
+	u32 ignore_next_local_disconnect;
+	u32 ignore_next_local_deauth;
+
 	u64 vendor_scan_cookie;
 	u64 remain_on_chan_cookie;
 	u64 send_frame_cookie;
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 0091032e55..cf10abd97d 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -4060,6 +4060,29 @@ int process_global_event(struct nl_msg *msg, void *arg)
 	int wdev_id_set = 0;
 	int wiphy_idx_set = 0;
 
+	/* event marker, all prior events have been processed */
+	if (gnlh->cmd == NL80211_CMD_GET_PROTOCOL_FEATURES) {
+		struct wpa_driver_nl80211_data *drv, *tmp;
+		u32 seq = nlmsg_hdr(msg)->nlmsg_seq;
+
+		dl_list_for_each_safe(drv, tmp, &global->interfaces,
+				      struct wpa_driver_nl80211_data, list) {
+			if (drv->ignore_next_local_deauth > 0 &&
+			    drv->ignore_next_local_deauth <= seq) {
+				wpa_printf(MSG_INFO, "nl80211: No DEAUTHENTICATE event was ignored");
+				drv->ignore_next_local_deauth = 0;
+			}
+
+			if (drv->ignore_next_local_disconnect > 0 &&
+			    drv->ignore_next_local_disconnect <= seq) {
+				wpa_printf(MSG_INFO, "nl80211: No DISCONNECT event was ignored");
+				drv->ignore_next_local_disconnect = 0;
+			}
+		}
+
+		return NL_SKIP;
+	}
+
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
 
-- 
2.38.1




More information about the Hostap mailing list