diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index baf2c1214030..6cb7389e2c06 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2172,6 +2172,27 @@ static bool ieee80211_rate_bw_usable(u16 rate_flags, return width <= cfg80211_chandef_get_width(chandef); } +static bool +ieee80211_vht_tx_rate_supported(const struct ieee80211_sta_vht_cap *vht_cap, + u8 mcs, u8 nss) +{ + u16 map = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map); + + if (!vht_cap->vht_supported) + return false; + + switch ((map >> (2 * (nss - 1))) & 3) { + case IEEE80211_VHT_MCS_SUPPORT_0_7: + return mcs <= 7; + case IEEE80211_VHT_MCS_SUPPORT_0_8: + return mcs <= 8; + case IEEE80211_VHT_MCS_SUPPORT_0_9: + return mcs <= 9; + default: + return false; + } +} + bool ieee80211_parse_tx_radiotap(struct sk_buff *skb, struct net_device *dev, const struct cfg80211_chan_def *chandef, @@ -2368,14 +2389,20 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb, hweight8(info->control.antennas)) info->control.antennas = 0; - info->control.rates[0].idx = rate; + /* MCS 32 and up aren't handled, e.g. by TX status */ + if (sband && sband->ht_cap.ht_supported && rate < 32 && + sband->ht_cap.mcs.rx_mask[rate / 8] & BIT(rate % 8)) + info->control.rates[0].idx = rate; } else if (rate_flags & IEEE80211_TX_RC_VHT_MCS) { /* reset antennas if not enough */ if (vht_nss > hweight8(info->control.antennas)) info->control.antennas = 0; - ieee80211_rate_set_vht(info->control.rates, vht_mcs, - vht_nss); + if (sband && + ieee80211_vht_tx_rate_supported(&sband->vht_cap, + vht_mcs, vht_nss)) + ieee80211_rate_set_vht(info->control.rates, + vht_mcs, vht_nss); } else if (sband) { for (i = 0; i < sband->n_bitrates; i++) { if (rate * 5 != sband->bitrates[i].bitrate)