IEEE80211_PROTO(9)

πŸ’– ieee80211_proto β€” 802.11 state machine support πŸ’–

okay bestie, welcome to IEEE80211_PROTO(9), straight out of the Kernel Developer's Manual 🫢 this one is the 802.11 state machine page and it's lowkey the blueprint for how net80211 drivers behave, so grab a snack and let's get into it ✨


🌸 SYNOPSIS 🌸

#include <net80211/ieee80211_var.h>

void
ieee80211_start_all(struct ieee80211com *);

void
ieee80211_stop_all(struct ieee80211com *);

void
ieee80211_suspend_all(struct ieee80211com *);

void
ieee80211_resume_all(struct ieee80211com *);

enum ieee80211_state;

int
ieee80211_new_state(struct ieee80211vap *, enum ieee80211_state, int);

void
ieee80211_wait_for_parent(struct ieee80211com *);

✨ DESCRIPTION ✨

so the net80211 layer that backs 802.11 device drivers runs a whole state machine to control how vaps operate. and no, it's not one single machine β€” these state machines change depending on what mode the vap is in. station mode state machines follow the 802.11 MLME states from the protocol spec, very by-the-book πŸ’…. the other state machines are simpler and just reflect whatever operational work is happening, like scanning for a BSS or auto-picking a channel to run on. when you've got multiple vaps live at once, the state machines coordinate stuff like channel selection. and plot twist β€” the state machine mechanism is also what binds the net80211 layer to a driver, which we get into below πŸ‘‡

these are the states defined for the state machines:

  • IEEE80211_S_INIT β€” the default/initial state. a vap sitting here should not be holding onto any dynamic state (think entries for associated stations in the node table, that kind of thing). the driver has to quiesce the hardware, meaning no interrupts should be firing. silence. periodt 🀫
  • IEEE80211_S_SCAN β€” scanning for a BSS, or choosing a channel to operate on. ngl scanning can also happen in other states (like when background scanning is active), but this state is what you enter when you're initially bringing a vap up to an operational state, or after an event like a beacon miss (in station mode).
  • IEEE80211_S_AUTH β€” authenticating to an access point (in station mode). you normally get here from IEEE80211_S_SCAN after selecting a BSS, but you can also arrive from IEEE80211_S_ASSOC or IEEE80211_S_RUN if the authentication handshake fails 😭
  • IEEE80211_S_ASSOC β€” associating to an access point (in station mode). you reach this from IEEE80211_S_AUTH after a successful auth, or from IEEE80211_S_RUN if a DisAssoc frame shows up uninvited.
  • IEEE80211_S_CAC β€” doing Channel Availability Check (CAC). this state only ever gets entered when DFS is enabled and the channel picked for operation requires CAC. very exclusive, very conditional ✨
  • IEEE80211_S_RUN β€” operational, the main character state πŸ‘‘ here a vap can transmit data frames, accept requests for stations associating, all of it. ⚠️ but beware: data traffic is also gated by whether the associated "port" is authorized. when WPA/802.11i/802.1x is operational, authorization can happen separately β€” like in station mode, wpa_supplicant(8) has to finish the handshakes and plumb the necessary keys before a port is authorized. in this state a BSS is operational and associated state is valid and usable; for example ic_bss and ic_bsschan are guaranteed to be usable. iconic.
  • IEEE80211_S_CSA β€” a Channel Switch Announcement (CSA) is pending. this one is only reached from IEEE80211_S_RUN, either when a CSA is received from an access point (station mode) or when the local station is getting ready to change channel. in this state traffic may be muted depending on the Mute setting in the CSA πŸ”‡
  • IEEE80211_S_SLEEP β€” asleep to save power (in station mode). only reached from IEEE80211_S_RUN, and only when power save operation is enabled and the local station is deemed sufficiently idle to drop into low power mode 😴
heads up bestie: the states are ordered, exactly as listed above. so a vap has to be in IEEE80211_S_RUN or "greater" before it can transmit frames. and some net80211 data is only valid in certain states β€” for example iv_bsschan, which specifies the channel for the operating BSS, should never be used except in IEEE80211_S_RUN or greater. don't do it. i'm serious πŸ’€

πŸ¦‹ STATE CHANGES πŸ¦‹

state machine changes are typically handled internally by the net80211 layer, reacting to ioctl(2) requests, received frames, or external events like a beacon miss. the ieee80211_new_state() function is what you call to kick off a state machine change on a vap β€” you hand it the new state plus an optional argument.

the request first gets processed to coordinate across multiple vaps. for example, only one vap at a time can be scanning: if several vaps ask to move to IEEE80211_S_SCAN, the first one gets to run and the rest get deferred until the scan operation finishes, at which point the selected channel gets adopted. same energy with combinations of vaps, like an AP plus a station vap, where the station might need to roam to follow the AP it's associated to β€” dragging the AP vap along to the new channel 🧳. another important coordination is how IEEE80211_S_CAC and IEEE80211_S_CSA get handled. and fr fr: no more than one vap can ever be actively changing state at a time. in fact net80211 single-threads the state machine logic into a dedicated taskqueue(9) thread, which is also used to synchronize work like scanning and beacon miss handling. one thread, zero chaos, we love to see it πŸ’…

once the multi-vap scheduling/coordination is done, the per-vap iv_newstate method is called to actually do the state change work. drivers use this entry to set up private state and then dispatch the call back to the net80211 layer using the previously defined method pointer β€” in OOP-parlance, they call the "super method" 🦸

net80211 handles two state changes specially:

  • on transition to IEEE80211_S_RUN, the IFF_DRV_OACTIVE bit on the vap's transmit queue is cleared so traffic can flow 🌊
  • on transition to IEEE80211_S_INIT, any state in the scan cache associated with the vap is flushed, and any frames pending on the transmit queue are flushed too 🧹

πŸ’œ DRIVER INTEGRATION πŸ’œ

drivers are expected to override the iv_newstate method so they can interpose their own code and handle the setup work that state changes require. other than that, drivers must call ieee80211_start_all() in response to being marked up through an SIOCSIFFLAGS ioctl request, and they should use ieee80211_suspend_all() and ieee80211_resume_all() to implement suspend/resume support.

there's also an ieee80211_stop_all() call that forces all vaps into an IEEE80211_S_INIT state β€” but a driver shouldn't need it. control is usually handled by net80211, or in the case of card eject or vap destroy, work gets initiated outside the driver. so like, not your problem, bestie πŸ™ˆ


🌈 SEE ALSO 🌈


⭐ HISTORY ⭐

the state machine concept was part of the original ieee80211 code base that first appeared in NetBSD 1.5. a true OG 🫢


and that's the whole page, bestie πŸ’– this one came from the Debian crew, dated August 4, 2009 β€” shoutout to the kernel devs, they ate and left no crumbs πŸ‘‘βœ¨

πŸ“¦ where this page comes from