summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPaul Zhang <quic_paulz@quicinc.com>2022-10-11 15:04:28 +0200
committerJohannes Berg <johannes.berg@intel.com>2022-10-21 12:36:35 +0200
commit18429c51c7ff6e6bfd627316c54670230967a7e5 (patch)
tree4f323895f7c6f3857da652129623e7d11e0ddff2 /net
parentwifi: cfg80211: fix memory leak in query_regdb_file() (diff)
downloadlinux-18429c51c7ff6e6bfd627316c54670230967a7e5.tar.xz
linux-18429c51c7ff6e6bfd627316c54670230967a7e5.zip
wifi: cfg80211: Fix bitrates overflow issue
When invoking function cfg80211_calculate_bitrate_eht about (320 MHz, EHT-MCS 13, EHT-NSS 2, EHT-GI 0), which means the parameters as flags: 0x80, bw: 7, mcs: 13, eht_gi: 0, nss: 2, this formula (result * rate->nss) will overflow and causes the returned bitrate to be 3959 when it should be 57646. Here is the explanation: u64 tmp; u32 result; … /* tmp = result = 4 * rates_996[0] * = 4 * 480388888 = 0x72889c60 */ tmp = result; /* tmp = 0x72889c60 * 6144 = 0xabccea90000 */ tmp *= SCALE; /* tmp = 0xabccea90000 / mcs_divisors[13] * = 0xabccea90000 / 5120 = 0x8970bba6 */ do_div(tmp, mcs_divisors[rate->mcs]); /* result = 0x8970bba6 */ result = tmp; /* normally (result * rate->nss) = 0x8970bba6 * 2 = 0x112e1774c, * but since result is u32, (result * rate->nss) = 0x12e1774c, * overflow happens and it loses the highest bit. * Then result = 0x12e1774c / 8 = 39595753, */ result = (result * rate->nss) / 8; Signed-off-by: Paul Zhang <quic_paulz@quicinc.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/wireless/util.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 1f285b515028..39680e7bad45 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1557,10 +1557,12 @@ static u32 cfg80211_calculate_bitrate_eht(struct rate_info *rate)
tmp = result;
tmp *= SCALE;
do_div(tmp, mcs_divisors[rate->mcs]);
- result = tmp;
/* and take NSS */
- result = (result * rate->nss) / 8;
+ tmp *= rate->nss;
+ do_div(tmp, 8);
+
+ result = tmp;
return result / 10000;
}