Date: Mon, 25 May 2026 01:33:11 +0000 From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 490c53e9353f - main - net80211: add initial README.md and PROTOCOL.md Message-ID: <6a13a6d7.4361b.5c217572@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by adrian: URL: https://cgit.FreeBSD.org/src/commit/?id=490c53e9353feb129fe0acb8d9ba8fa52db24e2c commit 490c53e9353feb129fe0acb8d9ba8fa52db24e2c Author: Adrian Chadd <adrian@FreeBSD.org> AuthorDate: 2026-04-26 23:32:35 +0000 Commit: Adrian Chadd <adrian@FreeBSD.org> CommitDate: 2026-05-25 01:32:33 +0000 net80211: add initial README.md and PROTOCOL.md * Add top level README.md, linking to in progress and todo items * Add an 802.11 protocol overview, with todo items - this is designed to provide a basic introduction to 802.11 for people wishing to work on net80211 and drivers. * DEBUG.md - cover the debug API * DATAPATH_TRANSMIT.md - transmit datapath * DATAPATH_RECEIVE.md - receive datapath * PROTOCOL.md - a high level (for values of "high") overview of the 802.11 protocol and where it intersects with net80211 Differential Revision: https://reviews.freebsd.org/D56760 --- sys/net80211/DATAPATH_RECEIVE.md | 160 +++++++++ sys/net80211/DATAPATH_TRANSMIT.md | 390 +++++++++++++++++++++ sys/net80211/DEBUG.md | 101 ++++++ sys/net80211/PROTOCOL.md | 563 +++++++++++++++++++++++++++++++ sys/net80211/README.md | 139 ++++++++ tools/kerneldoc/subsys/Doxyfile-net80211 | 3 +- 6 files changed, 1355 insertions(+), 1 deletion(-) diff --git a/sys/net80211/DATAPATH_RECEIVE.md b/sys/net80211/DATAPATH_RECEIVE.md new file mode 100644 index 000000000000..a930aba0c3da --- /dev/null +++ b/sys/net80211/DATAPATH_RECEIVE.md @@ -0,0 +1,160 @@ +# net80211 Datapath - Receive + +## Overview + +This document provides an overview for receive data paths in +net80211, between the interface to the operating system, through net80211 and +into the driver. + +The details about underlying implementations (eg how A-MPDU RX aggregation +is handled) will be covered in dedicated documents. + +## Concurrency Notes + +The transmit path(s), receive path and control / ioctl paths all run +in parallel and can be scheduled on multiple concurrently running +kernel threads. It's important to keep this in mind. + +## Receive Path + +### Concurrency + +There must only be one packet receive path into net80211. The net80211 stack +has not yet been fully validated to ensure that state changes all occur under +sufficient locking. + +### Data Path + +The receive path is split into three broad categories: + + * The normal 802.11/802.3 packet receive path from drivers; + * The input path for reinjected frames (eg WDS, 802.11s, BPF); + * Various side channels for offloaded non-data path (eg explicitly + scan results, management frames, etc.) + +#### Data Path - Initial Input + +The driver receive path begins in ieee80211_input.c . The four +entry points are: + + * ieee80211_input() / ieee80211_input_mimo() and + * ieee80211_input_all() / ieee80211_input_mimo_all(). + +The first two are called when the destination MAC address is a known +(struct ieee80211_node) node. These are passed up to the +VAP via a call to ni->ni_vap->iv_input(). + +The second two are called when the destination MAC address is NOT +a known node. In this instance, the frames are treated as broadcast +and routed to each VAP BSS node via a call to ieee80211_input_mimo(). + +Each VAP vap->iv_input() method handles the behavioural specific +needs of the interface. + +#### Data Path - VAP type / behaviour + +Each VAP type will do roughly the same thing - for example see +sta_input() in ieee80211_sta.c . + + * Check the frame size and protocol ID; + * Check if the frame has been decrypted in hardware; + * Grab A-MPDU session frames and put them in the reorder queue; + * Handle control frames sent to the node, or general scan frames; + * Get the frame QoS information / TID information if present; + * If appropriate, check the 802.11 receive sequence number; + * Break the handling up into data, management and control; + * Reinject into a radiotap/BPF session via a call to + ieee80211_radiotap_rx(). + +The data paths will typically do the following: + + * Do decryption if needed; + * Do 802.11 decap if needed; + * Enforce security requirements if needed; + * Eventually deliver the frame up to the higher level network + stack via a call to ieee80211_deliver_data() which will + strip away any last bits of 802.11 / net80211, + call ieee80211_vap_deliver_data(), which will call the + network stack input interface. + +The control and management paths will call vap->iv_recv_mgmt() +and vap->iv_recv_ctl() which implement the per VAP type behaviours. +These will include participating in driving the scan engine, +the per-node state machines and the VAP state machine. + +#### Reinjected Path + +#### Side Channels + +Drivers may need a specific side channel for management/control +frames, MAC layer events (eg A-MPDU aggregation session state); +some power state communication, scan information and other +things that would normally show up as 802.11 frames. + +These will be covered in more detail in other documents. + +### Receive Status and Parameters + +Received 802.11 / 802.3 frames can come with a variety of information +that isn't strictly the data payload. These include receive timestamps +(at beginning or end of frame), receive noise floor / signal strength, +channel / frequency, channel width, received rate, aggregation frame +boundaries, decryption state, etc. + +The original paths - ieee80211_input() and ieee80211_input_all() - +took a noise floor and rssi parameter. Later drivers provide +information about all of the above by attaching a (struct ieee80211_rx_stats) +to the receive mbuf via a call to ieee80211_add_rx_params() bafore +calling ieee80211_input_mimo() and ieee80211_input_mimo_all() . + +Existing drivers should be migrated to the mimo versions of these +APIs and the existing API should eventually be deprecated and +replace the mimo versions. + +All new drivers must use the ieee80211_input_mimo() and +ieee80211_input_mimo_all() API calls. + +### Driver Receive Path Requirements + +The driver receive path has a few top level requirements: + + * Driver / stack locks must not be held during receive. This means that + drivers should dequeue their frames first into a local list, release + whatever locks are needed and then pass the frames up to net80211. + + * Drivers are responsible for doing the node lookup before + calling ieee80211_input() / ieee80211_input_mimo() or + calling ieee80211_input_all() / ieee80211_input_mimo_all(). + + * Drivers are also responsible for creating and attaching the + ieee80211_rx_stats information via a call to ieee80211_add_rx_params(). + + * Drivers are responsible for tagging a frame as a potential + A_MPDU by tagging the received mbuf with the M_AMPDU flag. + They should do this by just tagging all mbufs to a node + with ni->ni_flags & IEEE80211_NODE_HT set w/ the M_AMPDU flag. + This is a holdover from the 802.11n code which enforces that + only potential AMPDU frames can be added to an A-MPDU receive + aggregation session and may be relaxed / removed in the future. + +### Driver Receive Path Methods + +Drivers can hook into the receive path processing in a variety of ways. +There are a number of vap methods that a driver can hook into +processing. The details will be covered in the driver document. + +These include: + + * vap->iv_input - the driver can replace the iv_input method + with its own method to first handle frames before they are passed + to the VAP type receive path. + * vap->iv_recv_mgmt - the driver can hook here to handle + management frames before the VAP type management receive path. + * vap->iv_recv_ctl - the driver can hook here to handle + control frames before the VAP type control receive path. + * vap->iv_bmiss - the driver can hook here to be informed of + beacon miss frames. + +These may be called at any time and overlapping with others (eg +the beacon miss event - which may be triggered by a timer - +can be called in parallel with the various receive path methods.) diff --git a/sys/net80211/DATAPATH_TRANSMIT.md b/sys/net80211/DATAPATH_TRANSMIT.md new file mode 100644 index 000000000000..b3122129d938 --- /dev/null +++ b/sys/net80211/DATAPATH_TRANSMIT.md @@ -0,0 +1,390 @@ +# net80211 Datapath - Transmit + +## Overview + +This document provides an overview for the transmit data path in +net80211, between the interface to the operating system, through net80211 and +into the driver. + +The details about underlying implementations (eg how A-MPDU RX aggregation +is handled) will be covered in dedicated documents. + +## Concurrency Notes + +The transmit path(s), receive path and control / ioctl paths all run +in parallel and can be scheduled on multiple concurrently running +kernel threads. It's important to keep this in mind. + +## Transmit Path + +There are two paths from the operating system layer into the net80211 transmit +path - the normal data path and the BPF / radiotap raw frame path. + +It is important to note that both paths have no serialisation between +them, and multiple sending paths in the OS can and will queue frames +simultaneously across multiple concurrently executing threads/CPUs. +Please keep this in mind when reading the transmit handling and +how it interacts with 802.11 sequence numbering and encryption IV. + +### Data Path - net80211 + +This is configured at the ifnet setup in ieee80211_vap_setup() - +the output path is ieee80211_vap_transmit(). This input path +takes 802.3 ethernet frames with no attached metadata (such as +rate control, transmit power, etc) - it is left up to the stack. + +This hands the packet off to ieee80211_start_pkt() which will +perform the initial 802.11 destination lookup, query the node +state (eg whether it's in power save) and the VAP state (eg +is the vap itself in power state, or in a non-RUN state) +and drop or queue the frame appropriately. + +It is then handed over to ieee80211_vap_pkt_send_dest() with +a destination ieee80211_node reference. + +ieee80211_vap_pkt_send_dest() performs the bulk of the +net80211 transmit handling. Packets will be queued here if the +destination node is in a power saving mode. + +This includes: + + * Firstly - checking if the packet needs to be queued for + power saving operation and will pass it via ieee80211_pwrsave() + if needed; + * QoS classification via a call to ieee80211_classify(); + * BPF TX tap via a call to BPF_MTAP(); + * handling 802.11 encapsulation via ieee80211_encap() if required; + * A-MPDU TX decisions, AMSDU and Atheros Fast-Frames decisions. + +At this point the packet has been 802.11 encapsulated if required, +marked as needing encryption if required, and has been optionally +fragmented into a list of 802.11 fragments. + +Finally, the packet / fragment packet chain is sent up to the driver via a call +to ieee80211_parent_xmitpkt(). The driver is expected to queue the +packet / fragment list or discard the packet / fragment list. The specific +format of the mbuf chain and how ieee80211_node references are kept +is documented in ieee80211_parent_xmitpkt(). + +#### Notes on transmit path serialisation + +Note that by default the IEEE80211_TX_LOCK() is held across the call to +ieee80211_encap() and ieee80211_parent_xmitpkt(). Drivers can register +that they properly handle 802.11 sequence number offloading via +IEEE80211_FEXT_SEQNO_OFFLOAD. The lock is to ensure that packets +queued to the driver layer are added to the driver transmit queue +in the same order that they are 802.11 encapsulated - which sets the +802.11 sequence number. Drivers which set IEEE80211_FEXT_SEQNO_OFFLOAD +indicate that they will assign the sequence number themselves - likely +at the same time that the transmit encryption IV number is assigned, +or simply offloaded in firmware - and thus this lock is not +required. + +### Data path - Driver + +The call ieee80211_parent_xmit() will call the driver ic->ic_transmit() +method. At this point the driver can choose to queue / send the frame +(and take ownership of it), or return an error, and return it back +to net80211. Currently net80211 will just free the mbuf and node reference +and return, but drivers should not assume that. + +The mbuf passed in will be either a single 802.11/802.3 frame in an mbuf, +or a list of 802.11 fragments chained by m->m_nextpkt. If the driver +has not set IEEE80211_FEXT_SEQNO_OFFLOAD then the packet will have +a sequence number assigned which the driver can fetch via M_SEQNO_GET(). +The mbuf also holds an ieee80211_node reference. + +(Note that fragments do not have sequence numbers assigned nor node +references.) + +The driver needs to do a few things with this frame. Notably if it's +an 802.3 offload device, it will be handed an 802.3 frame with no +802.11 information. In that case, the driver just needs to queue +it for send to the hardware/firmware. + +For devices which accept 802.11 frames, a few things are needed: + + * It needs to queue them for send, in the order they're given. + * If there are any reasons the frames need to be buffered in the + driver - eg node power state, asynchronous node/key/state updates - + then they'll be buffered here until needed. + * It needs to do any local hardware/firmware setup - rate control, + transmit configuration, destination queue decisions, etc. + * Hardware/firmware typically has some way to mark a frame as a type + (control, data, management), whether RTS/CTS is needed, + * If IEEE80211_FEXT_SEQNO_OFFLOAD is set in the driver, it may need to + allocate 802.11 sequence numbers via a call to ieee80211_output_seqno_assign(). + * If the frame is part of an MPDU (m->m_flags & M_AMPDU_MPDU) then + the frame may need to be handled differently. (For example rtwn(4) + leaves sequence number assignment up to the firmware when A-MPDU is + enabled.) + * If the mbuf is marked as needing encryption (IEEE80211_FC1_PROTECTED + is set in the 802.11 header) then the frame needs to be encrypted + with the current encryption state via a call to ieee80211_crypto_encap(). + * Finally, the frame is queued to the hardware/firmware. + +Again it is critical that the 802.11 sequence number and encryption be +called together in the same order. This is typically done by the TX work +being done in a lock, or all frames being pushed into a single software +TX queue. + +### Data path vs control path and the need to buffer frames + +net80211 currently treats encryption key programming, VAP state +and other updates as synchronous calls. For example, the +transmit path will call the driver to add a node, then +set the encryption keys and then queue a frame to be transmitted. + +For devices which are programmed directly with no queued operations +(such as the ath(4) devices) the encryption key and node programming +is immediate. However, for many other devices - firmware and +USB are two examples - these operations are asynchronous. +And these code paths tend to be in the transmit paths from +upper layers that may have locks held, so sleeping is not an option. + +So for now this needs to be implemented in the driver itself. +It will need to maintain a per-node queue of transmit frames; +it will need to track asynchronous node creation/updates and +encryption key updates and buffer transmit frames for a node +until the node add/update and encryption key add/update is +completed. + +### Transmit Completion Notifications + +The net80211 stack may request a completion notification +to be called when a transmit frame has completed. +This will be done via a call to ieee80211_add_callback(). +It is used in various parts of the net80211 stack to +drive the MAC state machines - for example, being notified +once an BAR (Block-ACK request) frame has completed so +the retry timer can be cancelled. + +This requires that mbufs that are transmitted with a requested +completion callback be checked and handled appropriately. +This is covered in the next section. + +### Completing and freeing transmit path mbufs + +There are two paths to freeing mbufs - ieee80211_free_mbuf() and +ieee80211_tx_complete(). + +#### Before transmit - ieee80211_free_mbuf() + +ieee80211_free_mbuf() is used in drivers and net80211 to free +a list of mbufs as part of the transmit path setup so it can +properly account for and free an 802.11 MPDU / 802.3 frame, +or a list of mbufs representing 802.11 fragments. It doesn't +handle the ieee80211_node reference as at the early stage +of transmit there is a single ieee80211_node reference +covering all of the fragments being passed to the driver +for transmit. + +If you're not supporting 802.11 fragment transmit (and you have +to register your driver with the IEEE80211_C_TXFRAG capability +to even support this) then you can ignore all of the above +and just not call ieee80211_free_mbuf() for now. + +This must not be used for receive mbufs. Yes, this is not +well named and should likely just be renamed. + +#### After transmit queueing / attempts - ieee80211_tx_complete(). + +In the general case of an transmit mbuf being completed (either +successfully or unsuccessfully) net80211 provides a call +to handle everything - ieee80211_tx_complete(). This takes +the relevant destination node (struct ieee80211_node), +the mbuf, and a status indiciating success or failure. + +A call to ieee80211_tx_complete() handles a variety of +common functions: + + * It increments the ifnet counters as appropriate; + * If the frame has a TX completion notification callback attached + it will process said callback; + * If a node is supplied then the node reference is freed + +In the past some drivers implemented the mbuf TX callback +handling themselves, resulting in some drivers supporting +callback and some drivers not supporting callbacks. The goal +here is to implement a single way for completions to be +handled. + +Note that some hardware / firmware do not support per-frame +completion / status notification. For example, USB devices +tend to not send individual notifications for frames - you +may be able to request it for specific frames, but the +status notifications are expensive. In these cases, drivers +may just call ieee80211_tx_complete() with a status based +on whether the frame was queued to the USB endpoint successfully +or not. + +#### Atheros Fast Frames / 802.11n A-MSDU transmit + +(Note this is purposely short - a larger write-up for this will be +done on a separate page.) + +The transmit path above will call ieee80211_ff_check() and +ieee80211_amsdu_check() to see if the given node/frame should be +queued for an Atheros Fast Frames MPDU or an A-MSDU. + +If the frame should be queued it will be queued locally and NULL +will be returned; if there's already a frame queued it may be +paired with a queued frame and both returned as a single mbuf / MPDU +to send. + +As far as the driver is concerned, it will be handed a single +802.11 MPDU to send. + +#### 802.11n A-MPDU transmit + +net80211 implements the A-MPDU negotiation and block-ack request/response +handling. However currently the driver must implement A-MPDU packet +queuing, buffering, submission and retransmission. + +There are some methods that the driver can override to control the +A-MPDU transmit negotiation flow (ic->ic_addba_request, ic->ic_addba_response, +ic->ic_addba_response_timeout, ic->ic_addba_stop) and the Block-Ack +response completion or error/timeout (ic->ic_bar_response). + +#### Driver queue completion + +Currently there are two things a driver should do when its own queues +are (mostly) empty: + + * When the transmit queue is empty or mostly empty, call ieee80211_ff_flush() + to flush out any pending A-MSDU / Atheros Fast Frames to be transmitted; + * When the receive queue is being handled, call ieee80211_ff_age_all() to + flush out any frames that are older than a provided time interval. + +These calls ensure that any queued frames in Fast Frames / A-MSDU queue +don't stay in there permanently. + +### Non data frame transmission (management, control, action, beacon, etc) + +Non data frames are sent via ieee80211_raw_output(). The main exception to +this is beacon frames, which are separately initialised and pulled from +net80211 into the driver by the driver specific beacon handling routines. + +Raw frames differ from data frames in a couple of ways: + + * Transmit parameters are typically sent from userland or the caller + (struct ieee80211_bpf_params \*), and + * The input path into the driver is via ic->ic_raw_xmit(), not ic->ic_transmit(). + +The driver can combine the data and non-data paths into a single path. +The main reason for keeping these separate is to cleanly support drivers +and firmware which allow 802.3 frames to be sent and received, but still +need a side channel to send and receive management frames for various other +functions. + +The raw frame output path is used by: + + * The BPF output path - ieee80211_output() ; + * The management frame output path - ieee80211_mgmt_output() ; + * The NULL data output path - ieee80211_send_nulldata() ; + * Sending probe requests - ieee80211_send_probereq() ; + * Sending probe responses - ieee80211_send_proberesp() ; + * Sending 802.11n BAR frames - ieee80211_send_bar() ; + * .. and anywhere where the individual protocol (eg 802.11s) wishes to send raw + non-data frames. + +This path is not REALLY designed for high speed data - for example, +it should work for basic packet injection, but it does not pass through +the normal functions for encryption, power save, TX aggregation and other +data specific operations. It expects to be handed a raw, already encapsulated +802.11 frame. + +Note this is not an 802.11 MPDU - this is an 802.11 frame. For example, +non-data frames may not have sequence numbers. NULL data frames have a sequence +number but that sequence number must be 0. + +Once the driver ic->ic_raw_xmit() call is made, the driver can handle the +802.11 frame in any way it sees fit. Again, it can't assume it's an 802.11 +data frame. + +### BPF path + +Control frames are injected from userland and net80211 via a raw transmit path, +separate from the data path. This dates back to the earliest Orinoco/WaveLAN +cards, where the earlier firmware only allowed 802.3 frames to be sent/received, +but later firmware introduced raw packet transmit to allow wpa_supplicant +operation. + +Packet injection begins via the BPF/radiotap input path. The code in +ieee80211_radiotap.c attaches a BPF operator to the VAP during the +call to ieee80211_radiotap_vattach(). + +Raw frames start in BPF and are queued via bpf_ieee80211_write(), which will +send the frame into the driver via a call to the VAP ifp->if_output() and then +if provided, a copy of the feedback mbuf via the VAP ifp->if_input(). + +The ifp->if_output() method by default is ieee80211_output(). The driver +can override this. This takes care of validating that it is an 802.11 +frame, extracts the (struct ieee80211_bpf_params \*) header from the +destination sockaddr passed in via BPF, finds the relevant +struct ieee80211_node \*) tx node, grabs a reference, some further sanity +checks and then calls ieee80211_raw_output(). The rest of the raw output +path is the same as net80211 sourced raw frames. + +### Power Save Management + +By default, net80211 will track legacy power-save state between IBSS nodes +and STA <-> AP nodes (ie, full node buffering via the power management bit +in the 802.11 header; TIM/ATIM bitmaps in beacons, NULL data frames to wake up) +and PS-POLL frames being sent by stations to request individual frames. + +The transmit path will pass frames destined to asleep stations to the power +save queue via a call to ieee80211_pwrsave(). + +There are a number of VAP methods for the driver to tie into if it needs to be +informed about this state (vap->iv_set_tim, vap->iv_recv_pspoll, vap->iv_node_ps). +These allow the driver to keep its own internal state in sync with net80211 +and allows it to better maintain its own transmit queue state. + +See the ath(4) driver for a comprehensive example of how these methods are used +to correctly transmit and buffer frames from an AP to STA device without packet +loss. + +### Transmit path encryption + +The net80211 stack needs to handle a variety of transmit encryption schemes +based on all the combinations that driver and firmware interfaces may require. + +In general, the transmit encryption is done in two phases: + + * In ieee80211_encap(), the transmit key is chosen via a call + to ieee80211_crypto_getucastkey() or ieee80211_crypto_getmcastkey() - the + key index is added to the 802.11 header and space is reserved between + the 802.11 header/payload and at the end for the encryption key data to be + added; + * Then when the driver transmits the frame, it calls ieee80211_crypto_encap() + to actually do the encryption. + +Some hardware will completely offload encryption, so although the key choice +is made, various driver configuration options are set to inform net80211 not +to add all the padding. Others will offload encryption but require the +space to be provided in the frame for the hardware/firmware to add the +encryption information into. + +### What is IEEE80211_F_DATAPAD ? + +This is actually to support hardware such as the Atheros 802.11abgn chips, +which have a 4 byte alignment requirement between the 802.11 header and +the data payload (including the encryption parts.) + +Yes, it likely should be a more generic option. + +### Future work + + * It would be nice to more formally define and enforce what drivers should be + doing with mbufs during the whole transmit lifecycle of an mbuf. + * Perhaps add a function or two for the drivers to use to + query whether a given mbuf has a TX notification attached (rather + than drivers querying M_TXCB) so they can individually + register for explicit notifications so they can provide more + accurate completion information. + * The fast frames age / flush routines should really be expanded to + be required functionality in net80211 drivers rather than optional + when IEEE80211_SUPPORT_SUPERG is enabled, so further software transmit + queue management is possible in net80211. + diff --git a/sys/net80211/DEBUG.md b/sys/net80211/DEBUG.md new file mode 100644 index 000000000000..2231a0992fe6 --- /dev/null +++ b/sys/net80211/DEBUG.md @@ -0,0 +1,101 @@ +# Debugging in net80211 + +This document describes how debugging is implemented in net80211. + +## Overview + +net80211 has run-time configurable debugging available. It is configured +per-VAP. It is implemented as a bitmask which can be controlled via a +sysctl at runtime. + +Debugging is compiled in when IEEE80211_DEBUG is defined. + +There is currently no global debugging API available; top-level net80211 +code is typically using printf() or some wrapper around it (eg +net80211_printf). + +The debug API is defined in (ieee80211_var.h). This includes the +debug field definitions and exported debugging API. The actual implementation +of the debugging routines is currently in (ieee80211_input.c) - see +(ieee80211_note) for an example. + +The bitmap of available debugging sections is in (ieee80211_var.h), prefixed +with IEEE80211_MSG . See (IEEE80211_MSG_DEBUG) for an example. + +## Usage + +Calls to the debugging APIs should not include a terminating '\n' character. +This will be added by the debug call. + +The simplest example is a call to IEEE80211_DPRINTF(). This takes a vap +pointer, which debug option to log to, then the format string and optional +arguments. For example: + +``` +IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N, "%s: called!", __func__); +``` + +The debug flags can be combined together using bitwise OR so they are +emitted if one or more debug options are set, for example: + +``` +IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N | IEEE80211_MSG_ASSOC, + "%s: called!", __func__); +``` + +There are a number of different debugging calls that are designed to be +used in different contexts. Although they all currently end up printing +to the same debug output, keeping them separate allows for future +behavioural changes whilst minimising rototilling the whole codebase (eg +allowing non-DPRINTF to turn into event tracing.) + + * Straight up debugging should be done through IEEE80211_DPRINTF() . + * Debugging that's related to a specific ieee80211_node (eg a state + change for a specific node) should be done via a call to IEEE80211_NOTE() . + * Debugging that's related to a specific ethernet MAC address (eg + scan results) should be done via a call to IEEE80211_NOTE_MAC() . + * Debugging that should include a frame header should be done via + a call to IEEE80211_NOTE_FRAME(). Note this takes a (struct ieee80211_frame \*) + pointer. + * Debugging involving discarding frames (eg invalid frames) should be + done via a call to IEEE80211_DISCARD() . + * Debugging involving discarding frames due to an invalid / bad IE should + be done via a call to IEEE80211_DISCARD_IE(). + * Debugging involving discarding frames due to a MAC address (eg ACL failure) + should be done via a call to IEEE80211_DISCARD_MAC(). + +## Usage Notes + + * It is required that the debugging be compiled in/out purely by defining or not + defining IEEE80211_DEBUG. This can often trip up unused variable warnings + when debugging is disabled, so just double-check both configurations. + + * It is important to ensure calls to the debugging (and any other logging API) + do not change any state/variables. For example, do not call a function that + updates some counter or some state variable inside a call to IEEE80211_DPRINTF(). + It won't be called at best and it will just be compiled out entirely at worst. + +## Configuration + + * The 'vap->iv_debug' field is controlled by the OS specific module. + * In FreeBSD (ieee80211_freebsd.c) it is assigned a sysctl (net.wlan.X.debug) + during (ieee80211_sysctl_vattach). + * FreeBSD ships the wlandebug(8) tool to query and set this at runtime. + +## Implementation Details + +* The debug API goes out of its way to do the debug flag check before evaluating + function parameters and potentially assembling the logging output. See + (IEEE80211_DPRINTF) for an example. + +## Future work + + * Top-level net80211 debugging APIs and control would be nice (for things + that are not specific to a VAP.) + * Drivers end up having to implement their own debugging API; it may be nice + to provide drivers a net80211 API to do their own driver specific logging. + * The debug macros should likely be refactored out to a new header file, + separate from ieee80211_var.h, so they can be more easily referenced. + * The debug fields should likely be refactored out into a new separate header + file that is designed to be consumed both by the kernel and by userland + utilities wishing to query/set the debug bitmask. diff --git a/sys/net80211/PROTOCOL.md b/sys/net80211/PROTOCOL.md new file mode 100644 index 000000000000..6d7c128bfc89 --- /dev/null +++ b/sys/net80211/PROTOCOL.md @@ -0,0 +1,563 @@ +# 802.11 protocol overview + +This is a quick overview of the 802.11 protocol and where it intersects with +net80211. It is not intended as a comprehensive deep dive into all of 802.11. + +TODO: link to appropriate sections in 802.11-2016 / 802.11-2020 depending upon +which PDF is freely available. + +## 802.11 overview + +The 802.11 protocol / specification is a very large document which covers +everything from the raw signals going out over the air up to how devices +need to behave in different operating modes. + +The IEEE specification documents and amendments describe what devices should +and must do in order to interoperate. It's important to note that the +intersection of "what the standard says" and "what devices do" is not always +fully aligned. The 802.11 specification has evolved over twenty-five years +and for the most part this allows interoperability between the original 802.11b +hardware and modern multi-band 802.11ax devices. + +It's also important to note that 802.11 is not just limited to the IEEE +specifications. 802.11 devices are almost exclusively RF devices (if you +read the specification you may find the old infrared / IR protocol definition!) +and so need to operate inside of the radio regulatory rules defined by each +country. These define a wide variety of RF environmental behaviours +including frequencies can be used, when devices can transmit, what transmit +power is allowed, interoperability with other devices (802.11 and non-802.11) +and radar interoperability. For the purposes of this document these will +be called "regulatory concerns" and will be covered elsewhere. + +The 802.11 specification breaks things up into a handful of top level areas: + + * the PHY layer - how the device interfaces with the RF environment and + encodes/decodes RF transmissions into data streams. + * the MAC layer - defines how data is packetized into individual data frames, + exchanged with the upper layer (ethernet/bridge), deciding when and what + to transmit via the PHY layer. + * MLME - (MAC layer management entities) - defines all of the state methods + and transitions that underpin the 802.11 MAC state machine. + * Security - the cipher and key management components. + * PHY specifications - the specific implementations of PHYs - 2GHz DSSS + (spread spectrum), 2GHZ CCK, OFDM, ERP, 802.11n / HT, 802.11ac / VHT, etc. + +Most 802.11 implementations do not implement a 1:1 definition of each of these +layers - notably implementing every single MLME state would be a huge amount +of work. + +## 802.11 revisions + +There have been many revisions of the 802.11 specification. The specifications +can be found online at https://www.ieee802.org/11/. + +The latest specification being implemented in net80211 is 802.11-2020, however +net80211 is far from completely compliant. Generally new code which implements +802.11 features / protocol handling should identify the specification and +section which it is referencing. + +## 802.11 protocol and frame definitions + +net80211 keeps most 802.11 frame and protocol definitions in a single location +(ieee80211.h). +This contains descriptions of the 802.11 frame and field definitions, ranging +from the lowest definition of the frame itself up through frame types/subtypes, +individual field definitions, information elements, action frames, and +anything else that can be found in the 802.11 specifications. + +The PHY definitions can be found in (ieee80211_phy.c) and (ieee80211_phy.h). +Notably those include the frame timing information useful for rate control +and frame duration calculations. + +## 802.11 Revisions + +(TBD) + +### Legacy 802.11 + +The earliest 802.11 devices implement 1Mbit/s and 2Mbit/s direct spread spectrum +frames. These include the earliest Wavelan devices. These are grandfathered +into 802.11b. The PHY specification can be found in 802.11-2020 Section 15.) + +### 802.11b + +802.11b devices implement Section 15 (1Mbit/2Mbit) PHYs as well as the high +rate DSSS specification (802.11-2020 Section 16) to provide 5.5Mbit and 11Mbit +CCK rates. They interoperate with legacy 802.11 devices by using compatible +PHY encodings and will limit their performance if said legacy devices are +detected. + +### 802.11a + +802.11a devices implement OFDM rates from 6Mbit/s to 54Mbit/s on the 5GHz +band. Among other features, it also defines 5MHz and 10MHz wide channel +behaviour. This is covered in the OFDM PHY specification (802.11-2020 +Section 17.) + +### 802.11g + +802.11g devices implement OFDM rates from 802.11a, the CCK rates from 802.11b +and the DSSS rates from legacy 802.11. These are covered in the ERP +specification (802.11-2020 Section 18.) There are some MAC extensions for +negotiating 802.11b / 802.11g interoperability and these are documented +throughout the MAC specification. This also specifies support for 5MHz and +10MHz wide channels. + +### 802.11n (HT) + +802.11n introduced a variety of high throughput rates and feature support +(hence why it's called HT - high throughput). It introduces higher density +OFDM rate encodings, 20 and 40MHz wide channels with interoperability for +earlier devices, packet aggregation via A-MPDU and A-MSDU, MIMO (multiple input, +multiple output spatial streams), some initial beamforming support, power +saving extensions and more. + +The physical layer support is covered in the HT PHY specification (802.11-2020 +Section 19.) The rest of the MAC extensions are documented throughout the +rest of the specification. + +### 802.11ac (VHT) + +802.11ac extends the 802.11n specification (hence why it's VHT - Very +High Throughput) and boosts performance by adding higher density OFDM QAM +encoding (256-QAM), wider channels (80MHz, 160MHz), split 80+80MHz channel +support, much larger A-MSDU / A-MPDU frame sizes, support for MU-MIMO +(multi-user MIMO) allowing APs to transmit to multiple STAs at the same time +and various other extensions. + +It builds on top of the 802.11n MAC and PHY specification, so a lot of +802.11n feature and MAC negotiation happens as part of 802.11ac negotiation. + +The PHY layer is covered in the VHT PHY Specification (802.11-2020 Section +21.) Again, the rest of the MAC extensions are documented throughout the +rest of the specification. + +### Greenfield versus backwards compatibility + +The various protocols supported by 802.11 build on top of earlier protocols. +So typically you're not building a single implementation for each protocol - +for example, you can't handle 802.11ac support without implementing a large +amount of 802.11n support. + +(As a side note, the 802.11 frame has a protocol version field, and +that actually changed in 802.11ah (900MHz and longer distance bands) - +which changes a lot of what the fields do. No, net80211 currently does not +support 802.11ah and will drop frames whose 802.11 protocol ID is not +supported.) + +At the PHY layer, later model hardware can transmit data encodings which +earlier model hardware just won't recognise. All they'll see is an increase +in RF power on the channel at best and signals that will confuse the +RX decoder / cause hardware issues at worst.) + +So each of the PHY specifications will lay out a few things: + + * How frames should be encoded in the air in a way that earlier + hardware can decode them enough to know it's not for them; + * How devices can identify that earlier protocol devices are around and + change the configuration (eg STA changing its own configuration, + AP changing the configuration of the network it controls, etc) + to provide backwards compatibility. + +These come at a performance cost. For example, an 802.11g AP which +supports 802.11b and 802.11 devices needs to notice that an 802.11b +device wishes to associate, and when it sees this, change some of +its configuration (notably "long preamble" so 802.11b devices can +decode frames that are being transmitted, whether destined to it or not.) + +Various devices allow backwards compatbility to be configured. +For example, an 802.11n AP may be configured to deny non-802.11n clients. +This may improve performance but then earlier clients can't connect. + +In 802.11n deployments this was known as a "greenfield deployment". +This typically disables any and all pre-11n interoperability at both +a MAC and PHY layer. net80211 has some flags for this to specifically +inform devices that they can configure the hardware for such a setup. +Not all drivers implement it however, and in a lot of cases they will +still handle pre-11n framing, even if the net80211 code will deny +association. + +There are other components to backwards compatibility which are worth +keeping in mind when reading through the 802.11 specification and +net80211 stack / driver code. These include: + + * short/long preamble - (vap_update_preamble) + * short/long slot time configuration - (vap_update_slot) + * 802.11g protection mode (vap_update_erp_protmode) - + whether to use CTS-to-self around each transmission + * 802.11n protection mode (vap_update_ht_protmode) - + whether to use RTS/CTS around each transmission + * 802.11n 20/40MHz BSS operation (whether an 802.11n AP sees other APs that + overlap its frequency range and need to reconfigure how to protect + transmissions) + +## How 802.11 (very briefly) works over the air + +This is a very brief and not at all comprehensive overview of how 802.11 +works over the air. The goal of this section is to provide enough background +information to help de-mystify reading the net80211 stack and wireless +driver source. + +### Why there's timing requirements in the first place + +Each of the PHY sections in the 802.11 specification describe what +the PHY needs to do in order to transmit and receive data. It's not +anywhere as easy as "toggle some bits on a wire". + +An important thing to understand is that hardware isn't immediate. +All the state machines in your 802.11 devices take non-zero time +to make decisions about when to transmit, when to receive, locking +onto a signal, deciding it can be decoded, getting reset for the next +frame, etc. + +So a lot of what you'll see in 802.11 negotiation and feature support +is linked to the underlying hardware implementations and limitations +of the time. For example the 802.11b specification defines the slot time +as 20uS, but the 802.11g specification lowers it to 9uS. The "slot time" +value defines the unit of time used for contention management / backoff, and +it's defined partly by what the speed of light dictates (ie how big +of a physical area you want to be able to "hear" in determining if the +area is busy) and how quickly the hardware can guarantee to respond. +It dropped to 9uS because hardware got better, but to interoperate +with older devices without starting to transmit before they're +ready to react, 802.11g devices will fall back to 20uS slot time when +they detect an 802.11b device. + +This carries through everywhere in odd places that you're not necessarily +aware of. For example, the 802.11n A-MPDU definition includes negotiated +padding between frames and limits encryption ciphers (typically CCMP or +GCMP.) This is due to hardware support - the MAC may be able to support +much less padding when no encryption is used, but setting up / resetting +the encryption / decryption blocks may take more time and thus larger +A-MPDU padding values are negotiated. + +### Wait, the speed of light? + +Yes. The speed of light is roughly 300 metres for each microsecond of +travel time. + +### Preambles, SIGs, PLCP, sending actual data and waiting / slot times + +There are a few things that are worth understanding at a high level. + + * The first thing that a device needs to do is determine + whether the air is busy or free. There'll be some hardware + to determine the signal level versus noise floor and provide + a signal to the transmit hardware that the air is free, + and to the receiver that it may want to try start decoding + something. + + * The receiver needs to get in synchronisation with the transmitter. + This is a one way operation - the transmitter needs to transmit + enough of a signal that the receiver can "lock onto" and get itself + ready for further data. This is called the "preamble" - it's + typically a low bitrate repeating pattern of data that gives + the receiver hardware time to lock onto, figure out the signal + level and be ready for the next phase. + + * Note that the receiver may pick up the preamble at any point in its + transmission so it can't guarantee it will see exactly "x" bits of some + repeating pattern. + + * Then there's other bits and pieces - eg look for L-SIG, HT-SIG + in the PHY documentation - which is used to further synchronise + what's about to happen. + + * Finally it will start transmitting the PHY framing bits needed to + identify what the upcoming transmit rate and configuration is + (all the stuff leading up to the PLCP header, then the PLCP header.) + +Things get more complicated with MIMO, MU-MIMO, 802.11ax OFDM-A, etc but +don't worry about those for now - they build on top of all of these +ideas. + +Once the data is transmitted, there's some quiet time between frames +before the receiver can ACK (and then a period of time where an ACK +is expected.) The transmitter needs to finish transmitting, then +reset its internal state back to idle to be ready to receive - and +there's the pesky speed of light speed of 300m per microsecond - +so there's some MAC (interframe spacing) and PHY (slot time) enforcing +quiet so everyone has a chance to receive the frame and the reciver *** 442 LINES SKIPPED ***home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a13a6d7.4361b.5c217572>
