Before an 802.11 device can be used, it must become associated with a
network by exchanging a series of management frames with the Access
Point. In some cases there is additional security handshaking required
after association. gPXE's 802.11 layer handles this transparently by
always having the association task running if association has not yet
succeeded, and using the link-up bit in the wrapping
indicate association status. Commands such as DHCP or autoboot will
therefore block on association success, and time out if an underlying
error condition rather than a transient failure is responsible for
association not working.
After association has succeeded, reassociation will be attempted upon a change in the SSID setting. It is not necessary to reassociate when the encryption key is changed, because association can only succeed with an invalid key on an open-system WEP network, and rekeying does not require reassociation in that case. If the user specified the encryption key erroneously at first, association will fail and be retried indefinitely, and will succeed soon after the correct key is provided.
Association is handled in a separate gPXE process, which runs through a series of states in predetermined order:
- First, all radio channels are scanned for beacon packets from the SSID specified in the network device's SSID setting. If no suitable Access Point is found, association restarts; if multiple APs for the same network are found, gPXE chooses the one with the strongest received signal strength indication. This is done using the
net80211_probe_*()functions, which are exported to allow for user-level code like
iwlistto use them as well. Once a good AP has been found, the
NET80211_PROBEDbit is set in
dev→state, and the
dev→ctxunion should henceforth be understood to contain an association context rather than a probe context.
- Assuming a suitable AP has been found, the
net80211_devicestate (BSSID, ESSID, supported rates) is set to reflect it and an authentication packet is sent using the Open System authentication method. If the access point uses WEP and requires Shared Key authentication, it will respond with a failure indication and gPXE will attempt Shared Key authentication instead. If that fails as well, association restarts. Otherwise, the
NET80211_AUTHENTICATEDbit is sert in
dev→state. If the AP does not respond within one second, the authentication packet will be resent a few times.
- Once authentication packets have been exchanged, gPXE sends an association request to the AP, which replies with an association reply. If the reply shows an error indication, association restarts; otherwise, we are now considered to be associated with the AP, and the
NET80211_ASSOCIATEDbit is set in
- After association, depending on the type of security for the network with which we are associating, it may be necessary to perform additional steps collectively termed “security handshaking”:
- If we are connecting to a WPA-Enterprise network, we will receive an EAP-Start packet. This is handed off to the appropriate EAP protocol handler, which negotiates authentication and provides a PMK to the WPA core.
- If we are connecting to any type of WPA network, we will receive an EAPOL-Start packet commencing the Four-Way Handshake, either immediately after association (for WPA-Personal) or after EAP-Success (for WPA-Enterprise). During the Four-Way Handshake, temporal keys are derived and installed to handle encryption and decryption for data traffic.
- Once security handshaking is complete, as indicated by a positive return from the security handshaker's
step()function (see below), the
NET80211_CRYPTO_SYNCEDbit is set in
dev→stateand the wrapping
net_deviceis set link-up. Data traffic can now proceed.
- WPA networks may periodically rekey, so the WPA core installs a protocol handler for EAPOL packets to handle such rekeying transparently.
The gPXE 802.11 layer includes abstract support for encrypted wireless networks, as well as implementations of that support for WEP- and WPA-protected networks. We introduce two abstractions: a security handshaker and a wireless cryptosystem.
A security handshaker is responsible for everything that must occur
before encrypted packets can be sent and received: deriving a master
encryption key from the user's specified
authenticating to the Access Point by some specified means, possibly
deriving more keys from the master key and using them instead of or in
addition to the master key, and specifying encryption keys and a
cryptosystem to use them for packet-level security. The currently
implemented security handshakers are “trivial”, WPA-Personal (PSK /
pre-shared key), and WPA-Enterprise (802.1X / EAP). The trivial
handshaker, used for WEP, just does some sanity checks on the
user-specified key and then installs it directly without a further
exchange with the AP. The WPA handshakers interface with a common WPA
core, supplying it with a pairwise master key derived either from the
user's passphrase (for Personal) or the EAP Master Session Key (for
It is not possible to manually specify the security handshaker to be
used for a network; it is autodetected by
net/80211/sec80211.c. gPXE's linker tables are searched for a
handshaker of the requisite type, a new structure is allocated with
space for the requested amount of private data, and
dev→handshaker is set to point at it. The
pointer remains valid from the time the handshaker's
is called to the time its
stop() method is called.
Additional security handshakers are declared using gPXE's linker table
mechanism, by defining a structure of type
tagged with the
_net80211_handshaker attribute, containing
the following fields:
protocol: one of the enumeration values of
net80211_security_protoindicating the type of network with which the handshaker should be used. For a new type of network it is necessary to modify the function
priv_len: the size of the private data area to allocate. When any of the methods below are called,
dev→handshaker→privwill point to this many bytes of dynamically allocated memory.
init(): a method called before the association process starts, to set up whatever is needed for association to succeed. In WPA, this sets
dev→rsn_ieto a pointer to the RSN information element that is to be advertised in the association request frame. In the trivial handshaker, this method installs the cryptosystem directly, and
start(): a method called immediately before the association request frame is sent, to set up things so that security packets received in response to it will be handled appropriately.
step(): called continually by the association process as long as it returns 0. It is expected to process security handshaking packets, or monitor the progress of their processing by an asynchronous handler, and indicate when a definitive success or failure state has been reached.
change_key(): called whenever the
netX/keysetting might have changed, to update the cryptosystem with the new key if that makes sense for this type of handshaker. (It does for WEP/trivial, but not for WPA, because it's not possible to associate with the wrong key on WPA.)
stop(): called just before the handshaker is freed due to reassociation or closing of the 802.11 device. This method can free memory and clean up resources.
When a security handshaker has finished negotiating whatever handshaking is necessary, it will usually need to finish its job by setting up the 802.11 device to use some sort of cryptography on all future data packets. This is accomplished by the function:
#include <gpxe/sec80211.h> int sec80211_install ( struct net80211_crypto **which, enum net80211_crypto_alg crypt, const void *key, int len, const void *rsc );
Install the 802.11 cryptosystem of type
crypt for packets handled
which, which is
&dev→crypto for unicast RX and all TX
&dev→gcrypto for broadcast RX packets. The encryption
len bytes and is pointed to by
key. If applicable to the
cryptosystem in question, the initial receive sequence counter is pointed
rsc with a cryptosystem-dependent length;
NULL can be passed
for an RSC of zero.
The currently defined values for
NET80211_CRYPT_NONE: an open network with no security
NET80211_CRYPT_WEP: WEP encryption
NET80211_CRYPT_TKIP: TKIP, the original encryption method for WPA
NET80211_CRYPT_CCMP: CCMP, a better encryption method added in WPA2
NET80211_CRYPT_UNKNOWN: anything else
Supporting a new crypto method, if one ever comes into use, is a
matter of updating
net/80211/sec80211.c to recognize it (if it
uses WPA handshaking, edit the
rsn_cipher_map array at the
beginning of that file) and adding a cryptosystem to implement it.
Similarly to security handshakers, cryptosystems are provided using a
linker table: define a
struct net80211_crypto tagged with
_net80211_crypto and including some or all of the following
net80211_crypto_algenumeration value implemented
priv_len: the size of private data to allocate
init(): initialize cryptosystem with a specific key and RSC
encrypt(): make an encrypted copy of an I/O buffer containing a frame to transmit
decrypt(): make a decrypted copy of an I/O buffer containing an encrypted frame that was received
The cryptosystem implementations are expected to be “pure”; that is,
they should not need to access any properties of the 802.11 device
that are not contained in the frame headers themselves. To enforce
this expectation, they are not provided with a
The implementation of
sec80211_install simply searches for a
cryptosystem implementing the requested algorithm, allocates storage
for it in
dev→gcrypto, and calls its
init() method with the key and RSC it is given.
The 802.11 code is extensively documented using Doxygen comments, on both API and internal functions. To further understand what it's doing, I recommend the following sources:
- The Linux wireless code (in
net/mac80211/and, to a lesser extent,
net/wireless/); while much more complicated than gPXE's implementation, it is an excellent, robust, and well-documented example of an 802.11 stack.
- The source for the Linux daemon program
wpa_supplicant, which handles the WPA Four-Way Handshake implemented by gPXE in
- The IEEE standard for 802.1X. This defines some data structures and semantics that are used in the WPA 4-Way Handshake.
The standard is divided into 19 “clauses” (roughly chapters) and 16 “annexes” (appendices). You certainly do not need to read all of them. The useful ones are
- Clause 3 (Definitions) and Clause 4 (Abbreviations and acronyms). Read these many times, and frequently refer to them when the main text gets impenetrable. The worst part of 802.11-2007 is the incredibly frequent use it makes of obscure acronyms; these are your guide to demystifying them.
- Clause 5 (General description). Read it once, briefly, but it's not worth spending much time on.
- Clause 7 (Frame formats) is exactly what it says: bit-level detail about all the types of frames you can use. The standard doesn't tell you what's commonly used; for instance, fragmentation and RTS/CTS are just about never used in practice, and you can get away without implementing QoS perfectly fine.
- Clause 8 (Security) contains all the necessary information for dealing with encrypted networks. 8.2.1 discusses WEP, 8.3 discusses what gPXE calls wireless cryptosystems for WPA, and 8.5-8.6 discuss what we call the security handshaking side of WPA. Note that the semantics given are all for RSN-style encrypted networks; before the standard for WPA was published, a different style was used, called vendor-style or (confusingly) WPA-style. The wpa_supplicant source code is the best reference I've found for the behavior of “old” WPA; I've tried to highlight the differences in gPXE.
- Clause 9 (MAC sublayer functional description) contains mostly things that are handled in hardware, but see 9.2 and 9.4-9.8.
- Clause 10 (Layer management) is basically a suggested API for providing the 802.11 services to software. There is no technical reason to implement it over any other, but other parts of the standard might refer to “submits MLME-ASSOCIATE.request” instead of “sends an association request frame”.
- Clause 11 (MLME) contains information about the association process. Only 11.1-11.3 are generally useful; the rest covers QoS and spectrum management issues that don't really need to be implemented.
- The rest of the spec deals with PHY-layer details.
- Annex H (RSNA reference implementation and test vectors) was useful in checking the security code.
If you run into something you can't figure out, email me (username oremanj located at the domain rwcr in the TLD .net) and I'll be happy to try and clarify.