[PATCH v3 20/46] nl80211: Factor out global event BSS lookup and add PD wdev event routing

Kavita Kavita kavita.kavita at oss.qualcomm.com
Wed May 13 02:59:44 PDT 2026


From: Veerendranath Jakkam <vjakkam at qti.qualcomm.com>

Introduce nl80211_get_event_bss() to centralize BSS selection for
process_global_event(). The helper performs an exact ifindex match
first, then checks if the wdev_id matches the active PD wdev so that
events arriving on the PD wdev are delivered to pd_bss which is not
part of the regular BSS list, and finally falls back to the existing
bridge/wiphy/wdev matching rules. The wiphy_idx fallback applies only
when wdev_id is not set so that wdev-specific events match exclusively
by exact wdev_id.

wdev_id is set during creation for wdev-only interfaces (P2P Device,
NAN, PD). For netdev interfaces it is not set via if_add_wdevid, so
fetch it from the kernel via GET_INTERFACE and store it in the BSS.
This ensures events that carry NL80211_ATTR_WDEV without
NL80211_ATTR_IFINDEX are routed by exact wdev_id match.

Signed-off-by: Veerendranath Jakkam <vjakkam at qti.qualcomm.com>
---
 src/drivers/driver_nl80211.c       | 31 ++++++++++
 src/drivers/driver_nl80211_event.c | 94 ++++++++++++++++--------------
 2 files changed, 81 insertions(+), 44 deletions(-)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 75178fd03..4b3b8d1c4 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -891,6 +891,8 @@ struct wiphy_idx_data {
 	enum nl80211_iftype nlmode;
 	u8 *macaddr;
 	u8 use_4addr;
+	u64 wdev_id;
+	int wdev_id_set;
 };
 
 
@@ -916,6 +918,11 @@ static int netdev_info_handler(struct nl_msg *msg, void *arg)
 	if (tb[NL80211_ATTR_4ADDR])
 		info->use_4addr = nla_get_u8(tb[NL80211_ATTR_4ADDR]);
 
+	if (tb[NL80211_ATTR_WDEV]) {
+		info->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+		info->wdev_id_set = 1;
+	}
+
 	return NL_SKIP;
 }
 
@@ -3591,6 +3598,30 @@ wpa_driver_nl80211_finish_drv_init(struct i802_bss *bss, const u8 *set_addr,
 	bss->wdev_id = drv->global->if_add_wdevid;
 	bss->wdev_id_set = drv->global->if_add_wdevid_set;
 
+	/*
+	 * wdev_id is set for wdev-only interfaces during creation. For netdev
+	 * interfaces it is not set, so fetch it via GET_INTERFACE to allow
+	 * event routing by exact wdev_id match.
+	 */
+	if (!bss->wdev_id_set) {
+		struct nl_msg *msg;
+		struct wiphy_idx_data info;
+
+		os_memset(&info, 0, sizeof(info));
+		msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE);
+		if (msg &&
+		    send_and_recv_resp(drv, msg, netdev_info_handler,
+				       &info) == 0 &&
+		    info.wdev_id_set) {
+			bss->wdev_id = info.wdev_id;
+			bss->wdev_id_set = 1;
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: %s wdev_id=0x%llx",
+				   bss->ifname,
+				   (unsigned long long) bss->wdev_id);
+		}
+	}
+
 	bss->if_dynamic = drv->ifindex == drv->global->if_add_ifindex;
 	bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set;
 	if (first)
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index b60de54c1..2f5d352e2 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -4831,13 +4831,51 @@ static bool nl80211_drv_in_list(struct nl80211_global *global,
 }
 
 
+static struct i802_bss *
+nl80211_get_event_bss(struct wpa_driver_nl80211_data *drv, int ifidx,
+		      int wiphy_idx_rx, int wiphy_idx_set,
+		      u64 wdev_id, int wdev_id_set)
+{
+	struct i802_bss *bss;
+	int wiphy_idx = -1;
+
+	if (ifidx != -1) {
+		for (bss = drv->first_bss; bss; bss = bss->next) {
+			if (ifidx == bss->ifindex)
+				return bss;
+		}
+	}
+
+#ifdef CONFIG_PR
+	if (wdev_id_set && drv->pd_bss && drv->pd_bss->wdev_id_set &&
+	    wdev_id == drv->pd_bss->wdev_id)
+		return drv->pd_bss;
+#endif /* CONFIG_PR */
+
+	for (bss = drv->first_bss; bss; bss = bss->next) {
+		if (wiphy_idx_set)
+			wiphy_idx = nl80211_get_wiphy_index(bss);
+		if ((ifidx == -1 && !wiphy_idx_set && !wdev_id_set) ||
+		    (bss->br_ifindex > 0 &&
+		     nl80211_has_ifidx(drv, bss->br_ifindex, ifidx)) ||
+		    (!wdev_id_set && wiphy_idx_set &&
+		     wiphy_idx == wiphy_idx_rx) ||
+		    (wdev_id_set && bss->wdev_id_set &&
+		     wdev_id == bss->wdev_id))
+			return bss;
+	}
+
+	return NULL;
+}
+
+
 int process_global_event(struct nl_msg *msg, void *arg)
 {
 	struct nl80211_global *global = arg;
 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
 	struct nlattr *tb[NL80211_ATTR_MAX + 1];
 	struct wpa_driver_nl80211_data *drv, *tmp;
-	int ifidx = -1, wiphy_idx = -1, wiphy_idx_rx = -1;
+	int ifidx = -1, wiphy_idx_rx = -1;
 	struct i802_bss *bss;
 	u64 wdev_id = 0;
 	int wdev_id_set = 0;
@@ -4890,50 +4928,18 @@ int process_global_event(struct nl_msg *msg, void *arg)
 			      struct wpa_driver_nl80211_data, list) {
 		unsigned int unique_drv_id = drv->unique_drv_id;
 
-		/* First pass: Check for exact ifindex match for events directed
-		 * to a specific interface to avoid incorrect selection based on
-		 * matching rules for bridged interfaces. */
-		if (ifidx != -1) {
-			for (bss = drv->first_bss; bss; bss = bss->next) {
-				if (ifidx == bss->ifindex) {
-					do_process_drv_event(bss, gnlh->cmd,
-							     tb);
-					return NL_SKIP;
-				}
-			}
-		}
+		bss = nl80211_get_event_bss(drv, ifidx, wiphy_idx_rx,
+					    wiphy_idx_set, wdev_id,
+					    wdev_id_set);
+		if (!bss)
+			continue;
 
-		/* Second pass: Check all other conditions including bridge */
-		for (bss = drv->first_bss; bss; bss = bss->next) {
-			if (wiphy_idx_set)
-				wiphy_idx = nl80211_get_wiphy_index(bss);
-			if ((ifidx == -1 && !wiphy_idx_set && !wdev_id_set) ||
-			    (bss->br_ifindex > 0 &&
-			     nl80211_has_ifidx(drv, bss->br_ifindex, ifidx)) ||
-			    (wiphy_idx_set && wiphy_idx == wiphy_idx_rx) ||
-			    (wdev_id_set && bss->wdev_id_set &&
-			     wdev_id == bss->wdev_id)) {
-				processed = true;
-				do_process_drv_event(bss, gnlh->cmd, tb);
-				/* There are two types of events that may need
-				 * to be delivered to multiple interfaces:
-				 * 1. Events for a wiphy, as it can have
-				 * multiple interfaces.
-				 * 2. "Global" events, like
-				 * NL80211_CMD_REG_CHANGE.
-				 *
-				 * Terminate early only if the event is directed
-				 * to a specific interface or wdev. */
-				if (ifidx != -1 || wdev_id_set)
-					return NL_SKIP;
-				/* The driver instance could have been removed,
-				 * e.g., due to NL80211_CMD_RADAR_DETECT event,
-				 * so need to stop the loop if that has
-				 * happened. */
-				if (!nl80211_drv_in_list(global, unique_drv_id))
-					break;
-			}
-		}
+		processed = true;
+		do_process_drv_event(bss, gnlh->cmd, tb);
+		if (ifidx != -1 || wdev_id_set)
+			return NL_SKIP;
+		if (!nl80211_drv_in_list(global, unique_drv_id))
+			break;
 	}
 
 	if (processed)
-- 
2.34.1




More information about the Hostap mailing list