ch12_9
12.9 Quick Reference
We've come a long way in this chapter — from the fundamental CSMA/CA handshake, to 802.11n A-MPDU aggregation, and on to 802.11s multi-hop routing. On paper, these protocols are abstract diagrams, but in the kernel code, they take the form of concrete function calls, structure members, and flag bits.
When you actually sit down to write a driver or debug mac80211, you don't need lengthy theoretical explanations — you need a map that quickly tells you "what does this function do" and "what does that flag mean."
That's the purpose of this section. It's not meant to be read — it's meant to be looked up.
Here I've listed some of the core methods mentioned in this chapter, along with that extremely complex ieee80211_rx_status flag dictionary. Treat this page like a glossary — when you get lost in the code jungle of drivers/net/wireless, come back here.
Core Methods Cheat Sheet
Most of these functions are defined under the net/mac80211/ directory. For easy reference, I've categorized them by function and added behavioral details critical during invocation that weren't mentioned in the main text.
1. Block Ack and Aggregation (A-MPDU / A-MSDU)
This is the core of 802.11n's throughput improvements. Drivers typically don't manipulate these details directly, but if you're debugging why aggregation isn't enabled, this is where you end up.
-
void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)- Purpose: Sends a Block Ack Request (BAR) control frame.
- Scenario: Called when you've sent a bunch of aggregated frames but the peer didn't send back a Block Ack, or when you want to explicitly trigger acknowledgment.
ssn(Starting Sequence Number) tells the peer: "acknowledge starting from this sequence number."
-
int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, u16 timeout)- Purpose: Starts a transmitter-side Block Ack session (aggregation session).
- Mechanism: It calls the driver's
ampdu_action()callback, passing inIEEE80211_AMPDU_TX_START. - Note: This is asynchronous. The driver must call back
ieee80211_start_tx_ba_cb()or the_irqsafevariant once ready before actual aggregation begins.
-
int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)- Purpose: Stops a transmitter-side Block Ack session.
- Mechanism: Calls the driver's
ampdu_action(), passingIEEE80211_AMPDU_TX_STOP. The driver must then call backieee80211_stop_tx_ba_cb()to complete cleanup.
-
static void ieee80211_send_addba_request(...)- Purpose: Sends an ADDBA Request management frame (Action Frame).
- Parameters:
buf_sizedetermines the receiver's aggregation window size (typically 64), andtimeoutdetermines the session timeout.
-
void ieee80211_process_addba_request(...)- Purpose: Handles a received ADDBA request on the receiver side. This is the core logic of
mac80211and is usually not called by the driver — it's automatically triggered by the kernel upon receiving an Action Frame.
- Purpose: Handles a received ADDBA request on the receiver side. This is the core logic of
-
static void ieee80211_send_addba_resp(...)- Purpose: Sends an ADDBA Response. In other words, telling the peer "okay, I can aggregate" or "no, your window is too small."
-
void ieee80211_process_delba(...)- Purpose: Handles a DELBA frame. The peer doesn't want to play anymore, or the peer is notifying you to stop sending aggregated frames.
-
void ieee80211_send_delba(...)- Purpose: Actively sends a DELBA frame to end a session.
-
static ieee80211_rx_result ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)- Purpose: Processes A-MSDU (Aggregated MSDU) on the RX path.
- Details: This is one link in the RX Handler chain. If the hardware passes de-aggregated packets to the kernel, this function is responsible for splitting a large packet back into multiple SKBs.
-
static void ieee80211_rx_reorder_ampdu(...)- Purpose: Manages the reordering buffer for A-MPDU.
- Pain point: Since out-of-order arrival is normal over wireless, this function inserts out-of-order MPDUs into the window, passes consecutively deliverable packets to the upper layer, and holds back missing-sequence packets to wait for a BAR.
2. Power Management
Power save logic in wireless is full of pitfalls. A STA wants to sleep, so the AP must help buffer frames; when the STA wakes up, it needs to grab data quickly.
-
void ieee80211_send_nullfunc(struct ieee80211_local *local, ... int powersave)- Purpose: Sends a Null Data frame.
- Key point: This is the signaling mechanism to tell the AP "I'm going to sleep" or "I'm awake." Implemented via the Power Management bit in the frame header.
-
void ieee80211_send_pspoll(...)- Purpose: Sends a PS-Poll control frame.
- Scenario: A STA wakes from sleep and actively asks the AP: "Do you have any buffered unicast data for me? If so, send it now."
-
static inline bool ieee80211_check_tim(..., u16 aid)- Purpose: Checks the TIM (Traffic Indication Map) bitmap.
- Scenario: After receiving a Beacon frame, the STA calls this function to check if the bit corresponding to its AID is set to 1. If so, it means the AP has goods waiting — time to send a PS-Poll.
3. Scanning, Authentication, and Association
This is the core flow of MLME.
-
int ieee80211_request_scan(...)- Purpose: Initiates an active scan.
-
void ieee80211_send_probe_req(...)- Purpose: Sends a Probe Request management frame.
- Parameters:
ssidandie(Information Elements) determine what you're asking about.
-
void ieee80211_send_auth(...)- Purpose: Sends an Authentication frame. This is the first step of connection and can be either Open System or Shared Key.
-
static void ieee80211_send_assoc(...)- Purpose: Sends an Association Request frame.
- Timing: Called after authentication succeeds. It carries all supported rates and capability information.
4. Mesh Routing (802.11s / HWMP)
If you're writing Mesh-related code, these functions are the concrete implementation entry points for the HWMP protocol in the kernel.
-
struct mesh_path *mesh_path_lookup(..., const u8 *dst)- Purpose: Looks up a path to
dstin the Mesh routing table. - Returns: NULL if not found, or a
mesh_pathstructure if found. This is the first step in forwarding data.
- Purpose: Looks up a path to
-
void mesh_path_tx_pending(struct mesh_path *mpath)- Purpose: Sends data packets backlogged in
mpath->frame_queue. - Scenario: When route discovery completes (e.g., upon receiving a PREP), the kernel calls this function to release the packets that were queued at the intersection.
- Purpose: Sends data packets backlogged in
-
static int mesh_path_sel_frame_tx(enum mpath_frame_type action, ...)- Purpose: Generic HWMP frame transmission function.
- Supports: Sends both PREQ (Path Request) and PREP (Path Reply). The
metricin the parameters is that famous "airtime" cost metric.
-
static void hwmp_preq_frame_process(...)- Purpose: Handles received PREQ frames. This is the core logic where Mesh nodes cooperate to find routes.
5. Device Registration and Low-Level Operations
These are the APIs that driver developers touch first.
-
struct ieee80211_hw *ieee80211_alloc_hw(...)- Purpose: Allocates a
ieee80211_hwdevice structure and the driver's private datapriv. The beginning of everything.
- Purpose: Allocates a
-
int ieee80211_register_hw(struct ieee80211_hw *hw)- Purpose: Registers this hardware device with the kernel. From this moment on, your network card is "alive" in the system.
-
int ieee80211_hw_config(..., u32 changed)- Purpose: Configures hardware parameters.
- Parameters:
changedspecifies what to change (e.g., useIEEE80211_CONF_CHANGE_CHANNELto change the channel). This function typically drops down to the driver'sconfig()callback.
-
void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb)- Purpose: Receives data packets.
- Feature: As the name implies, it can be safely called from hardware interrupt context. It uses softirqs (tasklets) to defer the packet reception work.
6. RX Processing and Status
Receiving packets isn't just about passing SKBs up the stack — you also need to check FCS, decryption status, and reordering.
-
struct ieee80211_rx_status *IEEE80211_SKB_RXCB(struct sk_buff *skb)- Purpose: Extracts
rx_statusfrom the SKB's control block (cb). - Key point: After the hardware driver receives a packet, it must fill in information like signal strength, rate, and MAC timestamp in this structure, place it in
skb->cb, and then hand it tomac80211.
- Purpose: Extracts
-
static ieee80211_rx_result ieee80211_rx_h_check(struct ieee80211_rx_data *rx)- Purpose: The first checkpoint in RX processing.
- Logic: Checks if this is a duplicate frame (Retransmission). If so, it increments the
dot11FrameDuplicateCountcounter and drops the frame.
-
static bool ieee80211_sta_manage_reorder_buf(...)- Purpose: The concrete implementation logic for managing the reordering buffer. It determines whether a packet should enter the buffer to wait or can be passed directly to the network stack.
Flag Dictionary: ieee80211_rx_status
This is one of the most error-prone areas in mac80211 driver development. The flag field in the rx_status structure is a 32-bit bitfield. Hardware drivers are responsible for setting these bits correctly, and mac80211 is responsible for doing the right thing based on them.
The table below is the "cryptic manual" I frequently flip through when debugging packet reception issues. I've expanded the meanings a bit so you don't end up staring blankly at the spec sheet.
Table 12-1: Rx Flags (the flag field of ieee80211_rx_status)
| Linux Symbolic Constant | Bit | True Meaning and Practical Tips |
|---|---|---|
| RX_FLAG_MMIC_ERROR | 0 | Michael MIC error. This frame passed CRC check, but its content was tampered with. Usually occurs with TKIP encryption. If this error is set, drop the packet immediately. |
| RX_FLAG_DECRYPTED | 1 | Hardware decrypted. An extremely important flag. If the hardware decrypted it for you (WEP/WPA/WPA2), you must set this bit. When the kernel sees it, it knows not to run software decryption algorithms. |
| RX_FLAG_MMIC_STRIPPED | 3 | MIC stripped. The hardware not only decrypted but also removed the trailing MIC checksum. The kernel will calculate the MIC accordingly. |
| RX_FLAG_IV_STRIPPED | 4 | IV/ICV stripped. After hardware decryption, the header IV (Initialization Vector) and trailing ICV (Integrity Check Value) were both removed. Setting this bit means the data you're giving the kernel is "clean" plaintext payload. |
| RX_FLAG_FAILED_FCS_CRC | 5 | FCS check failed. This packet is bad. Although you received it, the FCS (Frame Check Sequence) doesn't match. The kernel will usually silently drop it. |
| RX_FLAG_FAILED_PLCP_CRC | 6 | PLCP check failed. The physical layer preamble and signal header are wrong. This is usually caused by a very weak signal. |
| RX_FLAG_MACTIME_START | 7 | Timestamp valid (start time). The rx_status->mactime field stores the time the first symbol of the frame arrived. Critical for scenarios requiring precise ranging or synchronization (e.g., certain positioning protocols). |
| RX_FLAG_SHORTPRE | 8 | Short preamble. Uses the 802.11b Short Preamble mode. |
| RX_FLAG_HT | 9 | High Throughput (11n). This is an 802.11n frame. Note that in this case, the rate_idx field stores the MCS index, not the traditional legacy rate. |
| RX_FLAG_40MHZ | 10 | HT40 mode. Uses 40MHz channel bandwidth. |
| RX_FLAG_SHORT_GI | 11 | Short guard interval. Uses the 400ns Short Guard Interval, slightly faster than the 800ns GI. |
| RX_FLAG_NO_SIGNAL_VAL | 12 | No signal strength. The hardware didn't measure signal strength (RSSI), or doesn't support it at all. The rx_status->signal field is invalid at this point. |
| RX_FLAG_HT_GF | 13 | HT Greenfield. This is 802.11n Greenfield mode, without the Training Field added for backward compatibility with 802.11a/g. Fastest speed, but legacy devices can't understand it. |
| RX_FLAG_AMPDU_DETAILS | 14 | A-MPDU details known. This packet is part of an aggregated frame. In this case, ampdu_ref in rx_status must be valid, used to distinguish different A-MPDU bursts. |
| RX_FLAG_AMPDU_REPORT_ZEROLEN | 15 | Driver reports zero-length subframes. This is a somewhat special hardware behavior where some hardware reports empty packets within aggregated frames. |
| RX_FLAG_AMPDU_IS_ZEROLEN | 16 | This is a zero-length subframe. Corresponds to the report above, marking this packet itself as empty, typically used for monitoring. |
| RX_FLAG_AMPDU_LAST_KNOWN | 17 | Last frame known. The driver knows this is the last packet of this A-MPDU burst. |
| RX_FLAG_AMPDU_IS_LAST | 18 | This is the last frame. This packet is the terminator of this A-MPDU. |
| RX_FLAG_AMPDU_DELIM_CRC_ERROR | 19 | Delimiter CRC error. In A-MPDU, there are Delimiters between subframes. If this Delimiter's CRC fails, it means the hardware's parsing synchronization has gone wrong. |
| RX_FLAG_AMPDU_DELIM_CRC_KNOWN | 20 | Delimiter CRC value valid. If set, it means the rx_status->ampdu_delimiter_crc field stores that calculated CRC value. |
| RX_FLAG_MACTIME_END | 21 | Timestamp valid (end time).mactime records the time the last symbol of the frame (including FCS) was fully received. Mutually exclusive with the START flag. |
| RX_FLAG_VHT | 22 | Very High Throughput (11ac). This is an 802.11ac frame. rate_idx now stores the VHT MCS index. |
| RX_FLAG_80MHZ | 23 | VHT80 mode. 802.11ac, using 80MHz bandwidth. |
| RX_FLAG_80P80MHZ | 24 | VHT80+80 mode. Uses two non-contiguous 80MHz channels. This is an advanced feature of 802.11ac. |
| RX_FLAG_160MHZ | 25 | VHT160 mode. Contiguous 160MHz bandwidth. Not only does it require hardware support, but it also depends on whether local regulations allow you to use such a wide band. |
Chapter Echo
Well, that's the last piece of the wireless networking puzzle in this book.
Looking back at this chapter, we were essentially rebuilding a Tower of Babel inside the Linux kernel. At the physical layer (PHY), we talked to hardware through ieee80211_hw; at the MAC layer, we established the order of CSMA/CA through mac80211; and through the tug-of-war between FullMAC and SoftMAC, we saw the driver developer's dilemma.
We saw how the 802.11 protocol family evolved step by step from simple yielding (CSMA/CA), to greed (802.11n aggregation), and finally to intelligence (802.11s Mesh routing).
Remember that question from the beginning of this chapter — why is Wi-Fi so complicated in Linux? Now the answer is clear: because it tries to simulate a reliable, high-speed point-to-point dedicated line over a noisy, unreliable shared medium.
- FullMAC shoves the complexity into a black box — hardware vendors take the bullet for you, but they also tie your hands.
- SoftMAC (mac80211) hands the complexity to the kernel — you have to handle TIM, buffering, and reordering yourself, but you gain absolute control over the airwaves.
Next time you look at the rapid-fire output of iw, or stumble upon ieee80211_rx: mmic_error in the kernel logs, I hope you'll realize: this isn't just a log line — it's the battle damage report of this chip fighting through chaotic radio waves just to get that one bit of data from the antenna into memory.
This chapter is over. Retract your antennas — see you in the next chapter. There, we'll switch from "invisible waves" to "visible but intangible fiber optics" — RDMA. There, the kernel won't even intervene in data transfer; it merely paves the way.
Exercises
Exercise 1: Understanding
Question: In Infrastructure BSS mode, when a wireless client (STA) sends a data frame to an access point (AP), and that data ultimately needs to be forwarded to an external wired network, what values should the ToDS and FromDS bits in the 802.11 MAC header's Frame Control field be set to?
Answer and Analysis
Answer: ToDS = 1, FromDS = 0
Analysis: According to the 802.11 specification, the ToDS (Distribution System) bit indicates that the data frame is destined for the distribution system (i.e., the AP), and the FromDS bit indicates that the data frame comes from the distribution system. When a client sends data to the AP (to be forwarded out), the data is entering the distribution system, so ToDS is set to 1 and FromDS is set to 0. Conversely, when the AP sends data to the client, FromDS is 1 and ToDS is 0.
Exercise 2: Understanding
Question: When an access point (AP) in the mac80211 subsystem receives a Null Data Packet from a client and finds that the Power Management bit in the Frame Control field is 1, what does the AP do next?
Answer and Analysis
Answer: The AP will mark the client as having entered sleep mode and begin buffering unicast data packets destined for that client into the ps_tx_buf buffer.
Analysis: A Null Data Packet contains no payload and is primarily used for power management notification. According to the Power Save Mode mechanism, when the PM bit is 1, it indicates the station is about to enter power-save mode. Upon receiving this notification, the AP will store subsequent unicast packets destined for that station in the station's corresponding ps_tx_buf queue (up to 128 packets), until the station wakes up and retrieves the data via PS-Poll or a Null Data frame.
Exercise 3: Application
Question: Suppose you are developing a FullMAC wireless network card driver. Compared to a SoftMAC (using mac80211) driver, what are the main differences in logical responsibility for handling 802.11 management frames (such as Association Request, Authentication) in kernel space?
Answer and Analysis
Answer: In the FullMAC driver architecture, MLME (MAC Layer Management Entity) logic is primarily handled by firmware or hardware, and the kernel driver usually only handles data-plane transmission and basic control; in the SoftMAC (mac80211) architecture, MLME logic (such as association, authentication, and scanning state machines) is jointly handled by the mac80211 subsystem in the kernel and user-space daemons (such as wpa_supplicant/hostapd).
Analysis: FullMAC devices handle most MAC layer management functions themselves (such as state maintenance and frame exchanges), making the kernel driver relatively lightweight. mac80211 is a SoftMAC framework that places the complex protocol state machine in kernel software, thereby unifying the behavior of different hardware and allowing more flexible software-defined features (such as the complex routing of Mesh networks).
Exercise 4: Thinking
Question: IEEE 802.11n introduced two aggregation technologies, A-MPDU (Aggregated MAC Protocol Data Unit) and A-MSDU (Aggregated MAC Service Data Unit), to improve throughput. From the perspective of "retransmission overhead," why is A-MPDU generally more suitable than A-MSDU for wireless environments with high bit error rates?
Answer and Analysis
Answer: Because A-MPDU's retransmission granularity is at the MPDU (MAC Protocol Data Unit) level, while A-MSDU's retransmission granularity is the entire aggregated MSDU. In A-MPDU, if only one subframe in the aggregated block errors or is lost, the receiver can use the Block Ack mechanism to request retransmission of only that one erroneous subframe, without needing to retransmit the entire aggregated block. Conversely, A-MSDU packs multiple MSDUs into one large frame — if a bit error occurs during transmission causing CRC check failure, the entire large frame must be retransmitted, which significantly reduces effective throughput when channel quality is poor (high bit error rate).
Analysis: This question tests deep thinking about low-level link efficiency. Although A-MSDU reduces header overhead, its retransmission mechanism is "all-or-nothing." A-MPDU, paired with the Block Ack mechanism, provides finer-grained error recovery capability (Selective Retransmission). In unreliable wireless channels, the efficiency gains from this characteristic typically outweigh its slightly higher header overhead.
Key Takeaways
The Linux kernel treats wireless networking as an independent subsystem mac80211, rather than a simple variant of Ethernet, primarily due to the high unreliability of the wireless physical medium (frequent packet loss) and its unique medium access method (shifting from collision detection CD to collision avoidance CA). To cope with the rapid iteration of 802.11 protocols, Linux mainstream adopts the SoftMAC architecture: complex MAC layer logic (such as frame construction, encryption, and retransmission) is uniformly taken over by the kernel, while drivers only handle hardware interaction, yielding extremely high flexibility and control.
The 802.11 MAC header is far more complex than Ethernet's, containing up to 4 address fields (MAC Header 4 Addresses) and rich frame control bits. These structures define the frame's specific identity (management/control/data), direction (ToDS/FromDS), and behavioral attributes (such as power save mode, retransmission flag). This complexity stems from traffic forwarding requirements (AP forwarding data) and special mechanism needs in wireless networks. Driver developers must deeply understand these fields to correctly parse and construct data frames.
In Infrastructure mode, a client must complete two steps — authentication and association — before accessing the network and obtaining a unique AID (Association ID). To address the battery life concerns of mobile devices (such as phones and laptops), the protocol designed a meticulous Power Save Mode: clients notify the AP of sleep via a Null Data frame flag bit, the AP maintains a ps_tx_buf for each station to buffer unicast packets, and uses the TIM (Traffic Indication Map) bitmap in Beacon frames to notify clients that "goods are waiting for pickup," after which clients actively "pick up" their data via PS-Poll frames.
MLME (MAC Layer Management Entity) is responsible for handling the underlying logic of network discovery and maintenance. To find an AP, a device performs Scanning: passive scanning (silently listening for Beacons) must be used in the 5GHz radar band, while active scanning (sending Probe Requests and waiting for Probe Responses) is typically used in normal bands. When a client discovers an AP with a better signal while moving, it triggers the Roaming mechanism, establishing a connection with the new AP by sending a Reassociation Request frame that includes the original AP's address, achieving seamless network handoff.
At the kernel implementation level, the mac80211 framework decouples generic logic from hardware details. The core structure ieee80211_hw serves as the hardware's abstract ID card, while the ieee80211_ops callback function set defines the driver's operation specifications (such as tx for transmitting packets, config for configuring channels, and start for starting the device). Each connected peer station corresponds to a sta_info structure in the kernel — it not only stores the MAC address and statistics but also manages critical state such as the power-save buffer queue (ps_tx_buf), making it the core data structure for drivers to maintain connection relationships.