blob: 34803f7904a0674c133e143b380512b606a3a1ae [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_ELEMENT_H_
#define GARNET_LIB_WLAN_COMMON_INCLUDE_WLAN_COMMON_ELEMENT_H_
#include <wlan/common/bitfield.h>
#include <wlan/common/element_id.h>
#include <wlan/common/logging.h>
#include <wlan/common/macaddr.h>
#include <wlan/protocol/info.h>
#include <fuchsia/wlan/mlme/cpp/fidl.h>
#include <zircon/assert.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
#include <cstdint>
#include <unordered_map>
#include <utility>
#include <vector>
namespace wlan {
// IEEE Std 802.11-2016, 9.4.2.1
struct ElementHeader {
uint8_t id;
uint8_t len;
} __PACKED;
constexpr size_t kMaxSsidLen = 32;
// IEEE 802.11-2016 9.4.2.3.
// The MSB in a rate indicates "basic rate" and is ignored during comparison.
// Rates are in 0.5Mbps increment: 12 -> 6 Mbps, 11 -> 5.5 Mbps, etc.
struct SupportedRate : public common::BitField<uint8_t> {
constexpr SupportedRate() = default;
constexpr explicit SupportedRate(uint8_t val) : common::BitField<uint8_t>(val) {}
constexpr explicit SupportedRate(uint8_t val, bool is_basic) : common::BitField<uint8_t>(val) {
set_is_basic(static_cast<uint8_t>(is_basic));
}
static SupportedRate basic(uint8_t rate) { return SupportedRate(rate, true); }
static SupportedRate raw(uint8_t rate) { return SupportedRate(rate); }
WLAN_BIT_FIELD(rate, 0, 7);
WLAN_BIT_FIELD(is_basic, 7, 1);
operator uint8_t() const { return val(); }
bool operator==(const SupportedRate& other) const { return rate() == other.rate(); }
bool operator!=(const SupportedRate& other) const { return !this->operator==(other); }
bool operator<(const SupportedRate& other) const { return rate() < other.rate(); }
bool operator>(const SupportedRate& other) const { return rate() > other.rate(); }
} __PACKED;
static constexpr size_t kMaxSupportedRatesLen = 8;
// IEEE Std 802.11-2016, 9.4.2.4
struct DsssParamSet {
uint8_t current_chan;
};
// IEEE Std 802.11-2016, 9.4.2.5
struct CfParamSet {
uint8_t count;
uint8_t period;
uint16_t max_duration;
uint16_t dur_remaining;
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.6
class BitmapControl : public common::BitField<uint8_t> {
public:
BitmapControl() = default;
explicit BitmapControl(uint8_t raw) : BitField(raw) {}
WLAN_BIT_FIELD(group_traffic_ind, 0, 1);
WLAN_BIT_FIELD(offset, 1, 7);
};
// IEEE Std 802.11-2016, 9.4.2.6
struct TimHeader {
uint8_t dtim_count;
uint8_t dtim_period;
BitmapControl bmp_ctrl;
} __PACKED;
constexpr size_t kMaxTimBitmapLen = 251;
// IEEE Std 802.11-2016, 9.4.2.9. Figure 9-131, 9-132.
struct SubbandTriplet {
uint8_t first_channel_number;
uint8_t number_of_channels;
uint8_t max_tx_power; // dBm
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.9
struct Country {
static constexpr size_t kCountryLen = 3;
uint8_t data[kCountryLen];
} __PACKED;
static_assert(sizeof(Country) == Country::kCountryLen);
const uint16_t kEapolProtocolId = 0x888E;
// IEEE Std 802.11-2016, 9.4.2.98
struct MeshConfiguration {
enum PathSelProtoId : uint8_t {
kHwmp = 1u,
};
enum PathSelMetricId : uint8_t {
kAirtime = 1u,
};
enum CongestCtrlModeId : uint8_t {
kCongestCtrlInactive = 0u,
kCongestCtrlSignaling = 1u,
};
enum SyncMethodId : uint8_t {
kNeighborOffsetSync = 1u,
};
enum AuthProtoId : uint8_t {
kNoAuth = 0u,
kSae = 1u,
kIeee8021X = 2u,
};
struct MeshFormationInfo : public common::BitField<uint8_t> {
MeshFormationInfo() = default;
explicit MeshFormationInfo(uint8_t raw) : BitField(raw) {}
WLAN_BIT_FIELD(connected_to_mesh_gate, 0, 1);
WLAN_BIT_FIELD(num_peerings, 1, 6);
WLAN_BIT_FIELD(connected_to_as, 7, 1);
} __PACKED;
::fuchsia::wlan::mlme::MeshConfiguration ToFidl() const {
::fuchsia::wlan::mlme::MeshConfiguration ret;
ret.active_path_sel_proto_id = static_cast<uint8_t>(active_path_sel_proto_id);
ret.active_path_sel_metric_id = static_cast<uint8_t>(active_path_sel_metric_id);
ret.congest_ctrl_method_id = static_cast<uint8_t>(congest_ctrl_method_id);
ret.sync_method_id = static_cast<uint8_t>(sync_method_id);
ret.auth_proto_id = static_cast<uint8_t>(auth_proto_id);
ret.mesh_formation_info = mesh_formation_info.val();
ret.mesh_capability = mesh_capability.val();
return ret;
}
static MeshConfiguration FromFidl(const ::fuchsia::wlan::mlme::MeshConfiguration& f) {
return MeshConfiguration {
.active_path_sel_proto_id = static_cast<PathSelProtoId>(f.active_path_sel_proto_id),
.active_path_sel_metric_id = static_cast<PathSelMetricId>(f.active_path_sel_metric_id),
.congest_ctrl_method_id = static_cast<CongestCtrlModeId>(f.congest_ctrl_method_id),
.sync_method_id = static_cast<SyncMethodId>(f.sync_method_id),
.auth_proto_id = static_cast<AuthProtoId>(f.auth_proto_id),
.mesh_formation_info = MeshFormationInfo(f.mesh_formation_info),
.mesh_capability = MeshCapability(f.mesh_capability),
};
}
struct MeshCapability : public common::BitField<uint8_t> {
MeshCapability() = default;
explicit MeshCapability(uint8_t raw) : BitField(raw) {}
WLAN_BIT_FIELD(accepting_additional_peerings, 0, 1);
WLAN_BIT_FIELD(mcca_supported, 1, 1);
WLAN_BIT_FIELD(mcca_enabled, 2, 1);
WLAN_BIT_FIELD(forwarding, 3, 1);
WLAN_BIT_FIELD(mbca_enabled, 4, 1);
WLAN_BIT_FIELD(tbtt_adjusting, 5, 1);
WLAN_BIT_FIELD(power_save_level, 6, 1);
// bit 7 is reserved
} __PACKED;
PathSelProtoId active_path_sel_proto_id;
PathSelMetricId active_path_sel_metric_id;
CongestCtrlModeId congest_ctrl_method_id;
SyncMethodId sync_method_id;
AuthProtoId auth_proto_id;
MeshFormationInfo mesh_formation_info;
MeshCapability mesh_capability;
} __PACKED;
constexpr size_t kMaxMeshIdLen = 32;
// IEEE Std 802.11-2016, 9.4.2.113, Figure 9-478
struct PreqFlags : public common::BitField<uint8_t> {
WLAN_BIT_FIELD(gate_announcement, 0, 1);
WLAN_BIT_FIELD(addressing_mode, 1, 1);
WLAN_BIT_FIELD(proactive, 2, 1);
// bits 3-5 reserved
WLAN_BIT_FIELD(addr_ext, 6, 1);
// bit 7 reserved
};
// Fixed-length fields of the PREQ element that precede
// the optional Originator External Address field.
// IEEE Std 802.11-2016, 9.4.2.113, Figure 9-477
struct PreqHeader {
PreqFlags flags;
uint8_t hop_count;
uint8_t element_ttl;
uint32_t path_discovery_id;
common::MacAddr originator_addr;
uint32_t originator_hwmp_seqno;
} __PACKED;
static_assert(sizeof(PreqHeader) == 17);
// Fixed-length fields of the PREQ elements that follow the optional Originator External Address
// field and precede the variable length per-target fields.
// IEEE Std 802.11-2016, 9.4.2.113, Figure 9-477
struct PreqMiddle {
uint32_t lifetime;
uint32_t metric;
uint8_t target_count;
} __PACKED;
static_assert(sizeof(PreqMiddle) == 9);
// IEEE Std 802.11-2016, 9.4.2.113
constexpr size_t kPreqMaxTargets = 20;
// IEEE Std 802.11-2016, 9.4.2.113, Figure 9-479
struct PreqPerTargetFlags : public common::BitField<uint8_t> {
WLAN_BIT_FIELD(target_only, 0, 1);
// bit 1 reserved
WLAN_BIT_FIELD(usn, 2, 1);
// bits 3-7 reserved
};
// An entry of the variable-length part of PREQ
// IEEE Std 802.11-2016, 9.4.2.113, Figure 9-477
struct PreqPerTarget {
PreqPerTargetFlags flags;
common::MacAddr target_addr;
uint32_t target_hwmp_seqno;
} __PACKED;
static_assert(sizeof(PreqPerTarget) == 11);
// IEEE Std 802.11-2016, 9.4.2.114, Figure 9-481
struct PrepFlags : public common::BitField<uint8_t> {
PrepFlags() = default;
explicit PrepFlags(uint8_t raw_value) : common::BitField<uint8_t>(raw_value) {}
// bits 0-5 reserved
WLAN_BIT_FIELD(addr_ext, 6, 1);
// bit 7 reserved
};
// Fixed-length fields of the PREP element that precede
// the optional Target External Address field.
// IEEE Std 802.11-2016, 9.4.2.114, Figure 9-480
struct PrepHeader {
PrepFlags flags;
uint8_t hop_count;
uint8_t element_ttl;
common::MacAddr target_addr;
uint32_t target_hwmp_seqno;
} __PACKED;
static_assert(sizeof(PrepHeader) == 13);
// Fixed-length fields of the PREP element that follow
// the optional Target External Address field.
// IEEE Std 802.11-2016, 9.4.2.114, Figure 9-480
struct PrepTail {
uint32_t lifetime;
uint32_t metric;
common::MacAddr originator_addr;
uint32_t originator_hwmp_seqno;
} __PACKED;
static_assert(sizeof(PrepTail) == 18);
// IEEE Std 802.11-2016, 9.4.1.17
class QosInfo : public common::BitField<uint8_t> {
public:
constexpr explicit QosInfo(uint8_t value) : common::BitField<uint8_t>(value) {}
constexpr QosInfo() = default;
// AP specific QoS Info structure: IEEE Std 802.11-2016, 9.4.1.17, Figure 9-82
WLAN_BIT_FIELD(edca_param_set_update_count, 0, 4);
WLAN_BIT_FIELD(qack, 4, 1);
WLAN_BIT_FIELD(queue_request, 5, 1);
WLAN_BIT_FIELD(txop_request, 6, 1);
// 8th bit reserved
// Non-AP STA specific QoS Info structure: IEEE Std 802.11-2016, 9.4.1.17, Figure 9-83
WLAN_BIT_FIELD(ac_vo_uapsd_flag, 0, 1);
WLAN_BIT_FIELD(ac_vi_uapsd_flag, 1, 1);
WLAN_BIT_FIELD(ac_bk_uapsd_flag, 2, 1);
WLAN_BIT_FIELD(ac_be_uapsd_flag, 3, 1);
// qack already defined in AP specific structure.
WLAN_BIT_FIELD(max_sp_len, 5, 1);
WLAN_BIT_FIELD(more_data_ack, 6, 1);
// 8th bit reserved
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.30, Table 9-139
enum TsDirection : uint8_t {
kUplink = 0,
kDownlink = 1,
kDirectLink = 2,
kBidirectionalLink = 3,
};
// IEEE Std 802.11-2016, 9.4.2.30, Table 9-140
enum TsAccessPolicy : uint8_t {
// 0 reserved
kEdca = 1,
kHccaSpca = 2,
kMixedMode = 3,
};
// IEEE Std 802.11-2016, 9.4.2.30, Table 9-141
namespace ts_ack_policy {
enum TsAckPolicy : uint8_t {
kNormalAck = 0,
kNoAck = 1,
// 2 reserved
kBlockAck = 3,
};
} // namespace ts_ack_policy
// IEEE Std 802.11-2016, 9.4.2.30, Table 9-142
// Only used if TsInfo's access policy uses EDCA.
// Schedule Setting depends on TsInfo's ASPD and schedule fields.
enum TsScheduleSetting : uint8_t {
kNoSchedule = 0,
kUnschedledApsd = 1,
kScheduledPsmp_GcrSp = 2,
kScheduledApsd = 3,
};
// IEEE Std 802.11-2016, 9.4.2.30, Figure 9-266
class TsInfoPart1 : public common::BitField<uint16_t> {
public:
WLAN_BIT_FIELD(traffic_type, 0, 1);
WLAN_BIT_FIELD(tsid, 1, 4);
WLAN_BIT_FIELD(direction, 5, 2);
WLAN_BIT_FIELD(access_policy, 7, 2);
WLAN_BIT_FIELD(aggregation, 9, 1);
WLAN_BIT_FIELD(apsd, 10, 1);
WLAN_BIT_FIELD(user_priority, 11, 3);
WLAN_BIT_FIELD(ack_policy, 14, 2);
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.30, Figure 9-266
class TsInfoPart2 : public common::BitField<uint8_t> {
public:
WLAN_BIT_FIELD(schedule, 0, 1);
// Bit 17-23 reserved.
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.30, Figure 9-266
// Note: In order to use a 3 byte packed struct, the TsInfo was split into two parts.
struct TsInfo {
TsInfoPart1 p1;
TsInfoPart2 p2;
bool IsValidAggregation() const {
if (p1.access_policy() == TsAccessPolicy::kHccaSpca) { return true; }
return p1.access_policy() == TsAccessPolicy::kEdca && p2.schedule();
}
bool IsScheduleReserved() const { return p1.access_policy() != TsAccessPolicy::kEdca; }
TsScheduleSetting GetScheduleSetting() const {
return static_cast<TsScheduleSetting>(p1.apsd() | (p2.schedule() << 1));
}
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.30, Figure 9-267
struct NominalMsduSize : public common::BitField<uint16_t> {
WLAN_BIT_FIELD(size, 0, 15);
WLAN_BIT_FIELD(fixed, 15, 1);
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.30
struct Tspec {
// TODO(hahnr): The element will for now only be read by the AP when received from an associated
// client and there is no need for providing a custom constructor yet.
TsInfo ts_info;
NominalMsduSize nominal_msdu_size;
uint16_t max_msdu_size;
uint32_t min_service_interval;
uint32_t max_service_interval;
uint32_t inactivity_interval;
uint32_t suspension_interval;
uint32_t service_start_time;
uint32_t min_data_rate;
uint32_t mean_data_rate;
uint32_t peak_data_rate;
uint32_t burst_size;
uint32_t delay_bound;
uint32_t min_phy_rate;
uint16_t surplus_bw_allowance;
uint16_t medium_time;
// TODO(hahnr): Add min/mean/peak data rate support based on the provided fields.
// TODO(hahnr): Add min PHY rate support based on the provided field.
// TODO(hahnr): Add DMG support.
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.56.2
// Note this is a field of HtCapabilities element.
class HtCapabilityInfo : public common::BitField<uint16_t> {
public:
constexpr explicit HtCapabilityInfo(uint16_t ht_cap_info)
: common::BitField<uint16_t>(ht_cap_info) {}
constexpr HtCapabilityInfo() = default;
WLAN_BIT_FIELD(ldpc_coding_cap, 0, 1);
WLAN_BIT_FIELD(chan_width_set, 1, 1); // In spec: Supported Channel Width Set
WLAN_BIT_FIELD(sm_power_save, 2, 2); // Spatial Multiplexing Power Save
WLAN_BIT_FIELD(greenfield, 4, 1); // HT-Greenfield.
WLAN_BIT_FIELD(short_gi_20, 5, 1); // Short Guard Interval for 20 MHz
WLAN_BIT_FIELD(short_gi_40, 6, 1); // Short Guard Interval for 40 MHz
WLAN_BIT_FIELD(tx_stbc, 7, 1);
WLAN_BIT_FIELD(rx_stbc, 8, 2); // maximum number of spatial streams. Up to 3.
WLAN_BIT_FIELD(delayed_block_ack, 10, 1); // HT-delayed Block Ack
WLAN_BIT_FIELD(max_amsdu_len, 11, 1);
WLAN_BIT_FIELD(dsss_in_40, 12, 1); // DSSS/CCK Mode in 40 MHz
WLAN_BIT_FIELD(reserved, 13, 1);
WLAN_BIT_FIELD(intolerant_40, 14, 1); // 40 MHz Intolerant
WLAN_BIT_FIELD(lsig_txop_protect, 15, 1);
enum ChanWidthSet {
TWENTY_ONLY = 0,
TWENTY_FORTY = 1,
};
enum SmPowerSave {
STATIC = 0,
DYNAMIC = 1,
RESERVED = 2,
DISABLED = 3,
};
enum MaxAmsduLen {
OCTETS_3839 = 0,
OCTETS_7935 = 1,
};
static HtCapabilityInfo FromFidl(const ::fuchsia::wlan::mlme::HtCapabilityInfo& fidl) {
HtCapabilityInfo dst;
dst.set_ldpc_coding_cap(fidl.ldpc_coding_cap ? 1 : 0);
dst.set_chan_width_set(static_cast<ChanWidthSet>(fidl.chan_width_set));
dst.set_sm_power_save(static_cast<SmPowerSave>(fidl.sm_power_save));
dst.set_greenfield(fidl.greenfield ? 1 : 0);
dst.set_short_gi_20(fidl.short_gi_20 ? 1 : 0);
dst.set_short_gi_40(fidl.short_gi_40 ? 1 : 0);
dst.set_tx_stbc(fidl.tx_stbc ? 1 : 0);
dst.set_rx_stbc(fidl.rx_stbc);
dst.set_delayed_block_ack(fidl.delayed_block_ack ? 1 : 0);
dst.set_max_amsdu_len(static_cast<MaxAmsduLen>(fidl.max_amsdu_len));
dst.set_dsss_in_40(fidl.dsss_in_40 ? 1 : 0);
dst.set_intolerant_40(fidl.intolerant_40 ? 1 : 0);
dst.set_lsig_txop_protect(fidl.lsig_txop_protect ? 1 : 0);
return dst;
}
::fuchsia::wlan::mlme::HtCapabilityInfo ToFidl() const {
::fuchsia::wlan::mlme::HtCapabilityInfo fidl;
fidl.ldpc_coding_cap = (ldpc_coding_cap() == 1);
fidl.chan_width_set = chan_width_set();
fidl.sm_power_save = sm_power_save();
fidl.greenfield = (greenfield() == 1);
fidl.short_gi_20 = (short_gi_20() == 1);
fidl.short_gi_40 = (short_gi_40() == 1);
fidl.tx_stbc = (tx_stbc() == 1);
fidl.rx_stbc = rx_stbc();
fidl.delayed_block_ack = (delayed_block_ack() == 1);
fidl.max_amsdu_len = max_amsdu_len();
fidl.dsss_in_40 = (dsss_in_40() == 1);
fidl.intolerant_40 = (intolerant_40() == 1);
fidl.lsig_txop_protect = (lsig_txop_protect() == 1);
return fidl;
}
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.56.3
class AmpduParams : public common::BitField<uint8_t> {
public:
constexpr explicit AmpduParams(uint8_t params) : common::BitField<uint8_t>(params) {}
constexpr AmpduParams() = default;
WLAN_BIT_FIELD(exponent, 0, 2); // Maximum A-MPDU Length Exponent.
WLAN_BIT_FIELD(min_start_spacing, 2, 3); // Minimum MPDU Start Spacing.
WLAN_BIT_FIELD(reserved, 5, 3);
size_t max_ampdu_len() const { return (1 << (13 + exponent())) - 1; }
enum MinMPDUStartSpacing {
NO_RESTRICT = 0,
QUARTER_USEC = 1,
HALF_USEC = 2,
ONE_USEC = 3,
TWO_USEC = 4,
FOUR_USEC = 5,
EIGHT_USEC = 6,
SIXTEEN_USEC = 7,
};
static AmpduParams FromFidl(const ::fuchsia::wlan::mlme::AmpduParams& fidl) {
AmpduParams dst;
dst.set_exponent(fidl.exponent);
dst.set_min_start_spacing(static_cast<MinMPDUStartSpacing>(fidl.min_start_spacing));
return dst;
}
::fuchsia::wlan::mlme::AmpduParams ToFidl() const {
fuchsia::wlan::mlme::AmpduParams fidl;
fidl.exponent = exponent();
fidl.min_start_spacing = min_start_spacing();
return fidl;
}
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.56.4
class SupportedMcsRxMcsHead : public common::BitField<uint64_t> {
public:
constexpr explicit SupportedMcsRxMcsHead(uint64_t val) : common::BitField<uint64_t>(val) {}
constexpr SupportedMcsRxMcsHead() = default;
bool Support(uint8_t mcs_index) const { return 1 == (1 & (bitmask() >> mcs_index)); }
// HT-MCS table in IEEE Std 802.11-2016, Annex B.4.17.2
// VHT-MCS tables in IEEE Std 802.11-2016, 21.5
WLAN_BIT_FIELD(bitmask, 0, 64);
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.56.4
class SupportedMcsRxMcsTail : public common::BitField<uint32_t> {
public:
constexpr explicit SupportedMcsRxMcsTail(uint32_t val) : common::BitField<uint32_t>(val) {}
constexpr SupportedMcsRxMcsTail() = default;
WLAN_BIT_FIELD(bitmask, 0, 13);
WLAN_BIT_FIELD(reserved1, 13, 3);
WLAN_BIT_FIELD(highest_rate, 16, 10); // Mbps. Rx Highest Supported Rate.
WLAN_BIT_FIELD(reserved2, 26, 6);
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.56.4
class SupportedMcsTxMcs : public common::BitField<uint32_t> {
public:
constexpr explicit SupportedMcsTxMcs(uint32_t chunk) : common::BitField<uint32_t>(chunk) {}
constexpr SupportedMcsTxMcs() = default;
WLAN_BIT_FIELD(set_defined, 0, 1); // Add 96 for the original bit location
WLAN_BIT_FIELD(rx_diff, 1, 1);
WLAN_BIT_FIELD(max_ss, 2, 2);
WLAN_BIT_FIELD(ueqm, 4, 1); // Transmit Unequal Modulation.
WLAN_BIT_FIELD(reserved, 5, 27);
uint8_t max_ss_human() const { return max_ss() + 1; }
void set_max_ss_human(uint8_t num) {
constexpr uint8_t kLowerbound = 1;
constexpr uint8_t kUpperbound = 4;
if (num < kLowerbound) num = kLowerbound;
if (num > kUpperbound) num = kUpperbound;
set_max_ss(num - 1);
}
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.56.4
struct SupportedMcsSet {
SupportedMcsRxMcsHead rx_mcs_head;
SupportedMcsRxMcsTail rx_mcs_tail;
SupportedMcsTxMcs tx_mcs;
static SupportedMcsSet FromFidl(const ::fuchsia::wlan::mlme::SupportedMcsSet& fidl) {
SupportedMcsSet dst;
dst.rx_mcs_head.set_bitmask(fidl.rx_mcs_set);
dst.rx_mcs_tail.set_highest_rate(fidl.rx_highest_rate);
dst.tx_mcs.set_set_defined(fidl.tx_mcs_set_defined ? 1 : 0);
dst.tx_mcs.set_rx_diff(fidl.tx_rx_diff ? 1 : 0);
dst.tx_mcs.set_max_ss_human(fidl.tx_max_ss);
dst.tx_mcs.set_ueqm(fidl.tx_ueqm ? 1 : 0);
return dst;
}
::fuchsia::wlan::mlme::SupportedMcsSet ToFidl() const {
::fuchsia::wlan::mlme::SupportedMcsSet fidl;
fidl.rx_mcs_set = rx_mcs_head.bitmask();
fidl.rx_highest_rate = rx_mcs_tail.highest_rate();
fidl.tx_mcs_set_defined = (tx_mcs.set_defined() == 1);
fidl.tx_rx_diff = (tx_mcs.rx_diff() == 1);
fidl.tx_max_ss = tx_mcs.max_ss_human(); // Converting to human readable
fidl.tx_ueqm = (tx_mcs.ueqm() == 1);
return fidl;
}
// TODO(porce): Implement accessors
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.56.5
class HtExtCapabilities : public common::BitField<uint16_t> {
public:
constexpr explicit HtExtCapabilities(uint16_t ht_ext_cap)
: common::BitField<uint16_t>(ht_ext_cap) {}
constexpr HtExtCapabilities() = default;
WLAN_BIT_FIELD(pco, 0, 1);
WLAN_BIT_FIELD(pco_transition, 1, 2);
WLAN_BIT_FIELD(reserved1, 3, 5);
WLAN_BIT_FIELD(mcs_feedback, 8, 2);
WLAN_BIT_FIELD(htc_ht_support, 10, 1);
WLAN_BIT_FIELD(rd_responder, 11, 1);
WLAN_BIT_FIELD(reserved2, 12, 4);
enum PcoTransitionTime {
PCO_RESERVED = 0, // Often translated as "No transition".
PCO_400_USEC = 1,
PCO_1500_USEC = 2,
PCO_5000_USEC = 3,
};
enum McsFeedback {
MCS_NOFEEDBACK = 0,
MCS_RESERVED = 1,
MCS_UNSOLICIED = 2,
MCS_BOTH = 3,
};
static HtExtCapabilities FromFidl(const ::fuchsia::wlan::mlme::HtExtCapabilities& fidl) {
HtExtCapabilities dst;
dst.set_pco(fidl.pco);
dst.set_pco_transition(static_cast<PcoTransitionTime>(fidl.pco_transition));
dst.set_mcs_feedback(static_cast<McsFeedback>(fidl.mcs_feedback));
dst.set_htc_ht_support(fidl.htc_ht_support ? 1 : 0);
dst.set_rd_responder(fidl.rd_responder ? 1 : 0);
return dst;
}
::fuchsia::wlan::mlme::HtExtCapabilities ToFidl() const {
::fuchsia::wlan::mlme::HtExtCapabilities fidl;
fidl.pco = (pco() == 1);
fidl.pco_transition = pco_transition();
fidl.mcs_feedback = mcs_feedback();
fidl.htc_ht_support = (htc_ht_support() == 1);
fidl.rd_responder = (rd_responder() == 1);
return fidl;
}
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.56.6
class TxBfCapability : public common::BitField<uint32_t> {
public:
constexpr explicit TxBfCapability(uint32_t txbf_cap) : common::BitField<uint32_t>(txbf_cap) {}
constexpr TxBfCapability() = default;
WLAN_BIT_FIELD(implicit_rx, 0, 1);
WLAN_BIT_FIELD(rx_stag_sounding, 1, 1);
WLAN_BIT_FIELD(tx_stag_sounding, 2, 1);
WLAN_BIT_FIELD(rx_ndp, 3, 1);
WLAN_BIT_FIELD(tx_ndp, 4, 1);
WLAN_BIT_FIELD(implicit, 5, 1);
WLAN_BIT_FIELD(calibration, 6, 2);
WLAN_BIT_FIELD(csi, 8, 1); // Explicit CSI Transmit Beamforming.
WLAN_BIT_FIELD(noncomp_steering, 9, 1); // Explicit Noncompressed Steering
WLAN_BIT_FIELD(comp_steering, 10, 1); // Explicit Compressed Steering
WLAN_BIT_FIELD(csi_feedback, 11, 2);
WLAN_BIT_FIELD(noncomp_feedback, 13, 2);
WLAN_BIT_FIELD(comp_feedback, 15, 2);
WLAN_BIT_FIELD(min_grouping, 17, 2);
WLAN_BIT_FIELD(csi_antennas, 19, 2);
WLAN_BIT_FIELD(noncomp_steering_ants, 21, 2);
WLAN_BIT_FIELD(comp_steering_ants, 23, 2);
WLAN_BIT_FIELD(csi_rows, 25, 2);
WLAN_BIT_FIELD(chan_estimation, 27, 2);
WLAN_BIT_FIELD(reserved, 29, 3);
enum Calibration {
CALIBRATION_NONE = 0,
CALIBRATION_RESPOND_NOINITIATE = 1,
CALIBRATION_RESERVED = 2,
CALIBRATION_RESPOND_INITIATE = 3,
};
enum Feedback {
// Shared for csi_feedback, noncomp_feedback, comp_feedback
FEEDBACK_NONE = 0,
FEEDBACK_DELAYED = 1,
FEEDBACK_IMMEDIATE = 2,
FEEDBACK_DELAYED_IMMEDIATE = 3,
};
enum MinGroup {
MIN_GROUP_ONE = 0, // Meaning no grouping
MIN_GROUP_ONE_TWO = 1,
MIN_GROUP_ONE_FOUR = 2,
MIN_GROUP_ONE_TWO_FOUR = 3,
};
uint8_t csi_antennas_human() const { return csi_antennas() + 1; }
void set_csi_antennas_human(uint8_t num) {
constexpr uint8_t kLowerbound = 1;
constexpr uint8_t kUpperbound = 4;
if (num < kLowerbound) num = kLowerbound;
if (num > kUpperbound) num = kUpperbound;
set_csi_antennas(num - 1);
};
uint8_t noncomp_steering_ants_human() const { return noncomp_steering_ants() + 1; }
void set_noncomp_steering_ants_human(uint8_t num) {
constexpr uint8_t kLowerbound = 1;
constexpr uint8_t kUpperbound = 4;
if (num < kLowerbound) num = kLowerbound;
if (num > kUpperbound) num = kUpperbound;
set_noncomp_steering_ants(num - 1);
}
uint8_t comp_steering_ants_human() const { return comp_steering_ants() + 1; }
void set_comp_steering_ants_human(uint8_t num) {
constexpr uint8_t kLowerbound = 1;
constexpr uint8_t kUpperbound = 4;
if (num < kLowerbound) num = kLowerbound;
if (num > kUpperbound) num = kUpperbound;
set_comp_steering_ants(num - 1);
}
uint8_t csi_rows_human() const { return csi_rows() + 1; }
void set_csi_rows_human(uint8_t num) {
constexpr uint8_t kLowerbound = 1;
constexpr uint8_t kUpperbound = 4;
if (num < kLowerbound) num = kLowerbound;
if (num > kUpperbound) num = kUpperbound;
set_csi_rows(num - 1);
}
uint8_t chan_estimation_human() const { return chan_estimation() + 1; }
void set_chan_estimation_human(uint8_t num) {
constexpr uint8_t kLowerbound = 1;
constexpr uint8_t kUpperbound = 4;
if (num < kLowerbound) num = kLowerbound;
if (num > kUpperbound) num = kUpperbound;
set_chan_estimation(num - 1);
}
static TxBfCapability FromFidl(const ::fuchsia::wlan::mlme::TxBfCapability& fidl) {
TxBfCapability dst;
dst.set_implicit_rx(fidl.implicit_rx ? 1 : 0);
dst.set_rx_stag_sounding(fidl.rx_stag_sounding ? 1 : 0);
dst.set_tx_stag_sounding(fidl.tx_stag_sounding ? 1 : 0);
dst.set_rx_ndp(fidl.rx_ndp ? 1 : 0);
dst.set_tx_ndp(fidl.tx_ndp ? 1 : 0);
dst.set_implicit(fidl.implicit ? 1 : 0);
dst.set_calibration(static_cast<Calibration>(fidl.calibration));
dst.set_csi(fidl.csi ? 1 : 0);
dst.set_noncomp_steering(fidl.noncomp_steering ? 1 : 0);
dst.set_comp_steering(fidl.comp_steering ? 1 : 0);
dst.set_csi_feedback(static_cast<Feedback>(fidl.csi_feedback));
dst.set_noncomp_feedback(static_cast<Feedback>(fidl.noncomp_feedback));
dst.set_comp_feedback(static_cast<Feedback>(fidl.comp_feedback));
dst.set_min_grouping(static_cast<MinGroup>(fidl.min_grouping));
dst.set_csi_antennas_human(fidl.csi_antennas);
dst.set_noncomp_steering_ants_human(fidl.noncomp_steering_ants);
dst.set_comp_steering_ants_human(fidl.comp_steering_ants);
dst.set_csi_rows_human(fidl.csi_rows);
dst.set_chan_estimation_human(fidl.chan_estimation);
return dst;
}
::fuchsia::wlan::mlme::TxBfCapability ToFidl() const {
::fuchsia::wlan::mlme::TxBfCapability fidl;
fidl.implicit_rx = (implicit_rx() == 1);
fidl.rx_stag_sounding = (rx_stag_sounding() == 1);
fidl.tx_stag_sounding = (tx_stag_sounding() == 1);
fidl.rx_ndp = (rx_ndp() == 1);
fidl.tx_ndp = (tx_ndp() == 1);
fidl.implicit = (implicit() == 1);
fidl.calibration = calibration();
fidl.csi = (csi() == 1);
fidl.noncomp_steering = (noncomp_steering() == 1);
fidl.comp_steering = (comp_steering() == 1);
fidl.csi_feedback = csi_feedback();
fidl.noncomp_feedback = noncomp_feedback();
fidl.comp_feedback = comp_feedback();
fidl.min_grouping = min_grouping();
fidl.csi_antennas = csi_antennas_human(); // Converting to human readable
fidl.noncomp_steering_ants = noncomp_steering_ants_human(); // Converting to human readable
fidl.comp_steering_ants = comp_steering_ants_human(); // Converting to human readable
fidl.csi_rows = csi_rows_human(); // Converting to human readable
fidl.chan_estimation = chan_estimation_human(); // Converting to human readable
return fidl;
}
} __PACKED;
class AselCapability : public common::BitField<uint8_t> {
public:
constexpr explicit AselCapability(uint8_t asel_cap) : common::BitField<uint8_t>(asel_cap) {}
constexpr AselCapability() = default;
WLAN_BIT_FIELD(asel, 0, 1);
WLAN_BIT_FIELD(csi_feedback_tx_asel, 1, 1); // Explicit CSI Feedback based Transmit ASEL
WLAN_BIT_FIELD(ant_idx_feedback_tx_asel, 2, 1);
WLAN_BIT_FIELD(explicit_csi_feedback, 3, 1);
WLAN_BIT_FIELD(antenna_idx_feedback, 4, 1);
WLAN_BIT_FIELD(rx_asel, 5, 1);
WLAN_BIT_FIELD(tx_sounding_ppdu, 6, 1);
WLAN_BIT_FIELD(reserved, 7, 1);
static AselCapability FromFidl(const ::fuchsia::wlan::mlme::AselCapability& fidl) {
AselCapability dst;
dst.set_asel(fidl.asel ? 1 : 0);
dst.set_csi_feedback_tx_asel(fidl.csi_feedback_tx_asel ? 1 : 0);
dst.set_ant_idx_feedback_tx_asel(fidl.ant_idx_feedback_tx_asel ? 1 : 0);
dst.set_explicit_csi_feedback(fidl.explicit_csi_feedback ? 1 : 0);
dst.set_antenna_idx_feedback(fidl.antenna_idx_feedback ? 1 : 0);
dst.set_rx_asel(fidl.rx_asel ? 1 : 0);
dst.set_tx_sounding_ppdu(fidl.tx_sounding_ppdu ? 1 : 0);
return dst;
}
::fuchsia::wlan::mlme::AselCapability ToFidl() const {
::fuchsia::wlan::mlme::AselCapability fidl;
fidl.asel = (asel() == 1);
fidl.csi_feedback_tx_asel = (csi_feedback_tx_asel() == 1);
fidl.ant_idx_feedback_tx_asel = (ant_idx_feedback_tx_asel() == 1);
fidl.explicit_csi_feedback = (explicit_csi_feedback() == 1);
fidl.antenna_idx_feedback = (antenna_idx_feedback() == 1);
fidl.rx_asel = (rx_asel() == 1);
fidl.tx_sounding_ppdu = (tx_sounding_ppdu() == 1);
return fidl;
}
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.56
struct HtCapabilities {
HtCapabilityInfo ht_cap_info;
AmpduParams ampdu_params;
SupportedMcsSet mcs_set;
HtExtCapabilities ht_ext_cap;
TxBfCapability txbf_cap;
AselCapability asel_cap;
static HtCapabilities FromDdk(const wlan_ht_caps_t& ddk) {
HtCapabilities dst{};
dst.ht_cap_info.set_val(ddk.ht_capability_info);
dst.ampdu_params.set_val(ddk.ampdu_params);
dst.mcs_set.rx_mcs_head.set_val(ddk.mcs_set.rx_mcs_head);
dst.mcs_set.rx_mcs_tail.set_val(ddk.mcs_set.rx_mcs_tail);
dst.mcs_set.tx_mcs.set_val(ddk.mcs_set.tx_mcs);
dst.ht_ext_cap.set_val(ddk.ht_ext_capabilities);
dst.txbf_cap.set_val(ddk.tx_beamforming_capabilities);
dst.asel_cap.set_val(ddk.asel_capabilities);
return dst;
}
wlan_ht_caps_t ToDdk() const {
wlan_ht_caps_t ddk{};
ddk.ht_capability_info = ht_cap_info.val();
ddk.ampdu_params = ampdu_params.val();
ddk.mcs_set.rx_mcs_head = mcs_set.rx_mcs_head.val();
ddk.mcs_set.rx_mcs_tail = mcs_set.rx_mcs_tail.val();
ddk.mcs_set.tx_mcs = mcs_set.tx_mcs.val();
ddk.ht_ext_capabilities = ht_ext_cap.val();
ddk.tx_beamforming_capabilities = txbf_cap.val();
ddk.asel_capabilities = asel_cap.val();
return ddk;
}
static HtCapabilities FromFidl(const ::fuchsia::wlan::mlme::HtCapabilities& fidl) {
HtCapabilities dst;
dst.ht_cap_info = HtCapabilityInfo::FromFidl(fidl.ht_cap_info);
dst.ampdu_params = AmpduParams::FromFidl(fidl.ampdu_params);
dst.mcs_set = SupportedMcsSet::FromFidl(fidl.mcs_set);
dst.ht_ext_cap = HtExtCapabilities::FromFidl(fidl.ht_ext_cap);
dst.txbf_cap = TxBfCapability::FromFidl(fidl.txbf_cap);
dst.asel_cap = AselCapability::FromFidl(fidl.asel_cap);
return dst;
}
::fuchsia::wlan::mlme::HtCapabilities ToFidl() const {
::fuchsia::wlan::mlme::HtCapabilities fidl;
fidl.ht_cap_info = ht_cap_info.ToFidl();
fidl.ampdu_params = ampdu_params.ToFidl();
fidl.mcs_set = mcs_set.ToFidl();
fidl.ht_ext_cap = ht_ext_cap.ToFidl();
fidl.txbf_cap = txbf_cap.ToFidl();
fidl.asel_cap = asel_cap.ToFidl();
return fidl;
}
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.57
// Note this is a field within HtOperation element.
class HtOpInfoHead : public common::BitField<uint32_t> {
public:
constexpr explicit HtOpInfoHead(uint32_t op_info) : common::BitField<uint32_t>(op_info) {}
constexpr HtOpInfoHead() = default;
WLAN_BIT_FIELD(secondary_chan_offset, 0, 2);
WLAN_BIT_FIELD(sta_chan_width, 2, 1);
WLAN_BIT_FIELD(rifs_mode, 3, 1);
WLAN_BIT_FIELD(reserved1, 4, 4); // Note 802.11n D1.10 implementaions use these.
WLAN_BIT_FIELD(ht_protect, 8, 2);
WLAN_BIT_FIELD(nongreenfield_present, 10, 1); // Nongreenfield HT STAs present.
WLAN_BIT_FIELD(reserved2, 11, 1); // Note 802.11n D1.10 implementations use these.
WLAN_BIT_FIELD(obss_non_ht, 12, 1); // OBSS Non-HT STAs present.
// IEEE 802.11-2016 Figure 9-339 has an incosistency so this is Fuchsia interpretation:
// The channel number for the second segment in a 80+80 Mhz channel
WLAN_BIT_FIELD(center_freq_seg2, 13, 8); // VHT
WLAN_BIT_FIELD(reserved3, 21, 3);
WLAN_BIT_FIELD(reserved4, 24, 6);
WLAN_BIT_FIELD(dual_beacon, 30, 1);
WLAN_BIT_FIELD(dual_cts_protect, 31, 1);
enum SecChanOffset {
SECONDARY_NONE = 0, // No secondary channel
SECONDARY_ABOVE = 1, // Secondary channel is above the primary channel
RESERVED = 2,
SECONDARY_BELOW = 3, // Secondary channel is below the primary channel
};
enum StaChanWidth {
TWENTY = 0, // MHz
ANY = 1, // Any in the Supported Channel Width set
};
enum HtProtect {
NONE = 0,
NONMEMBER = 1,
TWENTY_MHZ = 2,
NON_HT_MIXED = 3,
};
} __PACKED;
class HtOpInfoTail : public common::BitField<uint8_t> {
public:
constexpr explicit HtOpInfoTail(uint8_t val) : common::BitField<uint8_t>(val) {}
constexpr HtOpInfoTail() = default;
WLAN_BIT_FIELD(stbc_beacon, 0, 1); // Add 32 for the original bit location.
WLAN_BIT_FIELD(lsig_txop_protect, 1, 1);
WLAN_BIT_FIELD(pco_active, 2, 1);
WLAN_BIT_FIELD(pco_phase, 3, 1);
WLAN_BIT_FIELD(reserved5, 4, 4);
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.57
struct HtOperation {
uint8_t primary_chan; // Primary 20 MHz channel.
// Implementation hack to support 40bits bitmap.
HtOpInfoHead head;
HtOpInfoTail tail;
SupportedMcsSet basic_mcs_set;
static HtOperation FromDdk(const wlan_ht_op_t& ddk) {
HtOperation dst{};
dst.primary_chan = ddk.primary_chan;
dst.head.set_val(ddk.head);
dst.tail.set_val(ddk.tail);
dst.basic_mcs_set.rx_mcs_head.set_val(ddk.basic_mcs_set.rx_mcs_head);
dst.basic_mcs_set.rx_mcs_tail.set_val(ddk.basic_mcs_set.rx_mcs_tail);
dst.basic_mcs_set.tx_mcs.set_val(ddk.basic_mcs_set.tx_mcs);
return dst;
}
wlan_ht_op_t ToDdk() const {
wlan_ht_op_t ddk{};
ddk.primary_chan = primary_chan;
ddk.head = head.val();
ddk.tail = tail.val();
ddk.basic_mcs_set.rx_mcs_head = basic_mcs_set.rx_mcs_head.val();
ddk.basic_mcs_set.rx_mcs_tail = basic_mcs_set.rx_mcs_tail.val();
ddk.basic_mcs_set.tx_mcs = basic_mcs_set.tx_mcs.val();
return ddk;
}
static HtOperation FromFidl(const ::fuchsia::wlan::mlme::HtOperation& fidl) {
HtOperation dst;
dst.primary_chan = fidl.primary_chan;
dst.basic_mcs_set = SupportedMcsSet::FromFidl(fidl.basic_mcs_set);
const auto& hoi = fidl.ht_op_info;
dst.head.set_secondary_chan_offset(
static_cast<HtOpInfoHead::SecChanOffset>(hoi.secondary_chan_offset));
dst.head.set_sta_chan_width(static_cast<HtOpInfoHead::StaChanWidth>(hoi.sta_chan_width));
dst.head.set_rifs_mode(hoi.rifs_mode ? 1 : 0);
dst.head.set_ht_protect(static_cast<HtOpInfoHead::HtProtect>(hoi.ht_protect));
dst.head.set_nongreenfield_present(hoi.nongreenfield_present ? 1 : 0);
dst.head.set_obss_non_ht(hoi.obss_non_ht ? 1 : 0);
dst.head.set_center_freq_seg2(hoi.center_freq_seg2);
dst.head.set_dual_beacon(hoi.dual_beacon ? 1 : 0);
dst.head.set_dual_cts_protect(hoi.dual_cts_protect ? 1 : 0);
dst.tail.set_stbc_beacon(hoi.stbc_beacon ? 1 : 0);
dst.tail.set_lsig_txop_protect(hoi.lsig_txop_protect ? 1 : 0);
dst.tail.set_pco_active(hoi.pco_active ? 1 : 0);
dst.tail.set_pco_phase(hoi.pco_phase ? 1 : 0);
return dst;
}
::fuchsia::wlan::mlme::HtOperation ToFidl() const {
::fuchsia::wlan::mlme::HtOperation fidl;
fidl.primary_chan = primary_chan;
fidl.basic_mcs_set = basic_mcs_set.ToFidl();
auto* ht_op_info = &fidl.ht_op_info;
ht_op_info->secondary_chan_offset = head.secondary_chan_offset();
ht_op_info->sta_chan_width = head.sta_chan_width();
ht_op_info->rifs_mode = (head.rifs_mode() == 1);
ht_op_info->ht_protect = head.ht_protect();
ht_op_info->nongreenfield_present = (head.nongreenfield_present() == 1);
ht_op_info->obss_non_ht = (head.obss_non_ht() == 1);
ht_op_info->center_freq_seg2 = head.center_freq_seg2();
ht_op_info->dual_beacon = (head.dual_beacon() == 1);
ht_op_info->dual_cts_protect = (head.dual_cts_protect() == 1);
ht_op_info->stbc_beacon = (tail.stbc_beacon() == 1);
ht_op_info->lsig_txop_protect = (tail.lsig_txop_protect() == 1);
ht_op_info->pco_active = (tail.pco_active() == 1);
ht_op_info->pco_phase = (tail.pco_phase() == 1);
return fidl;
}
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.158.2
// Note this is a field of VhtCapabilities element
struct VhtCapabilitiesInfo : public common::BitField<uint32_t> {
public:
constexpr explicit VhtCapabilitiesInfo(uint32_t vht_cap_info)
: common::BitField<uint32_t>(vht_cap_info) {}
constexpr VhtCapabilitiesInfo() = default;
WLAN_BIT_FIELD(max_mpdu_len, 0, 2);
// Supported channel width set. See IEEE Std 802.11-2016, Table 9-250.
WLAN_BIT_FIELD(supported_cbw_set, 2, 2);
WLAN_BIT_FIELD(rx_ldpc, 4, 1);
WLAN_BIT_FIELD(sgi_cbw80, 5, 1); // CBW80 only
WLAN_BIT_FIELD(sgi_cbw160, 6, 1); // CBW160 and CBW80P80
WLAN_BIT_FIELD(tx_stbc, 7, 1);
WLAN_BIT_FIELD(rx_stbc, 8, 3);
WLAN_BIT_FIELD(su_bfer, 11, 1); // Single user beamformer capable
WLAN_BIT_FIELD(su_bfee, 12, 1); // Single user beamformee capable
WLAN_BIT_FIELD(bfee_sts, 13, 3); // Beamformee Space-time spreading
WLAN_BIT_FIELD(num_sounding, 16, 3); // number of sounding dimensions
WLAN_BIT_FIELD(mu_bfer, 19, 1); // Multi user beamformer capable
WLAN_BIT_FIELD(mu_bfee, 20, 1); // Multi user beamformee capable
WLAN_BIT_FIELD(txop_ps, 21, 1); // Txop power save mode
WLAN_BIT_FIELD(htc_vht, 22, 1);
WLAN_BIT_FIELD(max_ampdu_exp, 23, 3);
WLAN_BIT_FIELD(link_adapt, 26, 2); // VHT link adaptation capable
WLAN_BIT_FIELD(rx_ant_pattern, 28, 1);
WLAN_BIT_FIELD(tx_ant_pattern, 29, 1);
// Extended number of spatial stream bandwidth supported
// See IEEE Std 80.211-2016, Table 9-250.
WLAN_BIT_FIELD(ext_nss_bw, 30, 2);
enum MaxMpduLen {
OCTETS_3895 = 0,
OCTETS_7991 = 1,
OCTETS_11454 = 2,
// 3 reserved
};
enum VhtLinkAdaptation {
LINK_ADAPT_NO_FEEDBACK = 0,
// 1 reserved
LINK_ADAPT_UNSOLICITED = 2,
LINK_ADAPT_BOTH = 3,
};
static VhtCapabilitiesInfo FromFidl(const ::fuchsia::wlan::mlme::VhtCapabilitiesInfo& fidl) {
VhtCapabilitiesInfo dst;
dst.set_max_mpdu_len(static_cast<MaxMpduLen>(fidl.max_mpdu_len));
dst.set_supported_cbw_set(fidl.supported_cbw_set);
dst.set_rx_ldpc(fidl.rx_ldpc ? 1 : 0);
dst.set_sgi_cbw80(fidl.sgi_cbw80 ? 1 : 0);
dst.set_sgi_cbw160(fidl.sgi_cbw160 ? 1 : 0);
dst.set_tx_stbc(fidl.tx_stbc ? 1 : 0);
dst.set_rx_stbc(fidl.rx_stbc ? 1 : 0);
dst.set_su_bfer(fidl.su_bfer ? 1 : 0);
dst.set_su_bfee(fidl.su_bfee ? 1 : 0);
dst.set_bfee_sts(fidl.bfee_sts);
dst.set_num_sounding(fidl.num_sounding);
dst.set_mu_bfer(fidl.mu_bfer ? 1 : 0);
dst.set_mu_bfee(fidl.mu_bfee ? 1 : 0);
dst.set_txop_ps(fidl.txop_ps ? 1 : 0);
dst.set_htc_vht(fidl.htc_vht ? 1 : 0);
dst.set_max_ampdu_exp(fidl.max_ampdu_exp);
dst.set_link_adapt(static_cast<VhtLinkAdaptation>(fidl.link_adapt));
dst.set_rx_ant_pattern(fidl.rx_ant_pattern ? 1 : 0);
dst.set_tx_ant_pattern(fidl.tx_ant_pattern ? 1 : 0);
dst.set_ext_nss_bw(fidl.ext_nss_bw);
return dst;
}
::fuchsia::wlan::mlme::VhtCapabilitiesInfo ToFidl() const {
::fuchsia::wlan::mlme::VhtCapabilitiesInfo fidl;
fidl.max_mpdu_len = max_mpdu_len();
fidl.supported_cbw_set = supported_cbw_set();
fidl.rx_ldpc = (rx_ldpc() == 1);
fidl.sgi_cbw80 = (sgi_cbw80() == 1);
fidl.sgi_cbw160 = (sgi_cbw160() == 1);
fidl.tx_stbc = (tx_stbc() == 1);
fidl.rx_stbc = (rx_stbc() == 1);
fidl.su_bfer = (su_bfer() == 1);
fidl.su_bfee = (su_bfee() == 1);
fidl.bfee_sts = bfee_sts();
fidl.num_sounding = num_sounding();
fidl.mu_bfer = (mu_bfer() == 1);
fidl.mu_bfee = (mu_bfee() == 1);
fidl.txop_ps = (txop_ps() == 1);
fidl.htc_vht = (htc_vht() == 1);
fidl.max_ampdu_exp = max_ampdu_exp();
fidl.link_adapt = link_adapt();
fidl.rx_ant_pattern = (rx_ant_pattern() == 1);
fidl.tx_ant_pattern = (tx_ant_pattern() == 1);
fidl.ext_nss_bw = ext_nss_bw();
return fidl;
}
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.158.3
struct VhtMcsNss : public common::BitField<uint64_t> {
public:
constexpr explicit VhtMcsNss(uint64_t vht_mcs_nss) : common::BitField<uint64_t>(vht_mcs_nss) {}
constexpr VhtMcsNss() = default;
// Rx VHT-MCS Map
WLAN_BIT_FIELD(rx_max_mcs_ss1, 0, 2);
WLAN_BIT_FIELD(rx_max_mcs_ss2, 2, 2);
WLAN_BIT_FIELD(rx_max_mcs_ss3, 4, 2);
WLAN_BIT_FIELD(rx_max_mcs_ss4, 6, 2);
WLAN_BIT_FIELD(rx_max_mcs_ss5, 8, 2);
WLAN_BIT_FIELD(rx_max_mcs_ss6, 10, 2);
WLAN_BIT_FIELD(rx_max_mcs_ss7, 12, 2);
WLAN_BIT_FIELD(rx_max_mcs_ss8, 14, 2);
WLAN_BIT_FIELD(rx_max_data_rate, 16, 13);
WLAN_BIT_FIELD(max_nsts, 29, 3);
// Tx VHT-MCS Map
WLAN_BIT_FIELD(tx_max_mcs_ss1, 32, 2);
WLAN_BIT_FIELD(tx_max_mcs_ss2, 34, 2);
WLAN_BIT_FIELD(tx_max_mcs_ss3, 36, 2);
WLAN_BIT_FIELD(tx_max_mcs_ss4, 38, 2);
WLAN_BIT_FIELD(tx_max_mcs_ss5, 40, 2);
WLAN_BIT_FIELD(tx_max_mcs_ss6, 42, 2);
WLAN_BIT_FIELD(tx_max_mcs_ss7, 44, 2);
WLAN_BIT_FIELD(tx_max_mcs_ss8, 46, 2);
WLAN_BIT_FIELD(tx_max_data_rate, 48, 13);
WLAN_BIT_FIELD(ext_nss_bw, 61, 1);
// bit 62, 63 reserved
enum VhtMcsSet {
VHT_MCS_0_TO_7 = 0,
VHT_MCS_0_TO_8 = 1,
VHT_MCS_0_TO_9 = 2,
VHT_MCS_NONE = 3,
};
uint8_t get_rx_max_mcs_ss(uint8_t ss_num) const {
ZX_DEBUG_ASSERT(1 <= ss_num && ss_num <= 8);
constexpr uint8_t kMcsBitOffset = 0; // rx_max_mcs_ss1
constexpr uint8_t kBitWidth = 2;
uint8_t offset = kMcsBitOffset + (ss_num - 1) * kBitWidth;
uint64_t mask = ((1ull << kBitWidth) - 1) << offset;
return (val() & mask) >> offset;
}
uint8_t get_tx_max_mcs_ss(uint8_t ss_num) const {
ZX_DEBUG_ASSERT(1 <= ss_num && ss_num <= 8);
constexpr uint8_t kMcsBitOffset = 32; // tx_max_mcs_ss1
constexpr uint8_t kBitWidth = 2;
uint8_t offset = kMcsBitOffset + (ss_num - 1) * kBitWidth;
uint64_t mask = ((1ull << kBitWidth) - 1) << offset;
return (val() & mask) >> offset;
}
void set_rx_max_mcs_ss(uint8_t ss_num, uint8_t mcs) {
ZX_DEBUG_ASSERT(1 <= ss_num && ss_num <= 8);
constexpr uint8_t kMcsBitOffset = 0; // rx_max_mcs_ss1
constexpr uint8_t kBitWidth = 2;
uint8_t offset = kMcsBitOffset + (ss_num - 1) * kBitWidth;
uint64_t mcs_val = static_cast<uint64_t>(mcs) << offset;
set_val(val() | mcs_val);
}
void set_tx_max_mcs_ss(uint8_t ss_num, uint8_t mcs) {
ZX_DEBUG_ASSERT(1 <= ss_num && ss_num <= 8);
constexpr uint8_t kMcsBitOffset = 32; // tx_max_mcs_ss1
constexpr uint8_t kBitWidth = 2;
uint8_t offset = kMcsBitOffset + (ss_num - 1) * kBitWidth;
uint64_t mcs_val = static_cast<uint64_t>(mcs) << offset;
set_val(val() | mcs_val);
}
static VhtMcsNss FromFidl(const ::fuchsia::wlan::mlme::VhtMcsNss& fidl) {
VhtMcsNss dst;
for (uint8_t ss_num = 1; ss_num <= 8; ss_num++) {
dst.set_rx_max_mcs_ss(ss_num, fidl.rx_max_mcs[ss_num - 1]);
}
dst.set_rx_max_data_rate(fidl.rx_max_data_rate);
dst.set_tx_max_data_rate(fidl.tx_max_data_rate);
for (uint8_t ss_num = 1; ss_num <= 8; ss_num++) {
dst.set_tx_max_mcs_ss(ss_num, fidl.tx_max_mcs[ss_num - 1]);
}
dst.set_max_nsts(fidl.max_nsts);
dst.set_ext_nss_bw(fidl.ext_nss_bw);
return dst;
}
::fuchsia::wlan::mlme::VhtMcsNss ToFidl() const {
::fuchsia::wlan::mlme::VhtMcsNss fidl;
for (uint8_t ss_num = 1; ss_num <= 8; ss_num++) {
fidl.rx_max_mcs[ss_num - 1] = get_rx_max_mcs_ss(ss_num);
}
fidl.rx_max_data_rate = rx_max_data_rate();
fidl.max_nsts = max_nsts();
for (uint8_t ss_num = 1; ss_num <= 8; ss_num++) {
fidl.tx_max_mcs[ss_num - 1] = get_tx_max_mcs_ss(ss_num);
}
fidl.tx_max_data_rate = tx_max_data_rate();
fidl.ext_nss_bw = (ext_nss_bw() == 1);
return fidl;
}
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.158
struct VhtCapabilities {
VhtCapabilitiesInfo vht_cap_info;
VhtMcsNss vht_mcs_nss;
static VhtCapabilities FromDdk(const wlan_vht_caps_t& ddk) {
VhtCapabilities dst{};
dst.vht_cap_info.set_val(ddk.vht_capability_info);
dst.vht_mcs_nss.set_val(ddk.supported_vht_mcs_and_nss_set);
return dst;
}
wlan_vht_caps_t ToDdk() const {
wlan_vht_caps_t ddk{};
ddk.vht_capability_info = vht_cap_info.val();
ddk.supported_vht_mcs_and_nss_set = vht_mcs_nss.val();
return ddk;
}
static VhtCapabilities FromFidl(const ::fuchsia::wlan::mlme::VhtCapabilities& fidl) {
VhtCapabilities dst;
dst.vht_cap_info = VhtCapabilitiesInfo::FromFidl(fidl.vht_cap_info);
dst.vht_mcs_nss = VhtMcsNss::FromFidl(fidl.vht_mcs_nss);
return dst;
}
::fuchsia::wlan::mlme::VhtCapabilities ToFidl() const {
::fuchsia::wlan::mlme::VhtCapabilities fidl;
fidl.vht_cap_info = vht_cap_info.ToFidl();
fidl.vht_mcs_nss = vht_mcs_nss.ToFidl();
return fidl;
}
} __PACKED;
// IEEE Std 802.11-2016, Figure 9-562
struct BasicVhtMcsNss : public common::BitField<uint16_t> {
public:
constexpr explicit BasicVhtMcsNss(uint16_t basic_mcs) : common::BitField<uint16_t>(basic_mcs) {}
constexpr BasicVhtMcsNss() = default;
WLAN_BIT_FIELD(ss1, 0, 2);
WLAN_BIT_FIELD(ss2, 2, 2);
WLAN_BIT_FIELD(ss3, 4, 2);
WLAN_BIT_FIELD(ss4, 6, 2);
WLAN_BIT_FIELD(ss5, 8, 2);
WLAN_BIT_FIELD(ss6, 10, 2);
WLAN_BIT_FIELD(ss7, 12, 2);
WLAN_BIT_FIELD(ss8, 14, 2);
enum VhtMcsEncoding {
VHT_MCS_0_TO_7 = 0,
VHT_MCS_0_TO_8 = 1,
VHT_MCS_0_TO_9 = 2,
VHT_MCS_NONE = 3,
};
uint8_t get_max_mcs_ss(uint8_t ss_num) const {
ZX_DEBUG_ASSERT(1 <= ss_num && ss_num <= 8);
constexpr uint8_t kMcsBitOffset = 0; // ss1
constexpr uint8_t kBitWidth = 2;
uint8_t offset = kMcsBitOffset + (ss_num - 1) * kBitWidth;
uint64_t mask = ((1ull << kBitWidth) - 1) << offset;
return (val() & mask) >> offset;
}
void set_max_mcs_ss(uint8_t ss_num, uint8_t mcs) {
ZX_DEBUG_ASSERT(1 <= ss_num && ss_num <= 8);
constexpr uint8_t kMcsBitOffset = 0; // ss1
constexpr uint8_t kBitWidth = 2;
uint8_t offset = kMcsBitOffset + (ss_num - 1) * kBitWidth;
uint64_t mcs_val = static_cast<uint64_t>(mcs) << offset;
set_val(val() | mcs_val);
}
static BasicVhtMcsNss FromFidl(const ::fuchsia::wlan::mlme::BasicVhtMcsNss& fidl) {
BasicVhtMcsNss dst;
for (uint8_t ss_num = 1; ss_num <= 8; ++ss_num) {
dst.set_max_mcs_ss(ss_num, fidl.max_mcs[ss_num - 1]);
}
return dst;
}
::fuchsia::wlan::mlme::BasicVhtMcsNss ToFidl() const {
::fuchsia::wlan::mlme::BasicVhtMcsNss fidl;
for (uint8_t ss_num = 1; ss_num <= 8; ss_num++) {
fidl.max_mcs[ss_num - 1] = get_max_mcs_ss(ss_num);
}
return fidl;
}
};
// IEEE Std 802.11-2016, 9.4.2.159
struct VhtOperation {
uint8_t vht_cbw;
uint8_t center_freq_seg0;
uint8_t center_freq_seg1;
BasicVhtMcsNss basic_mcs;
enum VhtChannelBandwidth {
VHT_CBW_20_40 = 0,
VHT_CBW_80_160_80P80 = 1,
VHT_CBW_160 = 2, // Deprecated
VHT_CBW_80P80 = 3, // Deprecated
// 4 - 255 reserved
};
static VhtOperation FromDdk(const wlan_vht_op_t& ddk) {
VhtOperation dst{};
dst.vht_cbw = ddk.vht_cbw;
dst.center_freq_seg0 = ddk.center_freq_seg0;
dst.center_freq_seg1 = ddk.center_freq_seg1;
dst.basic_mcs.set_val(ddk.basic_mcs);
return dst;
}
wlan_vht_op_t ToDdk() const {
wlan_vht_op_t dst{};
dst.vht_cbw = vht_cbw;
dst.center_freq_seg0 = center_freq_seg0;
dst.center_freq_seg1 = center_freq_seg1;
dst.basic_mcs = basic_mcs.val();
return dst;
}
static VhtOperation FromFidl(const ::fuchsia::wlan::mlme::VhtOperation& fidl) {
VhtOperation dst;
dst.vht_cbw = static_cast<VhtChannelBandwidth>(fidl.vht_cbw);
dst.center_freq_seg0 = fidl.center_freq_seg0;
dst.center_freq_seg1 = fidl.center_freq_seg1;
dst.basic_mcs = BasicVhtMcsNss::FromFidl(fidl.basic_mcs);
return dst;
}
::fuchsia::wlan::mlme::VhtOperation ToFidl() const {
::fuchsia::wlan::mlme::VhtOperation fidl;
fidl.vht_cbw = vht_cbw;
fidl.center_freq_seg0 = center_freq_seg0;
fidl.center_freq_seg1 = center_freq_seg1;
fidl.basic_mcs = basic_mcs.ToFidl();
return fidl;
}
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.102
// The fixed part of the Mesh Peering Management header
struct MpmHeader {
// IEEE Std 802.11-2016, table 9-222
enum Protocol : uint16_t {
MPM = 0,
AMPE = 1,
};
Protocol protocol;
uint16_t local_link_id;
} __PACKED;
// IEEE Std 802.11-2016, 9.4.2.102
// The optional "PMK" part of the MPM element
struct MpmPmk {
uint8_t data[16];
} __PACKED;
SupportedMcsSet IntersectMcs(const SupportedMcsSet& lhs, const SupportedMcsSet& rhs);
HtCapabilities IntersectHtCap(const HtCapabilities& lhs, const HtCapabilities& rhs);
VhtCapabilities IntersectVhtCap(const VhtCapabilities& lhs, const VhtCapabilities& rhs);
// Find common legacy rates between AP and client.
// The outcoming "Basic rates" follows those specified in AP
std::vector<SupportedRate> IntersectRatesAp(const std::vector<SupportedRate>& ap_rates,
const std::vector<SupportedRate>& client_rates);
} // namespace wlan
#endif // GARNET_LIB_WLAN_COMMON_INCLUDE_WLAN_COMMON_ELEMENT_H_