All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.