]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
wifi: mac80211: work around Cisco AP 9115 VHT MPDU length
authorJohannes Berg <johannes.berg@intel.com>
Mon, 18 Sep 2023 11:10:55 +0000 (14:10 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 25 Sep 2023 06:41:27 +0000 (08:41 +0200)
Cisco AP module 9115 with FW 17.3 has a bug and sends a too
large maximum MPDU length in the association response
(indicating 12k) that it cannot actually process.

Work around that by taking the minimum between what's in the
association response and the BSS elements (from beacon or
probe response).

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230918140607.d1966a9a532e.I090225babb7cd4d1081ee9acd40e7de7e41c15ae@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/cfg.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/vht.c

index e883c41a2163bac70f6416ecff747cffe30eb8b8..0e3a1753a51c6dcc904b004ec15aa2f9f2e1a413 100644 (file)
@@ -1860,7 +1860,8 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
        /* VHT can override some HT caps such as the A-MSDU max length */
        if (params->vht_capa)
                ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
-                                                   params->vht_capa, link_sta);
+                                                   params->vht_capa, NULL,
+                                                   link_sta);
 
        if (params->he_capa)
                ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
index e1900077bc4b94fbb52d112d837319cc1e3eceee..5542c93edfba0b0bdb9d167fbab633c103697cde 100644 (file)
@@ -1072,7 +1072,7 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
                                                   &chandef);
                        memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
                        ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
-                                                           &cap_ie,
+                                                           &cap_ie, NULL,
                                                            &sta->deflink);
                        if (memcmp(&cap, &sta->sta.deflink.vht_cap, sizeof(cap)))
                                rates_updated |= true;
index b3d00259e1d62eda9d7fd4dfca6fb40a7ccb1683..98ef1fe1226e72f8e19f785f8489537635c39799 100644 (file)
@@ -2141,6 +2141,7 @@ void
 ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_supported_band *sband,
                                    const struct ieee80211_vht_cap *vht_cap_ie,
+                                   const struct ieee80211_vht_cap *vht_cap_ie2,
                                    struct link_sta_info *link_sta);
 enum ieee80211_sta_rx_bandwidth
 ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta);
index f3d5bb0a59f1022ff7b48e5888fbb092dbf0a928..a1e526419e9d25ba4e95b53edbfdc94217e09851 100644 (file)
@@ -451,7 +451,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
                changed |= IEEE80211_RC_BW_CHANGED;
 
        ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
-                                           elems->vht_cap_elem,
+                                           elems->vht_cap_elem, NULL,
                                            &sta->deflink);
 
        ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, elems->he_cap,
index 46d46cfab6c8414b887be5d36abbeb10ffe57de0..0e61eb5a29d1813484e51d6baaf16d93f317d2e8 100644 (file)
@@ -4202,10 +4202,33 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
                                                  elems->ht_cap_elem,
                                                  link_sta);
 
-       if (elems->vht_cap_elem && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
+       if (elems->vht_cap_elem &&
+           !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)) {
+               const struct ieee80211_vht_cap *bss_vht_cap = NULL;
+               const struct cfg80211_bss_ies *ies;
+
+               /*
+                * Cisco AP module 9115 with FW 17.3 has a bug and sends a
+                * too large maximum MPDU length in the association response
+                * (indicating 12k) that it cannot actually process ...
+                * Work around that.
+                */
+               rcu_read_lock();
+               ies = rcu_dereference(cbss->ies);
+               if (ies) {
+                       const struct element *elem;
+
+                       elem = cfg80211_find_elem(WLAN_EID_VHT_CAPABILITY,
+                                                 ies->data, ies->len);
+                       if (elem && elem->datalen >= sizeof(*bss_vht_cap))
+                               bss_vht_cap = (const void *)elem->data;
+               }
+
                ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
                                                    elems->vht_cap_elem,
-                                                   link_sta);
+                                                   bss_vht_cap, link_sta);
+               rcu_read_unlock();
+       }
 
        if (elems->he_operation && !(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
            elems->he_cap) {
index c1250aa478083888697dd346a03838c251e1d635..b3a5c3e96a7205354692d86eb022ecebefa05d64 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Portions of this file
  * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
- * Copyright (C) 2018 - 2022 Intel Corporation
+ * Copyright (C) 2018 - 2023 Intel Corporation
  */
 
 #include <linux/ieee80211.h>
@@ -116,12 +116,14 @@ void
 ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_supported_band *sband,
                                    const struct ieee80211_vht_cap *vht_cap_ie,
+                                   const struct ieee80211_vht_cap *vht_cap_ie2,
                                    struct link_sta_info *link_sta)
 {
        struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap;
        struct ieee80211_sta_vht_cap own_cap;
        u32 cap_info, i;
        bool have_80mhz;
+       u32 mpdu_len;
 
        memset(vht_cap, 0, sizeof(*vht_cap));
 
@@ -317,11 +319,21 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
 
        link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
 
+       /*
+        * Work around the Cisco 9115 FW 17.3 bug by taking the min of
+        * both reported MPDU lengths.
+        */
+       mpdu_len = vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK;
+       if (vht_cap_ie2)
+               mpdu_len = min_t(u32, mpdu_len,
+                                le32_get_bits(vht_cap_ie2->vht_cap_info,
+                                              IEEE80211_VHT_CAP_MAX_MPDU_MASK));
+
        /*
         * FIXME - should the amsdu len be per link? store per link
         * and maintain a minimum?
         */
-       switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
+       switch (mpdu_len) {
        case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
                link_sta->pub->agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454;
                break;