From 175ad2ec89feb8c01f87be64882af67481b1b1f5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Jul 2022 18:08:03 +0200 Subject: [PATCH] wifi: mac80211: limit A-MSDU subframes for client too In AP/mesh where the stations are added by userspace, we limit the number of A-MSDU subframes according to the extended capabilities. Refactor the code and extend that also to client-side. Fixes: 506bcfa8abeb ("mac80211: limit the A-MSDU Tx based on peer's capabilities") Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 29 ++--------------------------- net/mac80211/mlme.c | 3 +++ net/mac80211/sta_info.c | 23 +++++++++++++++++++++++ net/mac80211/sta_info.h | 4 ++++ 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index bdc3d74eecc1..1545648e2031 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1776,33 +1776,8 @@ static int sta_apply_parameters(struct ieee80211_local *local, sta->sta.max_sp = params->max_sp; } - /* The sender might not have sent the last bit, consider it to be 0 */ - if (params->ext_capab_len >= 8) { - u8 val = (params->ext_capab[7] & - WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB) >> 7; - - /* we did get all the bits, take the MSB as well */ - if (params->ext_capab_len >= 9) { - u8 val_msb = params->ext_capab[8] & - WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB; - val_msb <<= 1; - val |= val_msb; - } - - switch (val) { - case 1: - sta->sta.max_amsdu_subframes = 32; - break; - case 2: - sta->sta.max_amsdu_subframes = 16; - break; - case 3: - sta->sta.max_amsdu_subframes = 8; - break; - default: - sta->sta.max_amsdu_subframes = 0; - } - } + ieee80211_sta_set_max_amsdu_subframes(sta, params->ext_capab, + params->ext_capab_len); /* * cfg80211 validates this (1-2007) and allows setting the AID diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 308a8fe50212..3263bb188284 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4488,6 +4488,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, sta->sta.mfp = false; } + ieee80211_sta_set_max_amsdu_subframes(sta, elems->ext_capab, + elems->ext_capab_len); + sta->sta.wme = (elems->wmm_param || elems->s1g_capab) && local->hw.queues >= IEEE80211_NUM_ACS; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f52a7fa6dde5..eed88630594f 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -2761,3 +2761,26 @@ void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id) sta_remove_link(sta, link_id, true); } + +void ieee80211_sta_set_max_amsdu_subframes(struct sta_info *sta, + const u8 *ext_capab, + unsigned int ext_capab_len) +{ + u8 val; + + sta->sta.max_amsdu_subframes = 0; + + if (ext_capab_len < 8) + return; + + /* The sender might not have sent the last bit, consider it to be 0 */ + val = u8_get_bits(ext_capab[7], WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB); + + /* we did get all the bits, take the MSB as well */ + if (ext_capab_len >= 9) + val |= u8_get_bits(ext_capab[8], + WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB) << 1; + + if (val) + sta->sta.max_amsdu_subframes = 4 << val; +} diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index ea0eeee808a5..6bc26a2c4607 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -910,6 +910,10 @@ void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta); unsigned long ieee80211_sta_last_active(struct sta_info *sta); +void ieee80211_sta_set_max_amsdu_subframes(struct sta_info *sta, + const u8 *ext_capab, + unsigned int ext_capab_len); + enum sta_stats_type { STA_STATS_RATE_TYPE_INVALID = 0, STA_STATS_RATE_TYPE_LEGACY,