Skip to content

command: fix wifiscan scanning every channel on each trigger - #129

Open
firasshaari wants to merge 1 commit into
Telecominfraproject:main-v4.2.0-LTSfrom
firasshaari:staging-WIFI-14822-wifiscan-single-channel-scan
Open

command: fix wifiscan scanning every channel on each trigger#129
firasshaari wants to merge 1 commit into
Telecominfraproject:main-v4.2.0-LTSfrom
firasshaari:staging-WIFI-14822-wifiscan-single-channel-scan

Conversation

@firasshaari

Copy link
Copy Markdown
Contributor

Fixes: WIFI-14822

Root Cause:

scan_trigger() described a single-channel scan with wiphy_freq, but NL80211_CMD_TRIGGER_SCAN does not consume NL80211_ATTR_WIPHY_FREQ — that attribute configures an operating channel, it is not a scan parameter. Netlink silently ignores attributes a command does not use, so the request was accepted and the scan succeeded, while the kernel, finding no scan_frequencies, fell back to scanning every supported channel.

trigger_scan_width() therefore triggered a full-band sweep on each of its iterations instead of visiting one channel. On a 5 GHz radio at 80 MHz that is 6 iterations × 28 channels = 168 channel visits, chained with no return to the operating channel. That is the ~23 s outage reported in the ticket.

Measured directly on the device:

wiphy_freq: 5180            -> kernel scanned 28 channel(s)
scan_frequencies: [ 5180 ]  -> kernel scanned  1 channel(s)

This also explains two earlier findings on the ticket that did not add up: toggling active/passive made no difference (the problem is structural, not scan type), and the mac80211 dwell reduction helped without resolving it (it shrinks per-channel cost, not the six-fold multiplication).

Solution:

Four changes, all in command/cmd_wifiscan.uc:

  1. Pass scan_frequencies so a single-channel scan really is one channel.
  2. Use the full 5 GHz frequency list. The width-keyed list is only six channels at 80 MHz; full coverage was previously obtained by accident, as a side effect of the bug.
  3. Dwell on the operating channel between visits. Without this the loop fires the next scan immediately, and 28 chained single-channel scans are indistinguishable from one 28-channel sweep — the outage and the deassociation both return.
  4. Collect results after each channel and merge by BSSID. The kernel expires cached BSSes after roughly 30 s while a full sweep takes longer, so a single GET_SCAN after the sweep dropped whichever channels were scanned first.

Items 3 and 4 are both required; each was verified to be load-bearing by testing without it.

Testing:

YunCore AX820, client associated on 5 GHz running continuous traffic, metrics.wifi-scan enabled.

client impact 5 GHz coverage
before 23 s outage per scan, STA deassociates full (side effect of the bug)
after max 50 ms inactivity, no disassociation all 17 frequencies that have neighbours

Verified end to end on the OWGW Kafka wifiscan topic rather than only on the device: the report reaching the controller carries 73 BSS entries — 24 × 2.4 GHz and 49 × 5 GHz across the same 17 frequencies an exhaustive manual scan finds. Net airtime is 28 channel visits per scan interval instead of 168.

Notes:

rrmd's scan() in scan.uc uses the identical wiphy_freq construct, so its per-tick background scan is also a full-band sweep. That needs the same correction and is tracked separately — it is out of scope for this repo.

This targets main-v4.2.0-LTS because that is where the fix was validated. main carries the same defect and needs the same change.

staging-WIFI-15235-fix-wifi-scan1 also touches this file (bandwidth key type, die() on trigger failure, HaLow phy skip). The changes here are disjoint from those, but the two will need ordering if both land.

Enabling metrics.wifi-scan takes the radio off its operating channel for
around 23 seconds on every scan interval, long enough that associated
clients deassociate.

scan_trigger() described a single channel scan with wiphy_freq, but
NL80211_CMD_TRIGGER_SCAN does not consume NL80211_ATTR_WIPHY_FREQ. That
attribute configures an operating channel, it is not a scan parameter.
Netlink silently ignores attributes a command does not use, so the request
was accepted and the scan succeeded, while the kernel, finding no
scan_frequencies, fell back to scanning every supported channel.
trigger_scan_width() therefore triggered a full band sweep on each of its
iterations instead of visiting one channel, six sweeps of 28 channels on a
5GHz radio operating at 80MHz.

Pass scan_frequencies so that a single channel scan really is one channel.
With that corrected the width keyed frequency list would only cover six
channels, so use the full list, and dwell on the operating channel between
visits so clients continue to be served while the sweep progresses.
Finally collect results after every channel and merge them by BSSID. The
kernel expires cached BSSes after roughly 30 seconds while a full sweep
takes longer than that, so a single GET_SCAN once the sweep finished
dropped the channels that had been scanned first.

Measured on a YunCore AX820 with a client running continuous traffic, the
worst observed client inactivity drops from a 23 second outage with
deassociation to 50ms, and the reported neighbour list gains the channels
that were previously missing.

Fixes: WIFI-14822
Signed-off-by: Firas Shaari <firas.shaari@shaariconsultancy.com>
@tanyasingh-ec tanyasingh-ec added this to the 4.2.7 milestone Aug 6, 2026
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.

2 participants