IEEE80211_SCAN(9)

πŸ’« ieee80211_scan β€” 802.11 scanning support πŸ’«

okay bestie, welcome to the net80211 scanning page πŸ’– this is a section 9 kernel developer's manual, so it's for people writing drivers and net80211 code, but honestly? the vibes are immaculate and you're gonna get it.


🌸 SYNOPSIS 🌸

#include <net80211/ieee80211_var.h>

int
ieee80211_start_scan(struct ieee80211vap *, int flags, u_int duration,
    u_int mindwell, u_int maxdwell, u_int nssid,
    const struct ieee80211_scan_ssid ssids[]);

int
ieee80211_check_scan(struct ieee80211vap *, int flags, u_int duration,
    u_int mindwell, u_int maxdwell, u_int nssid,
    const struct ieee80211_scan_ssid ssids[]);

int
ieee80211_check_scan_current(struct ieee80211vap *);

int
ieee80211_bg_scan(struct ieee80211vap *, int);

int
ieee80211_cancel_scan(struct ieee80211vap *);

int
ieee80211_cancel_scan_any(struct ieee80211vap *);

int
ieee80211_scan_next(struct ieee80211vap *);

int
ieee80211_scan_done(struct ieee80211vap *);

int
ieee80211_probe_curchan(struct ieee80211vap *, int);

void
ieee80211_add_scan(struct ieee80211vap *,
    const struct ieee80211_scanparams *, const struct ieee80211_frame *,
    int subtype, int rssi, int noise);

void
ieee80211_scan_timeout(struct ieee80211com *);

void
ieee80211_scan_assoc_fail(struct ieee80211vap *,
    const uint8_t mac[IEEE80211_ADDR_LEN], int reason);

void
ieee80211_scan_flush(struct ieee80211vap *);

void
ieee80211_scan_iterate(struct ieee80211vap *, ieee80211_scan_iter_func,
    void *);

void
ieee80211_scan_dump_channels(const struct ieee80211_scan_state *);

void
ieee80211_scanner_register(enum ieee80211_opmode,
    const struct ieee80211_scanner *);

void
ieee80211_scanner_unregister(enum ieee80211_opmode,
    const struct ieee80211_scanner *);

void
ieee80211_scanner_unregister_all(const struct ieee80211_scanner *);

const struct ieee80211_scanner *
ieee80211_scanner_get(enum ieee80211_opmode);

πŸ¦‹ DESCRIPTION πŸ¦‹

so the net80211 software layer gives you an extensible framework for scanning. and what even is scanning? it's the whole procedure a station uses to find a BSS to join (in infrastructure and IBSS mode), or to find a channel to use (when you're running as an AP or an IBSS master). 🫢

scans come in two flavors, and you gotta know the difference:

  • β€œactive” β€” an active scan sends one or more ProbeRequest frames every time it visits a channel.
  • β€œpassive” β€” a passive request visits each channel in the scan set but transmits zero frames; the station just listens for traffic. πŸ‘‚
heads up though: active scanning may still need to listen for traffic before sending ProbeRequest frames, depending on regulatory constraints. it's giving "read the room first" energy.

A scan operation is a whole little journey: construct a set of channels to inspect (that's the scan set), visit each channel and collect info (like, what BSS are even present here), then analyze the results to make decisions like which BSS to join. And the way this needs to be as fast as possible means net80211 does cute little optimizations like intelligently constructing scan sets and dwelling on a channel only as long as necessary. Scan results get cached, and the scan cache is used to avoid scanning when possible and to enable roaming between access points when you're in infrastructure mode. ✨

Scanning is handled by pluggable modules that implement policy per-operating mode. The core scanning support provides an infrastructure to support these modules and exports a common API to the rest of the net80211 layer. And what do the policy modules decide? Everything, honestly: what channels to visit, what state to record to make decisions, and which final station/channel to return as the result of a scan. πŸ‘‘

Scanning is done synchronously when initially bringing a vap to an operational state, and optionally in the background to maintain the scan cache for doing roaming and rogue AP monitoring. Scanning is not tied to the net80211 state machine that governs vaps, except for linkage to the IEEE80211_S_SCAN state. And here's the tea: only one vap at a time may be scanning. This scheduling policy is handled in ieee80211_new_state() and is transparent to scanning code.

Scanning is controlled by a set of parameters that (potentially) constrains the channel set and any desired SSID's and BSSID's. net80211 comes with a standard scanner module that works with all available operating modes and supports β€œbackground scanning” and β€œroaming” operation. 🧚


πŸ’… SCANNER MODULES πŸ’…

Scanning modules use a registration mechanism to hook into the net80211 layer. The lineup:

  • use ieee80211_scanner_register() to register a scan module for a particular operating mode
  • use ieee80211_scanner_unregister() or ieee80211_scanner_unregister_all() to clear entries (typically on module unload)
and bestie, listen: only one scanner module can be registered at any time for an operating mode. one. no sharing. πŸ™ˆ

πŸ”₯ DRIVER SUPPORT πŸ”₯

Scanning operations are usually managed by the net80211 layer. Drivers gotta bring their own methods though:

  • ic_scan_start and ic_scan_stop β€” called at the start of a scan and when the work is done. These should handle work such as enabling receive of Beacon and ProbeResponse frames and disable any BSSID matching.
  • ic_set_channel β€” used to change channels while scanning.
  • net80211 will generate ProbeRequest frames and transmit them using the ic_raw_xmit method.
  • Frames received while scanning are dispatched to net80211 using the normal receive path.

Devices that off-load scan work to firmware most easily mesh with net80211 by operating on a channel-at-a-time basis, because this defers control to net80211's scan machine scheduler. But multi-channel scanning is supported β€” if the driver manually dispatches results using the ieee80211_add_scan() routine to enter results into the scan cache. 😌


🌈 SCAN REQUESTS 🌈

Scan requests occur by way of the IEEE80211_SCAN_REQUEST ioctl, or through a change in a vap's state machine that requires scanning. In both cases the scan cache can be checked first, and if it's deemed suitably β€œwarm” then it's contents are used without leaving the current channel. πŸ›‹οΈ

  • To start a scan without checking the cache, call ieee80211_start_scan().
  • Otherwise, ieee80211_check_scan() can be used to first check the scan cache, kicking off a scan if the cache contents are out of date.
  • There's also ieee80211_check_scan_current(), which is a shorthand for using previously set scan parameters for checking the scan cache and then scanning.

Background scanning is done using ieee80211_bg_scan() in a co-routine fashion. The first call to this routine will start a background scan that runs for a limited period of time before returning to the BSS channel. Subsequent calls advance through the scan set until all channels are visited. Typically these later calls are timed to allow receipt of frames buffered by an access point for the station. πŸŽ€

Canceling a scan:

  • ieee80211_cancel_scan() β€” if it was initiated by the specified vap
  • ieee80211_cancel_scan_any() β€” to force termination regardless which vap started it

These requests are mostly used by net80211 in the transmit path to cancel background scans when frames are to be sent. Drivers should not need to use these calls (or most of the calls described on this page). fr fr, stay in your lane. πŸ’€

The ieee80211_scan_next() and ieee80211_scan_done() routines do explicit iteration through the scan set and should not normally be used by drivers. ieee80211_probe_curchan() handles the work of transmitting ProbeRequest frames when visiting a channel during an active scan. When the channel attributes are marked with IEEE80211_CHAN_PASSIVE this function will arrange that before any frame is transmitted, 802.11 traffic is first received (in order to comply with regulatory constraints). rules are rules bestie 🚦

Min/max dwell time parameters constrain time spent visiting a channel:

  • the maximum dwell time constrains the time spent listening for traffic
  • the minimum dwell time is used to reduce this time β€” when it is reached and one or more frames have been received, then an immediate channel change will be done

Drivers can override this behaviour through the iv_scan_mindwell method. πŸ‘‘


⭐ SCAN CACHE MANAGEMENT ⭐

The scan cache contents are managed by the scan policy module and are opaque outside this module. The net80211 scan framework defines API's for interacting. The validity of the scan cache contents are controlled by iv_scanvalid, which is exported to user space through the IEEE80211_SCAN_VALID request.

The cache contents can be explicitly flushed with ieee80211_scan_flush(), or by setting the IEEE80211_SCAN_FLUSH flag when starting a scan operation. 🧹

Scan cache entries are created with the ieee80211_add_scan() routine; usually on receipt of Beacon or ProbeResponse frames. Existing entries are typically updated based on the latest information, though some information such as RSSI and noise floor readings may be combined to present an average. πŸ“Š

The cache contents is aged through ieee80211_scan_timeout() calls. Typically these happen together with other station table activity; every IEEE80211_INACT_WAIT seconds (default 15). ⏰

Individual cache entries:

  • are marked usable with ieee80211_scan_assoc_success()
  • are marked faulty with ieee80211_scan_assoc_fail()

…with the latter taking an argument to identify if there was no response to Authentication/Association requests, or if a negative response was received (which might hasten cache eviction or blacklist the entry). 🚫

The cache contents can be viewed using the ieee80211_scan_iterate() call. Cache entries are exported in a public format that is exported to user applications through the IEEE80211_SCAN_RESULTS request. 🎁


🌸 SEE ALSO 🌸


and that's the whole page, bestie!! this one came from Debian, dated March 29, 2010 πŸ’– go forth and scan responsibly, mwah 🫢✨

πŸ“¦ where this page comes from