wifi: cfg80211: support reporting failed links
authorJohannes Berg <johannes.berg@intel.com>
Tue, 6 Sep 2022 09:27:57 +0000 (11:27 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 7 Oct 2022 13:23:48 +0000 (15:23 +0200)
For assoc and connect result APIs, support reporting
failed links; they should still come with the BSS
pointer in the case of assoc, so they're released
correctly. In the case of connect result, this is
optional.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/sme.c

index e09ff87146c1c56522ef7b5188951b94f60420cd..4d35a4234417879abe0c415eb173603362f668aa 100644 (file)
@@ -6933,6 +6933,8 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr);
  * @ap_mld_addr: AP MLD address (in case of MLO)
  * @links: per-link information indexed by link ID, use links[0] for
  *     non-MLO connections
+ * @links.status: Set this (along with a BSS pointer) for links that
+ *     were rejected by the AP.
  */
 struct cfg80211_rx_assoc_resp {
        const u8 *buf;
@@ -6944,6 +6946,7 @@ struct cfg80211_rx_assoc_resp {
        struct {
                const u8 *addr;
                struct cfg80211_bss *bss;
+               u16 status;
        } links[IEEE80211_MLD_MAX_NUM_LINKS];
 };
 
@@ -7454,6 +7457,9 @@ struct cfg80211_fils_resp_params {
  *     if the bss is expired during the connection, esp. for those drivers
  *     implementing connect op. Only one parameter among @bssid and @bss needs
  *     to be specified.
+ * @links.status: per-link status code, to report a status code that's not
+ *     %WLAN_STATUS_SUCCESS for a given link, it must also be in the
+ *     @valid_links bitmap and may have a BSS pointer (which is then released)
  */
 struct cfg80211_connect_resp_params {
        int status;
@@ -7470,6 +7476,7 @@ struct cfg80211_connect_resp_params {
                const u8 *addr;
                const u8 *bssid;
                struct cfg80211_bss *bss;
+               u16 status;
        } links[IEEE80211_MLD_MAX_NUM_LINKS];
 };
 
index 581df7f4c524091ac6c7a3b1a21ef54e2986a622..58e1fb18f85a41d87e0ef39d879d715498e143bc 100644 (file)
@@ -42,6 +42,10 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
        unsigned int link_id;
 
        for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
+               cr.links[link_id].status = data->links[link_id].status;
+               WARN_ON_ONCE(cr.links[link_id].status != WLAN_STATUS_SUCCESS &&
+                            (!cr.ap_mld_addr || !cr.links[link_id].bss));
+
                cr.links[link_id].bss = data->links[link_id].bss;
                if (!cr.links[link_id].bss)
                        continue;
index 8ff8b1c040f0b2ade057f6b762f28f052ee2b1fd..ad7393cd3d187e654a3a1a5c703ce5c99b6cb83c 100644 (file)
@@ -17745,6 +17745,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
                        link_info_size += (cr->links[link].bssid ||
                                           cr->links[link].bss) ?
                                          nla_total_size(ETH_ALEN) : 0;
+                       link_info_size += nla_total_size(sizeof(u16));
                }
        }
 
@@ -17813,7 +17814,9 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
                             nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, bssid)) ||
                            (cr->links[link].addr &&
                             nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
-                                    cr->links[link].addr)))
+                                    cr->links[link].addr)) ||
+                           nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
+                                       cr->links[link].status))
                                goto nla_put_failure;
 
                        nla_nest_end(msg, nested_mlo_links);
index d513536617bd9ea5161f0bfa0681ab01817d588d..f94497e9db431eea9c89d0638ccd11bd2da5284c 100644 (file)
@@ -793,6 +793,10 @@ void __cfg80211_connect_result(struct net_device *dev,
                }
 
                for_each_valid_link(cr, link) {
+                       /* don't do extra lookups for failures */
+                       if (cr->links[link].status != WLAN_STATUS_SUCCESS)
+                               continue;
+
                        if (cr->links[link].bss)
                                continue;
 
@@ -829,6 +833,16 @@ void __cfg80211_connect_result(struct net_device *dev,
        }
 
        memset(wdev->links, 0, sizeof(wdev->links));
+       for_each_valid_link(cr, link) {
+               if (cr->links[link].status == WLAN_STATUS_SUCCESS)
+                       continue;
+               cr->valid_links &= ~BIT(link);
+               /* don't require bss pointer for failed links */
+               if (!cr->links[link].bss)
+                       continue;
+               cfg80211_unhold_bss(bss_from_pub(cr->links[link].bss));
+               cfg80211_put_bss(wdev->wiphy, cr->links[link].bss);
+       }
        wdev->valid_links = cr->valid_links;
        for_each_valid_link(cr, link)
                wdev->links[link].client.current_bss =