blob: 79e58c83418014196b4b2efea9b4896fa133959a [file] [log] [blame]
/*
* Copyright 2018 The Fuchsia Authors.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef GARNET_DRIVERS_WLAN_THIRD_PARTY_ATHEROS_ATH10K_IEEE80211_H_
#define GARNET_DRIVERS_WLAN_THIRD_PARTY_ATHEROS_ATH10K_IEEE80211_H_
#include <stdint.h>
#include <zircon/assert.h>
#include "hw.h"
// clang-format off
// IEEE Std 802.11-2016, 9.2.3
struct ieee80211_frame_header {
uint16_t frame_ctrl;
uint16_t duration;
uint8_t addr1[ETH_ALEN];
uint8_t addr2[ETH_ALEN];
uint8_t addr3[ETH_ALEN];
uint16_t seq_ctrl;
uint8_t addr4[0];
} __PACKED;
// IEEE Std 802.11-2016, 9.3.3.7
struct ieee80211_assoc_resp {
uint16_t capabilities;
uint16_t status;
uint16_t assoc_id;
uint8_t info[0];
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.57
struct ieee80211_ht_info {
uint8_t primary_channel;
uint8_t ht_operation_info[5];
uint8_t rx_mcs[10];
} __PACKED;
// IEEE Std 802.11-2016, 9.2.4.1.3
enum ieee80211_frame_type {
IEEE80211_FRAME_TYPE_MGMT = 0x0,
IEEE80211_FRAME_TYPE_CTRL = 0x4,
IEEE80211_FRAME_TYPE_DATA = 0x8,
IEEE80211_FRAME_TYPE_EXT = 0xc,
};
// IEEE Std 802.11-2016, 9.2.4.1.3
enum ieee80211_frame_subtype {
/* MGMT */
IEEE80211_FRAME_SUBTYPE_ASSOC_REQ = 0x00,
IEEE80211_FRAME_SUBTYPE_ASSOC_RESP = 0x10,
IEEE80211_FRAME_SUBTYPE_BEACON = 0x80,
IEEE80211_FRAME_SUBTYPE_DISASSOC = 0xa0,
IEEE80211_FRAME_SUBTYPE_DEAUTH = 0xc0,
IEEE80211_FRAME_SUBTYPE_ACTION = 0xd0,
/* DATA */
IEEE80211_FRAME_SUBTYPE_PROBE_RESP = 0x50,
IEEE80211_FRAME_SUBTYPE_QOS = 0x80,
IEEE80211_FRAME_SUBTYPE_QOS_NULL = 0xc0,
/* CONTROL */
IEEE80211_FRAME_SUBTYPE_CTS = 0xc0,
IEEE80211_FRAME_SUBTYPE_ACK = 0xd0,
};
enum nl80211_band {
NL80211_BAND_2GHZ,
NL80211_BAND_5GHZ,
NL80211_BAND_60GHZ,
};
// IEEE Std 802.11-2016, 9.2.4.1.1
#define IEEE80211_FRAME_TYPE_MASK 0x000c
#define IEEE80211_FRAME_SUBTYPE_MASK 0x00f0
#define IEEE80211_FRAME_CTRL_TO_DS_MASK 0x0100
#define IEEE80211_FRAME_CTRL_FROM_DS_MASK 0x0200
#define IEEE80211_FRAME_CTRL_MORE_FRAGMENTS_MASK 0x0400
#define IEEE80211_FRAME_PROTECTED_MASK 0x4000
#define IEEE80211_FRAME_CTRL_HTC_ORDER_MASK 0x8000
// IEEE Std 802.11-2016, 9.2.4.5.1
#define IEEE80211_QOS_CTRL_A_MSDU_PRESENT 0x0080
static inline enum ieee80211_frame_type
ieee80211_get_frame_type(const struct ieee80211_frame_header* fh) {
return fh->frame_ctrl & IEEE80211_FRAME_TYPE_MASK;
}
static inline enum ieee80211_frame_subtype
ieee80211_get_frame_subtype(const struct ieee80211_frame_header* fh) {
return fh->frame_ctrl & IEEE80211_FRAME_SUBTYPE_MASK;
}
static inline bool ieee80211_pkt_is_protected(const struct ieee80211_frame_header* fh) {
return fh->frame_ctrl & IEEE80211_FRAME_PROTECTED_MASK;
}
static inline uint8_t* ieee80211_get_bssid(struct ieee80211_frame_header* fh) {
ZX_ASSERT(ieee80211_get_frame_type(fh) == IEEE80211_FRAME_TYPE_MGMT);
return fh->addr3;
}
static bool ieee80211_has_addr4(const struct ieee80211_frame_header* hdr) {
uint16_t mask = IEEE80211_FRAME_CTRL_TO_DS_MASK | IEEE80211_FRAME_CTRL_FROM_DS_MASK;
return (hdr->frame_ctrl & mask) == mask;
}
static inline size_t ieee80211_is_qos_data(struct ieee80211_frame_header* fh) {
return ieee80211_get_frame_type(fh) == IEEE80211_FRAME_TYPE_DATA
&& (ieee80211_get_frame_subtype(fh) & IEEE80211_FRAME_SUBTYPE_QOS);
}
static inline size_t ieee80211_get_qos_ctrl_offset(const struct ieee80211_frame_header* hdr) {
return sizeof(struct ieee80211_frame_header) + (ieee80211_has_addr4(hdr) ? ETH_ALEN : 0);
}
static inline size_t ieee80211_hdrlen(struct ieee80211_frame_header* fh) {
switch (ieee80211_get_frame_type(fh)) {
case IEEE80211_FRAME_TYPE_MGMT:
case IEEE80211_FRAME_TYPE_DATA:
return sizeof(struct ieee80211_frame_header)
+ (ieee80211_has_addr4(fh) ? ETH_ALEN : 0)
+ (ieee80211_is_qos_data(fh) ? 2 : 0)
+ ((fh->frame_ctrl & IEEE80211_FRAME_CTRL_HTC_ORDER_MASK) ? 4 : 0);
case IEEE80211_FRAME_TYPE_CTRL:
// See IEEE Std. 802.11-2016, 9.3.1
switch (ieee80211_get_frame_subtype(fh)) {
case IEEE80211_FRAME_SUBTYPE_CTS:
case IEEE80211_FRAME_SUBTYPE_ACK:
return 10;
default:
return 16;
}
default:
return sizeof(struct ieee80211_frame_header);
}
}
static inline uint8_t* ieee80211_get_dest_addr(struct ieee80211_frame_header* fh) {
if (fh->frame_ctrl & IEEE80211_FRAME_CTRL_TO_DS_MASK) {
return fh->addr3;
} else {
return fh->addr1;
}
}
static inline uint8_t* ieee80211_get_src_addr(struct ieee80211_frame_header* fh) {
uint16_t mask = IEEE80211_FRAME_CTRL_TO_DS_MASK | IEEE80211_FRAME_CTRL_FROM_DS_MASK;
switch (fh->frame_ctrl & mask) {
case IEEE80211_FRAME_CTRL_TO_DS_MASK | IEEE80211_FRAME_CTRL_FROM_DS_MASK:
return fh->addr4;
case IEEE80211_FRAME_CTRL_FROM_DS_MASK:
return fh->addr3;
default:
return fh->addr2;
}
}
#define IEEE80211_HT_MAX_AMPDU_FACTOR 13
// IEEE Std 802.11-2016, 9.4.2.1, Table 9-77
enum ieee80211_assoc_tags {
IEEE80211_ASSOC_TAG_RATES = 1,
IEEE80211_ASSOC_TAG_HT_CAPS = 45,
IEEE80211_ASSOC_TAG_EXTENDED_RATES = 50,
IEEE80211_ASSOC_TAG_HT_INFO = 61,
};
// IEEE Std 802.11-2016, 9.4.2.56.2, Figure 9-332
enum ieee80211_ht_caps {
IEEE80211_HT_CAPS_LDPC = 0x0001,
IEEE80211_HT_CAPS_CHAN_WIDTH = 0x0002,
IEEE80211_HT_CAPS_SMPS = 0x000c,
IEEE80211_HT_CAPS_SMPS_STATIC = 0x0000,
IEEE80211_HT_CAPS_SMPS_DYNAMIC = 0x0004,
IEEE80211_HT_CAPS_SMPS_DISABLED = 0x000c,
IEEE80211_HT_CAPS_SMPS_SHIFT = 2,
IEEE80211_HT_CAPS_GF = 0x0010,
IEEE80211_HT_CAPS_SGI_20 = 0x0020,
IEEE80211_HT_CAPS_SGI_40 = 0x0040,
IEEE80211_HT_CAPS_TX_STBC = 0x0080,
IEEE80211_HT_CAPS_RX_STBC = 0x0300,
IEEE80211_HT_CAPS_RX_STBC_SHIFT = 8,
IEEE80211_HT_CAPS_DELAYED_BLOCK_ACK = 0x0400,
IEEE80211_HT_CAPS_MAX_AMSDU_LEN = 0x0800,
IEEE80211_HT_CAPS_DSSS_CCK_40 = 0x1000,
/* RESERVED - bit 13 */
IEEE80211_HT_CAPS_40_INTOLERANT = 0x4000,
IEEE80211_HT_CAPS_L_SIG_TXOP_PROT = 0x8000
};
#define IEEE80211_HT_MCS_MASK_LEN 10
enum ieee80211_ampdu_params {
IEEE80211_AMPDU_RX_LEN_MASK = 0x03,
IEEE80211_AMPDU_RX_LEN_SHIFT = 0,
IEEE80211_AMPDU_DENSITY_MASK = 0x1c,
IEEE80211_AMPDU_DENSITY_SHIFT = 2
};
// IEEE Std. 802.11-2016 9.4.2.158.2
enum ieee80211_vht_caps {
IEEE80211_VHT_CAPS_MAX_MPDU_LEN = 0x3,
IEEE80211_VHT_CAPS_MAX_MPDU_LEN_SHIFT = 0,
IEEE80211_VHT_CAPS_SUPP_CHAN_WIDTH = 0xc,
IEEE80211_VHT_CAPS_SUPP_CHAN_WIDTH_SHIFT = 2,
IEEE80211_VHT_CAPS_RX_LDPC = 0x10,
IEEE80211_VHT_CAPS_RX_LDPC_SHIFT = 4,
IEEE80211_VHT_CAPS_SGI_80 = 0x20,
IEEE80211_VHT_CAPS_SGI_80_SHIFT = 5,
IEEE80211_VHT_CAPS_SGI_160 = 0x40,
IEEE80211_VHT_CAPS_SGI_160_SHIFT = 6,
IEEE80211_VHT_CAPS_TX_STBC = 0x80,
IEEE80211_VHT_CAPS_TX_STBC_SHIFT = 7,
IEEE80211_VHT_CAPS_RX_STBC = 0x700,
IEEE80211_VHT_CAPS_RX_STBC_SHIFT = 8,
IEEE80211_VHT_CAPS_SU_BEAMFORMER = 0x800,
IEEE80211_VHT_CAPS_SU_BEAMFORMER_SHIFT = 11,
IEEE80211_VHT_CAPS_SU_BEAMFORMEE = 0x1000,
IEEE80211_VHT_CAPS_SU_BEAMFORMEE_SHIFT = 12,
IEEE80211_VHT_CAPS_BEAMFORMEE_STS = 0xe000,
IEEE80211_VHT_CAPS_BEAMFORMEE_STS_SHIFT = 13,
IEEE80211_VHT_CAPS_SOUND_DIM = 0x70000,
IEEE80211_VHT_CAPS_SOUND_DIM_SHIFT = 16,
IEEE80211_VHT_CAPS_MU_BEAMFORMER = 0x80000,
IEEE80211_VHT_CAPS_MU_BEAMFORMER_SHIFT = 19,
IEEE80211_VHT_CAPS_MU_BEAMFORMEE = 0x100000,
IEEE80211_VHT_CAPS_MU_BEAMFORMEE_SHIFT = 20,
IEEE80211_VHT_CAPS_TXOP_PS = 0x200000,
IEEE80211_VHT_CAPS_TXOP_PS_SHIFT = 21,
IEEE80211_VHT_CAPS_HTC_VHT = 0x400000,
IEEE80211_VHT_CAPS_HTC_VHT_SHIFT = 22,
IEEE80211_VHT_CAPS_MAX_AMPDU_LEN = 0x3800000,
IEEE80211_VHT_CAPS_MAX_AMPDU_LEN_SHIFT = 23,
IEEE80211_VHT_CAPS_VHT_LINK_ADAPT = 0xc000000,
IEEE80211_VHT_CAPS_VHT_LINK_ADAPT_SHIFT = 26,
IEEE80211_VHT_CAPS_RX_ANT_CONSIST = 0x10000000,
IEEE80211_VHT_CAPS_RX_ANT_CONSIST_SHIFT = 28,
IEEE80211_VHT_CAPS_TX_ANT_CONSIST = 0x20000000,
IEEE80211_VHT_CAPS_TX_ANT_CONSIST_SHIFT = 29,
IEEE80211_VHT_CAPS_EXT_NSS_BW = 0xc0000000,
IEEE80211_VHT_CAPS_EXT_NSS_BW_SHIFT = 30
};
// IEEE Std. 802.11-2016 9.4.2.158.3
enum ieee80211_supported_vht_mcs_nss {
IEEE80211_VHT_MCS_NSS_RX_MCS_MAP = 0xffff,
IEEE80211_VHT_MCS_NSS_RX_MCS_MAP_SHIFT = 0,
IEEE80211_VHT_MCS_NSS_RX_MAX_LGI_RATE = 0x1fff0000,
IEEE80211_VHT_MCS_NSS_RX_MAX_LGI_RATE_SHIFT = 16,
IEEE80211_VHT_MCS_NSS_MAX_NSTS = 0xe0000000,
IEEE80211_VHT_MCS_NSS_MAX_NSTS_SHIFT = 29,
IEEE80211_VHT_MCS_NSS_TX_MCS_MAP = 0xffff00000000,
IEEE80211_VHT_MCS_NSS_TX_MCS_MAP_SHIFT = 32,
IEEE80211_VHT_MCS_NSS_TX_MAX_LGI_RATE = 0x1fff000000000000,
IEEE80211_VHT_MCS_NSS_TX_MAX_LGI_RATE_SHIFT = 48,
IEEE80211_VHT_MCS_NSS_EXT_NSS_BW_CAP = 0x2000000000000000,
IEEE80211_VHT_MCS_NSS_EXT_NSS_BW_CAP_SHIFT = 61,
};
// Max VHT-MCS SS encodings (IEEE Std. 802.11-2016 9.4.2.158.3)
#define IEEE80211_VHT_MCS_0_7 0
#define IEEE80211_VHT_MCS_0_8 1
#define IEEE80211_VHT_MCS_0_9 2
#define IEEE80211_VHT_MCS_NONE 3
#define IEEE80211_CCMP_MIC_LEN 8
#define IEEE80211_QOS_CTL_LEN 2
#define IEEE80211_MSDU_SIZE_MAX 2304
// IEEE Std 802.11-2016, 9.2.4.8
#define IEEE80211_FCS_LEN 4
// IEEE Std 802.11-2016, 12.3.2.2
#define IEEE80211_WEP_IV_LEN 4
#define IEEE80211_WEP_ICV_LEN 4
// IEEE Std 802.11-2016, 12.5.2.2
#define IEEE80211_TKIP_IV_LEN 8
#define IEEE80211_TKIP_ICV_LEN 4
// IEEE Std 802.11-2016, 12.5.3.2
#define IEEE80211_CCMP_HDR_LEN 8
#define IEEE80211_CCMP_128_MIC_LEN 8
// IEEE Std 802.11-2016, 9.4.2.2
#define IEEE80211_SSID_LEN_MAX 32
// IEEE Std 802.11-2016, 9.4.2.25.2, Table 9-131
enum ieee80211_cipher_suite {
IEEE80211_CIPHER_SUITE_GROUP = 0,
IEEE80211_CIPHER_SUITE_WEP_40 = 1,
IEEE80211_CIPHER_SUITE_TKIP = 2,
IEEE80211_CIPHER_SUITE_CCMP_128 = 4,
IEEE80211_CIPHER_SUITE_WEP_104 = 5,
IEEE80211_CIPHER_SUITE_CMAC_128 = 6,
IEEE80211_CIPHER_SUITE_GCMP_128 = 8,
IEEE80211_CIPHER_SUITE_GCMP_256 = 9,
IEEE80211_CIPHER_SUITE_CCMP_256 = 10,
IEEE80211_CIPHER_SUITE_GMAC_128 = 11,
IEEE80211_CIPHER_SUITE_GMAC_256 = 12,
IEEE80211_CIPHER_SUITE_CMAC_256 = 13,
IEEE80211_CIPHER_SUITE_NONE = 255, // Not in the spec, a special value for driver to delete
// a key.
};
static inline const char* ieee80211_cipher_str(uint8_t* oui, uint8_t cipher_type) {
if (oui[0] != 0 || oui[1] != 0x0f || oui[2] != 0xac) {
return "vendor-specific OUI\n";
}
switch (cipher_type) {
case IEEE80211_CIPHER_SUITE_GROUP:
return "group";
case IEEE80211_CIPHER_SUITE_WEP_40:
return "WEP40";
case IEEE80211_CIPHER_SUITE_TKIP:
return "TKIP";
case IEEE80211_CIPHER_SUITE_CCMP_128:
return "CCMP128";
case IEEE80211_CIPHER_SUITE_WEP_104:
return "WEP104";
case IEEE80211_CIPHER_SUITE_CMAC_128:
return "CMAC_128";
case IEEE80211_CIPHER_SUITE_GCMP_128:
return "GCMP128";
case IEEE80211_CIPHER_SUITE_GCMP_256:
return "GCMP256";
case IEEE80211_CIPHER_SUITE_CCMP_256:
return "CCMP256";
case IEEE80211_CIPHER_SUITE_GMAC_128:
return "GMAC128";
case IEEE80211_CIPHER_SUITE_GMAC_256:
return "GMAC256";
case IEEE80211_CIPHER_SUITE_CMAC_256:
return "CMAC256";
default:
return "reserved CID value\n";
}
}
// clang-format on
#endif // GARNET_DRIVERS_WLAN_THIRD_PARTY_ATHEROS_ATH10K_IEEE80211_H_