1 From 32d043fc10f1814e421c0ff90c0ee6b303f2821c Mon Sep 17 00:00:00 2001
2 From: Johannes Berg <johannes.berg@intel.com>
3 Date: Wed, 28 Feb 2024 12:01:57 +0100
4 Subject: [PATCH 351/351] wifi: mac80211: track capability/opmode NSS
7 We're currently tracking rx_nss for each station, and that
8 is meant to be initialized to the capability NSS and later
9 reduced by the operating mode notification NSS.
11 However, we're mixing up capabilities and operating mode
12 NSS in the same variable. This forces us to recalculate
13 the NSS capability on operating mode notification RX,
14 which is a bit strange; due to the previous fix I had to
15 never keep rx_nss as zero, it also means that the capa is
16 never taken into account properly.
18 Fix all this by storing the capability value, that can be
19 recalculated unconditionally whenever needed, and storing
20 the operating mode notification NSS separately, taking it
21 into account when assigning the final rx_nss value.
23 Cc: stable@vger.kernel.org
24 Fixes: dd6c064cfc3f ("wifi: mac80211: set station RX-NSS on reconfig")
25 Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
26 Link: https://msgid.link/20240228120157.0e1c41924d1d.I0acaa234e0267227b7e3ef81a59117c8792116bc@changeid
27 Signed-off-by: Johannes Berg <johannes.berg@intel.com>
28 (cherry picked from commit a8bca3e9371dc5e276af4168be099b2a05554c2a)
30 net/mac80211/cfg.c | 2 +-
31 net/mac80211/ieee80211_i.h | 2 +-
32 net/mac80211/rate.c | 2 +-
33 net/mac80211/sta_info.h | 6 ++++-
34 net/mac80211/vht.c | 46 ++++++++++++++++++--------------------
35 5 files changed, 30 insertions(+), 28 deletions(-)
37 --- a/net/mac80211/cfg.c
38 +++ b/net/mac80211/cfg.c
39 @@ -1836,7 +1836,7 @@ static int sta_link_apply_parameters(str
43 - ieee80211_sta_set_rx_nss(link_sta);
44 + ieee80211_sta_init_nss(link_sta);
48 --- a/net/mac80211/ieee80211_i.h
49 +++ b/net/mac80211/ieee80211_i.h
50 @@ -2101,7 +2101,7 @@ enum ieee80211_sta_rx_bandwidth
51 ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta);
52 enum ieee80211_sta_rx_bandwidth
53 ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta);
54 -void ieee80211_sta_set_rx_nss(struct link_sta_info *link_sta);
55 +void ieee80211_sta_init_nss(struct link_sta_info *link_sta);
56 enum ieee80211_sta_rx_bandwidth
57 ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width);
58 enum nl80211_chan_width
59 --- a/net/mac80211/rate.c
60 +++ b/net/mac80211/rate.c
61 @@ -37,7 +37,7 @@ void rate_control_rate_init(struct sta_i
62 struct ieee80211_supported_band *sband;
63 struct ieee80211_chanctx_conf *chanctx_conf;
65 - ieee80211_sta_set_rx_nss(&sta->deflink);
66 + ieee80211_sta_init_nss(&sta->deflink);
70 --- a/net/mac80211/sta_info.h
71 +++ b/net/mac80211/sta_info.h
73 * Copyright 2002-2005, Devicescape Software, Inc.
74 * Copyright 2013-2014 Intel Mobile Communications GmbH
75 * Copyright(c) 2015-2017 Intel Deutschland GmbH
76 - * Copyright(c) 2020-2022 Intel Corporation
77 + * Copyright(c) 2020-2024 Intel Corporation
81 @@ -485,6 +485,8 @@ struct ieee80211_fragment_cache {
82 * same for non-MLD STA. This is used as key for searching link STA
83 * @link_id: Link ID uniquely identifying the link STA. This is 0 for non-MLD
84 * and set to the corresponding vif LinkId for MLD STA
85 + * @op_mode_nss: NSS limit as set by operating mode notification, or 0
86 + * @capa_nss: NSS limit as determined by local and peer capabilities
87 * @link_hash_node: hash node for rhashtable
88 * @sta: Points to the STA info
89 * @gtk: group keys negotiated with this station, if any
90 @@ -520,6 +522,8 @@ struct link_sta_info {
94 + u8 op_mode_nss, capa_nss;
96 struct rhlist_head link_hash_node;
99 --- a/net/mac80211/vht.c
100 +++ b/net/mac80211/vht.c
103 * Portions of this file
104 * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
105 - * Copyright (C) 2018 - 2023 Intel Corporation
106 + * Copyright (C) 2018 - 2024 Intel Corporation
109 #include <linux/ieee80211.h>
110 @@ -541,15 +541,11 @@ ieee80211_sta_cur_vht_bw(struct link_sta
114 -void ieee80211_sta_set_rx_nss(struct link_sta_info *link_sta)
115 +void ieee80211_sta_init_nss(struct link_sta_info *link_sta)
117 u8 ht_rx_nss = 0, vht_rx_nss = 0, he_rx_nss = 0, eht_rx_nss = 0, rx_nss;
120 - /* if we received a notification already don't overwrite it */
121 - if (link_sta->pub->rx_nss)
124 if (link_sta->pub->eht_cap.has_eht) {
126 const u8 *rx_nss_mcs = (void *)&link_sta->pub->eht_cap.eht_mcs_nss_supp;
127 @@ -627,7 +623,15 @@ void ieee80211_sta_set_rx_nss(struct lin
128 rx_nss = max(vht_rx_nss, ht_rx_nss);
129 rx_nss = max(he_rx_nss, rx_nss);
130 rx_nss = max(eht_rx_nss, rx_nss);
131 - link_sta->pub->rx_nss = max_t(u8, 1, rx_nss);
132 + rx_nss = max_t(u8, 1, rx_nss);
133 + link_sta->capa_nss = rx_nss;
135 + /* that shouldn't be set yet, but we can handle it anyway */
136 + if (link_sta->op_mode_nss)
137 + link_sta->pub->rx_nss =
138 + min_t(u8, rx_nss, link_sta->op_mode_nss);
140 + link_sta->pub->rx_nss = rx_nss;
143 u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
144 @@ -637,7 +641,7 @@ u32 __ieee80211_vht_handle_opmode(struct
145 enum ieee80211_sta_rx_bandwidth new_bw;
146 struct sta_opmode_info sta_opmode = {};
151 /* ignore - no support for BF yet */
152 if (opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)
153 @@ -647,23 +651,17 @@ u32 __ieee80211_vht_handle_opmode(struct
154 nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;
157 - if (link_sta->pub->rx_nss != nss) {
158 - cur_nss = link_sta->pub->rx_nss;
159 - /* Reset rx_nss and call ieee80211_sta_set_rx_nss() which
160 - * will set the same to max nss value calculated based on capability.
162 - link_sta->pub->rx_nss = 0;
163 - ieee80211_sta_set_rx_nss(link_sta);
164 - /* Do not allow an nss change to rx_nss greater than max_nss
165 - * negotiated and capped to APs capability during association.
167 - if (nss <= link_sta->pub->rx_nss) {
168 - link_sta->pub->rx_nss = nss;
169 - sta_opmode.rx_nss = nss;
170 - changed |= IEEE80211_RC_NSS_CHANGED;
171 - sta_opmode.changed |= STA_OPMODE_N_SS_CHANGED;
172 + if (link_sta->op_mode_nss != nss) {
173 + if (nss <= link_sta->capa_nss) {
174 + link_sta->op_mode_nss = nss;
176 + if (nss != link_sta->pub->rx_nss) {
177 + link_sta->pub->rx_nss = nss;
178 + changed |= IEEE80211_RC_NSS_CHANGED;
179 + sta_opmode.rx_nss = link_sta->pub->rx_nss;
180 + sta_opmode.changed |= STA_OPMODE_N_SS_CHANGED;
183 - link_sta->pub->rx_nss = cur_nss;
184 pr_warn_ratelimited("Ignoring NSS change in VHT Operating Mode Notification from %pM with invalid nss %d",
185 link_sta->pub->addr, nss);