blob: 31caddc12b892aa8fde000cf7ee152dabf3465be [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GARNET_LIB_WLAN_COMMON_INCLUDE_WLAN_COMMON_MAC_FRAME_H_
#define GARNET_LIB_WLAN_COMMON_INCLUDE_WLAN_COMMON_MAC_FRAME_H_
#include <endian.h>
#include <fbl/algorithm.h>
#include <lib/zx/time.h>
#include <wlan/common/action_frame.h>
#include <wlan/common/bitfield.h>
#include <wlan/common/element.h>
#include <wlan/common/macaddr.h>
#include <wlan/common/span.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
#include <cstdint>
namespace wlan {
// TODO(NET-1985): Some of this file's definition are inconsistent in its naming and should not
// represent a frame.
// wlan_tu_t is an 802.11 Time Unit.
typedef uint64_t wlan_tu_t;
// One Time Unit is equal to 1024 microseconds.
static constexpr zx::duration TimeUnit = zx::usec(1024);
// Converts a WLAN TU to zx::duration.
//
// This is a template because it allows us to guard against some implicit conversion. For example,
// if this were a regular function accepting a wlan_tu_t, the following code would compile:
//
// foo(WLAN_TU(-1));
//
template <typename T> static inline constexpr zx::duration WLAN_TU(T n) {
static_assert(fbl::is_unsigned_integer<T>::value, "Time unit must be an unsigned integer");
return TimeUnit * n;
}
// Frame types and subtypes
// IEEE Std 802.11-2016, 9.2.4.1.3
enum FrameType : uint8_t {
kManagement = 0x00,
kControl = 0x01,
kData = 0x02, // TODO(porce): Distinguish from DataSubtype's kData by enum class.
kExtension = 0x03,
};
enum ManagementSubtype : uint8_t {
kAssociationRequest = 0x00,
kAssociationResponse = 0x01,
kReassociationRequest = 0x02,
kReassociationResponse = 0x03,
kProbeRequest = 0x04,
kProbeResponse = 0x05,
kTimingAdvertisement = 0x06,
kBeacon = 0x08,
kAtim = 0x09,
kDisassociation = 0x0a,
kAuthentication = 0x0b,
kDeauthentication = 0x0c,
kAction = 0x0d,
kActionNoAck = 0x0e,
};
enum ControlSubtype : uint8_t {
kBeamformingReportPoll = 0x04,
kVhtNdpAnnouncement = 0x05,
kControlFrameExtension = 0x06,
kControlWrapper = 0x07,
kBlockAckRequest = 0x08,
kBlockAck = 0x09,
kPsPoll = 0x0a,
kRts = 0x0b,
kCts = 0x0c,
kAck = 0x0d,
kCfEnd = 0x0e,
kCfEndCfAck = 0x0f,
};
// IEEE Std 802.11-2016, 9.2.4.1.3, Table 9-1
enum DataSubtypeBitmask : uint8_t {
// This leads to enum DataSubtype
kBitmaskCfAck = (1 << 0), // Bit 4
kBitmaskCfPoll = (1 << 1), // Bit 5
kBitmaskNull = (1 << 2), // Bit 6. If not Null, it means Data.
kBitmaskQos = (1 << 3), // Bit 7
};
// IEEE Std 802.11-2016, 9.2.4.1.3, Table 9-1
enum DataSubtype : uint8_t {
kDataSubtype = 0x00, // TODO(porce): Avoid namespace collision with enum FrameType's kData.
kDataCfack = 0x01,
kDataCfpoll = 0x02,
kDataCfackCfpoll = 0x03,
kNull = 0x04,
kCfack = 0x05,
kCfpoll = 0x06,
kCfackCfpoll = 0x07,
kQosdata = 0x08,
kQosdataCfack = 0x09,
kQosdataCfpoll = 0x0a,
kQosdataCfackCfpoll = 0x0b,
kQosnull = 0x0c,
// Reserved 0x0d,
kQosCfpoll = 0x0e,
kQosCfackCfpoll = 0x0f,
};
// IEEE Std 802.11-2016, 9.2.4.4
class SequenceControl : public common::BitField<uint16_t> {
public:
WLAN_BIT_FIELD(frag, 0, 4);
WLAN_BIT_FIELD(seq, 4, 12);
};
constexpr uint16_t kMaxSequenceNumber = (1 << 12) - 1;
// IEEE Std 802.11-2016, 9.2.4.5.4, Table 9-9
namespace ack_policy {
enum AckPolicy : uint8_t {
kNormalAck = 0, // or Implicit Block Ack Request
kNoAck = 1,
kNoExplicitAck = 2, // or PSMP Ack
kBlockAck = 3,
};
} // namespace ack_policy
// IEEE Std 802.11-2016, 9.2.4.5.1, Table 9-6
class QosControl : public common::BitField<uint16_t> {
public:
// Possible flags for the 'byte' field
constexpr static uint8_t kMeshControlPresentBit = 1 << 0;
constexpr static uint8_t kMeshPowerSaveLevelBit = 1 << 1;
constexpr static uint8_t kRspiBit = 1 << 2;
WLAN_BIT_FIELD(tid, 0, 4);
WLAN_BIT_FIELD(eosp, 4, 1); // End of Service Period
WLAN_BIT_FIELD(ack_policy, 5, 2);
WLAN_BIT_FIELD(amsdu_present, 7, 1);
// Interpretation varies
WLAN_BIT_FIELD(byte, 8, 8);
};
// IEEE Std 802.11-2016, 9.2.4.6
class HtControl : public common::BitField<uint32_t> {
public:
WLAN_BIT_FIELD(vht, 0, 1);
// Structure of this middle section is defined in 9.2.4.6.2 for HT,
// and 9.2.4.6.3 for VHT.
// TODO(tkilbourn): define bitfield structures for each of these variants
WLAN_BIT_FIELD(middle, 1, 29);
WLAN_BIT_FIELD(ac_constraint, 30, 1);
WLAN_BIT_FIELD(rdg_more_ppdu, 31, 1);
};
// IEEE Std 802.11-2016, 9.4.1.4
class CapabilityInfo : public common::BitField<uint16_t> {
public:
WLAN_BIT_FIELD(ess, 0, 1);
WLAN_BIT_FIELD(ibss, 1, 1);
WLAN_BIT_FIELD(cf_pollable, 2, 1);
WLAN_BIT_FIELD(cf_poll_req, 3, 1);
WLAN_BIT_FIELD(privacy, 4, 1);
WLAN_BIT_FIELD(short_preamble, 5, 1);
// bit 6-7 reserved
WLAN_BIT_FIELD(spectrum_mgmt, 8, 1);
WLAN_BIT_FIELD(qos, 9, 1);
WLAN_BIT_FIELD(short_slot_time, 10, 1);
WLAN_BIT_FIELD(apsd, 11, 1);
WLAN_BIT_FIELD(radio_msmt, 12, 1);
// bit 13 reserved
WLAN_BIT_FIELD(delayed_block_ack, 14, 1);
WLAN_BIT_FIELD(immediate_block_ack, 15, 1);
static CapabilityInfo FromDdk(uint32_t ddk_caps) {
CapabilityInfo cap{};
#define BITFLAG_TO_BIT(x, y) ((x & y) > 0 ? 1 : 0)
cap.set_short_preamble(BITFLAG_TO_BIT(ddk_caps, WLAN_CAP_SHORT_PREAMBLE));
cap.set_spectrum_mgmt(BITFLAG_TO_BIT(ddk_caps, WLAN_CAP_SPECTRUM_MGMT));
cap.set_short_slot_time(BITFLAG_TO_BIT(ddk_caps, WLAN_CAP_SHORT_SLOT_TIME));
cap.set_radio_msmt(BITFLAG_TO_BIT(ddk_caps, WLAN_CAP_RADIO_MSMT));
#undef BITFLAG_TO_BIT
return cap;
}
::fuchsia::wlan::mlme::CapabilityInfo ToFidl() const {
::fuchsia::wlan::mlme::CapabilityInfo c;
c.ess = (ess() == 1);
c.ibss = (ibss() == 1);
c.cf_pollable = (cf_pollable() == 1);
c.cf_poll_req = (cf_poll_req() == 1);
c.privacy = (privacy() == 1);
c.short_preamble = (short_preamble() == 1);
c.spectrum_mgmt = (spectrum_mgmt() == 1);
c.qos = (qos() == 1);
c.short_slot_time = (short_slot_time() == 1);
c.apsd = (apsd() == 1);
c.radio_msmt = (radio_msmt() == 1);
c.delayed_block_ack = (delayed_block_ack() == 1);
c.immediate_block_ack = (immediate_block_ack() == 1);
return c;
}
};
// TODO: Replace native ReasonCode with FIDL ReasonCode
// IEEE Std 802.11-2016, 9.4.1.7, Table 9-45
namespace reason_code {
enum ReasonCode : uint16_t {
// 0 Reserved
kUnspecifiedReason = 1,
kInvalidAuthentication = 2,
kLeavingNetworkDeauth = 3,
kReasonInactivity = 4,
kNoMoreStas = 5,
kInvalidClass2Frame = 6,
kInvalidClass3Frame = 7,
kLeavingNetworkDisassoc = 8,
kNotAuthenticated = 9,
kUnacceptablePowerCapability = 10,
kUnacceptableSupportedChannels = 11,
kBssTransitionDisassoc = 12,
kReasonInvalidElement = 13,
kMicFailure = 14,
k4WayHandshakeTimeout = 15,
kGkHandshakeTimeout = 16,
kHandshakeElementMismatch = 17,
kReasonInvalidGroupCipher = 18,
kReasonInvalidPairwiseCipher = 19,
kReasonInvalidAkmp = 20,
kUnsupportedRsneVersion = 21,
kInvalidRsneCapabilities = 22,
k8021XAuthFailed = 23,
kReasonCipherOutOfPolicy = 24,
kTdlsPeerUnreachable = 25,
kTdlsUnspecifiedReason = 26,
kSspRequestedDisassoc = 27,
kNoSspRoamingAgreement = 28,
kBadCipherOrAkm = 29,
kNotAuthorizedThisLocation = 30,
kServiceChangePrecludesTs = 31,
kUnspecifiedQosReason = 32,
kNotEnoughBandwidth = 33,
kMissingAcks = 34,
kExceededTxop = 35,
kStaLeaving = 36,
// The following groups of reasons share the same code
kEndTs = 37,
kEndBa = 37,
kEndDls = 37,
kUnknownTs = 38,
kUnknownBa = 38,
kTimeout = 39,
// 40-44 Reserved
kPeerkeyMismatch = 45,
kPeerInitiated = 46,
kApInitiated = 47,
kReasonInvalidFtActionFrameCount = 48,
kReasonInvalidPmkid = 49,
kReasonInvalidMde = 50,
kReasonInvalidFte = 51,
kMeshPeeringCanceled = 52,
kMeshMaxPeers = 53,
kMeshConfigurationPolicyViolation = 54,
kMeshCloseRcvd = 55,
kMeshMaxRetries = 56,
kMeshConfirmTimeout = 57,
kMeshInvalidGtk = 58,
kMeshInconsistentParameters = 59,
kMeshInvalidSecurityCapability = 60,
kMeshPathErrorNoProxyInformation = 61,
kMeshPathErrorNoForwardingInformation = 62,
kMeshPathErrorDestinationUnreachable = 63,
kMacAddressAlreadyExistsInMbss = 64,
kMeshChannelSwitchRegulatoryRequirements = 65,
kMeshChannelSwitchUnspecified = 66,
// 67 - 65535 Reserved
};
} // namespace reason_code
// IEEE Std 802.11-2016, 9.4.1.9, Table 9-46
namespace status_code {
enum StatusCode : uint16_t {
kSuccess = 0,
kRefused = 1,
kRefusedReasonUnspecified = 1,
kTdlsRejectedAlternativeProvided = 2,
kTdlsRejected = 3,
// 4 Reserved
kSecurityDisabled = 5,
kUnacceptableLifetime = 6,
kNotInSameBss = 7,
// 8-9 Reserved
kRefusedCapabilitiesMismatch = 10,
kDeniedNoAssociationExists = 11,
kDeniedOtherReason = 12,
kUnsupportedAuthAlgorithm = 13,
kTransactionSequenceError = 14,
kChallengeFailure = 15,
kRejectedSequenceTimeout = 16,
kDeniedNoMoreStas = 17,
kRefusedBasicRatesMismatch = 18,
kDeniedNoShortPreambleSupport = 19,
// 20-21 Reserved
kRejectedSpectrumManagementRequired = 22,
kRejectedBadPowerCapability = 23,
kRejectedBadSupportedChannels = 24,
kDeniedNoShortSlotTimeSupport = 25,
// 26 Reserved
kDeniedNoHtSupport = 27,
kR0khUnreachable = 28,
kDeniedPcoTimeNotSupported = 29,
kRefusedTemporarily = 30,
kRobustManagementPolicyViolation = 31,
kUnspecifiedQosFailure = 32,
kDeniedInsufficientBandwidth = 33,
kDeniedPoorChannelConditions = 34,
kDeniedQosNotSupported = 35,
// 36 Reserved
kRequestDeclined = 37,
kInvalidParameters = 38,
kRejectedWithSuggestedChanges = 39,
kStatusInvalidElement = 40,
kStatusInvalidGroupCipher = 41,
kStatusInvalidPairwiseCipher = 42,
kStatusInvalidAkmp = 43,
kUnsupportedRsneVersion = 44,
kInvalidRsneCapabilities = 45,
kStatusCipherOutOfPolicy = 46,
kRejectedForDelayPeriod = 47,
kDlsNotAllowed = 48,
kNotPresent = 49,
kNotQosSta = 50,
kDeniedListenIntervalTooLarge = 51,
kStatusInvalidFtActionFrameCount = 52,
kStatusInvalidPmkid = 53,
kStatusInvalidMde = 54,
kStatusInvalidFte = 55,
kRequestedTclasNotSupported_56 = 56, // see kRequestedTclasNotSupported_80 below
kInsufficientTclasProcessingResources = 57,
kTryAnotherBss = 58,
kGasAdvertisementProtocolNotSupported = 59,
kNoOutstandingGasRequest = 60,
kGasResponseNotReceivedFromServer = 61,
kGasQueryTimeout = 62,
kGasQueryResponseTooLarge = 63,
kRejectedHomeWithSuggestedChanges = 64,
kServerUnreachable = 65,
// 66 Reserved
kRejectedForSspPermissions = 67,
kRefusedUnauthenticatedAccessNotSupported = 68,
// 69-71 Reserved
kInvalidRsne = 72,
kUApsdCoexistanceNotSupported = 73,
kUApsdCoexModeNotSupported = 74,
kBadIntervalWithUApsdCoex = 75,
kAntiCloggingTokenRequired = 76,
kUnsupportedFiniteCyclicGroup = 77,
kCannotFindAlternativeTbtt = 78,
kTransmissionFailure = 79,
kRequestedTclasNotSupported_80 = 80, // see kRequestedTclasNotSupported_56 above
kTclasResourcesExhausted = 81,
kRejectedWithSuggestedBssTransition = 82,
kRejectWithSchedule = 83,
kRejectNoWakeupSpecified = 84,
kSuccessPowerSaveMode = 85,
kPendingAdmittingFstSession = 86,
kPerformingFstNow = 87,
kPendingGapInBaWindow = 88,
kRejectUPidSetting = 89,
// 90-91 Reserved
kRefusedExternalReason = 92,
kRefusedApOutOfMemory = 93,
kRejectedEmergencyServicesNotSupported = 94,
kQueryResponseOutstanding = 95,
kRejectDseBand = 96,
kTclasProcessingTerminated = 97,
kTsScheduleConflict = 98,
kDeniedWithSuggestedBandAndChannel = 99,
kMccaopReservationConflict = 100,
kMafLimitExceeded = 101,
kMccaTrackLimitExceeded = 102,
kDeniedDueToSpectrumManagement = 103,
kDeniedVhtNotSupported = 104,
kEnablementDenied = 105,
kRestrictionFromAuthorizedGdb = 106,
kAuthorizationDeenabled = 107,
// 108-65535 Reserved
};
} // namespace status_code
// IEEE Std 802.11-2016 9.2.3
// Length of optional fields
const uint16_t kHtCtrlLen = 4;
const uint16_t kQosCtrlLen = 2;
const uint16_t kFcsLen = 4;
struct EmptyHdr {
constexpr size_t len() const { return 0; }
static constexpr size_t max_len() { return 0; }
} __PACKED;
// IEEE Std 802.11-2016, 9.2.4.1.1
class FrameControl : public common::BitField<uint16_t> {
public:
constexpr explicit FrameControl(uint16_t fc) : BitField<uint16_t>(fc) {}
constexpr FrameControl() = default;
WLAN_BIT_FIELD(protocol_version, 0, 2);
WLAN_BIT_FIELD(type, 2, 2);
WLAN_BIT_FIELD(subtype, 4, 4);
WLAN_BIT_FIELD(to_ds, 8, 1);
WLAN_BIT_FIELD(from_ds, 9, 1);
WLAN_BIT_FIELD(more_frag, 10, 1);
WLAN_BIT_FIELD(retry, 11, 1);
WLAN_BIT_FIELD(pwr_mgmt, 12, 1);
WLAN_BIT_FIELD(more_data, 13, 1);
WLAN_BIT_FIELD(protected_frame, 14, 1);
WLAN_BIT_FIELD(htc_order, 15, 1);
// For type == Control and subtype == Control Frame Extension
WLAN_BIT_FIELD(cf_extension, 8, 4);
bool IsMgmt() const { return type() == FrameType::kManagement; }
bool IsCtrl() const { return type() == FrameType::kControl; }
bool IsData() const { return type() == FrameType::kData; }
bool HasHtCtrl() const { return htc_order() != 0; }
constexpr size_t len() const { return sizeof(*this); }
static constexpr size_t max_len() { return sizeof(FrameControl); }
};
// IEEE Std 802.11-2016, 9.3.3.2
struct MgmtFrameHeader {
static constexpr FrameType Type() { return FrameType::kManagement; }
static constexpr size_t max_len() { return sizeof(MgmtFrameHeader) + kHtCtrlLen; }
FrameControl fc;
uint16_t duration;
common::MacAddr addr1;
common::MacAddr addr2;
common::MacAddr addr3;
SequenceControl sc;
// Use accessors for optional field.
// uint8_t ht_ctrl[4];
size_t len() const {
size_t len = sizeof(MgmtFrameHeader);
if (fc.HasHtCtrl()) { len += kHtCtrlLen; }
return len;
}
const HtControl* ht_ctrl() const {
if (!fc.HasHtCtrl()) return nullptr;
size_t offset = sizeof(MgmtFrameHeader);
return reinterpret_cast<const HtControl*>(raw() + offset);
}
private:
// TODO(NET-500): Dangerous as this cast is undefined and should not be used.
const uint8_t* raw() const { return reinterpret_cast<const uint8_t*>(this); }
} __PACKED;
// IEEE Std 802.11-2016, 9.3.3.3
struct Beacon {
static constexpr ManagementSubtype Subtype() { return ManagementSubtype::kBeacon; }
static constexpr size_t max_len() { return sizeof(Beacon); }
// 9.4.1.10
uint64_t timestamp;
// 9.4.1.3
uint16_t beacon_interval;
// 9.4.1.4
CapabilityInfo cap;
constexpr size_t len() const { return sizeof(*this); }
} __PACKED;
// IEEE Std 802.11-2016, 9.3.3.10
struct ProbeRequest : EmptyHdr {
static constexpr ManagementSubtype Subtype() { return ManagementSubtype::kProbeRequest; }
} __PACKED;
// IEEE Std 802.11-2016, 9.3.3.11
struct ProbeResponse {
static constexpr ManagementSubtype Subtype() { return ManagementSubtype::kProbeResponse; }
static constexpr size_t max_len() { return sizeof(ProbeResponse); }
// 9.4.1.10
uint64_t timestamp;
// 9.4.1.3
uint16_t beacon_interval;
// 9.4.1.4
CapabilityInfo cap;
constexpr size_t len() const { return sizeof(*this); }
} __PACKED;
// IEEE Std 802.11-2016, 9.4.1.1
enum AuthAlgorithm : uint16_t {
kOpenSystem = 0,
kSharedKey = 1,
kFastBssTransitionAuth = 2,
kSae = 3,
// 4-65534 Reserved
kVendorSpecificAuth = 65535,
};
// IEEE Std 802.11-2016, 9.3.3.12
struct Authentication {
static constexpr ManagementSubtype Subtype() { return ManagementSubtype::kAuthentication; }
static constexpr size_t max_len() { return sizeof(Authentication); }
// 9.4.1.1
uint16_t auth_algorithm_number;
// 9.4.1.2
uint16_t auth_txn_seq_number;
// 9.4.1.9
uint16_t status_code;
constexpr size_t len() const { return sizeof(*this); }
} __PACKED;
// IEEE Std 802.11-2016, 9.3.3.13
struct Deauthentication {
static constexpr ManagementSubtype Subtype() { return ManagementSubtype::kDeauthentication; }
static constexpr size_t max_len() { return sizeof(Deauthentication); }
// 9.4.1.7
uint16_t reason_code;
constexpr size_t len() const { return sizeof(*this); }
} __PACKED;
// IEEE Std 802.11-2016, 9.3.3.6
struct AssociationRequest {
static constexpr ManagementSubtype Subtype() { return ManagementSubtype::kAssociationRequest; }
static constexpr size_t max_len() { return sizeof(AssociationRequest); }
// 9.4.1.4
CapabilityInfo cap;
// 9.4.1.6
uint16_t listen_interval;
constexpr size_t len() const { return sizeof(*this); }
} __PACKED;
constexpr uint16_t kAidMask = (1 << 11) - 1;
// IEEE Std 802.11-2016, 9.3.3.7
struct AssociationResponse {
static constexpr ManagementSubtype Subtype() { return ManagementSubtype::kAssociationResponse; }
static constexpr size_t max_len() { return sizeof(AssociationResponse); }
// 9.4.1.4
CapabilityInfo cap;
// 9.4.1.9
uint16_t status_code;
// 9.4.1.8
uint16_t aid;
constexpr size_t len() const { return sizeof(*this); }
} __PACKED;
// IEEE Std 802.11-2016, 9.3.3.8
struct ReassociationRequest {
CapabilityInfo cap;
uint16_t listen_interval;
common::MacAddr current_ap_addr;
} __PACKED;
// IEEE Std 802.11-2016, 9.3.3.9
struct ReassociationResponse {
CapabilityInfo cap;
uint16_t status_code;
uint16_t aid;
} __PACKED;
// IEEE Std 802.11-2016, 9.3.3.16
struct TimingAdvertisement {
uint64_t timestamp;
CapabilityInfo cap;
} __PACKED;
// IEEE Std 802.11-2016, 9.3.3.5
struct Disassociation {
static constexpr ManagementSubtype Subtype() { return ManagementSubtype::kDisassociation; }
static constexpr size_t max_len() { return sizeof(Disassociation); }
// 9.4.1.7
uint16_t reason_code;
constexpr size_t len() const { return sizeof(*this); }
} __PACKED;
// IEEE Std 802.11-2016, 9.3.2.1
struct DataFrameHeader {
static constexpr FrameType Type() { return FrameType::kData; }
static constexpr size_t max_len() {
return sizeof(DataFrameHeader) + common::kMacAddrLen + kQosCtrlLen + kHtCtrlLen;
}
FrameControl fc;
uint16_t duration;
common::MacAddr addr1;
common::MacAddr addr2;
common::MacAddr addr3;
SequenceControl sc;
// Use accessors for optional fields.
// MacAddr addr4;
// uint8_t qos_ctrl[2];
// HtControl* ht_ctrl;
bool HasAddr4() const { return fc.to_ds() && fc.from_ds(); }
bool HasQosCtrl() const {
// Warning: Following bitmasking includes subtype 0x0d - Reserved.
return (0 != (fc.subtype() & DataSubtypeBitmask::kBitmaskQos));
}
size_t len() const {
size_t hdr_len = sizeof(DataFrameHeader);
if (HasAddr4()) hdr_len += common::kMacAddrLen;
if (HasQosCtrl()) hdr_len += kQosCtrlLen;
if (fc.HasHtCtrl()) hdr_len += kHtCtrlLen;
return hdr_len;
}
const common::MacAddr* addr4() const {
if (!HasAddr4()) return nullptr;
size_t offset = sizeof(DataFrameHeader);
return reinterpret_cast<const common::MacAddr*>(raw() + offset);
}
common::MacAddr* addr4() { return const_cast<common::MacAddr*>(const_this()->addr4()); }
const QosControl* qos_ctrl() const {
if (!HasQosCtrl()) return nullptr;
size_t offset = sizeof(DataFrameHeader);
if (HasAddr4()) { offset += common::kMacAddrLen; }
return reinterpret_cast<const QosControl*>(raw() + offset);
}
QosControl* qos_ctrl() { return const_cast<QosControl*>(const_this()->qos_ctrl()); }
const HtControl* ht_ctrl() const {
if (!fc.HasHtCtrl()) return nullptr;
size_t offset = sizeof(DataFrameHeader);
if (HasAddr4()) { offset += common::kMacAddrLen; }
if (HasQosCtrl()) { offset += kQosCtrlLen; }
return reinterpret_cast<const HtControl*>(raw() + offset);
}
HtControl* ht_ctrl() { return const_cast<HtControl*>(const_this()->ht_ctrl()); }
private:
const uint8_t* raw() const { return reinterpret_cast<const uint8_t*>(this); }
const DataFrameHeader* const_this() { return const_cast<const DataFrameHeader*>(this); }
} __PACKED;
struct NullDataHdr : public EmptyHdr {
static bool IsSubtype(uint8_t subtype) {
return subtype == DataSubtype::kNull || subtype == DataSubtype::kQosnull;
}
} __PACKED;
// IEEE Std 802.11-2016, 9.3.1.1
// Although the FrameControl is part of every control frame, IEEE does not name
// the FrameControl to be a common header of all control frames.
// To provide consistent code which requires no handling of special cases such
// a common header is defined. This obviously also causes the FrameControl to
// *not* be part of individually defined control frame types such as PsPoll.
// In that sense, this implementation slightly, but knowingly diverges from IEEEs
// definition.
struct CtrlFrameHdr {
static constexpr FrameType Type() { return FrameType::kControl; }
static constexpr size_t max_len() { return sizeof(CtrlFrameHdr); }
FrameControl fc;
constexpr size_t len() const { return sizeof(*this); }
} __PACKED;
// IEEE Std 802.11-2016, 9.3.1.5
struct PsPollFrame {
static constexpr ControlSubtype Subtype() { return ControlSubtype::kPsPoll; }
static constexpr size_t max_len() { return sizeof(PsPollFrame); }
uint16_t aid;
common::MacAddr bssid;
common::MacAddr ta;
constexpr size_t len() const { return sizeof(*this); }
} __PACKED;
// IEEE Std 802.11-2016, Table 9-20
constexpr uint8_t kAddrExtNone = 0;
constexpr uint8_t kAddrExt4 = 1;
constexpr uint8_t kAddrExt56 = 2;
// IEEE Std 802.11-2016, 9.2.4.7.3, Figure 9-17
class MeshFlags : public common::BitField<uint8_t> {
public:
WLAN_BIT_FIELD(addr_ext_mode, 0, 2);
// bits 2-7 reserved
} __PACKED;
// IEEE Std 802.11-2016, 9.2.4.7.3, Figure 9-16
struct MeshControl {
MeshFlags flags;
uint8_t ttl;
uint32_t seq;
} __PACKED;
// IEEE Std 802.2, 1998 Edition, 3.2
// IETF RFC 1042
struct LlcHeader {
uint8_t dsap;
uint8_t ssap;
uint8_t control;
uint8_t oui[3];
uint16_t protocol_id;
constexpr size_t len() const { return sizeof(*this); }
static constexpr size_t max_len() { return sizeof(LlcHeader); }
} __PACKED;
// IEEE Std 802.11-2016, 9.3.2.2.2
struct AmsduSubframeHeader {
// Note this is the same as the IEEE 802.3 frame format.
common::MacAddr da;
common::MacAddr sa;
uint16_t msdu_len_be; // Stored in network byte order. Use accessors.
uint16_t msdu_len() const { return be16toh(msdu_len_be); }
constexpr size_t len() const { return sizeof(*this); }
static constexpr size_t max_len() { return sizeof(AmsduSubframeHeader); }
} __PACKED;
// IEEE Std 802.11-2016, 9.3.2.2.3
// Non-DMG stations do not transmit in this form.
struct AmsduSubframeHeaderShort {
uint16_t msdu_len_be;
} __PACKED;
// RFC 1042
constexpr uint8_t kLlcSnapExtension = 0xaa;
constexpr uint8_t kLlcUnnumberedInformation = 0x03;
const uint8_t kLlcOui[3] = {};
// IEEE Std 802.3-2015, 3.1.1
struct EthernetII {
common::MacAddr dest;
common::MacAddr src;
uint16_t ether_type;
constexpr size_t len() const { return sizeof(*this); }
static constexpr size_t max_len() { return sizeof(EthernetII); }
} __PACKED;
// IEEE Std 802.1X-2010, 11.3, Figure 11-1
struct EapolHdr {
uint8_t version;
uint8_t packet_type;
uint16_t packet_body_length;
size_t get_packet_body_length() const {
return static_cast<size_t>(be16toh(packet_body_length));
}
constexpr size_t len() const { return sizeof(*this); }
static constexpr size_t max_len() { return sizeof(EapolHdr); }
} __PACKED;
CapabilityInfo IntersectCapInfo(const CapabilityInfo& lhs, const CapabilityInfo& rhs);
} // namespace wlan
#endif // GARNET_LIB_WLAN_COMMON_INCLUDE_WLAN_COMMON_MAC_FRAME_H_