]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: mac80211: clean up initial STA NSS/bandwidth handling
authorJohannes Berg <johannes.berg@intel.com>
Wed, 15 Apr 2026 12:42:08 +0000 (14:42 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 28 Apr 2026 07:27:46 +0000 (09:27 +0200)
Currently, the initial STA bandwidth is set during each
parsing of HT/VHT/... elements to the station capabilities,
multiple times, in a confusing way that's not very good in
the case of NAN stations either.

For now, keep the NULL chandef pointer and all that, but
clean up the initial handling of NSS/BW capabilities and
then apply the VHT operation mode on top of that. This
clarifies the code and the client code now also handles
the bandwidth change from Operating Mode Notification in
association response.

The HT code is completely unnecessary now, since the VHT
(soon to be renamed) function will be called and handles
HT as well.

Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260415144514.a4d88eb27a8d.Id7a316e75e7e3dce2023d987e6939060f5286378@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/cfg.c
net/mac80211/eht.c
net/mac80211/he.c
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/ocb.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/vht.c

index 7b77d57c9f96fd6ed0bf2ca2655b25f50063f6d9..15a68d3f8e7354d8a8c8810c077bad4633a54be2 100644 (file)
@@ -2221,7 +2221,15 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
                ieee80211_s1g_cap_to_sta_s1g_cap(sdata, params->s1g_capa,
                                                 link_sta);
 
-       ieee80211_sta_init_nss(link_sta);
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_NAN:
+       case NL80211_IFTYPE_NAN_DATA:
+               /* not applicable - they don't use NSS/BW as capability */
+               break;
+       default:
+               ieee80211_sta_init_nss_bw_capa(link_sta, &link->conf->chanreq.oper);
+               break;
+       }
 
        if (params->opmode_notif_used) {
                enum nl80211_chan_width width = link->conf->chanreq.oper.width;
index 284b90aeb3e1af7870617c9b8a9ab3a4f839de43..3fb469ef27b7ac9997b9c468579157f73d9267b3 100644 (file)
@@ -74,8 +74,6 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,
 
        eht_cap->has_eht = true;
 
-       link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
-
        /*
         * The MPDU length bits are reserved on all but 2.4 GHz and get set via
         * VHT (5 GHz) or HE (6 GHz) capabilities.
index 19e2f359b7966b63dbe505f205fef5a0727f0a5f..e6e9c378ed3a4e1f381882fb862bffaf1c21ef9c 100644 (file)
@@ -159,8 +159,6 @@ _ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
 
        he_cap->has_he = true;
 
-       link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
-
        if (he_6ghz_capa)
                ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, link_sta);
 
index 3775d57d6c22437cc2f9122256db21f433429990..e32e40db081bdec77bfb3bc647659407842bd535 100644 (file)
@@ -140,14 +140,11 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
                                       const struct ieee80211_ht_cap *ht_cap_ie,
                                       struct link_sta_info *link_sta)
 {
-       struct ieee80211_bss_conf *link_conf;
        struct sta_info *sta = link_sta->sta;
        struct ieee80211_sta_ht_cap ht_cap, own_cap;
        u8 ampdu_info, tx_mcs_set_cap;
        int i, max_tx_streams;
        bool changed;
-       enum ieee80211_sta_rx_bandwidth bw;
-       enum nl80211_chan_width width;
 
        memset(&ht_cap, 0, sizeof(ht_cap));
 
@@ -256,41 +253,6 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
 
        memcpy(&link_sta->pub->ht_cap, &ht_cap, sizeof(ht_cap));
 
-       rcu_read_lock();
-       link_conf = rcu_dereference(sdata->vif.link_conf[link_sta->link_id]);
-       if (WARN_ON(!link_conf)) {
-               width = NL80211_CHAN_WIDTH_20_NOHT;
-       } else if (sdata->vif.type == NL80211_IFTYPE_NAN ||
-                  sdata->vif.type == NL80211_IFTYPE_NAN_DATA) {
-               /* In NAN, link_sta->bandwidth is invalid since NAN operates on
-                * multiple channels. Just take the maximum.
-                */
-               width = NL80211_CHAN_WIDTH_320;
-       } else {
-               width = link_conf->chanreq.oper.width;
-       }
-
-       switch (width) {
-       default:
-               WARN_ON_ONCE(1);
-               fallthrough;
-       case NL80211_CHAN_WIDTH_20_NOHT:
-       case NL80211_CHAN_WIDTH_20:
-               bw = IEEE80211_STA_RX_BW_20;
-               break;
-       case NL80211_CHAN_WIDTH_40:
-       case NL80211_CHAN_WIDTH_80:
-       case NL80211_CHAN_WIDTH_80P80:
-       case NL80211_CHAN_WIDTH_160:
-       case NL80211_CHAN_WIDTH_320:
-               bw = ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
-                               IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
-               break;
-       }
-       rcu_read_unlock();
-
-       link_sta->pub->bandwidth = bw;
-
        if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
            sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
            sta->sdata->vif.type == NL80211_IFTYPE_NAN ||
index 96f040b4672eb2d3a5ed95c3441297fbfeb7a30f..08690342cfaa3d3576ca9d0ba51a0d9f6f84d533 100644 (file)
@@ -553,7 +553,8 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta)
 
        memcpy(addr, sta->sta.addr, ETH_ALEN);
 
-       ieee80211_sta_init_nss(&sta->deflink);
+       ieee80211_sta_init_nss_bw_capa(&sta->deflink,
+                                      &sdata->deflink.conf->chanreq.oper);
 
        ibss_dbg(sdata, "Adding new IBSS station %pM\n", addr);
 
index 94201840677d9bf9990c09eee588bb68238c234d..37adb053213e6a60473d30e6a773f75f6938483d 100644 (file)
@@ -470,7 +470,8 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
                                            elems->eht_cap, elems->eht_cap_len,
                                            &sta->deflink);
 
-       ieee80211_sta_init_nss(&sta->deflink);
+       ieee80211_sta_init_nss_bw_capa(&sta->deflink,
+                                      &sdata->deflink.conf->chanreq.oper);
 
        if (bw != sta->sta.deflink.bandwidth)
                changed |= IEEE80211_RC_BW_CHANGED;
index 438cc2d4731df46672d6460d9d353ff55302a88d..ea190d54d1950a831c12bc774e06784098ef3afc 100644 (file)
@@ -5748,22 +5748,13 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
         * next beacon and update then.
         */
 
-       /*
-        * If an operating mode notification element is present, set the opmode
-        * NSS override to correct for the current number of spatial streams,
-        * overriding the capabilities. ieee80211_sta_init_nss() uses this.
-        */
-       if (elems->opmode_notif &&
-           !(*elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)) {
-               u8 nss;
+       ieee80211_sta_init_nss_bw_capa(link_sta, &bss_conf->chanreq.oper);
 
-               nss = *elems->opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK;
-               nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;
-               nss += 1;
-               link_sta->op_mode_nss = nss;
-       }
-
-       ieee80211_sta_init_nss(link_sta);
+       /* If an operating mode notification element is present, use it. */
+       if (elems->opmode_notif)
+               __ieee80211_vht_handle_opmode(sdata, link_sta,
+                                             *elems->opmode_notif,
+                                             sband->band);
 
        /*
         * Always handle WMM once after association regardless
index 447c84235c1c481ed5c6d397dc708cd33821c42d..e9bf4ba3e60b7bd85f5bf45067279b2701258713 100644 (file)
@@ -92,7 +92,8 @@ static struct sta_info *ieee80211_ocb_finish_sta(struct sta_info *sta)
 
        memcpy(addr, sta->sta.addr, ETH_ALEN);
 
-       ieee80211_sta_init_nss(&sta->deflink);
+       ieee80211_sta_init_nss_bw_capa(&sta->deflink,
+                                      &sdata->deflink.conf->chanreq.oper);
 
        ocb_dbg(sdata, "Adding new IBSS station %pM (dev=%s)\n",
                addr, sdata->name);
index 0f174a6a04a86257eda928f24916bd954b3ede5d..d53cd8c5df4cdb0acdd7a4987c4110461611c290 100644 (file)
@@ -3426,7 +3426,7 @@ void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id)
        sta_remove_link(sta, link_id, true);
 }
 
-void ieee80211_sta_init_nss(struct link_sta_info *link_sta)
+static u8 ieee80211_sta_nss_capability(struct link_sta_info *link_sta)
 {
        u8 ht_rx_nss = 0, vht_rx_nss = 0, he_rx_nss = 0, eht_rx_nss = 0, rx_nss;
        bool support_160;
@@ -3509,13 +3509,17 @@ void ieee80211_sta_init_nss(struct link_sta_info *link_sta)
        rx_nss = max(he_rx_nss, rx_nss);
        rx_nss = max(eht_rx_nss, rx_nss);
        rx_nss = max_t(u8, 1, rx_nss);
-       link_sta->capa_nss = rx_nss;
 
-       if (link_sta->op_mode_nss)
-               link_sta->pub->rx_nss =
-                       min_t(u8, rx_nss, link_sta->op_mode_nss);
-       else
-               link_sta->pub->rx_nss = rx_nss;
+       return rx_nss;
+}
+
+void ieee80211_sta_init_nss_bw_capa(struct link_sta_info *link_sta,
+                                   struct cfg80211_chan_def *chandef)
+{
+       link_sta->capa_nss = ieee80211_sta_nss_capability(link_sta);
+       link_sta->pub->rx_nss = link_sta->capa_nss;
+
+       link_sta->pub->bandwidth = _ieee80211_sta_cur_vht_bw(link_sta, chandef);
 }
 
 void ieee80211_sta_set_max_amsdu_subframes(struct sta_info *sta,
index d0987b546bb7a388775029ccd0b2050cb570ae5d..f0497d7d488a97110c388e09cb81b5200a2b3f3a 100644 (file)
@@ -997,7 +997,8 @@ void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta);
 
 unsigned long ieee80211_sta_last_active(struct sta_info *sta, int link_id);
 
-void ieee80211_sta_init_nss(struct link_sta_info *link_sta);
+void ieee80211_sta_init_nss_bw_capa(struct link_sta_info *link_sta,
+                                   struct cfg80211_chan_def *chandef);
 void ieee80211_sta_set_max_amsdu_subframes(struct sta_info *sta,
                                           const u8 *ext_capab,
                                           unsigned int ext_capab_len);
index b93d6a3200c8f77c598a23092dcca82a72ea671f..2a85c578e25204c6459795dcd8987d9a63d2f176 100644 (file)
@@ -301,8 +301,6 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                return;
        }
 
-       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.