When operating two TP-Link EAP225 Outdoor v3 devices with OpenWrt [1] in an 802.11s 5 GHz mesh (ath10k), I observed that the MCS does not recover correctly after a link temporarily goes out of signal range and then returns to good signal conditions. Instead, the low MCS selected when the link goes out of signal range is retained even after signal quality improves significantly. Only after a long delay (around 5 minutes) does the rate control recover and select an appropriate higher MCS again. I was able to reproduce this behavior reliably using a controlled test setup with two mesh nodes connected through adjustable RF attenuators (some details in [2]). In my measurements, the link commonly gets stuck at MCS 2 (45 Mbit/s), resulting in a throughput of roughly 35 Mbit/s despite great signal conditions. I experimented with various 802.11s and ath10k configuration parameters, but none resolved the issue. To address this, the proposed patch triggers a rate control initialization/update every time mesh_sta_info_init() is invoked, even if a beacon has already been processed. With this change, the MCS is updated correctly when signal conditions improve, and the observed issue is resolved in my setup (not posted in [2] for now). As I do not know if this is the right approach to solve this issue, I am submitting this patch as an RFC. Thanks :) Simon [1] Link: https://openwrt.org/toh/tp-link/eap225 [2] Link: https://forum.openwrt.org/t/802-11s-batman-5ghz-mesh-stuck-at-mcs-2-after-getting-into-range-again/243461 Signed-off-by: Simon Schippers --- net/mac80211/mesh_plink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 04c931cd2063..66d735e18461 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -425,68 +425,69 @@ u64 mesh_plink_deactivate(struct sta_info *sta) static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee802_11_elems *elems) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; u32 rates, changed = 0; enum ieee80211_sta_rx_bandwidth bw = sta->sta.deflink.bandwidth; sband = ieee80211_get_sband(sdata); if (!sband) return; rates = ieee80211_sta_get_rates(sdata, elems, sband->band, NULL); spin_lock_bh(&sta->mesh->plink_lock); sta->deflink.rx_stats.last_rx = jiffies; /* rates and capabilities don't change during peering */ if (sta->mesh->plink_state == NL80211_PLINK_ESTAB && sta->mesh->processed_beacon) goto out; sta->mesh->processed_beacon = true; if (sta->sta.deflink.supp_rates[sband->band] != rates) changed |= IEEE80211_RC_SUPP_RATES_CHANGED; sta->sta.deflink.supp_rates[sband->band] = rates; if (ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, elems->ht_cap_elem, &sta->deflink)) changed |= IEEE80211_RC_BW_CHANGED; ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, elems->vht_cap_elem, NULL, &sta->deflink); ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, elems->he_cap, elems->he_cap_len, elems->he_6ghz_capa, &sta->deflink); ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband, elems->he_cap, elems->he_cap_len, elems->eht_cap, elems->eht_cap_len, &sta->deflink); if (bw != sta->sta.deflink.bandwidth) changed |= IEEE80211_RC_BW_CHANGED; /* HT peer is operating 20MHz-only */ if (elems->ht_operation && !(elems->ht_operation->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { if (sta->sta.deflink.bandwidth != IEEE80211_STA_RX_BW_20) changed |= IEEE80211_RC_BW_CHANGED; sta->sta.deflink.bandwidth = IEEE80211_STA_RX_BW_20; } +out: /* FIXME: this check is wrong without SW rate control */ if (!test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) rate_control_rate_init(&sta->deflink); else rate_control_rate_update(local, sband, &sta->deflink, changed); -out: + spin_unlock_bh(&sta->mesh->plink_lock); } -- 2.43.0