[802.11] Clean up, document, and add helper inline functions to ieee80211.h
[people/oremanj/gpxe.git] / src / include / gpxe / ieee80211.h
index 911c7a8..b00b278 100644 (file)
@@ -12,101 +12,302 @@ FILE_LICENCE(GPL2_OR_LATER);
 
 /* Maximum lengths of things: */
 
-/* Maximum length of `data' field in frame: doesn't include any crypto
-   overhead, but DOES include the 802.3 LLC + SNAP headers in data frames! */
+/** Maximum length of frame payload
+ *
+ * This does not include cryptographic overhead, which can be up to 20
+ * bytes, but it DOES include the 802.2 LLC/SNAP headers that are used
+ * on data frames (but not management frames).
+ */
 #define IEEE80211_MAX_DATA_LEN          2304
-/* Length of said 802.3 LLC + SNAP headers. */
+
+/** Length of LLC/SNAP headers on data frames */
 #define IEEE80211_LLC_HEADER_LEN       8
-/* Amount of crypto overhead there might be. */
-#define IEEE80211_MAX_CRYPTO_HEADER    8    /* TKIP and CCMP */
-#define IEEE80211_MAX_CRYPTO_TRAILER    12   /* TKIP: 8-byte MIC, 4-byte ICV */
-#define IEEE80211_MAX_CRYPTO_OVERHEAD  20   /* HEADER + TRAILER */
-/* Number of bytes of real data we can put in one non-fragmented frame. */
-#define IEEE80211_MAX_FRAME_DATA       2296 /* DATA_LEN - LLC_HEADER_LEN */
 
-/* Frame header lengths - the LLC header is separate. We should never see
-   a frame with the maximum header length; it's included for completeness. */
-#define IEEE80211_TYP_FRAME_HEADER_LEN 24   /* for non-QoS, not-between-APs */
-#define IEEE80211_MAX_FRAME_HEADER_LEN 32   /* 4-address QoS format */
+/** Maximum cryptographic overhead before encrypted data */
+#define IEEE80211_MAX_CRYPTO_HEADER    8
+
+/** Maximum cryptographic overhead after encrypted data */
+#define IEEE80211_MAX_CRYPTO_TRAILER    12
+
+/** Total maximum cryptographic overhead */
+#define IEEE80211_MAX_CRYPTO_OVERHEAD  20
 
-#define IEEE80211_MAX_FRAME_LEN         2356 /* data + crypto + header */
+/** Bytes of network-layer data that can go into a regular data frame */
+#define IEEE80211_MAX_FRAME_DATA       2296
+
+/** Frame header length for frames we might work with
+ *
+ * QoS adds a two-byte field on top of this, and APs communicating
+ * with each other in Wireless Distribution System (WDS) mode add an
+ * extra 6-byte MAC address field, but we do not work with such
+ * frames.
+ */
+#define IEEE80211_TYP_FRAME_HEADER_LEN 24
+
+/** Theoretical maximum frame header length
+ *
+ * This includes the QoS and WDS Addr4 fields that we should never
+ * see.
+ */
+#define IEEE80211_MAX_FRAME_HEADER_LEN 32
 
+/** Maximum combined frame length
+ *
+ * The biggest frame will include 32 frame header bytes, 20 bytes of
+ * crypto overhead, and 2304 data bytes.
+ */
+#define IEEE80211_MAX_FRAME_LEN         2356
+
+/** Maximum length of an ESSID */
 #define IEEE80211_MAX_SSID_LEN          32
 
-/* Flags for Frame Control field, ieee80211_frame.fc: */
+/* ---------- Frame Control defines ---------- */
+
+/** 802.11 Frame Control field, Version bitmask */
 #define IEEE80211_FC_VERSION   0x0003
+
+/** Expected value of Version bits in Frame Control */
 #define  IEEE80211_THIS_VERSION  0x0000
+
+
+/** 802.11 Frame Control field, Frame Type bitmask */
 #define IEEE80211_FC_TYPE      0x000C
+
+/** Type value for management (layer-2) frames */
 #define  IEEE80211_TYPE_MGMT     0x0000
+
+/** Type value for control (layer-1, hardware-managed) frames */
 #define  IEEE80211_TYPE_CTRL     0x0004
+
+/** Type value for data frames */
 #define  IEEE80211_TYPE_DATA     0x0008
 
+
+/** 802.11 Frame Control field, Frame Subtype bitmask */
 #define IEEE80211_FC_SUBTYPE   0x00F0
-/* for management frames: */
+
+/** Subtype value for association-request management frames
+ *
+ * Association request frames are sent after authentication from the
+ * client to the Access Point to establish the client as part of the
+ * Access Point's network.
+ */
 #define  IEEE80211_STYPE_ASSOC_REQ    0x0000
+
+/** Subtype value for association-response management frames
+ *
+ * Association response frames are sent by the Access Point to confirm
+ * or deny the association requested in an association request frame.
+ */
 #define  IEEE80211_STYPE_ASSOC_RESP   0x0010
+
+/** Subtype value for reassociation-request management frames
+ *
+ * Reassociation request frames are sent by clients wishing to change
+ * from one Access Point to another while roaming within the same
+ * extended network (same ESSID).
+ */
 #define  IEEE80211_STYPE_REASSOC_REQ  0x0020
+
+/** Subtype value for reassociation-response management frames
+ *
+ * Reassociation response frames are sent by the Access Point to
+ * confirm or deny the swap requested in a reassociation request
+ * frame.
+ */
 #define  IEEE80211_STYPE_REASSOC_RESP 0x0030
+
+/** Subtype value for probe-request management frames
+ *
+ * Probe request frames are sent by clients to request that all Access
+ * Points on the sending channel, or all belonging to a particular
+ * ESSID, identify themselves by BSSID, supported transfer rates, RF
+ * configuration, and other capabilities.
+ */
 #define  IEEE80211_STYPE_PROBE_REQ    0x0040
+
+/** Subtype value for probe-response management frames
+ *
+ * Probe response frames are sent by Access Points in response to
+ * probe request frames, providing the requested information.
+ */
 #define  IEEE80211_STYPE_PROBE_RESP   0x0050
+
+/** Subtype value for beacon management frames
+ *
+ * Beacon frames are sent by Access Points at regular intervals,
+ * usually ten per second, on the channel on which they communicate.
+ * They can be used to probe passively for access points on a channel
+ * where local regulatory restrictions prohibit active scanning, or
+ * due to their regularity as a mechanism to determine the fraction of
+ * packets that are being dropped.
+ */
 #define  IEEE80211_STYPE_BEACON       0x0080
+
+/** Subtype value for disassociation management frames
+ *
+ * Disassociation frames are sent by either a client or an Access
+ * Point to unequivocally terminate the association between the two.
+ * They may be sent by clients upon leaving the network, or by an
+ * Access Point upon reconfiguration, among other reasons; they are
+ * usually more "polite" than deauthentication frames.
+ */
 #define  IEEE80211_STYPE_DISASSOC     0x00A0
+
+/** Subtype value for authentication management frames
+ *
+ * Authentication frames are exchanged between a client and an Access
+ * Point before association may be performed. Confusingly, in the most
+ * common authentication method (Open System) no security tokens are
+ * exchanged at all. Modern 802.11 security handshaking takes place
+ * after association.
+ */
 #define  IEEE80211_STYPE_AUTH         0x00B0
+
+/** Subtype value for deauthentication management frames
+ *
+ * Deauthentication frames are sent by either a client or an Access
+ * Point to terminate the authentication (and therefore also the
+ * association) between the two. They are generally more forceful than
+ * disassociation frames, sent for such reasons as a failure to
+ * set up security properly after associating.
+ */
 #define  IEEE80211_STYPE_DEAUTH       0x00C0
+
+/** Subtype value for action management frames
+ *
+ * Action frames are used to implement spectrum management and QoS
+ * features that gPXE currently does not support.
+ */
 #define  IEEE80211_STYPE_ACTION              0x00D0
-/* for control frames: */
+
+
+/** Subtype value for RTS (request to send) control frames */
 #define  IEEE80211_STYPE_RTS          0x00B0
+
+/** Subtype value for CTS (clear to send) control frames */
 #define  IEEE80211_STYPE_CTS          0x00C0
+
+/** Subtype value for ACK (acknowledgement) control frames */
 #define  IEEE80211_STYPE_ACK          0x00D0
-/* for data frames: */
+
+
+/** Subtype value for ordinary data frames, with no QoS or CF add-ons */
 #define  IEEE80211_STYPE_DATA         0x0000
+
+/** Subtype value for data frames containing no data */
 #define  IEEE80211_STYPE_NODATA       0x0040
 
-#define IEEE80211_FC_TODS       0x0100 /* to an access point */
-#define IEEE80211_FC_FROMDS     0x0200 /* from an access point */
-#define IEEE80211_FC_MORE_FRAG  0x0400 /* more fragments for this packet */
-#define IEEE80211_FC_RETRY      0x0800 /* this is a retransmission */
-#define IEEE80211_FC_PWR_MGMT   0x1000 /* set for powersave after this exchange */
-#define IEEE80211_FC_MORE_DATA  0x2000 /* more packets are queued */
-#define IEEE80211_FC_PROTECTED  0x4000 /* this frame is encrypted */
-#define IEEE80211_FC_ORDER      0x8000 /* "StrictlyOrdered service class" */
-
-/* Parts of Sequence Control field, ieee80211_frame.seq: */
-#define IEEE80211_SEQNR(seq)    ((seq) >> 4)
-#define IEEE80211_FRAG(seq)     ((seq) & 0x000F)
-#define IEEE80211_MAKESEQ(seqnr,frag) ((((seqnr) & 0xFFF) << 4) | ((frag) & 0xF))
-
-/* Generic data or management frame - non-QoS, not between APs. */
+
+/** 802.11 Frame Control field: To Data System flag
+ *
+ * This is set on data frames sent to an Access Point.
+ */
+#define IEEE80211_FC_TODS       0x0100
+
+/** 802.11 Frame Control field: From Data System flag
+ *
+ * This is set on data frames sent from an Access Point.
+ */
+#define IEEE80211_FC_FROMDS     0x0200
+
+/** 802.11 Frame Control field: More Fragments flag */
+#define IEEE80211_FC_MORE_FRAG  0x0400
+
+/** 802.11 Frame Control field: Retransmission flag */
+#define IEEE80211_FC_RETRY      0x0800
+
+/** 802.11 Frame Control field: Power Managed flag
+ *
+ * This is set on any frame sent by a low-power station that will go
+ * into a power-saving mode immediately after this frame. Access
+ * Points are not allowed to act as low-power stations.
+ */
+#define IEEE80211_FC_PWR_MGMT   0x1000
+
+/** 802.11 Frame Control field: More Data flag
+ *
+ * This is set on any frame sent by a station that has more data
+ * queued to be sent than is in the frame.
+ */
+#define IEEE80211_FC_MORE_DATA  0x2000
+
+/** 802.11 Frame Control field: Protected flag
+ *
+ * This is set on frames in which data is encrypted (by any method).
+ */
+#define IEEE80211_FC_PROTECTED  0x4000
+
+/** 802.11 Frame Control field: Ordered flag [?] */
+#define IEEE80211_FC_ORDER      0x8000
+
+
+/* ---------- Sequence Control defines ---------- */
+
+/** Extract sequence number from 802.11 Sequence Control field */
+#define IEEE80211_SEQNR( seq )         ( ( seq ) >> 4 )
+
+/** Extract fragment number from 802.11 Sequence Control field */
+#define IEEE80211_FRAG( seq )          ( ( seq ) & 0x000F )
+
+/** Make 802.11 Sequence Control field from sequence and fragment numbers */
+#define IEEE80211_MAKESEQ( seqnr, frag )       \
+       ( ( ( ( seqnr ) & 0xFFF ) << 4 ) | ( ( frag ) & 0xF ) )
+
+
+/* ---------- Frame header formats ---------- */
+
+/** An 802.11 data or management frame without QoS or WDS header fields */
 struct ieee80211_frame
 {
-       u16 fc;                 /**< Frame Control field */
+       u16 fc;                 /**< 802.11 Frame Control field */
        u16 duration;           /**< Microseconds to reserve link */
        u8 addr1[ETH_ALEN];     /**< Address 1 (immediate receiver) */
        u8 addr2[ETH_ALEN];     /**< Address 2 (immediate sender) */
        u8 addr3[ETH_ALEN];     /**< Address 3 (often "forward to") */
-       u16 seq;                /**< Sequence control/fragmentation */
-       u8 data[0];
+       u16 seq;                /**< 802.11 Sequence Control field */
+       u8 data[0];             /**< Beginning of frame data */
 } __attribute__((packed));
 
-/* The 802.3 link-layer header that begins the data, plus SNAP fields
-   for encapsulating Ethernet protocol type */
+/** The 802.2 LLC/SNAP header sent before actual data in a data frame
+ *
+ * This header is not acknowledged in the 802.11 standard at all; it
+ * is treated just like data for MAC-layer purposes, including
+ * fragmentation and encryption. It is actually two headers
+ * concatenated: a three-byte 802.2 LLC header indicating Subnetwork
+ * Accesss Protocol (SNAP) in both source and destination Service
+ * Access Point (SAP) fields, and a five-byte SNAP header indicating a
+ * zero OUI and two-byte Ethernet protocol type field.
+ *
+ * Thus, an eight-byte header in which six of the bytes are redundant.
+ * Lovely, isn't it?
+ */
 struct ieee80211_llc_snap_header
 {
        /* LLC part: */
-       u8 dsap;                /**< destination SAP id */
-       u8 ssap;                /**< source SAP id */
-       u8 ctrl;                /**< control info */
-#define IEEE80211_LLC_DSAP 0xAA        /* for SNAP */
-#define IEEE80211_LLC_SSAP 0xAA        /* for SNAP */
-#define IEEE80211_LLC_CTRL 0x03        /* Unnumbered Information */
+       u8 dsap;                /**< Destination SAP ID */
+       u8 ssap;                /**< Source SAP ID */
+       u8 ctrl;                /**< Control information */
 
        /* SNAP part: */
        u8 oui[3];              /**< Organization code, usually 0 */
        u16 ethertype;          /**< Ethernet Type field */
 } __attribute__((packed));
 
+/** Value for DSAP field in 802.2 LLC header for 802.11 frames: SNAP */
+#define IEEE80211_LLC_DSAP     0xAA
+
+/** Value for SSAP field in 802.2 LLC header for 802.11 frames: SNAP */
+#define IEEE80211_LLC_SSAP     0xAA
+
+/** Value for control field in 802.2 LLC header for 802.11 frames
+ *
+ * "Unnumbered Information".
+ */
+#define IEEE80211_LLC_CTRL     0x03
 
-/* Control frame formats, with abbreviated frame header. */
+
+/** 16-byte RTS frame format, with abbreviated header */
 struct ieee80211_rts
 {
        u16 fc;
@@ -115,35 +316,74 @@ struct ieee80211_rts
        u8 addr2[ETH_ALEN];
 } __attribute__((packed));
 
-struct ieee80211_cts
+/** Length of 802.11 RTS control frame */
+#define IEEE80211_RTS_LEN      16
+
+/** 10-byte CTS or ACK frame format, with abbreviated header */
+struct ieee80211_cts_or_ack
 {
        u16 fc;
        u16 duration;
        u8 addr1[ETH_ALEN];
 } __attribute__((packed));
 
-#define ieee80211_ack ieee80211_cts
-
-
-/* Defines for the `capability' and `status' fields of management
-   frames; [c] set according to configuration, [h] set according to
-   hardware, [0,1] currently fixed at such in gPXE. */
-#define IEEE80211_CAPAB_MANAGED       0x0001 /* [1] Managed mode (with an Access Point) */
-#define IEEE80211_CAPAB_ADHOC         0x0002 /* [0] Ad-hoc mode (no Access Point) */
-#define IEEE80211_CAPAB_CFPOLL        0x0004 /* [0] CF-Pollable */
-#define IEEE80211_CAPAB_CFPR          0x0008 /* [0] CF-Poll Request */
-#define IEEE80211_CAPAB_PRIVACY       0x0010 /* [c] Encrypted network */
-#define IEEE80211_CAPAB_SHORT_PMBL    0x0020 /* [h] Short RF preambles supported */
-#define IEEE80211_CAPAB_PBCC          0x0040 /* [0] PBCC modulation supported */
-#define IEEE80211_CAPAB_CHAN_AGILITY  0x0080 /* [0] Channel Agility supported */
-#define IEEE80211_CAPAB_SPECTRUM_MGMT 0x0100 /* [0] Spectrum Management required */
-#define IEEE80211_CAPAB_QOS           0x0200 /* [0] QoS supported */
-#define IEEE80211_CAPAB_SHORT_SLOT    0x0400 /* [h] Short Slot Time option supported */
-#define IEEE80211_CAPAB_APSD          0x0800 /* [0] APSD option supported */
-#define IEEE80211_CAPAB_DSSS_OFDM     0x2000 /* [0] DSSS/OFDM modulation supported
-                                                   (802.11g/b interoperability) */
-#define IEEE80211_CAPAB_DELAYED_BACK  0x4000 /* [0] Delayed block ACK supported */
-#define IEEE80211_CAPAB_IMMED_BACK    0x8000 /* [0] Immediate block ACK supported */
+#define ieee80211_cts ieee80211_cts_or_ack
+#define ieee80211_ack ieee80211_cts_or_ack
+
+/** Length of 802.11 CTS control frame */
+#define IEEE80211_CTS_LEN      10
+
+/** Length of 802.11 ACK control frame */
+#define IEEE80211_ACK_LEN      10
+
+
+/* ---------- Capability and status defines ---------- */
+
+/** Management frame capability field: Set if using an Access Point */
+#define IEEE80211_CAPAB_MANAGED       0x0001
+
+/** Management frame capability field: Set if operating in IBSS (no-AP) mode */
+#define IEEE80211_CAPAB_ADHOC         0x0002
+
+/** Management frame capability field: Set if we support CF operation */
+#define IEEE80211_CAPAB_CFPOLL        0x0004
+
+/** Management frame capability field: Set if we wish to be CF-Polled */
+#define IEEE80211_CAPAB_CFPR          0x0008
+
+/** Management frame capability field: Set if the network is encrypted */
+#define IEEE80211_CAPAB_PRIVACY       0x0010
+
+/** Management frame capability field: Set if PHY supports short preambles */
+#define IEEE80211_CAPAB_SHORT_PMBL    0x0020
+
+/** Management frame capability field: Set if PHY supports PBCC modulation */
+#define IEEE80211_CAPAB_PBCC          0x0040
+
+/** Management frame capability field: Set if we support Channel Agility */
+#define IEEE80211_CAPAB_CHAN_AGILITY  0x0080
+
+/** Management frame capability field: Set if we support spectrum management */
+#define IEEE80211_CAPAB_SPECTRUM_MGMT 0x0100
+
+/** Management frame capability field: Set if we support Quality of Service */
+#define IEEE80211_CAPAB_QOS           0x0200
+
+/** Management frame capability field: Set if PHY supports short slot time */
+#define IEEE80211_CAPAB_SHORT_SLOT    0x0400
+
+/** Management frame capability field: Set if PHY supports APSD option */
+#define IEEE80211_CAPAB_APSD          0x0800
+
+/** Management frame capability field: Set if PHY supports DSSS/OFDM modulation */
+#define IEEE80211_CAPAB_DSSS_OFDM     0x2000
+
+/** Management frame capability field: Set if we support delayed block ACK */
+#define IEEE80211_CAPAB_DELAYED_BACK  0x4000
+
+/** Management frame capability field: Set if we support immediate block ACK */
+#define IEEE80211_CAPAB_IMMED_BACK    0x8000
+
 
 #define IEEE80211_STATUS_SUCCESS                  0
 #define IEEE80211_STATUS_FAILURE                  1
@@ -177,187 +417,612 @@ struct ieee80211_cts
 #define IEEE80211_STATUS_ASSOC_LISTEN_TOO_HIGH    51
 
 
-/* Information elements for management frames: */
+/* ---------- Information element declarations ---------- */
+
+/** Generic 802.11 information element
+ *
+ * Many management frames include a section that amounts to a
+ * concatenation of IEs, so that the sender can choose which
+ * information to send and the receiver can ignore the parts it
+ * doesn't understand. Each IE contains this two-byte header, followed
+ * by IE-specific data.
+ */
+struct ieee80211_ie_header {
+       u8 id;                  /**< Information element ID */
+       u8 len;                 /**< Information element length */
+} __attribute__ ((packed));
+
+
+/** 802.11 SSID information element */
+struct ieee80211_ie_ssid {
+       u8 id;                  /**< SSID ID: 0 */
+       u8 len;                 /**< SSID length */
+       char ssid[0];           /**< SSID data, not NUL-terminated */
+} __attribute__ ((packed));
+
+/** Information element ID for SSID information element */
+#define IEEE80211_IE_SSID      0
+
+
+/** 802.11 rates information element
+ *
+ * The first 8 rates go in an IE of type RATES (1), and any more rates
+ * go in one of type EXT_RATES (50). Each rate is a byte with the low
+ * 7 bits equal to the rate in units of 500 kbps, and the high bit set
+ * if and only if the rate is "basic" (must be supported by all
+ * connected stations).
+ */
+struct ieee80211_ie_rates {
+       u8 id;                  /**< Rates ID: 1 or 50 */
+       u8 len;                 /**< Number of rates */
+       u8 rates[0];            /**< Rates data, one rate per byte */
+} __attribute__ ((packed));
+
+/** Information element ID for rates information element */
+#define IEEE80211_IE_RATES     1
+
+/** Information element ID for extended rates information element */
+#define IEEE80211_IE_EXT_RATES 50
+
+
+/** 802.11 Direct Spectrum parameter information element
+ *
+ * This just contains the channel number.
+ */
+struct ieee80211_ie_ds_param {
+       u8 id;                  /**< DS parameter ID: 3 */
+       u8 len;                 /**< DS parameter length: 1 */
+       u8 current_channel;     /**< Current channel number, 1-14 */
+} __attribute__ ((packed));
+
+/** Information element ID for Direct Spectrum parameter information element */
+#define IEEE80211_IE_DS_PARAM  3
+
+
+/** 802.11 Country information element regulatory extension triplet */
+struct ieee80211_ie_country_ext_triplet {
+       u8 reg_ext_id;          /**< Regulatory extension ID */
+       u8 reg_class_id;        /**< Regulatory class ID */
+       u8 coverage_class;      /**< Coverage class */
+} __attribute__ ((packed));
+
+/** 802.11 Country information element regulatory band triplet */
+struct ieee80211_ie_country_band_triplet {
+       u8 first_channel;       /**< Channel number for first channel in band */
+       u8 nr_channels;         /**< Number of contiguous channels in band */
+       u8 max_txpower;         /**< Maximum TX power in dBm */
+} __attribute__ ((packed));
+
+/** 802.11 Country information element regulatory triplet
+ *
+ * It is a band triplet if the first byte is 200 or less, and a
+ * regulatory extension triplet otherwise.
+ */
+union ieee80211_ie_country_triplet {
+       /** Differentiator between band and ext triplets */
+       u8 first;
+
+       /** Information about a band of channels */
+       struct ieee80211_ie_country_band_triplet band;
+
+       /** Regulatory extension information */
+       struct ieee80211_ie_country_ext_triplet ext;
+};
+
+/** 802.11 Country information element
+ *
+ * This contains some data about RF regulations.
+ */
+struct ieee80211_ie_country {
+       u8 id;                  /**< Country information ID: 7 */
+       u8 len;                 /**< Country information length: varies */
+       char name[2];           /**< ISO Alpha2 country code */
+       char in_out;            /**< 'I' for indoor, 'O' for outdoor */
+
+       /** List of regulatory triplets */
+       union ieee80211_ie_country_triplet triplet[0];
+} __attribute__ ((packed));
+
+/** Information element ID for Country information element */
+#define IEEE80211_IE_COUNTRY   7
+
 
-/* Security information element */
+/** 802.11 Request information element
+ *
+ * This contains a list of information element types we would like to
+ * be included in probe response frames.
+ */
+struct ieee80211_ie_request {
+       u8 id;                  /**< Request ID: 10 */
+       u8 len;                 /**< Number of IEs requested */
+       u8 request[0];          /**< List of IEs requested */
+} __attribute__ ((packed));
+
+/** Information element ID for Request information element */
+#define IEEE80211_IE_REQUEST   10
+
+
+/** 802.11 Challenge Text information element
+ *
+ * This is used in authentication frames under Shared Key
+ * authentication.
+ */
+struct ieee80211_ie_challenge_text {
+       u8 id;                  /**< Challenge Text ID: 16 */
+       u8 len;                 /**< Challenge Text length: usually 128 */
+       u8 challenge_text[0];   /**< Challenge Text data */
+} __attribute__ ((packed));
+
+/** Information element ID for Challenge Text information element */
+#define IEEE80211_IE_CHALLENGE_TEXT    16
+
+
+/** 802.11 Power Constraint information element
+ *
+ * This is used to specify an additional power limitation on top of
+ * the Country requirements.
+ */
+struct ieee80211_ie_power_constraint {
+       u8 id;                  /**< Power Constraint ID: 52 */
+       u8 len;                 /**< Power Constraint length: 1 */
+       u8 power_constraint;    /**< Decrease in allowed TX power, dBm */
+} __attribute__ ((packed));
+
+/** Information element ID for Power Constraint information element */
+#define IEEE80211_IE_POWER_CONSTRAINT  52
+
+
+/** 802.11 Power Capability information element
+ *
+ * This is used in association request frames to indicate the extremes
+ * of our TX power abilities.
+ */
+struct ieee80211_ie_power_capab {
+       u8 id;                  /**< Power Capability ID: 33 */
+       u8 len;                 /**< Power Capability length: 2 */
+       u8 min_txpower;         /**< Minimum possible TX power, dBm */
+       u8 max_txpower;         /**< Maximum possible TX power, dBm */
+} __attribute__ ((packed));
+
+/** Information element ID for Power Capability information element */
+#define IEEE80211_IE_POWER_CAPAB       33
+
+
+/** 802.11 Channels information element channel band tuple */
+struct ieee80211_ie_channels_channel_band {
+       u8 first_channel;       /**< Channel number of first channel in band */
+       u8 nr_channels;         /**< Number of channels in band */
+} __attribute__ ((packed));
+
+/** 802.11 Channels information element
+ *
+ * This is used in association frames to indicate the channels we can
+ * use.
+ */
+struct ieee80211_ie_channels {
+       u8 id;                  /**< Channels ID: 36 */
+       u8 len;                 /**< Channels length: 2 */
+
+       /** List of (start, length) channel bands we can use */
+       struct ieee80211_ie_channels_channel_band channels[0];
+} __attribute__ ((packed));
+
+/** Information element ID for Channels information element */
+#define IEEE80211_IE_CHANNELS  36
+
+
+/** 802.11 ERP Information information element
+ *
+ * This is used to communicate some PHY-level flags.
+ */
+struct ieee80211_ie_erp_info {
+       u8 id;                  /**< ERP Information ID: 42 */
+       u8 len;                 /**< ERP Information length: 1 */
+       u8 erp_info;            /**< ERP flags */
+} __attribute__ ((packed));
+
+/** Information element ID for ERP Information information element */
+#define IEEE80211_IE_ERP_INFO  42
+
+/** ERP information element: Flag set if 802.11b stations are present */
+#define  IEEE80211_ERP_NONERP_PRESENT  0x01
+
+/** ERP information element: Flag set if CTS protection must be used */
+#define  IEEE80211_ERP_USE_PROTECTION  0x02
+
+/** ERP information element: Flag set if long preambles must be used */
+#define  IEEE80211_ERP_BARKER_LONG     0x04
+
+
+/** Information element ID for Robust Security Network information element */
+#define IEEE80211_IE_RSN       48
+
+/** 802.11 Robust Security Network ("WPA") information element
+ *
+ * Showing once again a striking clarity of design, the IEEE folks put
+ * dynamically-sized data in the middle of this structure. As such,
+ * the below structure definition is only a guideline; the
+ * @c IEEE80211_RSN_FIELD, @c IEEE80211_RSN_CIPHER, and
+ * @c IEEE80211_RSN_AUTHTYPE macros should be used to access any
+ * data.
+ *
+ * Also inspired was IEEE's choice of 16-bit fields to count the
+ * number of 4-byte elements in a structure with a maximum length of
+ * 255 bytes.
+ *
+ * Many fields reference a cipher or authentication-type ID; this is a
+ * three-byte OUI followed by one byte identifying the cipher with
+ * respect to that OUI. For all standard ciphers the OUI is 00:0F:AC.
+ *
+ * The authentication types referenced in this structure have nothing
+ * to do with 802.11 authentication frames or the @c algorithm field
+ * within them.
+ */
 struct ieee80211_ie_rsn {
-       /* The RSN structure has dynamically-sized data at its middle.
-          The below assumes the most common case of pairwise_count ==
-          akm_count == 1; in other cases some munging is necessary. */
-#define  IEEE80211_RSN_VERSION  1
+       /** Information element ID */
+       u8 id;
+
+       /** Information element length */
+       u8 len;
+
+       /** RSN information element version */
        u16 version;
-       
-       /* cipher id is 00 0F AC ss, where ss = CTYPE or ATYPE #define: */
+
+       /** Cipher ID for the cipher used in multicast/broadcast frames */
        u8 group_cipher[4];
-#define  IEEE80211_RSN_CTYPE_WEP40  1
-#define  IEEE80211_RSN_CTYPE_TKIP   2
-#define  IEEE80211_RSN_CTYPE_CCMP   4
-#define  IEEE80211_RSN_CTYPE_WEP104 5
        
+       /** Number of unicast ciphers supported */
        u16 pairwise_count;
+
+       /** List of cipher IDs for supported unicast frame ciphers */
        u8 pairwise_cipher[4];
-#define  IEEE80211_RSN_CTYPE_USEGROUP 0
        
+       /** Number of authentication types supported */
        u16 akm_count;
+
+       /** List of authentication type IDs for supported types */
        u8 akm_list[4];
-#define  IEEE80211_RSN_ATYPE_8021X  1
-#define  IEEE80211_RSN_ATYPE_PSK    2
        
+       /** Security capabilities field. */
        u16 rsn_capab;
-#define  IEEE80211_RSN_CAPAB_PREAUTH      0x001
-#define  IEEE80211_RSN_CAPAB_NO_PAIRWISE  0x002
-#define  IEEE80211_RSN_CAPAB_PTKSA_REPLAY 0x00C
-#define  IEEE80211_RSN_CAPAB_GTKSA_REPLAY 0x030
-#define  IEEE80211_RSN_CAPAB_PEERKEY      0x200
 
+       /** Number of PMKIDs included (present only in association frames) */
        u16 pmkid_count;
-       u8 pmkid_list[0];       /* 16 bytes per PMKID, pmkid_count PMKIDs */
+
+       /** List of PMKIDs included, each a 16-byte SHA1 hash */
+       u8 pmkid_list[0];
 } __attribute__((packed));
 
-/* Generic information element */
-struct ieee80211_ie 
+/** Extract RSN IE version field */
+#define  IEEE80211_RSN_FIELD_version( rsnp ) ( (rsnp)->version )
+
+/** Extract RSN IE group_cipher field */
+#define  IEEE80211_RSN_FIELD_group_cipher( rsnp ) ( (rsnp)->group_cipher )
+
+/** Extract RSN IE pairwise_count field */
+#define  IEEE80211_RSN_FIELD_pairwise_count( rsnp ) ( (rsnp)->pairwise_count )
+
+/** Extract RSN IE akm_count field */
+#define  IEEE80211_RSN_FIELD_akm_count( rsnp )                 \
+       ( ( ( struct ieee80211_ie_rsn * ) ( ( void * ) ( rsnp ) + \
+               4*( ( rsnp )->pairwise_count - 1 ) ) )->akm_count )
+
+/** Extract RSN IE rsn_capab field */
+#define  IEEE80211_RSN_FIELD_rsn_capab( rsnp )                 \
+       ( ( ( struct ieee80211_ie_rsn * ) ( ( void * ) ( rsnp ) + \
+               4*( ( rsnp )->pairwise_count - 1 ) +            \
+               4*( ( rsnp )->akm_count - 1 ) ) )->rsn_capab )
+
+/** Extract RSN IE pmkid_count field */
+#define  IEEE80211_RSN_FIELD_pmkid_count( rsnp )               \
+       ( ( ( struct ieee80211_ie_rsn * ) ( ( void * ) ( rsnp ) + \
+               4*( ( rsnp )->pairwise_count - 1 ) +            \
+               4*( ( rsnp )->akm_count - 1 ) ) )->pmkid_count )
+
+/** Extract field from RSN information element
+ *
+ * @v rsnp     Pointer to RSN information element
+ * @v field    Name of field to extract
+ * @ret val    Lvalue of the requested field
+ *
+ * You must fill the fields of the structure in order for this to work
+ * properly.
+ */
+#define  IEEE80211_RSN_FIELD( rsnp, field ) IEEE80211_RSN_FIELD_ ## field ( rsnp )
+
+/** Get pointer to pairwise cipher from RSN information element
+ *
+ * @v rsnp     Pointer to RSN information element
+ * @v cipher   Index of pairwise cipher to extract
+ * @ret ptr    Pointer to requested cipher
+ */
+#define  IEEE80211_RSN_CIPHER( rsnp, cipher )  \
+       ( ( rsnp )->pairwise_cipher + 4 * ( cipher ) )
+
+/** Get pointer to authentication type from RSN information element
+ *
+ * @v rsnp     Pointer to RSN information element
+ * @v akm      Index of authentication type to extract
+ * @ret ptr    Pointer to requested authentication type
+ *
+ * The @c pairwise_count field must be correct.
+ */
+#define  IEEE80211_RSN_AUTHTYPE( rsnp, akm )   \
+    ( ( rsnp )->akm_list + 4 * ( ( rsnp )->pairwise_count - 1 ) + 4 * ( akm ) )
+
+/** Get pointer to PMKID from RSN information element
+ *
+ * @v rsnp     Pointer to RSN information element
+ * @v idx      Index of PMKID to extract
+ * @ret ptr    Pointer to requested PMKID
+ *
+ * The @c pairwise_count and @c akm_count fields must be correct.
+ */
+#define  IEEE80211_RSN_PMKID( rsnp, idx )      \
+       ( ( rsnp )->pmkid_list + 4 * ( ( rsnp )->pairwise_count - 1 ) + \
+                       4 * ( ( rsnp )->akm_count - 1 ) + 16 * ( idx ) )
+
+/** Verify size of RSN information element
+ *
+ * @v rsnp     Pointer to RSN information element
+ * @ret ok     TRUE if count fields are consistent with length field
+ *
+ * It is important to drop any RSN IE that does not pass this function
+ * before using the @c IEEE80211_RSN_FIELD, @c IEEE80211_RSN_CIPHER,
+ * and @c IEEE80211_RSN_AUTHTYPE macros, to avoid potential security
+ * compromise due to a malformed RSN IE.
+ *
+ * This function does not consider the possibility of some PMKIDs
+ * included in the RSN IE, because PMKIDs are only included in RSN IEs
+ * sent in association request frames, and we should never receive an
+ * association request frame. Such RSN IEs will always fail this check.
+ */
+static inline int ieee80211_rsn_check ( struct ieee80211_ie_rsn *rsnp ) {
+       if ( rsnp->len < 12 + 4 * rsnp->pairwise_count )        
+               return 0;
+       return ( rsnp->len == 12 + 4 * ( rsnp->pairwise_count +
+                               IEEE80211_RSN_FIELD ( rsnp, akm_count ) ) );
+}
+
+/** Calculate necessary size of RSN information element
+ *
+ * @v npair    Number of pairwise ciphers supported
+ * @v nauth    Number of authentication types supported
+ * @v npmkid   Number of PMKIDs to include
+ * @ret size   Necessary size of RSN IE, including header bytes
+ */
+static inline size_t ieee80211_rsn_size ( int npair, int nauth, int npmkid ) {
+       return 16 + 4 * ( npair + nauth ) + 16 * npmkid;
+}
+
+/** 802.11 RSN IE: expected version number */
+#define  IEEE80211_RSN_VERSION         1
+
+/** 802.11 RSN IE: fourth byte of cipher type for 40-bit WEP */
+#define  IEEE80211_RSN_CTYPE_WEP40     1
+
+/** 802.11 RSN IE: fourth byte of cipher type for 104-bit WEP */
+#define  IEEE80211_RSN_CTYPE_WEP104    5
+
+/** 802.11 RSN IE: fourth byte of cipher type for TKIP ("WPA") */
+#define  IEEE80211_RSN_CTYPE_TKIP      2
+
+/** 802.11 RSN IE: fourth byte of cipher type for CCMP ("WPA2") */
+#define  IEEE80211_RSN_CTYPE_CCMP      4
+
+/** 802.11 RSN IE: fourth byte of cipher type for "use group"
+ *
+ * This can only appear as a pairwise cipher, and means unicast frames
+ * should be encrypted in the same way as broadcast/multicast frames.
+ */
+#define  IEEE80211_RSN_CTYPE_USEGROUP  0
+
+/** 802.11 RSN IE: fourth byte of auth method type for using an 802.1X server */
+#define  IEEE80211_RSN_ATYPE_8021X     1
+
+/** 802.11 RSN IE: fourth byte of auth method type for using a pre-shared key */
+#define  IEEE80211_RSN_ATYPE_PSK       2
+
+/** 802.11 RSN IE capabilities: AP supports pre-authentication */
+#define  IEEE80211_RSN_CAPAB_PREAUTH   0x001
+
+/** 802.11 RSN IE capabilities: Node has conflict between TKIP and WEP
+ *
+ * This is a legacy issue; APs always set it to 0, and gPXE sets it to
+ * 0.
+ */
+#define  IEEE80211_RSN_CAPAB_NO_PAIRWISE 0x002
+
+/** 802.11 RSN IE capabilities: Number of PTKSA replay counters
+ *
+ * A value of 0 means one replay counter, 1 means two, 2 means four,
+ * and 3 means sixteen.
+ */
+#define  IEEE80211_RSN_CAPAB_PTKSA_REPLAY 0x00C
+
+/** 802.11 RSN IE capabilities: Number of GTKSA replay counters
+ *
+ * A value of 0 means one replay counter, 1 means two, 2 means four,
+ * and 3 means sixteen.
+ */
+#define  IEEE80211_RSN_CAPAB_GTKSA_REPLAY 0x030
+
+/** 802.11 RSN IE capabilities: PeerKey Handshaking is suported */
+#define  IEEE80211_RSN_CAPAB_PEERKEY   0x200
+
+
+
+/** Any 802.11 information element
+ *
+ * This is formatted for ease of use, so IEs with complex structures
+ * get referenced in full, while those with only one byte of data or a
+ * simple array are pulled in to avoid a layer of indirection like
+ * ie->channels.channels[0].
+ */
+union ieee80211_ie
 {
-       u8 id;
-       u8 len;
-       union {
-#define IEEE80211_IE_SSID  0
-               char ssid[0];
-
-               /* For both `rates' IEs, each basic
-                  (must-be-supported) rate is a byte with the high
-                  bit set and the low 7 bits equal to the rate
-                  divided by 500 kbps. The high bit is clear for
-                  non-basic rates. */
-#define IEEE80211_IE_RATES  1
-               u8 rates[0];
-#define IEEE80211_IE_EXT_RATES  50
-               u8 ext_rates[0];
-
-#define IEEE80211_IE_DS_PARAM  3
-               struct {
-                       u8 current_channel;
-               } __attribute__((packed)) ds_param;     /* for DSSS modulation */
-
-#define IEEE80211_IE_COUNTRY  7
-               struct {
-                       char name[3];
-                       /* A regulatory triplet can simply specify a
-                          channel range + maximum transmission power
-                          (in dBm). If first_channel >= 201, it is
-                          interpreted as a regulatory extension, with
-                          everything an index into some tables not
-                          included here. */
-                       struct {
-                               union {
-                                       struct {
-                                               u8 first_channel;
-                                               u8 nr_channels;
-                                               s8 max_txpower;
-                                       } __attribute__((packed)) band;
-                                       struct {
-                                               u8 reg_ext_id;
-                                               u8 reg_class_id;
-                                               u8 coverage_class;
-                                       } __attribute__((packed)) ext;
-                               };
-                       } __attribute__((packed)) triplet[0];
-               } __attribute__((packed)) country;
-               
-#define IEEE80211_IE_REQUEST  10
-               u8 request[0];
-
-#define IEEE80211_IE_CHALLENGE_TEXT  16
-               char challenge_text[0];
-
-               /* Power constraint in this channel, taking
-                  mitigation requirements into account, in dBm. Real
-                  max power = country max power - power constraint. */
-#define IEEE80211_IE_POWER_CONSTRAINT  32
-               u8 power_constraint;
-
-               /* Describes the min/max power we're capable of using,
-                  irrespective of regulatory restrictions. */
-#define IEEE80211_IE_POWER_CAPAB  33
-               struct {
-                       s8 min_txpower;
-                       s8 max_txpower;
-               } __attribute__((packed)) power_capab;
-
-#define IEEE80211_IE_CHANNELS  36
-               struct {
-                       u8 first_channel;
-                       u8 nr_channels;
-               } __attribute__((packed)) channels[0];
-
-#define IEEE80211_IE_ERP_INFO  42
-#define  IEEE80211_ERP_NONERP_PRESENT  0x01
-#define  IEEE80211_ERP_USE_PROTECTION  0x02
-#define  IEEE80211_ERP_BARKER_LONG     0x04
-               u8 erp_info;
-
-#define IEEE80211_IE_RSN  48
-               struct ieee80211_ie_rsn rsn;
+       /** Generic and simple information element info */
+       struct {
+               u8 id;          /**< Information element ID */
+               u8 len;         /**< Information element data length */
+               union {
+                       char ssid[0];   /**< SSID text */
+                       u8 rates[0];    /**< Rates data */
+                       u8 request[0];  /**< Request list */
+                       u8 challenge_text[0]; /**< Challenge text data */
+                       u8 power_constraint; /**< Power constraint, dBm */
+                       u8 erp_info;    /**< ERP information flags */
+                       /** List of channels */
+                       struct ieee80211_ie_channels_channel_band channels[0];
+               };
        };
-} __attribute__((packed));
 
+       /** DS parameter set */
+       struct ieee80211_ie_ds_param ds_param;
+
+       /** Country information */
+       struct ieee80211_ie_country country;
+
+       /** Power capability */
+       struct ieee80211_ie_power_capab power_capab;
+
+       /** Security information */
+       struct ieee80211_ie_rsn rsn;
+};
+
+/** Advance to next 802.11 information element
+ *
+ * @v ie       Current information element pointer
+ * @v end      Pointer to first byte not in information element space
+ * @ret next   Pointer to next information element, or NULL if no more
+ *
+ * When processing received IEs, @a end should be set to the I/O
+ * buffer tail pointer; when marshalling IEs for sending, @a end
+ * should be NULL.
+ */
+static inline union ieee80211_ie *ieee80211_next_ie ( union ieee80211_ie *ie,
+                                                     void *end ) 
+{
+       void *next_ie_byte = ( void * ) ie + ie->len + 2;
+       union ieee80211_ie *next_ie = next_ie_byte;
+
+       if ( ! end )
+               return next_ie;
+
+       if ( next_ie_byte < end && next_ie_byte + next_ie->len <= end )
+               return next_ie;
+
+       return NULL;
+}
 
-/* Internal structure for management frames. */
-struct ieee80211_beacon
+
+/* ---------- Management frame data formats ---------- */
+
+/** Beacon or probe response frame data */
+struct ieee80211_beacon_or_probe_resp
 {
+       /** 802.11 TSFT value at frame send */
        u64 timestamp;
+
+       /** Beacons sent every beacon_interval*1024 us */
        u16 beacon_interval;
+
+       /** Capability flags */
        u16 capability;
-       struct ieee80211_ie info_element[0];
+
+       /** List of information elements */
+       union ieee80211_ie info_element[0];
 } __attribute__((packed));
 
-struct ieee80211_disassoc
+#define ieee80211_beacon       ieee80211_beacon_or_probe_resp
+#define ieee80211_probe_resp   ieee80211_beacon_or_probe_resp
+
+/** Disassociation or deauthentication frame data */
+struct ieee80211_disassoc_or_deauth
 {
+       /** Reason code */
        u16 reason;
 } __attribute__((packed));
 
+#define ieee80211_disassoc     ieee80211_disassoc_or_deauth
+#define ieee80211_deauth       ieee80211_disassoc_or_deauth
+
+/** Association request frame data */
 struct ieee80211_assoc_req
 {
+       /** Capability flags */
        u16 capability;
+
+       /** Power-managed stations wake up every listen_interval beacons */
        u16 listen_interval;
-       struct ieee80211_ie info_element[0];
+
+       /** List of information elements */
+       union ieee80211_ie info_element[0];
 } __attribute__((packed));
 
-struct ieee80211_assoc_resp
+/** Association or reassociation response frame data */
+struct ieee80211_assoc_or_reassoc_resp
 {
+       /** Capability flags */
        u16 capability;
+
+       /** Status code */
        u16 status;
+
+       /** Association ID */
        u16 aid;
-       struct ieee80211_ie info_element[0];
+
+       /** List of information elements */
+       union ieee80211_ie info_element[0];
 } __attribute__((packed));
 
+#define ieee80211_assoc_resp   ieee80211_assoc_or_reassoc_resp
+#define ieee80211_reassoc_resp ieee80211_assoc_or_reassoc_resp
+
+/** Reassociation request frame data */
 struct ieee80211_reassoc_req
 {
+       /** Capability flags */
        u16 capability;
+
+       /** Power-managed stations wake up every listen_interval beacons */
        u16 listen_interval;
+
+       /** MAC address of current Access Point */
        u8 current_addr[ETH_ALEN];
-       struct ieee80211_ie info_element[0];
-} __attribute__((packed));
 
-#define ieee80211_reassoc_resp ieee80211_assoc_resp
+       /** List of information elements */
+       union ieee80211_ie info_element[0];
+} __attribute__((packed));
 
+/** Probe request frame data */
 struct ieee80211_probe_req
 {
-       struct ieee80211_ie info_element[0];
+       /** List of information elements */
+       union ieee80211_ie info_element[0];
 } __attribute__((packed));
 
-#define ieee80211_probe_resp ieee80211_beacon
-
+/** Authentication frame data */
 struct ieee80211_auth
 {
+       /** Authentication algorithm */
        u16 algorithm;
-#define IEEE80211_AUTH_OPEN_SYSTEM  0
-#define IEEE80211_AUTH_SHARED_KEY   1
 
+       /** Sequence number of this frame; first from client to AP is 1 */
        u16 tx_seq;
+
+       /** Status code */
        u16 status;
-       struct ieee80211_ie info_element[0];
+
+       /** List of information elements */
+       union ieee80211_ie info_element[0];
 } __attribute__((packed));
 
-#define ieee80211_deauth ieee80211_disassoc
+/** Open System authentication algorithm */
+#define IEEE80211_AUTH_OPEN_SYSTEM  0
+
+/** Shared Key authentication algorithm */
+#define IEEE80211_AUTH_SHARED_KEY   1
+
 
 #endif