Commit 3e61c5b6 authored by Ryder Lee's avatar Ryder Lee Committed by Ziyang Xuan
Browse files

mt76: mt7915: fix txrate reporting

mainline inclusion
from mainline-v5.13-rc1
commit f43b941f
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I94J23
CVE: CVE-2021-47028

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f43b941fd61003659a3f0e039595e5e525917aa8



--------------------------------

Properly check rate_info to fix unexpected reporting.

[ 1215.161863] Call trace:
[ 1215.164307]  cfg80211_calculate_bitrate+0x124/0x200 [cfg80211]
[ 1215.170139]  ieee80211s_update_metric+0x80/0xc0 [mac80211]
[ 1215.175624]  ieee80211_tx_status_ext+0x508/0x838 [mac80211]
[ 1215.181190]  mt7915_mcu_get_rx_rate+0x28c/0x8d0 [mt7915e]
[ 1215.186580]  mt7915_mac_tx_free+0x324/0x7c0 [mt7915e]
[ 1215.191623]  mt7915_queue_rx_skb+0xa8/0xd0 [mt7915e]
[ 1215.196582]  mt76_dma_cleanup+0x7b0/0x11d0 [mt76]
[ 1215.201276]  __napi_poll+0x38/0xf8
[ 1215.204668]  napi_workfn+0x40/0x80
[ 1215.208062]  process_one_work+0x1fc/0x390
[ 1215.212062]  worker_thread+0x48/0x4d0
[ 1215.215715]  kthread+0x120/0x128
[ 1215.218935]  ret_from_fork+0x10/0x1c

Fixes: e57b7901 ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets")
Fixes: e4c5ead6 ("mt76: mt7915: rename mt7915_mcu_get_rate_info to mt7915_mcu_get_tx_rate")
Reported-by: default avatarEvelyn Tsai <evelyn.tsai@mediatek.com>
Signed-off-by: default avatarRyder Lee <ryder.lee@mediatek.com>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
Signed-off-by: default avatarZiyang Xuan <william.xuanziyang@huawei.com>
parent 10bdbb97
Loading
Loading
Loading
Loading
+24 −14
Original line number Diff line number Diff line
@@ -418,54 +418,62 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb)
	dev->hw_pattern++;
}

static void
static int
mt7915_mcu_tx_rate_parse(struct mt76_phy *mphy, struct mt7915_mcu_ra_info *ra,
			 struct rate_info *rate, u16 r)
{
	struct ieee80211_supported_band *sband;
	u16 ru_idx = le16_to_cpu(ra->ru_idx);
	u16 flags = 0;
	bool cck = false;

	rate->mcs = FIELD_GET(MT_RA_RATE_MCS, r);
	rate->nss = FIELD_GET(MT_RA_RATE_NSS, r) + 1;

	switch (FIELD_GET(MT_RA_RATE_TX_MODE, r)) {
	case MT_PHY_TYPE_CCK:
		cck = true;
		fallthrough;
	case MT_PHY_TYPE_OFDM:
		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
			sband = &mphy->sband_5g.sband;
		else
			sband = &mphy->sband_2g.sband;

		rate->mcs = mt76_get_rate(mphy->dev, sband, rate->mcs, cck);
		rate->legacy = sband->bitrates[rate->mcs].bitrate;
		break;
	case MT_PHY_TYPE_HT:
	case MT_PHY_TYPE_HT_GF:
		rate->mcs += (rate->nss - 1) * 8;
		flags |= RATE_INFO_FLAGS_MCS;
		if (rate->mcs > 31)
			return -EINVAL;

		rate->flags = RATE_INFO_FLAGS_MCS;
		if (ra->gi)
			flags |= RATE_INFO_FLAGS_SHORT_GI;
			rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
		break;
	case MT_PHY_TYPE_VHT:
		flags |= RATE_INFO_FLAGS_VHT_MCS;
		if (rate->mcs > 9)
			return -EINVAL;

		rate->flags = RATE_INFO_FLAGS_VHT_MCS;
		if (ra->gi)
			flags |= RATE_INFO_FLAGS_SHORT_GI;
			rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
		break;
	case MT_PHY_TYPE_HE_SU:
	case MT_PHY_TYPE_HE_EXT_SU:
	case MT_PHY_TYPE_HE_TB:
	case MT_PHY_TYPE_HE_MU:
		if (ra->gi > NL80211_RATE_INFO_HE_GI_3_2 || rate->mcs > 11)
			return -EINVAL;

		rate->he_gi = ra->gi;
		rate->he_dcm = FIELD_GET(MT_RA_RATE_DCM_EN, r);

		flags |= RATE_INFO_FLAGS_HE_MCS;
		rate->flags = RATE_INFO_FLAGS_HE_MCS;
		break;
	default:
		break;
		return -EINVAL;
	}
	rate->flags = flags;

	if (ru_idx) {
		switch (ru_idx) {
@@ -502,6 +510,8 @@ mt7915_mcu_tx_rate_parse(struct mt76_phy *mphy, struct mt7915_mcu_ra_info *ra,
			break;
		}
	}

	return 0;
}

static void
@@ -532,11 +542,11 @@ mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb)
		mphy = dev->mt76.phy2;

	/* current rate */
	mt7915_mcu_tx_rate_parse(mphy, ra, &rate, curr);
	if (!mt7915_mcu_tx_rate_parse(mphy, ra, &rate, curr))
		stats->tx_rate = rate;

	/* probing rate */
	mt7915_mcu_tx_rate_parse(mphy, ra, &prob_rate, probe);
	if (!mt7915_mcu_tx_rate_parse(mphy, ra, &prob_rate, probe))
		stats->prob_rate = prob_rate;

	if (attempts) {