Skip to content

wifi: mt7932: hear radar-channel APs before joining, forget APs leaving - #319

Draft
maralcbr wants to merge 1 commit into
integration/aurorafrom
mt7932-radar-followups
Draft

maralcbr wants to merge 1 commit into
integration/aurorafrom
mt7932-radar-followups

Conversation

@maralcbr

Copy link
Copy Markdown
Member

Problem

Follow-up to #318, which lets the MT7932 join APs on radar (DFS) channels and leave when they announce a channel switch. Review found two gaps.

A stale BSS was enough to transmit on a radar channel. mt_connect_prepare() checks only channel flags. connect_bss comes from cfg80211_get_bss(), which returns entries up to 30 s old, and this driver informs beacons without a receive time, so ts_boottime is always 0. An AP that left the channel because of radar can still be in the table, and the station would send authentication to it there. A station without radar detection should transmit on a radar channel only after it has heard the AP. Whether the firmware waits for a beacon itself is unknown.

After a switch announcement, iwd rejoins the AP on the old channel, then avoids it. The same CSA beacon that triggers the local disconnect is then passed to cfg80211_inform_bss_frame(), which refreshes the entry on the old channel. iwd reconnects to it, the next CSA beacon fails the join with -ECONNRESET, and iwd blacklists the BSSID. The BSSID doesn't change when the AP moves, so iwd won't follow it to the new channel until the blacklist expires. It falls back to 2.4 GHz, where the mesh band-steers it again: the problem #318 set out to fix.

Change

  • Beacons carry their receive time. mt_packet_receive() informs through cfg80211_inform_bss_frame_data() with boottime_ns, so ts_boottime and nl80211's BSS_LAST_SEEN_BOOTTIME are real for every BSS, not only for radar channels.
  • A radar or no-IR candidate must be heard during this attempt. mt_connect() and mt_connect_discover() set connect_heard_since when the attempt starts listening. mt_connect_find_bss() returns a radar or no-IR entry only if it was seen after that (mt7932_bss_heard()). Otherwise the connect worker runs its existing passive discovery. When userspace names the channel, as iwd does, that is a single dwell of about 220 ms on that channel. The worst-case age at submission is the length of the discovery pass, not 30 s.
  • An AP leaving a radar channel is forgotten there. A beacon on a radar channel carrying a complete CSA or ECSA is no longer informed, and that BSSID's entry on the channel is unlinked. This happens after response_lock is released, because cfg80211_unlink_bss() takes bss_lock with spin_lock_bh. The disconnect and abandon-join paths from wifi: mt7932: join APs on radar channels, leave on their switch announcement #318 are unchanged.
  • One local disconnect sequence. The block wifi: mt7932: join APs on radar channels, leave on their switch announcement #318 copied from mt_disconnect() moves to mt_disconnect_local_locked(), used by both.
  • Testable announcement check. The CSA/ECSA check moves to packet.h as mt7932_rx_switch_announced(), so KUnit can call it. The radar-flag check stays in frontend.c.

Not changed: iwd still blacklists the BSSID if it tries to join during the countdown, before the entry is unlinked. Following the AP to its new channel (cfg80211_ch_switch_notify()) would need firmware CSA support that isn't established.

Testing

  • Compiled for arm64 against integration/aurora at 1630ee1 with LLVM 18 and W=1 (defconfig + asahi.config, with MT7932 and its KUnit tests enabled): no warnings in the driver.
  • KUnit, kunit.py run --arch=arm64 in QEMU (-cpu neoverse-n1, 16K pages), mt7932* suites: 47/47 passed, including the new mt7932_rx_switch_announced_test (complete and truncated CSA/ECSA, no elements, CSA after another element) and mt_bss_heard_test.
  • Not tested on hardware. Things to check on a J700:
    • Joining the channel 52 BSS still works and logs CONNECT_DISCOVERY: refreshing missing scan candidate before CONNECT_SUBMITTED.
    • The added passive dwell doesn't noticeably slow the join.
    • RADAR_CHANNEL_SWITCH and the unlink haven't run on air; that needs an AP that can be made to switch away from a DFS channel.

Follow-up to the radar channel support.

A radar or no-IR candidate now has to have been heard during the
current connect attempt. cfg80211 keeps a BSS for 30 s, and the driver
did not stamp entries with a receive time, so a cached entry for an AP
that had already left the channel for radar was enough to send
authentication there. Beacons are now informed with their boot time,
and mt_connect_find_bss() returns a radar or no-IR entry only if it was
seen after the attempt started listening; otherwise the connect worker
runs its passive discovery for it, a single dwell when userspace names
the channel.

A beacon announcing a switch away from a radar channel is no longer
informed, and the AP's entry on that channel is unlinked. Before, the
same beacon refreshed the entry right after the driver left, so iwd
rejoined the AP on the old channel, failed, and then avoided its BSSID
even once it was heard on the new channel.

The local disconnect sequence shared by .disconnect and the switch
announcement moves to mt_disconnect_local_locked(). The announcement
check moves to packet.h as mt7932_rx_switch_announced() so KUnit can
cover it, along with the freshness rule.

Signed-off-by: Marcelo Alcantara <maralc@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant