# Copyright 2020 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

# This file contains descriptions of fields, structs and frames that are necessary to generate and inject 802.11 frames.
# Descriptions specified here follow the IEEE 802.11-2016 standard. It can be accessed here: https://ieeexplore.ieee.org/document/7786995 (the document is freely available through the IEEE GET program™).

include <linux/ieee80211.h>

# Mac addresses of virtual wifi devices created during executor initialization.
type ieee80211_fixed_mac_addr[LAST] {
	byte0	const[0x8, int8]
	byte1	const[0x2, int8]
	byte2	const[0x11, int8]
	byte3	const[0x0, int8]
	byte4	const[0x0, int8]
	byte5	LAST
} [packed]

ieee80211_mac_addr [
	device_a	ieee80211_fixed_mac_addr[const[0x0, int8]]
	device_b	ieee80211_fixed_mac_addr[const[0x1, int8]]
	broadcast	array[const[0xff, int8], 6]
]

ieee80211_ssid [
	random			array[int8, 0:IEEE80211_MAX_SSID_LEN]
	default_ibss_ssid	array[const[0x1, int8], 6]
	default_ap_ssid		array[const[0x2, int8], 6]
] [varlen]

ieee80211_mesh_id [
	default	array[const[0x3, int8], 6]
] [varlen]

ieee80211_frame [
	data_frame	ieee80211_data_frame
	mgmt_frame	ieee80211_mgmt_frame
	ctrl_frame	ieee80211_ctrl_frame
] [varlen]

ieee80211_bssid [
	initial		array[const[0x50, int8], 6]
	from_mac	ieee80211_mac_addr
	random		array[int8, 6]
]

# Inject an 802.11 frame.
# mac_addr -- mac address of the device that will receive the message (actually it determines
#   the network interface that will receive this message).
# buf -- raw 802.11 frame. It should neither include an FCS, nor leave space for it at the end of the frame.
syz_80211_inject_frame(mac_addr ptr[in, ieee80211_mac_addr], buf ptr[in, ieee80211_frame], buf_len len[buf]) (remote_cover)

# Pseudo system call that puts a specific interface into IBSS state and joins an IBSS network.
# Although it is done for all interfaces at executor initialization and the nl80211 commands that it executes
# are present in syzkaller descriptions of nl80211, experiments demonstrated that addition of this pseudo
# syscall provokes a much bigger number of issues.
# Also, this pseudo call makes it possible to put interfaces generated by sendmsg$NL80211_CMD_NEW_INTERFACE
# into an operable state at runtime.
syz_80211_join_ibss(interface ptr[in, string[nl80211_devnames]], ssid ptr[in, ieee80211_ssid], ssid_len len[ssid], join_mode flags[join_ibss_modes])

# Modes of syz_80211_join_ibss operation:
# JOIN_IBSS_NO_SCAN -- channel scan is not performed and syz_80211_join_ibss waits until the interface reaches IF_OPER_UP
# JOIN_IBSS_BG_SCAN -- channel scan is performed (takes ~ 9 seconds), syz_80211_join_ibss does not await IF_OPER_UP
# JOIN_IBSS_BG_NO_SCAN -- channel scan is not performed, syz_80211_join_ibss does not await IF_OPER_UP

define JOIN_IBSS_NO_SCAN	0x0
define JOIN_IBSS_BG_SCAN	0x1
define JOIN_IBSS_BG_NO_SCAN	0x2

join_ibss_modes = JOIN_IBSS_NO_SCAN, JOIN_IBSS_BG_SCAN, JOIN_IBSS_BG_NO_SCAN

################################################################################
#  Common fields and enums.
################################################################################

# As defined in drivers/net/wireless/mac80211_hwsim.c
ieee80211_channel_freq_mhz = 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484, 5180, 5200, 5220, 5240, 5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700, 5745, 5765, 5785, 5805, 5825, 5845, 5855, 5860, 5865, 5870, 5875, 5880, 5885, 5890, 5895, 5900, 5905, 5910, 5915, 5920, 5925

ieee80211_raw_rates = 10, 20, 55, 60, 90, 110, 120, 180, 240, 360, 480, 540

# Combined set of 802.11 rates for 5Mhz, 10Mhz and other channel widths.
# Only rates for drivers/net/wireless/mac80211_hwsim.c are defined.
ieee80211_rate_label = 1, 2, 3, 4, 5, 6, 9, 11, 12, 18, 22, 24, 27, 36, 48, 54, 72, 96, 108

# Rates as they are represented (see 9.4.2.3 of IEEEE 802.11-2016).
ieee80211_rate {
	label		flags[ieee80211_rate_label, int8:7]
	mandatory	int8:1
} [packed]

type ieee80211_beacon_interval[BASE_TYPE] [
	default	const[100, BASE_TYPE]
	random	BASE_TYPE
]

type ieee80211_timestamp int64

ieee80211_assoc_id [
	default	const[0x1, int16]
	random	int16
]

# Pseudo syscalls and initially created devices use the default frequency below.
type ieee80211_frequency_mhz[BASE_TYPE] [
	default	const[2412, BASE_TYPE]
	random	flags[ieee80211_channel_freq_mhz, BASE_TYPE]
]

# These are the channels supported by mac80211_hwsim.
ieee80211_channels = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165, 169, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185
type ieee80211_channel[BASE_TYPE] flags[ieee80211_channels, BASE_TYPE]

# HT Capabilities (see 9.4.2.56 of IEEE 802.11-2016).
ieee80211_ht_cap_info = IEEE80211_HT_CAP_LDPC_CODING, IEEE80211_HT_CAP_SUP_WIDTH_20_40, IEEE80211_HT_CAP_SM_PS, IEEE80211_HT_CAP_SM_PS_SHIFT, IEEE80211_HT_CAP_GRN_FLD, IEEE80211_HT_CAP_SGI_20, IEEE80211_HT_CAP_SGI_40, IEEE80211_HT_CAP_TX_STBC, IEEE80211_HT_CAP_RX_STBC, IEEE80211_HT_CAP_RX_STBC_SHIFT, IEEE80211_HT_CAP_DELAY_BA, IEEE80211_HT_CAP_MAX_AMSDU, IEEE80211_HT_CAP_DSSSCCK40, IEEE80211_HT_CAP_RESERVED, IEEE80211_HT_CAP_40MHZ_INTOLERANT, IEEE80211_HT_CAP_LSIG_TXOP_PROT

ieee80211_ht_ext_cap_info = IEEE80211_HT_EXT_CAP_PCO, IEEE80211_HT_EXT_CAP_PCO_TIME, IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT, IEEE80211_HT_EXT_CAP_MCS_FB, IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT, IEEE80211_HT_EXT_CAP_HTC_SUP, IEEE80211_HT_EXT_CAP_RD_RESPONDER

# See 9.4.2.56.4 of IEEE 802.11-2016.
ieee80211_mcs_info {
	rx_bitmask_1		int64
	rx_bitmask_2		int64:13
	reserved		const[0, int64:3]
	rx_highest_dr		int64:10
	reserved_2		const[0, int64:6]
	tx_set_defined		int64:1
	tx_rx_not_eq		int64:1
	max_spac_streams	int64:2
	uneq_modulation		int64:1
	reserved_3		const[0, int64:27]
} [packed]

# See Fig. 9-332 of IEEE 802.11-2016.
ieee80211_ht_cap {
	cap_info		flags[ieee80211_ht_cap_info, int16]
	a_mpdu_exponent		int8:2
	a_mpdu_min_spacing	int8:3
	a_mpdu_reserved		const[0, int8:3]
	mcs			ieee80211_mcs_info
	extended_ht_cap_info	flags[ieee80211_ht_ext_cap_info, int16]
	tx_BF_cap_info		int32
	antenna_selection_info	int8
} [packed]

# VHT Capabilities (see 9.4.2.56 of IEEE 802.11-2016).
ieee80211_vht_cap_info = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895, IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991, IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, IEEE80211_VHT_CAP_MAX_MPDU_MASK, IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ, IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ, IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK, IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT, IEEE80211_VHT_CAP_RXLDPC, IEEE80211_VHT_CAP_SHORT_GI_80, IEEE80211_VHT_CAP_SHORT_GI_160, IEEE80211_VHT_CAP_TXSTBC, IEEE80211_VHT_CAP_RXSTBC_1, IEEE80211_VHT_CAP_RXSTBC_2, IEEE80211_VHT_CAP_RXSTBC_3, IEEE80211_VHT_CAP_RXSTBC_4, IEEE80211_VHT_CAP_RXSTBC_MASK, IEEE80211_VHT_CAP_RXSTBC_SHIFT, IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE, IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE, IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT, IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT, IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE, IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE, IEEE80211_VHT_CAP_VHT_TXOP_PS, IEEE80211_VHT_CAP_HTC_VHT, IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT, IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB, IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB, IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN, IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN, IEEE80211_VHT_CAP_EXT_NSS_BW_SHIFT, IEEE80211_VHT_CAP_EXT_NSS_BW_MASK

ieee80211_vht_mcs_info {
	rx_mcs_map	int16
	rx_highest	int16
	tx_mcs_map	int16
	tx_highest	int16
} [packed]

ieee80211_vht_cap {
	vht_cap_info	flags[ieee80211_vht_cap_info, int32]
	supp_mcs	ieee80211_vht_mcs_info
} [packed]

# As defined by Table 9-45 of IEEE 802.11-2016.
type ieee80211_reason_code[BASE_TYPE] BASE_TYPE[0:66]

# As defined by Table 9-46 of IEEE 802.11-2016.
type ieee80211_status_code[BASE_TYPE] BASE_TYPE[0:107]

# Only NAV is supported at the moment. No CPE or PS-Poll frames.
ieee80211_duration {
	duration	int16:15
	nav_flag	const[0, int16:1]
} [packed]

# As defined in sect. 9.2.4.4.1 of IEEE 802.11-2016.
ieee80211_seq_control {
	frag_number	int16:4
	seq_number	int16:12
} [packed]

ieee80211_block_ack_ssc {
	fragment	int16:4
	ssn		int16:12
} [packed]

# As defined by Table 9-342 of IEEE 802.11-2016.
ieee80211_tdls_action_codes = WLAN_TDLS_SETUP_REQUEST, WLAN_TDLS_SETUP_RESPONSE, WLAN_TDLS_SETUP_CONFIRM, WLAN_TDLS_TEARDOWN, WLAN_TDLS_PEER_TRAFFIC_INDICATION, WLAN_TDLS_CHANNEL_SWITCH_REQUEST, WLAN_TDLS_CHANNEL_SWITCH_RESPONSE, WLAN_TDLS_PEER_PSM_REQUEST, WLAN_TDLS_PEER_PSM_RESPONSE, WLAN_TDLS_PEER_TRAFFIC_RESPONSE, WLAN_TDLS_DISCOVERY_REQUEST

# As defined by Table 9-131 of IEEE 802.11-2016.
ieee80211_cipher_suites = WLAN_CIPHER_SUITE_USE_GROUP, WLAN_CIPHER_SUITE_WEP40, WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, WLAN_CIPHER_SUITE_WEP104, WLAN_CIPHER_SUITE_AES_CMAC, WLAN_CIPHER_SUITE_GCMP, WLAN_CIPHER_SUITE_GCMP_256, WLAN_CIPHER_SUITE_CCMP_256, WLAN_CIPHER_SUITE_BIP_GMAC_128, WLAN_CIPHER_SUITE_BIP_GMAC_256, WLAN_CIPHER_SUITE_BIP_CMAC_256

# As defined by Table 9-133 of IEEE 802.11-2016.
ieee80211_akm_suites = WLAN_AKM_SUITE_8021X, WLAN_AKM_SUITE_PSK, WLAN_AKM_SUITE_FT_8021X, WLAN_AKM_SUITE_FT_PSK, WLAN_AKM_SUITE_8021X_SHA256, WLAN_AKM_SUITE_PSK_SHA256, WLAN_AKM_SUITE_TDLS, WLAN_AKM_SUITE_SAE, WLAN_AKM_SUITE_FT_OVER_SAE, WLAN_AKM_SUITE_AP_PEER_KEY, WLAN_AKM_SUITE_8021X_SUITE_B, WLAN_AKM_SUITE_8021X_SUITE_B_192, WLAN_AKM_SUITE_FT_8021X_SHA384, WLAN_AKM_SUITE_FILS_SHA256, WLAN_AKM_SUITE_FILS_SHA384, WLAN_AKM_SUITE_FT_FILS_SHA256, WLAN_AKM_SUITE_FT_FILS_SHA384, WLAN_AKM_SUITE_OWE, WLAN_AKM_SUITE_FT_PSK_SHA384, WLAN_AKM_SUITE_PSK_SHA384

# Capability Information field (see sect. 9.4.1.4 of IEEE 802.11-2016).
ieee80211_capabilities = WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_CF_POLLABLE, WLAN_CAPABILITY_CF_POLL_REQUEST, WLAN_CAPABILITY_PRIVACY, WLAN_CAPABILITY_SHORT_PREAMBLE, WLAN_CAPABILITY_PBCC, WLAN_CAPABILITY_CHANNEL_AGILITY, WLAN_CAPABILITY_SPECTRUM_MGMT, WLAN_CAPABILITY_QOS, WLAN_CAPABILITY_SHORT_SLOT_TIME, WLAN_CAPABILITY_APSD, WLAN_CAPABILITY_RADIO_MEASURE, WLAN_CAPABILITY_DSSS_OFDM, WLAN_CAPABILITY_DEL_BACK, WLAN_CAPABILITY_IMM_BACK

type ieee80211_capability[TYPE] flags[ieee80211_capabilities, TYPE]

# QoS Control field is quite complicated (see Table 9-6 of IEEE 802.11-2016), but
# for fuzzing purposes we don't really care about most of its bits.
type ieee80211_qos_control[A_MSDU] {
	tid		int8:4
	eosp		int8:1
	ack_policy	int8:2
	a_msdu		const[A_MSDU, int8:1]
	rest		int8
} [packed]

# Operating Mode field (see sect. 9.4.1.53 of IEEE 802.11-2016).
ieee80211_operating_mode {
	channel_width	int8:2
	supp_160_80_80	int8:1
	no_ldpc		int8:1
	rx_nss		int8:3
	rx_nss_type	int8:1
} [packed]

# SM Power Control field (see sect. 9.4.1.23 of IEEE 802.11-2016).
ieee80211_sm_power_control {
	smps_enabled	int8:1
	sm_mode		int8:1
	reserver	const[0, int8:6]
} [packed]

#############################################
# Basic 802.11 frame structures.
#############################################

ieee80211_ht_control_80211n {
	vht			const[0, int16:1]
	link_adaptation_ctrl	int16:15
	calibration_pos		int8:2
	calibration_seq		int8:2
	reserved_1		const[0, int8:2]
	csi_steering		int8:2
	ndp			int8:1
	reserved_2		const[0, int8:5]
	ac			int8:1
	rdg			int8:1
} [packed]

# 802.11ac introduced another version of this struct, but it is omitted because HT header is not supported by mac80211 anyway
ieee80211_ht_control [
	ver_80211n	ieee80211_ht_control_80211n
]

# Generic Frame Control field.
type ieee80211_fc[TO_DS, FROM_DS, TYPE, SUBTYPE] {
	version		const[0, int8:2]
	type		TYPE
	subtype		SUBTYPE
	to_ds		const[TO_DS, int8:1]
	from_ds		const[FROM_DS, int8:1]
	more		int8:1
	retry		int8:1
	power_mgmt	int8:1
	more_data	int8:1
	protected	const[0, int8:1]
	order		int8:1
} [packed]

# Control packets use a simpler version of Frame Control.
type ieee80211_control_fc[SUBTYPE_CONST] {
	version	const[0, int8:2]
	type	const[0x1, int8:2]
	subtype	const[SUBTYPE_CONST, int8:4]
	rest	const[0, int8:6]
} [packed]

define IEEE80211_MGMT_FRAME_TYPE	(IEEE80211_FTYPE_MGMT >> 2)
define IEEE80211_DATA_FRAME_TYPE	(IEEE80211_FTYPE_DATA >> 2)
define IEEE80211_CTL_FRAME_TYPE	(IEEE80211_FTYPE_CTL >> 2)

############################################
# Information Elements.
############################################

# Information Element structure (see 9.4.2.1 of IEEE 802.11-2016).
type ieee80211_generic_ie[ID_TYPE, DATA_TYPE] {
	id	ID_TYPE
	len	len[data, int8]
	data	DATA_TYPE
} [packed]

type ieee80211_generic_ie_const[ID_VAL, DATA_TYPE] ieee80211_generic_ie[const[ID_VAL, int8], DATA_TYPE]

type ieee80211_random_vendor_ie ieee80211_generic_ie_const[WLAN_EID_VENDOR_SPECIFIC, array[int8, 6:255]]

# SSID Information Element (see 9.4.2.2 of IEEE 802.11-2016).
type ieee80211_ie_ssid ieee80211_generic_ie_const[WLAN_EID_SSID, ieee80211_ssid]

# SSID Information Element (see 9.4.2.3 of IEEE 802.11-2016).
type ieee80211_ie_supported_rates ieee80211_generic_ie_const[WLAN_EID_SUPP_RATES, array[ieee80211_rate, 0:8]]

# DS Parameter Set / DSSS Information Element (see 9.4.2.4 of IEEE 802.11-2016).
type ieee80211_ie_dsss ieee80211_generic_ie_const[WLAN_EID_DS_PARAMS, ieee80211_channel[int8]]

# CF Parameter Set Information Element (see 9.4.2.5 of IEEE 802.11-2016).
ieee80211_ie_cf_payload {
	count		int8
	period		int8
	max_duration	int16
	dur_remaining	int16
} [packed]

type ieee80211_ie_cf ieee80211_generic_ie_const[WLAN_EID_CF_PARAMS, ieee80211_ie_cf_payload]

# Traffic Indication Map (TIM) Information Element (see 9.4.2.6 of IEEE 802.11-2016).
ieee80211_ie_tim_payload {
	dtim_count	int8
	dtim_period	int8[1:255]
	bitmap_control	int8
	partial_bitmap	array[int8, 0:251]
} [packed]

type ieee80211_ie_tim ieee80211_generic_ie_const[WLAN_EID_TIM, ieee80211_ie_tim_payload]

# IBSS Parameter Set Information Element (see 9.4.2.7 of IEEE 802.11-2016).
type ieee80211_ie_ibss ieee80211_generic_ie_const[WLAN_EID_IBSS_PARAMS, int16]

# Challenge Text Information Element (see 9.4.2.8 of IEEE 802.11-2016).
type ieee80211_ie_challenge ieee80211_generic_ie_const[WLAN_EID_CHALLENGE, int8[1:253]]

# Extended Rate PHY (ERP) Information Element (see 9.4.2.12 of IEEE 802.11-2016).
ieee80211_ie_erp_payload {
	non_erp_present		int8:1
	use_protection		int8:1
	barker_preamble_mode	int8:1
	reserved		const[0, int8:5]
} [packed]

type ieee80211_ie_erp ieee80211_generic_ie_const[WLAN_EID_ERP_INFO, ieee80211_ie_erp_payload]

# Channel Switch Announcement Information Element (see 9.4.2.19 of IEEE 802.11-2016).
ieee80211_ie_channel_switch_annce_payload {
	switch_mode	int8[0:1]
	new_channel	ieee80211_channel[int8]
	switch_count	int8
} [packed]

type ieee80211_ie_channel_switch ieee80211_generic_ie_const[WLAN_EID_CHANNEL_SWITCH, ieee80211_ie_channel_switch_annce_payload]

# Secondary Channel Offset Information Element (see 9.4.2.20 of IEEE 802.11-2016).
type ieee80211_ie_sec_chan_ofs ieee80211_generic_ie_const[WLAN_EID_SECONDARY_CHANNEL_OFFSET, int8[0:3]]

# Measurement Request Information Element (see 9.4.2.21 of IEEE 802.11-2016).
ieee80211_ie_measure_req_payload {
	token		int8
	mode		int8
	type		int8
	req_details	array[int8]
} [packed]

type ieee80211_ie_measure_req ieee80211_generic_ie_const[WLAN_EID_MEASURE_REQUEST, ieee80211_ie_measure_req_payload]

# Fast BSS Transition element (FTE) (see 9.4.2.48 of IEEE 802.11-2016).
ieee80211_ie_fast_bss_trans_payload {
	mic_control_reserved	int8
	mic_element_count	len[params, int8]
	mic			array[int8, 16]
	a_nonce			array[int8, 32]
	s_nonce			array[int8, 32]
	params			array[ieee80211_generic_ie[int8[1:4], array[int8, 0:40]]]
} [packed]

type ieee80211_ie_fast_bss_trans ieee80211_generic_ie_const[WLAN_EID_FAST_BSS_TRANSITION, ieee80211_ie_fast_bss_trans_payload]

# Extended Channel Switch Announcement Information Element (see 9.4.2.53 of IEEE 802.11-2016).
ieee80211_ie_ext_channel_switch_annce_payload {
	switch_mode	int8[0:1]
	new_class	int8
	new_channel	ieee80211_channel[int8]
	switch_count	int8
} [packed]

type ieee80211_ie_ext_channel_switch ieee80211_generic_ie_const[WLAN_EID_EXT_CHANSWITCH_ANN, ieee80211_ie_ext_channel_switch_annce_payload]

# Management MIC Information Element (see 9.4.2.55 of IEEE 802.11-2016).
type ieee80211_ie_mic ieee80211_generic_ie_const[WLAN_EID_MIC, ieee80211_ie_mic_payload]

ieee80211_ie_mic_code [
	short	array[int8, 8]
	long	array[int8, 16]
] [varlen]

ieee80211_ie_mic_payload {
	key_id	int16[0:4095]
	ipn	array[int8, 6]
	mic	ieee80211_ie_mic_code
} [packed]

# HT Capabilities Information Element (see 9.4.2.56 of IEEE 802.11-2016).
type ieee80211_ie_ht ieee80211_generic_ie_const[WLAN_EID_HT_CAPABILITY, ieee80211_ht_cap]

# Link Identifier Information Element (see 9.4.2.62 of IEEE 802.11-2016).
ieee80211_ie_link_id_payload {
	bssid		ieee80211_bssid
	initiator	ieee80211_mac_addr
	responder	ieee80211_mac_addr
} [packed]

type ieee80211_ie_link_id ieee80211_generic_ie_const[WLAN_EID_LINK_ID, ieee80211_ie_link_id_payload]

# Channel Switch Timing Information Element (see 9.4.2.64 of IEEE 802.11-2016).
ieee80211_ie_channel_switch_timing_payload {
	switch_time	int16
	switch_timeout	int16
} [packed]

type ieee80211_ie_channel_switch_timing ieee80211_generic_ie_const[WLAN_EID_CHAN_SWITCH_TIMING, ieee80211_ie_channel_switch_timing_payload]

# Mesh Configuration Information Element (see 9.4.2.98 of IEEE 802.11-2016).
type ieee80211_ie_mesh_config ieee80211_generic_ie_const[WLAN_EID_MESH_CONFIG, ieee80211_ie_mesh_config_payload]

ieee80211_ie_mesh_config_payload {
	psel_proto	int8[-1:1]
	psel_metric	int8[-1:1]
	cmode_id	int8[-1:1]
	syncm_id	int8[-1:1]
	auth_proto	int8[-1:2]
	mesh_info	int8
	mesh_cap	flags[mesh_config_capab_flags, int8]
} [packed]

mesh_config_capab_flags = IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS, IEEE80211_MESHCONF_CAPAB_FORWARDING, IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING, IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL

# Mesh Channel Switch Information Element (see 9.4.2.103 of IEEE 802.11-2016).
ieee80211_ie_mesh_channel_switch_payload {
	mesh_ttl	int8
	mesh_flags	int8
	mesh_reason	ieee80211_reason_code[int16]
	meash_pre_value	int16
} [packed]

type ieee80211_ie_mesh_channel_switch ieee80211_generic_ie_const[WLAN_EID_CHAN_SWITCH_PARAM, ieee80211_ie_mesh_channel_switch_payload]

# GCR Group Address Information Element (see 9.4.2.126 of IEEE 802.11-2016).
type ieee80211_ie_gcr_ga ieee80211_generic_ie_const[WLAN_EID_GCR_GROUP_ADDR, ieee80211_mac_addr]

# PREQ Information Element (see 9.4.2.113 of IEEE 802.11.2016).
type ieee80211_ie_preq ieee80211_generic_ie_const[WLAN_EID_PREQ, ieee80211_ie_preq_payload]

# See Figure 9-478 of IEEE 802.11-2016.
ieee80211_preq_flags {
	gate_anncement	int8:1
	addr_mode	int8:1
	proactive_prep	int8:1
	reserved	const[0, int8:3]
	ae		int8:1
	reserved_2	const[0, int8:1]
} [packed]

# See Figure 9-479 of IEEE 802.11-2016.
ieee80211_preq_target_flags {
	target_only	int8:1
	reserved	const[0, int8:1]
	usn		int8:1
	reserved2	const[0, int8:5]
} [packed]

ieee80211_preq_target {
	flags		ieee80211_preq_target_flags
	target_addr	ieee80211_mac_addr
	target_sn	int32
} [packed]

ieee80211_ie_preq_payload {
	flags		ieee80211_preq_flags
	hop_count	int8
	ttl		int8
	discovery_id	int32
	originator	ieee80211_mac_addr
	originator_sn	int32
	originator_ext	ieee80211_mac_addr	(if[value[flags:ae] == 1])
	lifetime	int32
	metric		int32
	target_count	len[targets, int8]
	targets		array[ieee80211_preq_target]
} [packed]

# PREP Information Element (see 9.4.2.113 of IEEE 802.11.2016).
type ieee80211_ie_prep ieee80211_generic_ie_const[WLAN_EID_PREP, ieee80211_ie_prep_payload]

# See Figure 9-481 and Figure 9-483 of IEEE 802.11.2016.
ieee80211_ae_flags {
	reserved	const[0, int8:6]
	ae		int8:1
	reserved2	const[0, int8:1]
} [packed]

ieee80211_ie_prep_payload {
	flags		ieee80211_ae_flags
	hop_count	int8
	ttl		int8
	target_addr	ieee80211_mac_addr
	target_sn	int32
	target_ext	ieee80211_mac_addr	(if[value[flags:ae] == 1])
	lifetime	int32
	metric		int32
	originator	ieee80211_mac_addr
	originator_sn	int32
} [packed]

# PERR Information Element (see 9.4.2.115 of IEEE 802.11.2016).
type ieee80211_ie_perr ieee80211_generic_ie_const[WLAN_EID_PERR, ieee80211_ie_perr_payload]

ieee80211_ie_perr_payload {
	ttl		int8
	dest_count	len[dest_list, int8]
	dest_list	array[ieee80211_ie_perr_dest, 0:19]
} [packed]

ieee80211_ie_perr_dest {
	flags		ieee80211_ae_flags
	dest_addr	ieee80211_mac_addr
	dest_sn		int32
	dest_ext	ieee80211_mac_addr	(if[value[flags:ae] == 1])
	reason		ieee80211_reason_code[int16]
} [packed]

# RANN Information Element (see 9.4.2.112 of IEEE 802.11-2016).
type ieee80211_ie_rann ieee80211_generic_ie_const[WLAN_EID_RANN, ieee80211_ie_rann_payload]

# See Figure 9-476 of IEEE 802.11-2016.
ieee80211_rann_flags {
	gate_annce	int8:1
	reserved	int8:7
} [packed]

ieee80211_ie_rann_payload {
	flags		ieee80211_rann_flags
	hop_count	int8
	ttl		int8
	root_sta	ieee80211_mac_addr
	hwmp_seqno	int32
	interval	int32
	metric		int32
} [packed]

# Mesh ID Information Element (see 9.4.2.99 of IEEE 802.11-2016).
type ieee80211_ie_mesh_id ieee80211_generic_ie_const[WLAN_EID_MESH_ID, ieee80211_mesh_id]

# Mesh Peering Management (see 9.4.2.102 of IEEE 802.11-2016).
type ieee80211_ie_peer_mgmt ieee80211_generic_ie_const[WLAN_EID_PEER_MGMT, ieee80211_ie_peering_mgmt_payload]

ieee80211_ie_peering_mgmt_payload {
	proto_id	int16[0:1]
	local_link_id	int16
	peer_link_id	optional[int16]
	reason_code	optional[ieee80211_reason_code[int16]]
	pmk		optional[array[int8, 16]]
} [packed]

# This union is not used in packet descriptions because IEs have a strictly specified order there.
# It is only needed to feed nl80211 commands that require IEs.
ieee80211_ie [
	ssid			ieee80211_ie_ssid
	supported_rates		ieee80211_ie_supported_rates
	dsss			ieee80211_ie_dsss
	cf			ieee80211_ie_cf
	tim			ieee80211_ie_tim
	ibss			ieee80211_ie_ibss
	challenge		ieee80211_ie_challenge
	erp			ieee80211_ie_erp
	channel_switch		ieee80211_ie_channel_switch
	sec_chan_ofs		ieee80211_ie_sec_chan_ofs
	measure_req		ieee80211_ie_measure_req
	fast_bss_trans		ieee80211_ie_fast_bss_trans
	ext_channel_switch	ieee80211_ie_ext_channel_switch
	ht			ieee80211_ie_ht
	link_id			ieee80211_ie_link_id
	chsw_timing		ieee80211_ie_channel_switch_timing
	mesh_chsw		ieee80211_ie_mesh_channel_switch
	gcr_ga			ieee80211_ie_gcr_ga
	preq			ieee80211_ie_preq
	prep			ieee80211_ie_prep
	perr			ieee80211_ie_perr
	rann			ieee80211_ie_rann
	mesh_id			ieee80211_ie_mesh_id
	mesh_config		ieee80211_ie_mesh_config
	peer_mgmt		ieee80211_ie_peer_mgmt
	mic			ieee80211_ie_mic
	random_vendor		ieee80211_random_vendor_ie
	random			ieee80211_generic_ie[int8, array[int8, 0:253]]
] [varlen]

##################################################
# 802.11 Data frames (9.3.2 of IEEE 802.11-2016)
##################################################

# Specific 802.11 data frame headers determined by to_ds and from_ds values.
# See Table 26 of IEEE 802.11-2016.

type ieee80211_data_gen_hdr[TO, FROM, ADDR_1, ADDR_2, ADDR_3, ADDR_4, A_MSDU] {
	fc		ieee80211_fc[TO, FROM, const[IEEE80211_DATA_FRAME_TYPE, int8:2], int8:4]
	duration	ieee80211_duration
	addr_1		ADDR_1
	addr_2		ADDR_2
	addr_3		ADDR_3
	seqno		ieee80211_seq_control
	addr_4		ADDR_4
	qos		ieee80211_qos_control[A_MSDU]	(if[value[fc:subtype] & 0x8])
# It can be somewhat more nuanced, but for data frames it should work.
	ht		ieee80211_ht_control	(if[value[fc:order] == 1])
} [packed]

ieee80211_msdu_header [
# 00: RA = DA, TA = SA, BSSID
	type00	ieee80211_data_gen_hdr[0, 0, ieee80211_mac_addr, ieee80211_mac_addr, ieee80211_bssid, void, 0]
# 01: RA = DA, TA = BSSID, SA
	type01	ieee80211_data_gen_hdr[0, 1, ieee80211_mac_addr, ieee80211_bssid, ieee80211_mac_addr, void, 0]
# 10: RA = BSSID, TA = SA, DA
	type10	ieee80211_data_gen_hdr[1, 0, ieee80211_bssid, ieee80211_mac_addr, ieee80211_mac_addr, void, 0]
# 11: RA, TA, DA, SA
	type11	ieee80211_data_gen_hdr[1, 1, ieee80211_mac_addr, ieee80211_mac_addr, ieee80211_mac_addr, ieee80211_mac_addr, 0]
] [varlen]

ieee80211_a_msdu_header [
# 00: RA = DA, TA = SA, BSSID
	type00	ieee80211_data_gen_hdr[0, 0, ieee80211_mac_addr, ieee80211_mac_addr, ieee80211_bssid, void, 1]
# 01: RA = DA, TA = BSSID, BSSID
	type01	ieee80211_data_gen_hdr[0, 1, ieee80211_mac_addr, ieee80211_bssid, ieee80211_bssid, void, 1]
# 10: RA = BSSID, TA = SA, BSSID
	type10	ieee80211_data_gen_hdr[1, 0, ieee80211_bssid, ieee80211_mac_addr, ieee80211_bssid, void, 1]
# 11: RA, TA, BSSID, SA
	type11	ieee80211_data_gen_hdr[1, 1, ieee80211_mac_addr, ieee80211_mac_addr, ieee80211_bssid, ieee80211_mac_addr, 1]
] [varlen]

ieee80211_data_frame_hdr [
	msdu	ieee80211_msdu_header
	a_msdu	ieee80211_a_msdu_header
] [varlen]

ieee80211_a_msdu_subframe {
	da	ieee80211_mac_addr
	sa	ieee80211_mac_addr
	len	len[data, int16]
	data	array[int8]
} [packed, align[4]]

ieee80211_data_frame_payload [
	random	array[int8, 0:IEEE80211_MAX_DATA_LEN]
# TODO: here it could have helped to reference conditional fields in if[].
	a_msdu	array[ieee80211_a_msdu_subframe]
] [varlen]

ieee80211_data_frame {
	header	ieee80211_data_frame_hdr
	payload	ieee80211_data_frame_payload
} [packed]

###############################################
# 802.11 Management frames
###############################################

define IEEE80211_MGMT_FRAME_ASSOC_REQ	(IEEE80211_STYPE_ASSOC_REQ >> 4)
define IEEE80211_MGMT_FRAME_ASSOC_RESP	(IEEE80211_STYPE_ASSOC_RESP >> 4)
define IEEE80211_MGMT_FRAME_REASSOC_REQ	(IEEE80211_STYPE_REASSOC_REQ >> 4)
define IEEE80211_MGMT_FRAME_REASSOC_RESP	(IEEE80211_STYPE_REASSOC_RESP >> 4)
define IEEE80211_MGMT_FRAME_PROBE_REQ	(IEEE80211_STYPE_PROBE_REQ >> 4)
define IEEE80211_MGMT_FRAME_PROBE_RESP	(IEEE80211_STYPE_PROBE_RESP >> 4)
define IEEE80211_MGMT_FRAME_BEACON	(IEEE80211_STYPE_BEACON >> 4)
define IEEE80211_MGMT_FRAME_ATIM	(IEEE80211_STYPE_ATIM >> 4)
define IEEE80211_MGMT_FRAME_DISASSOC	(IEEE80211_STYPE_DISASSOC >> 4)
define IEEE80211_MGMT_FRAME_AUTH	(IEEE80211_STYPE_AUTH >> 4)
define IEEE80211_MGMT_FRAME_DEAUTH	(IEEE80211_STYPE_DEAUTH >> 4)
define IEEE80211_MGMT_FRAME_ACTION	(IEEE80211_STYPE_ACTION >> 4)
define IEEE80211_MGMT_FRAME_ACTION_NOACK	((IEEE80211_STYPE_ACTION >> 4) + 1)

type ieee80211_mgmt_header[SUBTYPE_CONST] {
	fc		ieee80211_fc[0, 0, const[IEEE80211_MGMT_FRAME_TYPE, int8:2], const[SUBTYPE_CONST, int8:4]]
	duration	ieee80211_duration
	addr_1		ieee80211_mac_addr
	addr_2		ieee80211_mac_addr
	addr_3		ieee80211_bssid
	seqno		ieee80211_seq_control
	ht		ieee80211_ht_control	(if[value[fc:order] == 1])
} [packed]

# Beacon frame (see Table 9-27 of IEEE 802.11-2016).
ieee80211_mgmt_beacon {
	header		ieee80211_mgmt_header[IEEE80211_MGMT_FRAME_BEACON]
	timestamp	ieee80211_timestamp
	beacon_interval	ieee80211_beacon_interval[int16]
	capability	ieee80211_capability[int16]
	ssid		optional[ieee80211_ie_ssid]
	supported_rates	optional[ieee80211_ie_supported_rates]
	dsss		optional[ieee80211_ie_dsss]
	cf		optional[ieee80211_ie_cf]
	ibss		optional[ieee80211_ie_ibss]
	tim		optional[ieee80211_ie_tim]
	chsw		optional[ieee80211_ie_channel_switch]
	erp		optional[ieee80211_ie_erp]
	expt_chsw	optional[ieee80211_ie_ext_channel_switch]
	ht		optional[ieee80211_ie_ht]
	mesh_id		optional[ieee80211_ie_mesh_id]
	mesh_config	optional[ieee80211_ie_mesh_config]
	mesh_chsw	optional[ieee80211_ie_mesh_channel_switch]
	vendor		array[ieee80211_random_vendor_ie]
} [packed]

# Disassociation frame (see Table 9-28 of IEEE 802.11-2016).
ieee80211_mgmt_disassoc_frame {
	header		ieee80211_mgmt_header[IEEE80211_MGMT_FRAME_DISASSOC]
	reason_code	ieee80211_reason_code[int16]
	mic		optional[ieee80211_ie_mic]
} [packed]

# Association Request (see Table 9-29 of IEEE 802.11-2016).
ieee80211_mgmt_assoc_req_frame {
	header		ieee80211_mgmt_header[IEEE80211_MGMT_FRAME_ASSOC_REQ]
	capabilities	ieee80211_capability[int16]
	listen_interval	int16
	ssid		ieee80211_ie_ssid
	supported_rates	optional[ieee80211_ie_supported_rates]
	ht		optional[ieee80211_ie_ht]
	vendor		array[ieee80211_random_vendor_ie]
} [packed]

# Association Response (see Table 9-30 of IEEE 802.11-2016).
ieee80211_mgmt_assoc_resp_frame {
	header		ieee80211_mgmt_header[IEEE80211_MGMT_FRAME_ASSOC_RESP]
	capabilities	ieee80211_capability[int16]
	status_code	ieee80211_status_code[int16]
	assoc_id	ieee80211_assoc_id
	supported_rates	optional[ieee80211_ie_supported_rates]
	ht		optional[ieee80211_ie_ht]
	vendor		array[ieee80211_random_vendor_ie]
} [packed]

# Reassociation Request (see Table 9-31 of IEEE 802.11-2016).
ieee80211_mgmt_reassoc_req_frame {
	header		ieee80211_mgmt_header[IEEE80211_MGMT_FRAME_REASSOC_REQ]
	capabilities	ieee80211_capability[int16]
	listen_interval	int16
	current_ap	ieee80211_mac_addr
	ssid		ieee80211_ie_ssid
	supported_rates	optional[ieee80211_ie_supported_rates]
	ht		optional[ieee80211_ie_ht]
	vendor		array[ieee80211_random_vendor_ie]
} [packed]

# Reassociation Response (see Table 9-32 of IEEE 802.11-2016).
ieee80211_mgmt_reassoc_resp_frame {
	header		ieee80211_mgmt_header[IEEE80211_MGMT_FRAME_REASSOC_RESP]
	capabilities	ieee80211_capability[int16]
	status_code	ieee80211_status_code[int16]
	assoc_id	ieee80211_assoc_id
	supported_rates	optional[ieee80211_ie_supported_rates]
	ht		optional[ieee80211_ie_ht]
	vendor		array[ieee80211_random_vendor_ie]
} [packed]

# Probe Request (see Table 9-33 of IEEE 802.11-2016).
ieee80211_mgmt_probe_request {
	header		ieee80211_mgmt_header[IEEE80211_MGMT_FRAME_PROBE_REQ]
	ssid		optional[ieee80211_ie_ssid]
	supported_rates	optional[ieee80211_ie_supported_rates]
	dsss		optional[ieee80211_ie_dsss]
	ht		optional[ieee80211_ie_ht]
	mesh_id		optional[ieee80211_ie_mesh_id]
	vendor		array[ieee80211_random_vendor_ie]
} [packed]

# Probe Response (see Table 9-34 of IEEE 802.11-2016).
ieee80211_mgmt_probe_response {
	header		ieee80211_mgmt_header[IEEE80211_MGMT_FRAME_PROBE_RESP]
	timestamp	ieee80211_timestamp
	beacon_interval	ieee80211_beacon_interval[int16]
	capabilities	ieee80211_capability[int16]
	ssid		optional[ieee80211_ie_ssid]
	supported_rates	optional[ieee80211_ie_supported_rates]
	dsss		optional[ieee80211_ie_dsss]
	cf		optional[ieee80211_ie_cf]
	ibss		optional[ieee80211_ie_ibss]
	ht		optional[ieee80211_ie_ht]
	mesh_id		optional[ieee80211_ie_mesh_id]
	mesh_config	optional[ieee80211_ie_mesh_config]
	vendor		array[ieee80211_random_vendor_ie]
} [packed]

# Authentication (see Table 9-35 of IEEE 802.11-2016).
ieee80211_mgmt_auth_frame {
	header		ieee80211_mgmt_header[IEEE80211_MGMT_FRAME_AUTH]
	algo		int16[0:1]
	trans_seq	int16[0:4]
	status		ieee80211_status_code[int16]
	challenge_tag	optional[ieee80211_ie_challenge]
	vendor		array[ieee80211_random_vendor_ie]
} [packed]

# Deauthenticaiton (see Table 9-37 of IEEE 802.11-2016).
ieee80211_mgmt_deauth_frame {
	header		ieee80211_mgmt_header[IEEE80211_MGMT_FRAME_DEAUTH]
	reason_code	ieee80211_reason_code[int16]
	mic		optional[ieee80211_ie_mic]
} [packed]

ieee80211_mgmt_frame [
	probe_request	ieee80211_mgmt_probe_request
	probe_response	ieee80211_mgmt_probe_response
	beacon		ieee80211_mgmt_beacon
	action		ieee80211_mgmt_action
	action_no_ack	ieee80211_mgmt_action_no_ack
	assoc_req	ieee80211_mgmt_assoc_req_frame
	assoc_resp	ieee80211_mgmt_assoc_resp_frame
	disassoc	ieee80211_mgmt_disassoc_frame
	deauth		ieee80211_mgmt_deauth_frame
	reassoc_req	ieee80211_mgmt_reassoc_req_frame
	reassoc_resp	ieee80211_mgmt_reassoc_resp_frame
	auth		ieee80211_mgmt_auth_frame
] [varlen]

######################################################
# 802.11 Management Action frames
######################################################

# This is a large group of frames, so it is placed in a separate section.

type ieee80211_mgmt_action_raw[CATEGORY, ACTION, PAYLOAD_TYPE] {
	category	const[CATEGORY, int8]
	action		const[ACTION, int8]
	payload		PAYLOAD_TYPE
} [packed]

# Measurement Request (see sect. 9.6.2.2 of IEEE 802.11-2016).
ieee80211_mgmt_action_measure_req {
	dialog_token	int8
	ie		array[ieee80211_ie_measure_req]
} [packed]

# Channel Switch Announcement (see sect. 9.6.2.6 of IEEE 802.11-2016).
ieee80211_mgmt_action_channel_switch {
	channel_switch	ieee80211_ie_channel_switch
	secondary	optional[ieee80211_ie_sec_chan_ofs]
	mesh		optional[ieee80211_ie_mesh_channel_switch]
} [packed]

# ADDBA Request (see sect. 9.6.5.2 of IEEE 802.11-2016).
ieee80211_mgmt_action_addba_req {
	dialog_token	int8
	block_ack_param	ieee80211_block_ack_param_set
	timeout_value	int16
	ssc		ieee80211_block_ack_ssc
} [packed]

ieee80211_block_ack_param_set {
	amsdu_supported		int16:1
	block_ack_policy	int16:1
	tid			int16:4
	buffer_size		int16:10
} [packed]

# ADDBA Response (see sect. 9.6.5.3 of IEEE 802.11-2016).
ieee80211_mgmt_action_addba_resp {
	dialog_token	int8
	status		ieee80211_status_code[int16]
	block_ack_param	ieee80211_block_ack_param_set
	timeout_value	int16
} [packed]

# DELBA (see sect. 9.6.5.4 of IEEE 802.11-2016).
ieee80211_mgmt_action_delba {
	delba_params	ieee80211_delba_param_set
	reason		ieee80211_reason_code[int16]
	group_addr_ie	ieee80211_ie_gcr_ga
} [packed]

ieee80211_delba_param_set {
	reserved	const[0, int16:11]
	initiator	int16:1
	tid		int16:4
} [packed]

# Extended Channel Switch Announcement (see sect. 9.6.8.7 of IEEE 802.11-2016).
ieee80211_mgmt_action_ext_chan_switch {
	annce_ie	ieee80211_ie_ext_channel_switch_annce_payload
	mesh_ie		optional[ieee80211_ie_mesh_channel_switch]
} [packed]

# See Table 9-343 and Table 9-344 of 802.11-2016.
type ieee80211_mgmt_action_generic_tdls_setup[ACTION, STATUS] {
	category	const[WLAN_CATEGORY_TDLS, int8]
	action		const[ACTION, int8]
	status		STATUS
	dialog_token	int8
	capability	optional[ieee80211_capability[int16]]
	supported_rates	optional[ieee80211_ie_supported_rates]
	ht		optional[ieee80211_ie_ht]
	link_id		optional[ieee80211_ie_link_id]
} [packed]

# TDLS Setup Confirm (see sect. 9.6.13.4 of IEEE 802.11-2016).
ieee80211_mgmt_action_tdls_cfm {
	status		ieee80211_status_code[int16]
	dialog_token	int8
} [packed]

# TDLS Channel Switch Request (see sect. 9.6.13.7 of IEEE 802.11-2016).
ieee80211_mgmt_action_tdls_chsw_req {
	target_channel	ieee80211_channel[int8]
	operating_class	int8
	secondary	optional[ieee80211_ie_sec_chan_ofs]
	link_id		ieee80211_ie_link_id
	timing		ieee80211_ie_channel_switch_timing
} [packed]

# TDLS Channel Switch Response (see sect. 9.6.13.8 of IEEE 802.11-2016).
ieee80211_mgmt_action_tdls_chsw_resp {
	status	ieee80211_status_code[int16]
	link_id	ieee80211_ie_link_id
	timing	ieee80211_ie_channel_switch_timing
} [packed]

# TDLS Discovery Request (see sect. 9.6.13.12 of IEEE 802.11-2016).
ieee80211_mgmt_action_tdls_disc_req {
	dialog_token	int8
	link_id		ieee80211_ie_link_id
} [packed]

# TDLS Teardown (see sect. 9.6.13.5 of IEEE 802.11-2016).
ieee80211_mgmt_action_tdls_teardown {
	reason	ieee80211_reason_code[int16]
	fte	ieee80211_ie_fast_bss_trans
	link_id	ieee80211_ie_link_id
} [packed]

# Notify Channel Width (see sect. 9.6.12.2 of IEEE 802.11-2016).
type ieee80211_mgmt_action_notify_ch_sw int8[0:1]

# Group ID Management (see sect. 9.6.23.3 of IEEE 802.11-2016).
ieee80211_mgmt_action_group_id {
	membership_status	int64
	user_positions		array[int8, 16]
} [packed]

# Operating Mode Notification (see sect. 9.6.23.4 of IEEE 802.11-2016).
type ieee80211_mgmt_action_op_mode_ntf ieee80211_operating_mode

# HWMP Mesh Path Selection (see sect. 9.6.17.3 of IEEE 802.11-2016).
ieee80211_mgmt_action_hwmp_path_sel {
	preq	optional[ieee80211_ie_preq]
	prep	optional[ieee80211_ie_prep]
	perr	optional[ieee80211_ie_perr]
	rann	optional[ieee80211_ie_rann]
} [packed]

# Mesh Peering Open (see sect. 9.6.16.2 of IEEE 802.11-2016).
ieee80211_mgmt_action_mesh_peering_open {
	capability	ieee80211_capability[int16]
	supported_rates	ieee80211_ie_supported_rates
	mesh_id		optional[ieee80211_ie_mesh_id]
	ht		optional[ieee80211_ie_ht]
} [packed]

# Mesh Peering Confirm (see sect. 9.6.16.3 of IEEE 802.11-2016).
ieee80211_mgmt_action_mesh_peering_confirm {
	capability	ieee80211_capability[int16]
	aid		ieee80211_assoc_id
	supported_rates	ieee80211_ie_supported_rates
	mesh_id		optional[ieee80211_ie_mesh_id]
	ht		optional[ieee80211_ie_ht]
} [packed]

# Mesh Peering Close (see sect. 9.6.16.4 of IEEE 802.11-2016).
ieee80211_mgmt_action_mesh_peering_close {
	mesh_id	ieee80211_ie_mesh_id
	mgmt	ieee80211_ie_peer_mgmt
} [packed]

ieee80211_mgmt_action_payload [
	measure_req	ieee80211_mgmt_action_raw[WLAN_CATEGORY_SPECTRUM_MGMT, WLAN_ACTION_SPCT_MSR_REQ, ieee80211_mgmt_action_measure_req]
	channel_switch	ieee80211_mgmt_action_raw[WLAN_CATEGORY_SPECTRUM_MGMT, WLAN_ACTION_SPCT_CHL_SWITCH, ieee80211_mgmt_action_channel_switch]
	addba_req	ieee80211_mgmt_action_raw[WLAN_CATEGORY_BACK, WLAN_ACTION_ADDBA_REQ, ieee80211_mgmt_action_addba_req]
	addba_resp	ieee80211_mgmt_action_raw[WLAN_CATEGORY_BACK, WLAN_ACTION_ADDBA_RESP, ieee80211_mgmt_action_addba_resp]
	delba		ieee80211_mgmt_action_raw[WLAN_CATEGORY_BACK, WLAN_ACTION_DELBA, ieee80211_mgmt_action_delba]
	ext_ch_sw	ieee80211_mgmt_action_raw[WLAN_CATEGORY_PUBLIC, WLAN_PUB_ACTION_EXT_CHANSW_ANN, ieee80211_mgmt_action_ext_chan_switch]
	ntf_ch_w	ieee80211_mgmt_action_raw[WLAN_CATEGORY_HT, WLAN_HT_ACTION_NOTIFY_CHANWIDTH, ieee80211_mgmt_action_notify_ch_sw]
	smps		ieee80211_mgmt_action_raw[WLAN_CATEGORY_HT, WLAN_HT_ACTION_SMPS, ieee80211_sm_power_control]
	sa_query_req	ieee80211_mgmt_action_raw[WLAN_CATEGORY_SA_QUERY, WLAN_ACTION_SA_QUERY_REQUEST, int16]
	tdls_setup_req	ieee80211_mgmt_action_generic_tdls_setup[WLAN_TDLS_SETUP_REQUEST, void]
	tdls_setup_resp	ieee80211_mgmt_action_generic_tdls_setup[WLAN_TDLS_SETUP_RESPONSE, ieee80211_status_code[int16]]
	tdls_setup_cfm	ieee80211_mgmt_action_raw[WLAN_CATEGORY_TDLS, WLAN_TDLS_SETUP_CONFIRM, ieee80211_mgmt_action_tdls_cfm]
	tdls_teardown	ieee80211_mgmt_action_raw[WLAN_CATEGORY_TDLS, WLAN_TDLS_TEARDOWN, ieee80211_mgmt_action_tdls_teardown]
	tdls_chsw_req	ieee80211_mgmt_action_raw[WLAN_CATEGORY_TDLS, WLAN_TDLS_CHANNEL_SWITCH_REQUEST, ieee80211_mgmt_action_tdls_chsw_req]
	tdls_chsw_resp	ieee80211_mgmt_action_raw[WLAN_CATEGORY_TDLS, WLAN_TDLS_CHANNEL_SWITCH_RESPONSE, ieee80211_mgmt_action_tdls_chsw_resp]
	tdls_disc_req	ieee80211_mgmt_action_raw[WLAN_CATEGORY_TDLS, WLAN_TDLS_DISCOVERY_REQUEST, ieee80211_mgmt_action_tdls_disc_req]
	vht_op_mode_ntf	ieee80211_mgmt_action_raw[WLAN_CATEGORY_VHT, WLAN_VHT_ACTION_OPMODE_NOTIF, ieee80211_mgmt_action_op_mode_ntf]
	vht_group_id	ieee80211_mgmt_action_raw[WLAN_CATEGORY_VHT, WLAN_VHT_ACTION_GROUPID_MGMT, ieee80211_mgmt_action_group_id]
	mesh_hwmp_psel	ieee80211_mgmt_action_raw[WLAN_CATEGORY_MESH_ACTION, WLAN_MESH_ACTION_HWMP_PATH_SELECTION, ieee80211_mgmt_action_hwmp_path_sel]
	sp_mp_open	ieee80211_mgmt_action_raw[WLAN_CATEGORY_SELF_PROTECTED, WLAN_SP_MESH_PEERING_OPEN, ieee80211_mgmt_action_mesh_peering_open]
	sp_mp_confirm	ieee80211_mgmt_action_raw[WLAN_CATEGORY_SELF_PROTECTED, WLAN_SP_MESH_PEERING_CONFIRM, ieee80211_mgmt_action_mesh_peering_confirm]
	sp_mp_close	ieee80211_mgmt_action_raw[WLAN_CATEGORY_SELF_PROTECTED, WLAN_SP_MESH_PEERING_CLOSE, ieee80211_mgmt_action_mesh_peering_close]
] [varlen]

ieee80211_mgmt_action {
	header	ieee80211_mgmt_header[IEEE80211_MGMT_FRAME_ACTION]
	payload	ieee80211_mgmt_action_payload
} [packed]

ieee80211_mgmt_action_no_ack {
	header	ieee80211_mgmt_header[IEEE80211_MGMT_FRAME_ACTION_NOACK]
	payload	ieee80211_mgmt_action_payload
} [packed]

####################################
#  Control frames.
####################################

# For details see sect. 9.3.1 of IEEE 802.11-2016.

define IEEE80211_MGMT_CTL_CTL_EXT	(IEEE80211_STYPE_CTL_EXT >> 4)
define IEEE80211_MGMT_CTL_BACK_REQ	(IEEE80211_STYPE_BACK_REQ >> 4)
define IEEE80211_MGMT_CTL_BACK	(IEEE80211_STYPE_BACK >> 4)
define IEEE80211_MGMT_CTL_PSPOLL	(IEEE80211_STYPE_PSPOLL >> 4)
define IEEE80211_MGMT_CTL_RTS	(IEEE80211_STYPE_RTS >> 4)
define IEEE80211_MGMT_CTL_CTS	(IEEE80211_STYPE_CTS >> 4)
define IEEE80211_MGMT_CTL_ACK	(IEEE80211_STYPE_ACK >> 4)
define IEEE80211_MGMT_CTL_CFEND	(IEEE80211_STYPE_CFEND >> 4)
define IEEE80211_MGMT_CTL_CFENDACK	(IEEE80211_STYPE_CFENDACK >> 4)

# Request to Send (RTS) frame.
ieee80211_ctrl_rts {
	header		ieee80211_control_fc[IEEE80211_MGMT_CTL_RTS]
	duration	ieee80211_duration
	receiver	ieee80211_mac_addr
	transmitter	ieee80211_mac_addr
} [packed]

# Clear to Send (CTS) frame.
ieee80211_ctrl_cts {
	header		ieee80211_control_fc[IEEE80211_MGMT_CTL_CTS]
	duration	ieee80211_duration
	receiver	ieee80211_mac_addr
} [packed]

# Acknowledgement (ACK) frame.
ieee80211_ctrl_ack {
	header		ieee80211_control_fc[IEEE80211_MGMT_CTL_ACK]
	duration	ieee80211_duration
	receiver	ieee80211_mac_addr
} [packed]

# Contention-Free End (CF-End) frame.
ieee80211_ctrl_cf_end {
	header		ieee80211_control_fc[IEEE80211_MGMT_CTL_CFEND]
	duration	ieee80211_duration
	receiver	ieee80211_mac_addr
	bssid		ieee80211_bssid
} [packed]

# CF-End & CF-Ack frame.
ieee80211_ctrl_cf_end_cf_ack {
	header		ieee80211_control_fc[IEEE80211_MGMT_CTL_CFENDACK]
	duration	ieee80211_duration
	receiver	ieee80211_mac_addr
	transmitter	ieee80211_mac_addr
} [packed]

# Power-Save Poll (PS-Poll) frame.
ieee80211_ctrl_pspoll {
	header		ieee80211_control_fc[IEEE80211_MGMT_CTL_PSPOLL]
	assoc_id	ieee80211_assoc_id
	bssid		ieee80211_bssid
	transmitter	ieee80211_mac_addr
} [packed]

# Block Ack Request (BAR) frame (802.11n).
type ieee80211_ctrl_bar_control[MULTI_CONST, COMPRESSED_CONST, TID_INFO] {
	ack_policy		int8:1
	multi_tid		const[MULTI_CONST, int8:1]
	compressed_bitmap	const[COMPRESSED_CONST, int8:1]
	reserved		const[0, int16:9]
	tid_info		TID_INFO
} [packed]

type ieee80211_ctrl_bar_info[SUFFIX] {
	tid_reserved	const[0, int16:12]
	tid_value	int16:4
	ssc		ieee80211_block_ack_ssc
	suffix		SUFFIX
} [packed]

type ieee80211_ctrl_bar_simple_req[COMPRESSED] {
	control_hdr	ieee80211_ctrl_bar_control[0, COMPRESSED, int8:4]
	ssc		ieee80211_block_ack_ssc
} [packed]

ieee80211_ctrl_bar_multi {
	control		ieee80211_ctrl_bar_control[1, 1, len[ieee80211_ctrl_bar_multi:bar_info, int8:4]]
	bar_info	array[ieee80211_ctrl_bar_info[array[int8, 8]]]
} [packed]

ieee80211_ctrl_bar_any [
	basic		ieee80211_ctrl_bar_simple_req[0]
	compressed	ieee80211_ctrl_bar_simple_req[1]
	multi		ieee80211_ctrl_bar_multi
] [varlen]

ieee80211_ctrl_bar {
	header		ieee80211_control_fc[IEEE80211_MGMT_CTL_BACK_REQ]
	duration	ieee80211_duration
	receiver	ieee80211_mac_addr
	transmitter	ieee80211_mac_addr
	payload		ieee80211_ctrl_bar_any
} [packed]

# Block Ack (BA) frame (802.11n).
type ieee80211_ctrl_ba_single[COMPRESSED, LEN] {
	control		ieee80211_ctrl_bar_control[0, COMPRESSED, int8:4]
	ssc		ieee80211_block_ack_ssc
	ack_bitmap	array[int8, LEN]
} [packed]

ieee80211_ctrl_ba_multi {
	control		ieee80211_ctrl_bar_control[1, 1, len[ieee80211_ctrl_ba_multi:tid_list, int8:4]]
	tid_list	array[ieee80211_ctrl_bar_info[array[int8, 8]]]
# There must be TID_INFO + 1 entries, so we add an extra one.
	extra_tid	ieee80211_ctrl_bar_info[array[int8, 8]]
} [packed]

ieee80211_ctrl_ba_any [
	basic		ieee80211_ctrl_ba_single[0, 128]
	compressed	ieee80211_ctrl_ba_single[1, 8]
	multi		ieee80211_ctrl_ba_multi
] [varlen]

ieee80211_ctrl_ba {
	header		ieee80211_control_fc[IEEE80211_MGMT_CTL_BACK]
	duration	ieee80211_duration
	receiver	ieee80211_mac_addr
	transmitter	ieee80211_mac_addr
	payload		ieee80211_ctrl_ba_any
} [packed]

ieee80211_ctrl_frame [
	rts		ieee80211_ctrl_rts
	cts		ieee80211_ctrl_cts
	ack		ieee80211_ctrl_ack
	pspoll		ieee80211_ctrl_pspoll
	bar		ieee80211_ctrl_bar
	ba		ieee80211_ctrl_ba
	cf_end		ieee80211_ctrl_cf_end
	cf_end_cf_ack	ieee80211_ctrl_cf_end_cf_ack
] [varlen]
