lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20260106095346.706635-1-simon.schippers@tu-dortmund.de>
Date: Tue,  6 Jan 2026 10:53:46 +0100
From: Simon Schippers <simon.schippers@...dortmund.de>
To: johannes@...solutions.net, linux-wireless@...r.kernel.org,
        linux-kernel@...r.kernel.org
Cc: Simon Schippers <simon.schippers@...dortmund.de>
Subject: [PATCH RFC] wifi: mac80211: Update mesh rate control per beacon to restore correct MCS

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 <simon.schippers@...dortmund.de>
---
 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


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ