In an earlier article I gave a high level overview of Broadcast Integrity Protocol, and the basics of the Linux WiFi stack, now it’s time to get our hands dirty diving into the Linux kernel mac80211 source code.
All code snippets are taken from the latest LTS kernel source tree1, which at the time of writing is v6.6.18, and the 2.10 version of hostapd2. The current stable LTS release may have changed since this article was written. All references to the IEEE 802.11 standard are from the 2020 version3.
The next two articles in this series will look into how BIP is configured for beacon frames, how beacons are created, then how beacons including the MME are transmitted and received/validated in the context of the mac80211 based Linux stack.
Summary
There are four main areas to consider with BIP and the Linux WiFi stack, being: configuration of PMF/beacon protection, creation of beacon frames, and transmit and receive of beacons including creation and validation of the MME. This functionality is split between userspace and kernelspace, across both hostapd/wpa_supplicant and cfg80211/mac80211.
Configuration of beacon protection and Protected Management Frames (PMF) is via hostapd.conf. In addition, the hostapd nl80211 driver queries the mac80211 device specific driver as to whether it supports beacon protection.
Creation of the beacon frame for mac80211 is within hostapd, with the creation of the ‘pre-TIM’ and ‘post-TIM’ buffers containing the majority of beacon content, that is, a beacon template. This template and associated metadata is then passed into the kernel, where they are retained in order to create a new beacon at the request of the mac80211 device specific driver.
Transmit and receive and of beacon frames, and the associated MME creation and validation will be detailed in a follow-up article.
The following sections outline the configuration of BIP and creation of beacons with respect to hostapd and the mac80211 driver.
Configuration of PMF
Protected Management Frames (PMF) was introduced in the IEEE 802.11w addendum to the IEEE 802.11 standard in 2009, and rolled into the maintenance revision of IEEE 802.11 in 2012. Broadcast Integrity Protocol is one part of the overall PMF solution, and is supported by hostapd and mac80211.
The following diagram outlines the configuration options to support both PMF and BIP, as well as some of the important flags and functions (both userspace and kernelspace). These areas will be examined in further detail in this section.
Enabling of BIP and beacon protection is via the hostapd configuration file. The following screensnip show the interesting parts of the configuration file.
Note: hostapd uses the incorrect terminology in the config file, it refers to ‘MFP’ (Management Frame Protection) which was Cisco’s early work to protect management frames4. The correct acronym is ‘PMF’.
PMF optional or mandatory config
The ‘ieee80211w’ variable within hostapd specifies the level of support for PMF.
From the IEEE802.11 2020 edition, PMF support and usage is negotiated through the Management Frame Protection Capable (MFPC) and Management Frame Protection Required (MFPR) bits within the RSN capabilities field (section 9.4.2.24.4), which itself is part of the RSN IE (section 9.4.2.24).
The value configured in the 80211w configuration within hostapd/wpa_supplicant translates directly to these two bits, which are populated into the RSN IE capabilities field:
The rules for PMF and association are shown in table 12-5 of IEEE80211-2020.
Beacon protection config - userspace
As per the hostapd configuration file, even if beacon protection is enabled, the underlying driver must support beacon protection. Tracing back through the hostapd/wpa_supplicant code (wpa_supplicant/ctrl_iface.c), we see an internal flag ‘WPA_DRIVER_FLAGS_BEACON_PROTECTION’ is used to gate logic dealing with beacon protection. This is seen in the ‘GET_CAPABILITY’ functionality of wpa_cli:
If we trace this flag back further, we see the flag is set in the ‘capa→flags’ field in the wiphy_info_ext_feature_flags function in src/drivers/driver_nl80211_capa.c:
Backtracing from the wiphy_info_ext_feature_flags function, the call path is thus:
hapd_init (i802_init callback) →
send_and_recv_msgs (NL80211_CMD_GET_WIPHY command) →
send_and_recv → (userspace → kernelspace via netlink) →
wiphy_info_handler (netlink callback registered via libnl) →
Note: there are other code paths which lead to this point as well - find them with cscope!
The capability flags are filled based on the capabilities advertised by cfg80211 through the netlink NL80211_CMD_GET_WIPHY command (called from ‘wpa_driver_nl80211_get_info’), which returns a series of attributes, the attribute of interest for PMF being NL80211_ATTR_EXT_FEATURES. This attribute contains flags as specified in the enum nl80211_ext_feature_index within include/uapi/linux/nl80211.h. The capability flag of interest is NL80211_EXT_FEATURE_BEACON_PROTECTION, which from the nl80211 documentation states:
The driver supports Beacon protection and can receive key configuration for BIGTK using key indexes 6 and 7.
The capabilities flags from this attribute are copied across to the ‘drv_flags’ variable when an interface is created.
Beacon protection config - kernelspace
On the kernel side of things, the cfg80211 module accepts the NL80211_CMD_GET_WIPHY command which is a callback in the nl80211_ops array, pointing to nl80211_get_wiphy. This then chains into sending a response NL80211_NEW_WIPHY message via the ‘nl80211_send_wiphy’ function.
The nl80211_send_wiphy function fills out the NL80211_NEW_WIPHY message based on the flags advertised by the underlying mac80211 driver. This is done inside the ‘case 12:’ switch point, line 2851.
The call to get the capabilities via netlink is synchronous, and does not come into the hostapd driver via the netlink event code, the return point at userspace is the callback installed via libnl, the wiphy_info_handler function.
A note on driver support
It should be noted that from a search of the 6.6.18 LTS kernel source tree, there are two mac80211 drivers which support BIP (those that set the NL80211_EXT_FEATURE_BEACON_PROTECTION flag), being the Intel iwlwifi driver(s) and the mac80211_hwsim driver.
Beacon creation
Userspace
Now that we’ve unravelled the control path for BIP, let’s take a look at how the beacon is created and how BIP impacts this code path.
The following diagram outlines the key structures, flags and functions at both userspace and kernelspace, which are involved in beacon creation.
Beacon creation is a combination of userspace and kernelspace working together. For the purposes of this article, we are discussing the Linux WiFi stack running with the mac80211 driver via nl80211.
When configuring hostapd to use nl80211, the macro ‘NEED_AP_MLME’ is set to ‘y’ (src/drivers/drivers.mak). This macro is used extensively within the hostapd source, do a quick search using grep or cscope. The NEED_AP_MLME macro implies that the userspace hostapd will create the beacon templates for use by the kernel.
Note: a beacon template is created as the full contents of an individual beacon cannot be fully determined ahead of time by high-level code. Examples of fields and IEs which need filling in as close to the transmission of the frame as possible are the timestamp (TSF) field, sequence/fragment number, and the TIM IE.
The beacon template is created inside the ‘ieee802_11_build_ap_params’ function (src/ap/beacon.c file), and consists of a head (prior to the TIM IE) and tail (post TIM IE) section. These two sections are filled out to the best of hostapd’s knowledge.
In addition to the head and tail sections of the beacon, the ieee802_11_build_ap_params function also sets up a metadata ‘params’ field which contains relevant information about the beacon such as pointers to the head and tail buffers, basic rates, SSID etc. These fields are contained within the ‘wpa_driver_ap_params’ structure.
The wpa_driver_ap_params structure is then passed into the driver via the ‘set_ap’ callback, which in the case of nl80211 points to ‘wpa_driver_nl80211_set_ap’:
The wpa_driver_nl80211_set_ap function translates from the internal wpa_driver_ap_params structure to the netlink equivalent NL80211_CMD_SET_BEACON command.
This is all very interesting, but where does BIP fit in here? If we search once again in the hostapd source code for the beacon protection flag (WPA_DRIVER_FLAGS_BEACON_PROTECTION) we find this one interesting part of the code which is actually modifying part of the extended capabilities field (section 9.4.2.26 of IEEE802.11 2020), in the function ‘hostapd_ext_capab_byte’.
…
In this screensnip we see that in bits 80-87 (case 10), and if ‘beacon_prot’ is enabled and the driver supports beacon protection, set bit 84 to advertise beacon protection. This is consistent as per table 9-153 of IEEE802.11 2020.
The ‘hostapd_ext_capab_byte’ function is called from ‘hostapd_eid_ext_capab’ which in turn is called from ‘ieee802_11_build_ap_params’.
Kernelspace
On the kernel side of the beacon creation, the entry point of the NL80211_CMD_SET_BEACON command is within the ‘nl80211_set_beacon’ function. This function performs validation/verification of the incoming netlink command, translates it into the ‘struct cfg80211_beacon_data’ format, and eventually calls into the ‘rdev_change_beacon’ function, which in turn invokes the ‘change_beacon’ callback (part of the cfg80211_ops struct), which for mac80211 points to the ‘ieee80211_change_beacon’ function:
This function does more verification/validation, updates internal state, then chains into ‘ieee80211_link_info_change_notify’. ieee80211_link_info_change_notify then calls ‘drv_link_info_changed’, which then calls either the ‘link_info_changed’ or ‘bss_info_changed’ callbacks registered by the mac80211 driver. This is the lowest point in the common kernel code, the device driver then deals with the hardware specifics for beacon update such as programming registers, sending messages to the lower MAC etc. An example of the bss_info_changed callback is in the ath12k driver, in ‘ath12k_mac_op_bss_info_changed’.
Once again, all very interesting, but what about BIP? Where’s my protected beacon?! Note that the MME for each beacon is generated just prior to transmission, and will be calculated once the entire beacon is in a ready-to-transmit form. This includes populating rapidly changing IEs such as the TIM, which is filled in ‘just-in-time’, not at template creation time.
The transmission and reception, and associated creation and validation of the MME will be discussed in the next article.
Conclusion
This article gave an overview of how beacons are configured and beacon templates created in the context of the Linux WiFi stack using mac80211. Both configuration of PMF/beacon protection and creation of the beacon templates involves userspace (hostapd) and kernelspace (mac80211).
The transmit and receive, and corresponding creation and validation of the MME will be covered in my next article, including investigation into potential issues in the code, as well as how beacon transmission and reception work in the context of the mac80211_hwsim virtual driver.
I hope you enjoyed this article, please subscribe to receive these articles directly to your inbox!
Constructive feedback is always welcome. Please tell me where I got things wrong or incomplete so I can improve the article quality.
Linux Stable tree, tag v6.6.18 https://gitlab.com/linux-kernel/stable/-/tree/v6.6.18?ref_type=tags
hostapd source code online git tree, tag hostap_2_10 https://w1.fi/cgit/hostap/tree/?h=hostap_2_10
IEEE Standard for Information Technology — Telecommunications and Information Exchange between Systems Local and Metropolitan Area Networks — Specific Requirements.
Part 11: Wireless LAN Medium Access Control (MAC) and Physical Layer (PHY) Specifications (IEEE Std 802.11™️‐2020) - https://ieeexplore.ieee.org/document/9363693