wifi: mac80211: Sanity check tx bitrate if not provided by driver
authorStephen Douthit <stephen.douthit@gmail.com>
Mon, 13 Feb 2023 20:40:24 +0000 (15:40 -0500)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 13 Sep 2023 14:24:05 +0000 (16:24 +0200)
If the driver doesn't fill NL80211_STA_INFO_TX_BITRATE in sta_set_sinfo()
then as a fallback sta->deflink.tx_stats.last_rate is used.  Unfortunately
there's no guarantee that this has actually been set before it's used.

Originally found when 'iw <dev> link' would always return a tx rate of
6Mbps regardless of actual link speed for the QCA9337 running firmware
WLAN.TF.2.1-00021-QCARMSWP-1 in my netbook.

Use the sanity check logic from ieee80211_fill_rx_status() and refactor
that to use the new inline function.

Signed-off-by: Stephen Douthit <stephen.douthit@gmail.com>
Link: https://lore.kernel.org/r/20230213204024.3377-1-stephen.douthit@gmail.com
[change to bool ..._rate_valid() instead of int ..._rate_invalid()]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/mac80211.h
net/mac80211/airtime.c
net/mac80211/sta_info.c

index 09fe460..8d993f6 100644 (file)
@@ -1078,6 +1078,11 @@ struct ieee80211_tx_rate {
 
 #define IEEE80211_MAX_TX_RETRY         31
 
+static inline bool ieee80211_rate_valid(struct ieee80211_tx_rate *rate)
+{
+       return rate->idx >= 0 && rate->count > 0;
+}
+
 static inline void ieee80211_rate_set_vht(struct ieee80211_tx_rate *rate,
                                          u8 mcs, u8 nss)
 {
index 14be7b5..fdf8b65 100644 (file)
@@ -557,7 +557,7 @@ static int ieee80211_fill_rx_status(struct ieee80211_rx_status *stat,
        if (ieee80211_fill_rate_info(hw, stat, band, ri))
                return 0;
 
-       if (rate->idx < 0 || !rate->count)
+       if (!ieee80211_rate_valid(rate))
                return -1;
 
        if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
index 7243c6a..ba36fc2 100644 (file)
@@ -2703,7 +2703,8 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
        }
 
        if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)) &&
-           !sta->sta.valid_links) {
+           !sta->sta.valid_links &&
+           ieee80211_rate_valid(&sta->deflink.tx_stats.last_rate)) {
                sta_set_rate_info_tx(sta, &sta->deflink.tx_stats.last_rate,
                                     &sinfo->txrate);
                sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);