Skip to main content

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 in IEEE80211_AMPDU_TX_START.
    • Note: This is asynchronous. The driver must call back ieee80211_start_tx_ba_cb() or the _irqsafe variant 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(), passing IEEE80211_AMPDU_TX_STOP. The driver must then call back ieee80211_stop_tx_ba_cb() to complete cleanup.
  • static void ieee80211_send_addba_request(...)

    • Purpose: Sends an ADDBA Request management frame (Action Frame).
    • Parameters: buf_size determines the receiver's aggregation window size (typically 64), and timeout determines the session timeout.
  • void ieee80211_process_addba_request(...)

    • Purpose: Handles a received ADDBA request on the receiver side. This is the core logic of mac80211 and is usually not called by the driver — it's automatically triggered by the kernel upon receiving an Action Frame.
  • 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: ssid and ie (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 dst in the Mesh routing table.
    • Returns: NULL if not found, or a mesh_path structure if found. This is the first step in forwarding data.
  • 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.
  • 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 metric in 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_hw device structure and the driver's private data priv. The beginning of everything.
  • 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: changed specifies what to change (e.g., use IEEE80211_CONF_CHANGE_CHANNEL to change the channel). This function typically drops down to the driver's config() 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_status from 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 to mac80211.
  • 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 dot11FrameDuplicateCount counter 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 ConstantBitTrue Meaning and Practical Tips
RX_FLAG_MMIC_ERROR0Michael 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_DECRYPTED1Hardware 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_STRIPPED3MIC stripped.
The hardware not only decrypted but also removed the trailing MIC checksum. The kernel will calculate the MIC accordingly.
RX_FLAG_IV_STRIPPED4IV/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_CRC5FCS 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_CRC6PLCP check failed.
The physical layer preamble and signal header are wrong. This is usually caused by a very weak signal.
RX_FLAG_MACTIME_START7Timestamp 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_SHORTPRE8Short preamble.
Uses the 802.11b Short Preamble mode.
RX_FLAG_HT9High 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_40MHZ10HT40 mode.
Uses 40MHz channel bandwidth.
RX_FLAG_SHORT_GI11Short guard interval.
Uses the 400ns Short Guard Interval, slightly faster than the 800ns GI.
RX_FLAG_NO_SIGNAL_VAL12No 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_GF13HT 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_DETAILS14A-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_ZEROLEN15Driver reports zero-length subframes.
This is a somewhat special hardware behavior where some hardware reports empty packets within aggregated frames.
RX_FLAG_AMPDU_IS_ZEROLEN16This is a zero-length subframe.
Corresponds to the report above, marking this packet itself as empty, typically used for monitoring.
RX_FLAG_AMPDU_LAST_KNOWN17Last frame known.
The driver knows this is the last packet of this A-MPDU burst.
RX_FLAG_AMPDU_IS_LAST18This is the last frame.
This packet is the terminator of this A-MPDU.
RX_FLAG_AMPDU_DELIM_CRC_ERROR19Delimiter 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_KNOWN20Delimiter CRC value valid.
If set, it means the rx_status->ampdu_delimiter_crc field stores that calculated CRC value.
RX_FLAG_MACTIME_END21Timestamp 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_VHT22Very High Throughput (11ac).
This is an 802.11ac frame. rate_idx now stores the VHT MCS index.
RX_FLAG_80MHZ23VHT80 mode.
802.11ac, using 80MHz bandwidth.
RX_FLAG_80P80MHZ24VHT80+80 mode.
Uses two non-contiguous 80MHz channels. This is an advanced feature of 802.11ac.
RX_FLAG_160MHZ25VHT160 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.