diff options
author | David S. Miller <davem@davemloft.net> | 2020-08-28 15:16:48 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-08-28 15:16:48 +0200 |
commit | 51458c97058deaec49f9d42028450e7a404c0653 (patch) | |
tree | 7f3e72843b6e1f3cbf584d7d4593572007db908c /net | |
parent | rxrpc: Fix memory leak in rxkad_verify_response() (diff) | |
parent | cfg80211: Adjust 6 GHz frequency to channel conversion (diff) | |
download | linux-51458c97058deaec49f9d42028450e7a404c0653.tar.xz linux-51458c97058deaec49f9d42028450e7a404c0653.zip |
Merge tag 'mac80211-for-davem-2020-08-28' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211
Johannes Berg says:
====================
We have:
* fixes for AQL (airtime queue limits)
* reduce packet loss detection false positives
* a small channel number fix for the 6 GHz band
* a fix for 80+80/160 MHz negotiation
* an nl80211 attribute (NL80211_ATTR_HE_6GHZ_CAPABILITY) fix
* add a missing sanity check for the regulatory code
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/airtime.c | 202 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 5 | ||||
-rw-r--r-- | net/mac80211/status.c | 43 | ||||
-rw-r--r-- | net/wireless/chan.c | 15 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 2 | ||||
-rw-r--r-- | net/wireless/reg.c | 3 | ||||
-rw-r--r-- | net/wireless/util.c | 8 |
7 files changed, 192 insertions, 86 deletions
diff --git a/net/mac80211/airtime.c b/net/mac80211/airtime.c index 366f76c9003d..314973033d03 100644 --- a/net/mac80211/airtime.c +++ b/net/mac80211/airtime.c @@ -405,18 +405,14 @@ ieee80211_calc_legacy_rate_duration(u16 bitrate, bool short_pre, return duration; } -u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw, - struct ieee80211_rx_status *status, - int len) +static u32 ieee80211_get_rate_duration(struct ieee80211_hw *hw, + struct ieee80211_rx_status *status, + u32 *overhead) { - struct ieee80211_supported_band *sband; - const struct ieee80211_rate *rate; bool sgi = status->enc_flags & RX_ENC_FLAG_SHORT_GI; - bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE; int bw, streams; int group, idx; u32 duration; - bool cck; switch (status->bw) { case RATE_INFO_BW_20: @@ -437,20 +433,6 @@ u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw, } switch (status->encoding) { - case RX_ENC_LEGACY: - if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ)) - return 0; - - sband = hw->wiphy->bands[status->band]; - if (!sband || status->rate_idx >= sband->n_bitrates) - return 0; - - rate = &sband->bitrates[status->rate_idx]; - cck = rate->flags & IEEE80211_RATE_MANDATORY_B; - - return ieee80211_calc_legacy_rate_duration(rate->bitrate, sp, - cck, len); - case RX_ENC_VHT: streams = status->nss; idx = status->rate_idx; @@ -477,51 +459,144 @@ u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw, duration = airtime_mcs_groups[group].duration[idx]; duration <<= airtime_mcs_groups[group].shift; + *overhead = 36 + (streams << 2); + + return duration; +} + + +u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw, + struct ieee80211_rx_status *status, + int len) +{ + struct ieee80211_supported_band *sband; + u32 duration, overhead = 0; + + if (status->encoding == RX_ENC_LEGACY) { + const struct ieee80211_rate *rate; + bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE; + bool cck; + + if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ)) + return 0; + + sband = hw->wiphy->bands[status->band]; + if (!sband || status->rate_idx >= sband->n_bitrates) + return 0; + + rate = &sband->bitrates[status->rate_idx]; + cck = rate->flags & IEEE80211_RATE_MANDATORY_B; + + return ieee80211_calc_legacy_rate_duration(rate->bitrate, sp, + cck, len); + } + + duration = ieee80211_get_rate_duration(hw, status, &overhead); + if (!duration) + return 0; + duration *= len; duration /= AVG_PKT_SIZE; duration /= 1024; - duration += 36 + (streams << 2); - - return duration; + return duration + overhead; } EXPORT_SYMBOL_GPL(ieee80211_calc_rx_airtime); -static u32 ieee80211_calc_tx_airtime_rate(struct ieee80211_hw *hw, - struct ieee80211_tx_rate *rate, - u8 band, int len) +static bool ieee80211_fill_rate_info(struct ieee80211_hw *hw, + struct ieee80211_rx_status *stat, u8 band, + struct rate_info *ri) { - struct ieee80211_rx_status stat = { - .band = band, - }; + struct ieee80211_supported_band *sband = hw->wiphy->bands[band]; + int i; - if (rate->idx < 0 || !rate->count) + if (!ri || !sband) + return false; + + stat->bw = ri->bw; + stat->nss = ri->nss; + stat->rate_idx = ri->mcs; + + if (ri->flags & RATE_INFO_FLAGS_HE_MCS) + stat->encoding = RX_ENC_HE; + else if (ri->flags & RATE_INFO_FLAGS_VHT_MCS) + stat->encoding = RX_ENC_VHT; + else if (ri->flags & RATE_INFO_FLAGS_MCS) + stat->encoding = RX_ENC_HT; + else + stat->encoding = RX_ENC_LEGACY; + + if (ri->flags & RATE_INFO_FLAGS_SHORT_GI) + stat->enc_flags |= RX_ENC_FLAG_SHORT_GI; + + stat->he_gi = ri->he_gi; + + if (stat->encoding != RX_ENC_LEGACY) + return true; + + stat->rate_idx = 0; + for (i = 0; i < sband->n_bitrates; i++) { + if (ri->legacy != sband->bitrates[i].bitrate) + continue; + + stat->rate_idx = i; + return true; + } + + return false; +} + +static int ieee80211_fill_rx_status(struct ieee80211_rx_status *stat, + struct ieee80211_hw *hw, + struct ieee80211_tx_rate *rate, + struct rate_info *ri, u8 band, int len) +{ + memset(stat, 0, sizeof(*stat)); + stat->band = band; + + if (ieee80211_fill_rate_info(hw, stat, band, ri)) return 0; + if (rate->idx < 0 || !rate->count) + return -1; + if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) - stat.bw = RATE_INFO_BW_80; + stat->bw = RATE_INFO_BW_80; else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - stat.bw = RATE_INFO_BW_40; + stat->bw = RATE_INFO_BW_40; else - stat.bw = RATE_INFO_BW_20; + stat->bw = RATE_INFO_BW_20; - stat.enc_flags = 0; + stat->enc_flags = 0; if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - stat.enc_flags |= RX_ENC_FLAG_SHORTPRE; + stat->enc_flags |= RX_ENC_FLAG_SHORTPRE; if (rate->flags & IEEE80211_TX_RC_SHORT_GI) - stat.enc_flags |= RX_ENC_FLAG_SHORT_GI; + stat->enc_flags |= RX_ENC_FLAG_SHORT_GI; - stat.rate_idx = rate->idx; + stat->rate_idx = rate->idx; if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { - stat.encoding = RX_ENC_VHT; - stat.rate_idx = ieee80211_rate_get_vht_mcs(rate); - stat.nss = ieee80211_rate_get_vht_nss(rate); + stat->encoding = RX_ENC_VHT; + stat->rate_idx = ieee80211_rate_get_vht_mcs(rate); + stat->nss = ieee80211_rate_get_vht_nss(rate); } else if (rate->flags & IEEE80211_TX_RC_MCS) { - stat.encoding = RX_ENC_HT; + stat->encoding = RX_ENC_HT; } else { - stat.encoding = RX_ENC_LEGACY; + stat->encoding = RX_ENC_LEGACY; } + return 0; +} + +static u32 ieee80211_calc_tx_airtime_rate(struct ieee80211_hw *hw, + struct ieee80211_tx_rate *rate, + struct rate_info *ri, + u8 band, int len) +{ + struct ieee80211_rx_status stat; + + if (ieee80211_fill_rx_status(&stat, hw, rate, ri, band, len)) + return 0; + return ieee80211_calc_rx_airtime(hw, &stat, len); } @@ -536,7 +611,7 @@ u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw, struct ieee80211_tx_rate *rate = &info->status.rates[i]; u32 cur_duration; - cur_duration = ieee80211_calc_tx_airtime_rate(hw, rate, + cur_duration = ieee80211_calc_tx_airtime_rate(hw, rate, NULL, info->band, len); if (!cur_duration) break; @@ -572,26 +647,41 @@ u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw, if (pubsta) { struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + struct ieee80211_rx_status stat; struct ieee80211_tx_rate *rate = &sta->tx_stats.last_rate; - u32 airtime; + struct rate_info *ri = &sta->tx_stats.last_rate_info; + u32 duration, overhead; + u8 agg_shift; - if (!(rate->flags & (IEEE80211_TX_RC_VHT_MCS | - IEEE80211_TX_RC_MCS))) - ampdu = false; + if (ieee80211_fill_rx_status(&stat, hw, rate, ri, band, len)) + return 0; + if (stat.encoding == RX_ENC_LEGACY || !ampdu) + return ieee80211_calc_rx_airtime(hw, &stat, len); + + duration = ieee80211_get_rate_duration(hw, &stat, &overhead); /* * Assume that HT/VHT transmission on any AC except VO will * use aggregation. Since we don't have reliable reporting - * of aggregation length, assume an average of 16. + * of aggregation length, assume an average size based on the + * tx rate. * This will not be very accurate, but much better than simply - * assuming un-aggregated tx. + * assuming un-aggregated tx in all cases. */ - airtime = ieee80211_calc_tx_airtime_rate(hw, rate, band, - ampdu ? len * 16 : len); - if (ampdu) - airtime /= 16; - - return airtime; + if (duration > 400) /* <= VHT20 MCS2 1S */ + agg_shift = 1; + else if (duration > 250) /* <= VHT20 MCS3 1S or MCS1 2S */ + agg_shift = 2; + else if (duration > 150) /* <= VHT20 MCS5 1S or MCS3 2S */ + agg_shift = 3; + else + agg_shift = 4; + + duration *= len; + duration /= AVG_PKT_SIZE; + duration /= 1024; + + return duration + (overhead >> agg_shift); } if (!conf) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 9d398c9daa4c..d5010116cf4d 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -524,7 +524,7 @@ struct ieee80211_sta_rx_stats { * @status_stats.retry_failed: # of frames that failed after retry * @status_stats.retry_count: # of retries attempted * @status_stats.lost_packets: # of lost packets - * @status_stats.last_tdls_pkt_time: timestamp of last TDLS packet + * @status_stats.last_pkt_time: timestamp of last ACKed packet * @status_stats.msdu_retries: # of MSDU retries * @status_stats.msdu_failed: # of failed MSDUs * @status_stats.last_ack: last ack timestamp (jiffies) @@ -597,7 +597,7 @@ struct sta_info { unsigned long filtered; unsigned long retry_failed, retry_count; unsigned int lost_packets; - unsigned long last_tdls_pkt_time; + unsigned long last_pkt_time; u64 msdu_retries[IEEE80211_NUM_TIDS + 1]; u64 msdu_failed[IEEE80211_NUM_TIDS + 1]; unsigned long last_ack; @@ -611,6 +611,7 @@ struct sta_info { u64 packets[IEEE80211_NUM_ACS]; u64 bytes[IEEE80211_NUM_ACS]; struct ieee80211_tx_rate last_rate; + struct rate_info last_rate_info; u64 msdu[IEEE80211_NUM_TIDS + 1]; } tx_stats; u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; diff --git a/net/mac80211/status.c b/net/mac80211/status.c index adb1d30ce06e..0794396a7988 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -755,12 +755,16 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, * - current throughput (higher value for higher tpt)? */ #define STA_LOST_PKT_THRESHOLD 50 +#define STA_LOST_PKT_TIME HZ /* 1 sec since last ACK */ #define STA_LOST_TDLS_PKT_THRESHOLD 10 #define STA_LOST_TDLS_PKT_TIME (10*HZ) /* 10secs since last ACK */ static void ieee80211_lost_packet(struct sta_info *sta, struct ieee80211_tx_info *info) { + unsigned long pkt_time = STA_LOST_PKT_TIME; + unsigned int pkt_thr = STA_LOST_PKT_THRESHOLD; + /* If driver relies on its own algorithm for station kickout, skip * mac80211 packet loss mechanism. */ @@ -773,21 +777,20 @@ static void ieee80211_lost_packet(struct sta_info *sta, return; sta->status_stats.lost_packets++; - if (!sta->sta.tdls && - sta->status_stats.lost_packets < STA_LOST_PKT_THRESHOLD) - return; + if (sta->sta.tdls) { + pkt_time = STA_LOST_TDLS_PKT_TIME; + pkt_thr = STA_LOST_PKT_THRESHOLD; + } /* * If we're in TDLS mode, make sure that all STA_LOST_TDLS_PKT_THRESHOLD * of the last packets were lost, and that no ACK was received in the * last STA_LOST_TDLS_PKT_TIME ms, before triggering the CQM packet-loss * mechanism. + * For non-TDLS, use STA_LOST_PKT_THRESHOLD and STA_LOST_PKT_TIME */ - if (sta->sta.tdls && - (sta->status_stats.lost_packets < STA_LOST_TDLS_PKT_THRESHOLD || - time_before(jiffies, - sta->status_stats.last_tdls_pkt_time + - STA_LOST_TDLS_PKT_TIME))) + if (sta->status_stats.lost_packets < pkt_thr || + !time_after(jiffies, sta->status_stats.last_pkt_time + pkt_time)) return; cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr, @@ -1033,9 +1036,7 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw, sta->status_stats.lost_packets = 0; /* Track when last TDLS packet was ACKed */ - if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) - sta->status_stats.last_tdls_pkt_time = - jiffies; + sta->status_stats.last_pkt_time = jiffies; } else if (noack_success) { /* nothing to do here, do not account as lost */ } else { @@ -1137,9 +1138,17 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw, struct ieee80211_tx_info *info = status->info; struct ieee80211_sta *pubsta = status->sta; struct ieee80211_supported_band *sband; + struct sta_info *sta; int retry_count; bool acked, noack_success; + if (pubsta) { + sta = container_of(pubsta, struct sta_info, sta); + + if (status->rate) + sta->tx_stats.last_rate_info = *status->rate; + } + if (status->skb) return __ieee80211_tx_status(hw, status); @@ -1154,10 +1163,6 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw, noack_success = !!(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED); if (pubsta) { - struct sta_info *sta; - - sta = container_of(pubsta, struct sta_info, sta); - if (!acked && !noack_success) sta->status_stats.retry_failed++; sta->status_stats.retry_count += retry_count; @@ -1168,9 +1173,8 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw, if (sta->status_stats.lost_packets) sta->status_stats.lost_packets = 0; - /* Track when last TDLS packet was ACKed */ - if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) - sta->status_stats.last_tdls_pkt_time = jiffies; + /* Track when last packet was ACKed */ + sta->status_stats.last_pkt_time = jiffies; } else if (test_sta_flag(sta, WLAN_STA_PS_STA)) { return; } else if (noack_success) { @@ -1259,8 +1263,7 @@ void ieee80211_tx_status_8023(struct ieee80211_hw *hw, if (sta->status_stats.lost_packets) sta->status_stats.lost_packets = 0; - if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) - sta->status_stats.last_tdls_pkt_time = jiffies; + sta->status_stats.last_pkt_time = jiffies; } else { ieee80211_lost_packet(sta, info); } diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 90f0f82cd9ca..edee3a645c06 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -10,6 +10,7 @@ */ #include <linux/export.h> +#include <linux/bitfield.h> #include <net/cfg80211.h> #include "core.h" #include "rdev-ops.h" @@ -912,6 +913,7 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, struct ieee80211_sta_vht_cap *vht_cap; struct ieee80211_edmg *edmg_cap; u32 width, control_freq, cap; + bool support_80_80 = false; if (WARN_ON(!cfg80211_chandef_valid(chandef))) return false; @@ -979,9 +981,13 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, return false; break; case NL80211_CHAN_WIDTH_80P80: - cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; - if (chandef->chan->band != NL80211_BAND_6GHZ && - cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) + cap = vht_cap->cap; + support_80_80 = + (cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) || + (cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ && + cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) || + u32_get_bits(cap, IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) > 1; + if (chandef->chan->band != NL80211_BAND_6GHZ && !support_80_80) return false; /* fall through */ case NL80211_CHAN_WIDTH_80: @@ -1001,7 +1007,8 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, return false; cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ && - cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) + cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ && + !(vht_cap->cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK)) return false; break; default: diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c04fc6cf6583..19dc0ee807f6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6011,7 +6011,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]) params.he_6ghz_capa = - nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]); + nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]); if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]) params.airtime_weight = diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 35b8847a2f6d..d8a90d397423 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2946,6 +2946,9 @@ int regulatory_hint_user(const char *alpha2, if (WARN_ON(!alpha2)) return -EINVAL; + if (!is_world_regdom(alpha2) && !is_an_alpha2(alpha2)) + return -EINVAL; + request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); if (!request) return -ENOMEM; diff --git a/net/wireless/util.c b/net/wireless/util.c index dfad1c0f57ad..c62eb3d9ab3d 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -123,11 +123,13 @@ int ieee80211_freq_khz_to_channel(u32 freq) return (freq - 2407) / 5; else if (freq >= 4910 && freq <= 4980) return (freq - 4000) / 5; - else if (freq < 5945) + else if (freq < 5925) return (freq - 5000) / 5; + else if (freq == 5935) + return 2; else if (freq <= 45000) /* DMG band lower limit */ - /* see 802.11ax D4.1 27.3.22.2 */ - return (freq - 5940) / 5; + /* see 802.11ax D6.1 27.3.22.2 */ + return (freq - 5950) / 5; else if (freq >= 58320 && freq <= 70200) return (freq - 56160) / 2160; else |