From: Mark Anthony Agarro When a non-MLO station associates, mgd_complete_tx() aborts the join ROC as soon as the association succeeds, which is right before the supplicant sends message 2 of the 4-way handshake. With the abort that close to message 2, the adapter acknowledges nothing the AP sends for the next several ms: the AP sends message 3 and its seven retries within about 5 ms, none is acknowledged, and the handshake ends with reason 15 (4WAY_HANDSHAKE_TIMEOUT). Keep the ROC after a successful (re)association on a non-MLD station interface and release it when the station is authorized, on disassociation, or when the station is removed. The ROC timer still ends it if none of that happens. MLD interfaces keep the old behaviour: there the ROC that is active at this point is the MLO ROC set up by mt7925_mac_set_links(), and holding it makes mt7925_set_mlo_roc() fail with -EBUSY in the link activation work, which leaves one link instead of two. Tested by a reporter on an MT7925U (USB) against a FRITZ!Box 5690 Pro on a 6 GHz-only, non-MLO SSID, kernel 7.2.3, from traces and monitor captures taken in separate runs: handshakes first M3 acked abort before M2 unpatched 8 of 84 0 of 83 84 of 84 this patch 30 of 30 31 of 31 0 of 30 With the patch the AP sends message 3 once and the adapter acknowledges it straight away; the ROC is released right after the station is authorized. A 20 ms delay after the abort instead of this change gave 15 of 15, which points at the abort timing and not at the delay. Tested here on an MT7925 and an MT7927 (PCIe), kernel 7.3.0-rc4: on a non-MLO SSID neither build showed the failure (1 stalled handshake in 110 unpatched, none patched), so no effect could be measured there. On an MLO connection the change is inert: 16 of 16 link activations succeeded in two rounds per build, with two active links and the same ROC order as before. Not tested: other APs, other USB parts, MT7927 over USB, MLO connections beyond the check above. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Reported-by: Mark Junker Closes: https://github.com/morrownr/mt76/issues/106 Tested-by: Mark Junker Signed-off-by: Mark Anthony Agarro Signed-off-by: Devin Wittmayer --- This goes on top of the mt7921 version, which adds the flag both use: https://lore.kernel.org/linux-wireless/20261005203846.239445-1-lucid_duck@justthetip.ca/ .../net/wireless/mediatek/mt76/mt7925/main.c | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 5993b31e1aae..6b0a09e2f6cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1243,6 +1243,13 @@ int mt7925_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct ieee80211_link_sta *link_sta = &sta->deflink; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + + if (mvif->roc_join_held && !sta->tdls && + (ev == MT76_STA_EVENT_AUTHORIZE || ev == MT76_STA_EVENT_DISASSOC)) { + mvif->roc_join_held = false; + mt7925_abort_roc(mvif->phy, &mvif->bss_conf); + } switch (ev) { case MT76_STA_EVENT_ASSOC: @@ -1438,6 +1445,7 @@ void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (vif->type == NL80211_IFTYPE_STATION) { mvif->wep_sta = NULL; + mvif->roc_join_held = false; ewma_rssi_init(&mvif->bss_conf.rssi); } @@ -2089,6 +2097,25 @@ static void mt7925_mgd_complete_tx(struct ieee80211_hw *hw, { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + /* The AP starts the 4-way handshake as soon as the association + * succeeds. Releasing the join ROC at this point makes the firmware + * unresponsive for several ms right when message 3 arrives, so it + * can be lost and the handshake times out. Keep the ROC until the + * station is authorized; mt7925_mac_sta_event() releases it. If that + * never happens, the ROC timer or the station removal does. + * + * Not for MLO: there the ROC active here is the MLO ROC set up by + * mt7925_mac_set_links(), which has to be released before the link + * activation work sets its own. + */ + if (vif->type == NL80211_IFTYPE_STATION && !ieee80211_vif_is_mld(vif) && + info->success && + (info->subtype == IEEE80211_STYPE_ASSOC_REQ || + info->subtype == IEEE80211_STYPE_REASSOC_REQ)) { + mvif->roc_join_held = true; + return; + } + mt7925_abort_roc(mvif->phy, &mvif->bss_conf); } -- 2.55.0