The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH] wifi: nl80211: say why the association BSS lookup failed
@ 2026-07-11  4:34 Louis Kotze
  0 siblings, 0 replies; only message in thread
From: Louis Kotze @ 2026-07-11  4:34 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, linux-kernel, loukot

The BSS lookup for an association request can fail for three distinct
reasons: cfg80211 has no scan entry at all for the BSSID/channel, an
entry exists but is older than IEEE80211_SCAN_RESULT_EXPIRE (and not
held), or a fresh entry exists but its use_for flags do not allow
this use. All three currently surface as the same generic extack
message "Error fetching BSS for link" on the MLO path, and as a bare
-ENOENT with no message on the non-MLO path.

Since wpa_supplicant logs the extack message verbatim ("nl80211:
kernel reports: ..."), that message is often the only diagnostic a
user sees when an MLO association degrades to fewer links, and it
does not say whether rescanning would help. In practice the expired
case is common for MLO partner links: 6 GHz is passive-scan in many
regulatory domains, so the partner-link entry is routinely stale by
the time userspace requests the association even though the link is
perfectly usable.

Add a cfg80211 helper that classifies, on the failure path only, why
matching entries were rejected, and set a distinct extack message
for each case in nl80211_assoc_bss(). Also give the -EINVAL paths
there proper messages while at it, and keep pointing the bad_attr at
the failing link.

Signed-off-by: Louis Kotze <loukot@gmail.com>
---
Compile-tested (W=1 clean) and exercised on a UML/hwsim rig: an MLO
reassociation whose partner-link entry had aged out now gets
"nl80211: kernel reports: BSS not found in scan results" in the
wpa_supplicant debug log instead of the generic message.

 net/wireless/core.h    | 12 +++++++++++
 net/wireless/nl80211.c | 37 +++++++++++++++++++++++--------
 net/wireless/scan.c    | 49 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 89 insertions(+), 9 deletions(-)

diff --git a/net/wireless/core.h b/net/wireless/core.h
index df47ed6208a5..a3778c6e07e4 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -332,6 +332,18 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
 void cfg80211_bss_expire(struct cfg80211_registered_device *rdev);
 void cfg80211_bss_age(struct cfg80211_registered_device *rdev,
                       unsigned long age_secs);
+
+/* why __cfg80211_get_bss() found no usable BSS entry */
+#define CFG80211_BSS_MISS_EXPIRED	BIT(0)
+#define CFG80211_BSS_MISS_USE_FOR	BIT(1)
+
+u32 cfg80211_get_bss_miss_reasons(struct wiphy *wiphy,
+				  struct ieee80211_channel *channel,
+				  const u8 *bssid,
+				  const u8 *ssid, size_t ssid_len,
+				  enum ieee80211_bss_type bss_type,
+				  enum ieee80211_privacy privacy,
+				  u32 use_for);
 void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev,
 				     unsigned int link,
 				     struct ieee80211_channel *channel);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 242071ad10d6..a68390ae6d2c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -13036,6 +13036,7 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
 }
 
 static struct cfg80211_bss *nl80211_assoc_bss(struct cfg80211_registered_device *rdev,
+					      struct genl_info *info,
 					      const u8 *ssid, int ssid_len,
 					      struct nlattr **attrs,
 					      int assoc_link_id, int link_id)
@@ -13043,10 +13044,12 @@ static struct cfg80211_bss *nl80211_assoc_bss(struct cfg80211_registered_device
 	struct ieee80211_channel *chan;
 	struct cfg80211_bss *bss;
 	const u8 *bssid;
-	u32 freq, use_for = 0;
+	u32 freq, miss, use_for = 0;
 
-	if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_WIPHY_FREQ])
+	if (!attrs[NL80211_ATTR_MAC] || !attrs[NL80211_ATTR_WIPHY_FREQ]) {
+		NL_SET_ERR_MSG(info->extack, "BSSID or frequency missing");
 		return ERR_PTR(-EINVAL);
+	}
 
 	bssid = nla_data(attrs[NL80211_ATTR_MAC]);
 
@@ -13055,8 +13058,10 @@ static struct cfg80211_bss *nl80211_assoc_bss(struct cfg80211_registered_device
 		freq += nla_get_u32(attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
 
 	chan = nl80211_get_valid_chan(&rdev->wiphy, freq);
-	if (!chan)
+	if (!chan) {
+		NL_SET_ERR_MSG(info->extack, "invalid or disabled channel");
 		return ERR_PTR(-EINVAL);
+	}
 
 	if (assoc_link_id >= 0)
 		use_for = NL80211_BSS_USE_FOR_MLD_LINK;
@@ -13068,8 +13073,23 @@ static struct cfg80211_bss *nl80211_assoc_bss(struct cfg80211_registered_device
 				 IEEE80211_BSS_TYPE_ESS,
 				 IEEE80211_PRIVACY_ANY,
 				 use_for);
-	if (!bss)
+	if (!bss) {
+		miss = cfg80211_get_bss_miss_reasons(&rdev->wiphy, chan,
+						     bssid, ssid, ssid_len,
+						     IEEE80211_BSS_TYPE_ESS,
+						     IEEE80211_PRIVACY_ANY,
+						     use_for);
+		if (miss & CFG80211_BSS_MISS_USE_FOR)
+			NL_SET_ERR_MSG(info->extack,
+				       "BSS cannot be used for this association");
+		else if (miss & CFG80211_BSS_MISS_EXPIRED)
+			NL_SET_ERR_MSG(info->extack,
+				       "BSS entry is expired, scan again");
+		else
+			NL_SET_ERR_MSG(info->extack,
+				       "BSS not found in scan results");
 		return ERR_PTR(-ENOENT);
+	}
 
 	return bss;
 }
@@ -13106,13 +13126,12 @@ static int nl80211_process_links(struct cfg80211_registered_device *rdev,
 			return -EINVAL;
 		}
 		links[link_id].bss =
-			nl80211_assoc_bss(rdev, ssid, ssid_len, attrs,
+			nl80211_assoc_bss(rdev, info, ssid, ssid_len, attrs,
 					  assoc_link_id, link_id);
 		if (IS_ERR(links[link_id].bss)) {
 			err = PTR_ERR(links[link_id].bss);
 			links[link_id].bss = NULL;
-			NL_SET_ERR_MSG_ATTR(info->extack, link,
-					    "Error fetching BSS for link");
+			NL_SET_BAD_ATTR(info->extack, link);
 			return err;
 		}
 
@@ -13328,8 +13347,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
 		if (req.link_id >= 0)
 			return -EINVAL;
 
-		req.bss = nl80211_assoc_bss(rdev, ssid, ssid_len, info->attrs,
-					    -1, -1);
+		req.bss = nl80211_assoc_bss(rdev, info, ssid, ssid_len,
+					    info->attrs, -1, -1);
 		if (IS_ERR(req.bss))
 			return PTR_ERR(req.bss);
 		ap_addr = req.bss->bssid;
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 05b7dc6b766c..f0e13b178b74 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1655,6 +1655,55 @@ struct cfg80211_bss *__cfg80211_get_bss(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(__cfg80211_get_bss);
 
+/*
+ * Report why __cfg80211_get_bss() with the same arguments found no
+ * usable entry: matching entries exist but are expired, or are not
+ * usable for the requested use. Returns 0 if no entry matches at all.
+ */
+u32 cfg80211_get_bss_miss_reasons(struct wiphy *wiphy,
+				  struct ieee80211_channel *channel,
+				  const u8 *bssid,
+				  const u8 *ssid, size_t ssid_len,
+				  enum ieee80211_bss_type bss_type,
+				  enum ieee80211_privacy privacy,
+				  u32 use_for)
+{
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+	struct cfg80211_internal_bss *bss;
+	unsigned long now = jiffies;
+	u32 reasons = 0;
+	int bss_privacy;
+
+	spin_lock_bh(&rdev->bss_lock);
+
+	list_for_each_entry(bss, &rdev->bss_list, list) {
+		if (!cfg80211_bss_type_match(bss->pub.capability,
+					     bss->pub.channel->band, bss_type))
+			continue;
+
+		bss_privacy = (bss->pub.capability & WLAN_CAPABILITY_PRIVACY);
+		if ((privacy == IEEE80211_PRIVACY_ON && !bss_privacy) ||
+		    (privacy == IEEE80211_PRIVACY_OFF && bss_privacy))
+			continue;
+		if (channel && bss->pub.channel != channel)
+			continue;
+		if (!is_valid_ether_addr(bss->pub.bssid))
+			continue;
+		if (!is_bss(&bss->pub, bssid, ssid, ssid_len))
+			continue;
+
+		if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) &&
+		    !atomic_read(&bss->hold))
+			reasons |= CFG80211_BSS_MISS_EXPIRED;
+		else if ((bss->pub.use_for & use_for) != use_for)
+			reasons |= CFG80211_BSS_MISS_USE_FOR;
+	}
+
+	spin_unlock_bh(&rdev->bss_lock);
+
+	return reasons;
+}
+
 static bool rb_insert_bss(struct cfg80211_registered_device *rdev,
 			  struct cfg80211_internal_bss *bss)
 {

base-commit: ac798f757d6475dc6fee2ec899980d6740714596
-- 
2.55.0


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-07-11  4:34 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-11  4:34 [PATCH] wifi: nl80211: say why the association BSS lookup failed Louis Kotze

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox