use crate::buffer_reader::BufferReader;
use crate::mac::ReasonCode;
use crate::organization::Oui;
use crate::UnalignedView;
use ieee80211::MacAddr;
use static_assertions::const_assert_eq;
use std::mem::size_of;
use wlan_bitfield::bitfield;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned};
use {
banjo_fuchsia_wlan_ieee80211 as banjo_ieee80211, fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211,
};
macro_rules! pub_const {
($name:ident, $val:expr) => {
pub const $name: Self = Self($val);
};
}
#[bitfield(
0..=6 rate,
7 basic,
)]
#[repr(C)]
#[derive(
PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy,
)]
pub struct SupportedRate(pub u8);
impl SupportedRate {
pub fn is_bss_membership_selector(&self) -> bool {
match self.0 {
0xFF | 0xFE => true,
_ => false,
}
}
}
#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
#[repr(C)]
pub struct DsssParamSet {
pub current_channel: u8,
}
#[bitfield(
0 group_traffic,
1..=7 offset,
)]
#[repr(C)]
#[derive(
PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy,
)]
pub struct BitmapControl(pub u8);
#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, Clone, Copy)]
#[repr(C, packed)]
pub struct TimHeader {
pub dtim_count: u8,
pub dtim_period: u8,
pub bmp_ctrl: BitmapControl,
}
pub struct TimView<B> {
pub header: TimHeader,
pub bitmap: B,
}
#[bitfield(
0..=7 union {
client_wmm_info as ClientWmmInfo(u8),
ap_wmm_info as ApWmmInfo(u8),
}
)]
#[repr(C)]
#[derive(
PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Default,
)]
pub struct WmmInfo(pub u8);
#[bitfield(
0..=3 parameter_set_count,
4..=6 _, 7 uapsd
)]
#[repr(C)]
#[derive(PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
pub struct ApWmmInfo(pub u8);
#[bitfield(
0 ac_vo_uapsd,
1 ac_vi_uapsd,
2 ac_bk_uapsd,
3 ac_be_uapsd,
4 _, 5..=6 max_sp_length,
7 _ )]
#[repr(C)]
#[derive(PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
pub struct ClientWmmInfo(pub u8);
#[repr(C, packed)]
#[derive(
PartialEq,
Eq,
Clone,
Copy,
Debug,
IntoBytes,
KnownLayout,
FromBytes,
Immutable,
Unaligned,
Default,
)]
pub struct WmmParam {
pub wmm_info: WmmInfo,
pub _reserved: u8,
pub ac_be_params: WmmAcParams,
pub ac_bk_params: WmmAcParams,
pub ac_vi_params: WmmAcParams,
pub ac_vo_params: WmmAcParams,
}
#[repr(C, packed)]
#[derive(
PartialEq,
Eq,
Clone,
Copy,
Debug,
IntoBytes,
KnownLayout,
FromBytes,
Immutable,
Unaligned,
Default,
)]
pub struct WmmAcParams {
pub aci_aifsn: WmmAciAifsn,
pub ecw_min_max: EcwMinMax,
pub txop_limit: u16,
}
#[bitfield(
0..=3 aifsn,
4 acm,
5..=6 aci,
7 _ )]
#[repr(C)]
#[derive(
PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Default,
)]
pub struct WmmAciAifsn(pub u8);
#[bitfield(
0..=3 ecw_min,
4..=7 ecw_max,
)]
#[repr(C)]
#[derive(
PartialEq, Eq, Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Default,
)]
pub struct EcwMinMax(pub u8);
pub struct CountryView<B> {
pub country_code: [u8; 2],
pub environment: CountryEnvironment,
pub subbands: B,
}
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct CountryEnvironment(pub u8);
impl CountryEnvironment {
pub const INDOOR: Self = Self(b'I');
pub const OUTDOOR: Self = Self(b'O');
pub const NON_COUNTRY: Self = Self(b'X');
pub const ANY: Self = Self(b' ');
}
#[repr(C, packed)]
#[derive(
PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
)]
pub struct HtCapabilities {
pub ht_cap_info: HtCapabilityInfo, pub ampdu_params: AmpduParams, pub mcs_set: SupportedMcsSet, pub ht_ext_cap: HtExtCapabilities, pub txbf_cap: TxBfCapability, pub asel_cap: AselCapability, }
impl From<banjo_ieee80211::HtCapabilities> for HtCapabilities {
fn from(cap: banjo_ieee80211::HtCapabilities) -> Self {
const_assert_eq!(
std::mem::size_of::<HtCapabilities>(),
banjo_ieee80211::HT_CAP_LEN as usize,
);
HtCapabilities::read_from_bytes(&cap.bytes[..]).unwrap()
}
}
impl From<HtCapabilities> for banjo_ieee80211::HtCapabilities {
fn from(cap: HtCapabilities) -> Self {
let mut banjo_cap = Self { bytes: Default::default() };
banjo_cap.bytes.copy_from_slice(&cap.as_bytes()[..]);
banjo_cap
}
}
impl From<fidl_ieee80211::HtCapabilities> for HtCapabilities {
fn from(cap: fidl_ieee80211::HtCapabilities) -> Self {
const_assert_eq!(
std::mem::size_of::<HtCapabilities>(),
fidl_ieee80211::HT_CAP_LEN as usize,
);
HtCapabilities::read_from_bytes(&cap.bytes[..]).unwrap()
}
}
impl From<HtCapabilities> for fidl_ieee80211::HtCapabilities {
fn from(cap: HtCapabilities) -> Self {
let mut fidl_cap = Self { bytes: Default::default() };
fidl_cap.bytes.copy_from_slice(&cap.as_bytes()[..]);
fidl_cap
}
}
impl From<fidl_ieee80211::VhtCapabilities> for VhtCapabilities {
fn from(cap: fidl_ieee80211::VhtCapabilities) -> Self {
const_assert_eq!(
std::mem::size_of::<VhtCapabilities>(),
fidl_ieee80211::VHT_CAP_LEN as usize,
);
VhtCapabilities::read_from_bytes(&cap.bytes[..]).unwrap()
}
}
impl From<VhtCapabilities> for fidl_ieee80211::VhtCapabilities {
fn from(cap: VhtCapabilities) -> Self {
let mut fidl_cap = Self { bytes: Default::default() };
fidl_cap.bytes.copy_from_slice(&cap.as_bytes()[..]);
fidl_cap
}
}
#[bitfield(
0 ldpc_coding_cap,
1..=1 chan_width_set as ChanWidthSet(u8), 2..=3 sm_power_save as SmPowerSave(u8), 4 greenfield, 5 short_gi_20, 6 short_gi_40, 7 tx_stbc,
8..=9 rx_stbc, 10 delayed_block_ack, 11..=11 max_amsdu_len as MaxAmsduLen(u8),
12 dsss_in_40, 13 _, 14 intolerant_40, 15 lsig_txop_protect,
)]
#[repr(C)]
#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
pub struct HtCapabilityInfo(pub u16);
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct ChanWidthSet(pub u8);
impl ChanWidthSet {
pub_const!(TWENTY_ONLY, 0);
pub_const!(TWENTY_FORTY, 1);
}
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct SmPowerSave(pub u8);
impl SmPowerSave {
pub_const!(STATIC, 0);
pub_const!(DYNAMIC, 1);
pub_const!(DISABLED, 3);
}
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct MaxAmsduLen(pub u8);
impl MaxAmsduLen {
pub_const!(OCTETS_3839, 0);
pub_const!(OCTETS_7935, 1);
}
#[bitfield(
0..=1 max_ampdu_exponent as MaxAmpduExponent(u8), 2..=4 min_start_spacing as MinMpduStartSpacing(u8), 5..=7 _, )]
#[repr(C)]
#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
pub struct AmpduParams(pub u8);
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct MaxAmpduExponent(pub u8);
impl MaxAmpduExponent {
pub fn to_len(&self) -> usize {
(1 << (13 + self.0)) - 1 as usize
}
}
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct MinMpduStartSpacing(pub u8);
impl MinMpduStartSpacing {
pub_const!(NO_RESTRICT, 0);
pub_const!(QUATER_USEC, 1);
pub_const!(HALF_USEC, 2);
pub_const!(ONE_USEC, 3);
pub_const!(TWO_USEC, 4);
pub_const!(FOUR_USEC, 5);
pub_const!(EIGHT_USEC, 6);
pub_const!(SIXTEEN_USEC, 7);
}
#[bitfield(
0..=76 rx_mcs as RxMcsBitmask(u128),
77..=79 _, 80..=89 rx_highest_rate, 90..=95 _, 96 tx_set_defined,
97 tx_rx_diff,
98..=99 tx_max_ss as NumSpatialStreams(u8),
100 tx_ueqm, 101..=127 _, )]
#[repr(C)]
#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
pub struct SupportedMcsSet(pub u128);
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct RxMcsBitmask(pub u128);
impl RxMcsBitmask {
pub fn support(&self, mcs_index: u8) -> bool {
mcs_index <= 76 && (self.0 & (1 << mcs_index)) != 0
}
}
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct NumSpatialStreams(u8);
impl NumSpatialStreams {
pub_const!(ONE, 0);
pub_const!(TWO, 1);
pub_const!(THREE, 2);
pub_const!(FOUR, 3);
pub fn to_human(&self) -> u8 {
1 + self.0
}
pub fn from_human(val: u8) -> Result<Self, String> {
if Self::ONE.to_human() <= val && val <= Self::FOUR.to_human() {
Ok(Self(val - 1))
} else {
Err(format!("Number of spatial stream must be between 1 and 4. {} is invalid", val))
}
}
}
#[bitfield(
0 pco,
1..=2 pco_transition as PcoTransitionTime(u8),
3..=7 _, 8..=9 mcs_feedback as McsFeedback(u8),
10 htc_ht_support,
11 rd_responder,
12..=15 _, )]
#[repr(C)]
#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
pub struct HtExtCapabilities(pub u16);
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct PcoTransitionTime(pub u8);
impl PcoTransitionTime {
pub_const!(PCO_RESERVED, 0); pub_const!(PCO_400_USEC, 1);
pub_const!(PCO_1500_USEC, 2);
pub_const!(PCO_5000_USEC, 3);
}
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct McsFeedback(pub u8);
impl McsFeedback {
pub_const!(NO_FEEDBACK, 0);
pub_const!(UNSOLICITED, 2);
pub_const!(BOTH, 3);
}
#[bitfield(
0 implicit_rx,
1 rx_stag_sounding,
2 tx_stag_sounding,
3 rx_ndp,
4 tx_ndp,
5 implicit,
6..=7 calibration as Calibration(u8),
8 csi, 9 noncomp_steering, 10 comp_steering, 11..=12 csi_feedback as Feedback(u8),
13..=14 noncomp_feedback as Feedback(u8),
15..=16 comp_feedback as Feedback(u8),
17..=18 min_grouping as MinGroup(u8),
19..=20 csi_antennas as NumAntennas(u8),
21..=22 noncomp_steering_ants as NumAntennas(u8),
23..=24 comp_steering_ants as NumAntennas(u8),
25..=26 csi_rows as NumCsiRows(u8),
27..=28 chan_estimation as NumSpaceTimeStreams(u8),
29..=31 _, )]
#[repr(C)]
#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
pub struct TxBfCapability(pub u32);
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct Calibration(pub u8);
impl Calibration {
pub_const!(NONE, 0);
pub_const!(RESPOND_NO_INITIATE, 1);
pub_const!(RESPOND_INITIATE, 3);
}
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct Feedback(pub u8);
impl Feedback {
pub_const!(NONE, 0);
pub_const!(DELAYED, 1);
pub_const!(IMMEDIATE, 2);
pub_const!(DELAYED_IMMEDIATE, 3);
}
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct MinGroup(pub u8);
impl MinGroup {
pub_const!(ONE, 0); pub_const!(TWO, 1);
pub_const!(FOUR, 2);
pub_const!(TWO_FOUR, 3);
}
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct NumAntennas(u8);
impl NumAntennas {
pub_const!(ONE, 0);
pub_const!(TWO, 1);
pub_const!(THREE, 2);
pub_const!(FOUR, 3);
pub fn to_human(&self) -> u8 {
1 + self.0
}
pub fn from_human(val: u8) -> Result<Self, String> {
if Self::ONE.to_human() <= val && val <= Self::FOUR.to_human() {
Ok(Self(val - 1))
} else {
Err(format!("Number of antennas must be between 1 and 4. {} is invalid", val))
}
}
}
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct NumCsiRows(u8);
impl NumCsiRows {
pub_const!(ONE, 0);
pub_const!(TWO, 1);
pub_const!(THREE, 2);
pub_const!(FOUR, 3);
pub fn to_human(&self) -> u8 {
1 + self.0
}
pub fn from_human(val: u8) -> Result<Self, String> {
if Self::ONE.to_human() <= val && val <= Self::FOUR.to_human() {
Ok(Self(val - 1))
} else {
Err(format!("Number of csi rows must be between 1 and 4. {} is invalid", val))
}
}
}
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct NumSpaceTimeStreams(u8);
impl NumSpaceTimeStreams {
pub_const!(ONE, 0);
pub_const!(TWO, 1);
pub_const!(THREE, 2);
pub_const!(FOUR, 3);
pub fn to_human(&self) -> u8 {
1 + self.0
}
pub fn from_human(val: u8) -> Result<Self, String> {
if 1 <= val && val <= 4 {
Ok(Self(val - 1))
} else {
Err(format!("Number of channel estimation must be between 1 and 4. {} is invalid", val))
}
}
}
#[bitfield(
0 asel,
1 csi_feedback_tx_asel, 2 ant_idx_feedback_tx_asel,
3 explicit_csi_feedback,
4 antenna_idx_feedback,
5 rx_asel,
6 tx_sounding_ppdu,
7 _, )]
#[repr(C)]
#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
pub struct AselCapability(pub u8);
#[repr(C, packed)]
#[derive(
PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
)]
pub struct HtOperation {
pub primary_channel: u8, pub ht_op_info: HtOpInfo,
pub basic_ht_mcs_set: SupportedMcsSet, }
impl From<HtOperation> for fidl_ieee80211::HtOperation {
fn from(op: HtOperation) -> Self {
let mut ht_op = Self { bytes: Default::default() };
ht_op.bytes.copy_from_slice(&op.as_bytes()[..]);
ht_op
}
}
#[bitfield(
0..=1 secondary_chan_offset as SecChanOffset(u8),
2..=2 sta_chan_width as StaChanWidth(u8),
3 rifs_mode_permitted,
4..=7 _, 8..=9 ht_protection as HtProtection(u8),
10 nongreenfield_present,
11 _, 12 obss_non_ht_stas_present,
13..=20 center_freq_seg2, 21..=23 _, 24..=29 _, 30 dual_beacon, 31 dual_cts_protection, 32 stbc_beacon, 33 lsig_txop_protection, 34 pco_active,
35..=35 pco_phase as PcoPhase(u8),
36..=39 _, )]
#[repr(C)]
#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
pub struct HtOpInfo(pub [u8; 5]);
impl HtOpInfo {
pub fn new() -> HtOpInfo {
HtOpInfo([0u8; 5])
}
}
#[repr(C, packed)]
#[derive(
Debug,
PartialOrd,
PartialEq,
Eq,
Clone,
Copy,
IntoBytes,
KnownLayout,
FromBytes,
Immutable,
Unaligned,
)]
pub struct SecChanOffset(pub u8);
impl SecChanOffset {
pub_const!(SECONDARY_NONE, 0); pub_const!(SECONDARY_ABOVE, 1); pub_const!(SECONDARY_BELOW, 3); }
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy)]
pub struct StaChanWidth(pub u8);
impl StaChanWidth {
pub_const!(TWENTY_MHZ, 0);
pub_const!(ANY, 1); }
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy)]
pub struct HtProtection(pub u8);
impl HtProtection {
pub_const!(NONE, 0);
pub_const!(NON_MEMBER, 1);
pub_const!(TWENTY_MHZ, 2);
pub_const!(NON_HT_MIXED, 3);
}
#[bitfield(
0 link_measurement_enabled,
1 neighbor_report_enabled,
2 parallel_measurements_enabled,
3 repeated_measurements_enabled,
4 beacon_passive_measurement_enabled,
5 beacon_active_measurement_enabled,
6 beacon_table_measurement_enabled,
7 beacon_measurement_reporting_conditions_enabled,
8 frame_measurement_enabled,
9 channel_load_measurement_enabled,
10 noise_histogram_measurement_enabled,
11 statistics_measurement_enabled,
12 lci_measurement_enabled,
13 lci_azimuth_enabled,
14 tx_stream_category_measurement_enabled,
15 trigerred_tx_stream_category_measurement_enabled,
16 ap_channel_report_enabled,
17 rm_mib_enabled,
18..=20 operating_channel_max_measurement_duration,
21..=23 nonoperating_channel_max_measurement_duration,
24..=26 measurement_pilot_capability,
27 measurement_pilot_tx_info_enabled,
28 neighbor_report_tsf_offset_enabled,
29 rcpi_measurement_enabled,
30 rsni_measurement_enabled,
31 bss_average_access_delay_enabled,
32 bss_available_admission_capacity_enabled,
33 antenna_enabled,
34 ftm_range_report_enabled,
35 civic_location_measurement_enabled,
36..=39 _,
)]
#[repr(C)]
#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
pub struct RmEnabledCapabilities(pub [u8; 5]);
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy)]
pub struct PcoPhase(pub u8);
impl PcoPhase {
pub_const!(TWENTY_MHZ, 0);
pub_const!(FORTY_MHZ, 1);
}
#[repr(C)]
#[derive(PartialEq, Eq, Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
pub struct MpmProtocol(pub u16);
impl MpmProtocol {
pub_const!(MPM, 0);
pub_const!(AMPE, 1);
pub_const!(VENDOR_SPECIFIC, 255);
}
pub struct ExtCapabilitiesView<B> {
pub ext_caps_octet_1: Option<Ref<B, ExtCapabilitiesOctet1>>,
pub ext_caps_octet_2: Option<Ref<B, ExtCapabilitiesOctet2>>,
pub ext_caps_octet_3: Option<Ref<B, ExtCapabilitiesOctet3>>,
pub remaining: B,
}
#[bitfield(
0 twenty_forty_bss_coexistence_mgmt_support,
1 _, 2 extended_channel_switching,
3 _, 4 psmp_capability,
5 _, 6 s_psmp_support,
7 event,
)]
#[repr(C)]
#[derive(
PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy, Unaligned,
)]
pub struct ExtCapabilitiesOctet1(pub u8);
#[bitfield(
0 diagnostics,
1 multicast_diagnostics,
2 location_tracking,
3 fms,
4 proxy_arp_service,
5 collocated_interference_reporting,
6 civic_location,
7 geospatial_location,
)]
#[repr(C)]
#[derive(
PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy, Unaligned,
)]
pub struct ExtCapabilitiesOctet2(pub u8);
#[bitfield(
0 tfs,
1 wnm_sleep_mode,
2 tim_broadcast,
3 bss_transition,
4 qos_traffic_capability,
5 ac_station_count,
6 multiple_bssid,
7 timing_measurement,
)]
#[repr(C)]
#[derive(
PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy, Unaligned,
)]
pub struct ExtCapabilitiesOctet3(pub u8);
#[bitfield(
0 gate_announcement,
1 addressing_mode,
2 proactive,
3..=5 _, 6 addr_ext,
7 _, )]
#[repr(C)]
#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
pub struct PreqFlags(pub u8);
#[repr(C, packed)]
#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
pub struct PreqHeader {
pub flags: PreqFlags,
pub hop_count: u8,
pub element_ttl: u8,
pub path_discovery_id: u32,
pub originator_addr: MacAddr,
pub originator_hwmp_seqno: u32,
}
#[repr(C, packed)]
#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
pub struct PreqMiddle {
pub lifetime: u32,
pub metric: u32,
pub target_count: u8,
}
#[bitfield(
0 target_only,
1 _, 2 usn,
3..=7 _, )]
#[repr(C)]
#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
pub struct PreqPerTargetFlags(pub u8);
#[repr(C, packed)]
#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
pub struct PreqPerTarget {
pub flags: PreqPerTargetFlags,
pub target_addr: MacAddr,
pub target_hwmp_seqno: u32,
}
pub struct PreqView<B> {
pub header: Ref<B, PreqHeader>,
pub originator_external_addr: Option<Ref<B, MacAddr>>,
pub middle: Ref<B, PreqMiddle>,
pub targets: Ref<B, [PreqPerTarget]>,
}
#[bitfield(
0..=5 _, 6 addr_ext,
7 _, )]
#[repr(C)]
#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
pub struct PrepFlags(pub u8);
#[repr(C, packed)]
#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
pub struct PrepHeader {
pub flags: PrepFlags,
pub hop_count: u8,
pub element_ttl: u8,
pub target_addr: MacAddr,
pub target_hwmp_seqno: u32,
}
#[repr(C, packed)]
#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
pub struct PrepTail {
pub lifetime: u32,
pub metric: u32,
pub originator_addr: MacAddr,
pub originator_hwmp_seqno: u32,
}
pub struct PrepView<B> {
pub header: Ref<B, PrepHeader>,
pub target_external_addr: Option<Ref<B, MacAddr>>,
pub tail: Ref<B, PrepTail>,
}
#[repr(C, packed)]
#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
pub struct PerrHeader {
pub element_ttl: u8,
pub num_destinations: u8,
}
#[bitfield(
0..=5 _, 6 addr_ext,
7 _, )]
#[repr(C)]
#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
pub struct PerrDestinationFlags(pub u8);
#[repr(C, packed)]
#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
pub struct PerrDestinationHeader {
pub flags: PerrDestinationFlags,
pub dest_addr: MacAddr,
pub hwmp_seqno: u32,
}
pub struct PerrDestinationView<B> {
pub header: Ref<B, PerrDestinationHeader>,
pub ext_addr: Option<Ref<B, MacAddr>>,
pub reason_code: UnalignedView<B, ReasonCode>,
}
pub struct PerrView<B> {
pub header: Ref<B, PerrHeader>,
pub destinations: PerrDestinationListView<B>,
}
pub struct PerrDestinationListView<B>(pub B);
impl<B: SplitByteSlice> IntoIterator for PerrDestinationListView<B> {
type Item = PerrDestinationView<B>;
type IntoIter = PerrDestinationIter<B>;
fn into_iter(self) -> Self::IntoIter {
PerrDestinationIter(BufferReader::new(self.0))
}
}
impl<'a, B: SplitByteSlice> IntoIterator for &'a PerrDestinationListView<B> {
type Item = PerrDestinationView<&'a [u8]>;
type IntoIter = PerrDestinationIter<&'a [u8]>;
fn into_iter(self) -> Self::IntoIter {
PerrDestinationIter(BufferReader::new(&self.0[..]))
}
}
impl<B: SplitByteSlice> PerrDestinationListView<B> {
pub fn iter(&self) -> PerrDestinationIter<&[u8]> {
self.into_iter()
}
}
pub struct PerrDestinationIter<B>(BufferReader<B>);
impl<B: SplitByteSlice> Iterator for PerrDestinationIter<B> {
type Item = PerrDestinationView<B>;
fn next(&mut self) -> Option<Self::Item> {
let have_ext_addr = self.0.peek::<PerrDestinationHeader>()?.flags.addr_ext();
let dest_len = size_of::<PerrDestinationHeader>()
+ if have_ext_addr { size_of::<MacAddr>() } else { 0 }
+ size_of::<ReasonCode>();
if self.0.bytes_remaining() < dest_len {
None
} else {
let header = self.0.read().unwrap();
let ext_addr = if have_ext_addr { Some(self.0.read().unwrap()) } else { None };
let reason_code = self.0.read_unaligned().unwrap();
Some(PerrDestinationView { header, ext_addr, reason_code })
}
}
}
impl<B: SplitByteSlice> PerrDestinationIter<B> {
pub fn bytes_remaining(&self) -> usize {
self.0.bytes_remaining()
}
}
#[repr(C, packed)]
#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
pub struct ChannelSwitchAnnouncement {
pub mode: u8,
pub new_channel_number: u8,
pub channel_switch_count: u8,
}
#[repr(C, packed)]
#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
pub struct ExtendedChannelSwitchAnnouncement {
pub mode: u8,
pub new_operating_class: u8,
pub new_channel_number: u8,
pub channel_switch_count: u8,
}
#[repr(C, packed)]
#[derive(Clone, Copy, Debug, IntoBytes, KnownLayout, FromBytes, Immutable)]
pub struct WideBandwidthChannelSwitch {
pub new_width: VhtChannelBandwidth,
pub new_center_freq_seg0: u8,
pub new_center_freq_seg1: u8,
}
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct MaxTransmitPowerUnitInterpretation(pub u8);
impl MaxTransmitPowerUnitInterpretation {
pub const EIRP: Self = Self(0);
}
#[bitfield(
0..=2 max_transmit_power_count,
3..=5 max_transmit_power_unit_interpretation as MaxTransmitPowerUnitInterpretation(u8),
6..=7 _, )]
#[repr(C)]
#[derive(Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned)]
pub struct TransmitPowerInfo(pub u8);
#[repr(C)]
#[derive(
Clone, Copy, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Eq, PartialEq, Debug,
)]
pub struct TransmitPower(pub u8);
pub struct TransmitPowerEnvelopeView<B> {
pub transmit_power_info: Ref<B, TransmitPowerInfo>,
pub max_transmit_power_20: Ref<B, TransmitPower>,
pub max_transmit_power_40: Option<Ref<B, TransmitPower>>,
pub max_transmit_power_80: Option<Ref<B, TransmitPower>>,
pub max_transmit_power_160: Option<Ref<B, TransmitPower>>,
}
pub struct ChannelSwitchWrapperView<B> {
pub new_country: Option<CountryView<B>>,
pub wide_bandwidth_channel_switch: Option<Ref<B, WideBandwidthChannelSwitch>>,
pub new_transmit_power_envelope: Option<TransmitPowerEnvelopeView<B>>,
}
#[derive(Debug)]
pub enum VendorIe<B: SplitByteSlice> {
MsftLegacyWpa(B),
Wsc(B),
WmmInfo(B),
WmmParam(B),
Unknown { oui: Oui, body: B },
}
#[repr(C, packed)]
#[derive(
PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
)]
pub struct VhtCapabilities {
pub vht_cap_info: VhtCapabilitiesInfo, pub vht_mcs_nss: VhtMcsNssSet, }
impl From<banjo_ieee80211::VhtCapabilities> for VhtCapabilities {
fn from(cap: banjo_ieee80211::VhtCapabilities) -> Self {
const_assert_eq!(
std::mem::size_of::<VhtCapabilities>(),
banjo_ieee80211::VHT_CAP_LEN as usize,
);
VhtCapabilities::read_from_bytes(&cap.bytes[..]).unwrap()
}
}
impl From<VhtCapabilities> for banjo_ieee80211::VhtCapabilities {
fn from(cap: VhtCapabilities) -> Self {
let mut banjo_cap = Self { bytes: Default::default() };
banjo_cap.bytes.copy_from_slice(&cap.as_bytes()[..]);
banjo_cap
}
}
#[bitfield(
0..=1 max_mpdu_len as MaxMpduLen(u8),
2..=3 supported_cbw_set, 4 rx_ldpc,
5 sgi_cbw80, 6 sgi_cbw160, 7 tx_stbc,
8..=10 rx_stbc,
11 su_bfer, 12 su_bfee, 13..=15 bfee_sts, 16..=18 num_sounding, 19 mu_bfer, 20 mu_bfee, 21 txop_ps, 22 htc_vht,
23..=25 max_ampdu_exponent as MaxAmpduExponent(u8), 26..=27 link_adapt as VhtLinkAdaptation(u8), 28 rx_ant_pattern,
29 tx_ant_pattern,
30..=31 ext_nss_bw, )]
#[repr(C)]
#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
pub struct VhtCapabilitiesInfo(pub u32);
#[repr(C, packed)]
#[derive(
PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy,
)]
pub struct BssMaxIdlePeriod {
pub max_idle_period: u16,
pub idle_options: IdleOptions,
}
#[bitfield(
0 protected_keep_alive_required, 1..=7 _, )]
#[repr(C)]
#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
pub struct IdleOptions(pub u8);
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct MaxMpduLen(pub u8);
impl MaxMpduLen {
pub_const!(OCTECTS_3895, 0);
pub_const!(OCTECTS_7991, 1);
pub_const!(OCTECTS_11454, 2);
}
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct VhtLinkAdaptation(pub u8);
impl VhtLinkAdaptation {
pub_const!(NO_FEEDBACK, 0);
pub_const!(UNSOLICITED, 2);
pub_const!(BOTH, 3);
}
#[bitfield(
0..=15 rx_max_mcs as VhtMcsNssMap(u16),
16..=28 rx_max_data_rate, 29..=31 max_nsts,
32..=47 tx_max_mcs as VhtMcsNssMap(u16),
48..=60 tx_max_data_rate, 61 ext_nss_bw, 62..=63 _, )]
#[repr(C)]
#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
pub struct VhtMcsNssSet(pub u64);
#[bitfield(
0..=1 ss1 as VhtMcsSet(u8),
2..=3 ss2 as VhtMcsSet(u8),
4..=5 ss3 as VhtMcsSet(u8),
6..=7 ss4 as VhtMcsSet(u8),
8..=9 ss5 as VhtMcsSet(u8),
10..=11 ss6 as VhtMcsSet(u8),
12..=13 ss7 as VhtMcsSet(u8),
14..=15 ss8 as VhtMcsSet(u8),
)]
#[repr(C)]
#[derive(PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Clone, Copy)]
pub struct VhtMcsNssMap(pub u16);
impl VhtMcsNssMap {
const BIT_WIDTH: u8 = 2;
const MASK: u16 = (1 << Self::BIT_WIDTH) - 1;
pub fn ss(&self, num: u8) -> Result<VhtMcsSet, String> {
if num >= 1 && num <= 8 {
Ok(VhtMcsSet((self.0 >> ((num - 1) * Self::BIT_WIDTH) & Self::MASK) as u8))
} else {
Err(format!("spatial stream number must be between 1 and 8, {} invalid", num))
}
}
pub fn set_ss(&mut self, num: u8, val: VhtMcsSet) -> Result<(), String> {
if num == 0 || num > 8 {
Err(format!("spatial stream number must be between 1 and 8, {} invalid", num))
} else if val.0 > 3 {
Err(format!("bitfield is only 2 bit wide, {} invalid", val.0))
} else {
let offset = (num - 1) * Self::BIT_WIDTH;
let mask = Self::MASK << offset;
self.0 = (self.0 & (!mask)) | (((val.0 as u16) & Self::MASK) << offset);
Ok(())
}
}
}
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct VhtMcsSet(pub u8);
impl VhtMcsSet {
pub_const!(UP_TO_7, 0);
pub_const!(UP_TO_8, 1);
pub_const!(UP_TO_9, 2);
pub_const!(NONE, 3);
}
#[repr(C, packed)]
#[derive(
PartialEq, Eq, Hash, IntoBytes, KnownLayout, FromBytes, Immutable, Unaligned, Clone, Copy, Debug,
)]
pub struct VhtOperation {
pub vht_cbw: VhtChannelBandwidth, pub center_freq_seg0: u8, pub center_freq_seg1: u8, pub basic_mcs_nss: VhtMcsNssMap, }
impl From<VhtOperation> for fidl_ieee80211::VhtOperation {
fn from(op: VhtOperation) -> Self {
let mut banjo_op = Self { bytes: Default::default() };
banjo_op.bytes.copy_from_slice(&op.as_bytes()[..]);
banjo_op
}
}
#[repr(C)]
#[derive(
Debug,
PartialOrd,
PartialEq,
Eq,
Hash,
IntoBytes,
KnownLayout,
FromBytes,
Immutable,
Clone,
Copy,
)]
pub struct VhtChannelBandwidth(pub u8);
impl VhtChannelBandwidth {
pub_const!(CBW_20_40, 0);
pub_const!(CBW_80_160_80P80, 1);
pub_const!(CBW_160, 2); pub_const!(CBW_80P80, 3); }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ht_cap_mcs_set_conversion() {
let from = banjo_ieee80211::HtCapabilities {
bytes: [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11,
0x12, 0, 0x13, 0, 0, 0, 0x14, 0x15, ],
};
let ht_cap = Ref::<&[u8], HtCapabilities>::from_bytes(&from.bytes[..]).unwrap();
let mcs_set = ht_cap.mcs_set;
assert_eq!(
mcs_set.as_bytes(),
[3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12]
);
}
#[test]
fn perr_iter_empty() {
let empty: [u8; 0] = [];
let mut iter = PerrDestinationListView(&empty[..]).into_iter();
assert!(iter.next().is_none());
assert_eq!(0, iter.bytes_remaining());
}
#[test]
fn perr_iter_two_destinations() {
#[rustfmt::skip]
let data = [
0x40, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, 0x44, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x55, 0x66, 0, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, ];
let mut iter = PerrDestinationListView(&data[..]).into_iter();
assert!(iter.bytes_remaining() > 0);
{
let target = iter.next().expect("expected first target");
assert_eq!(0x44332211, { target.header.hwmp_seqno });
let ext_addr = target.ext_addr.expect("expected external addr");
assert_eq!(MacAddr::from([0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a]), *ext_addr);
assert_eq!(0x6655, target.reason_code.get().0);
}
assert!(iter.bytes_remaining() > 0);
{
let target = iter.next().expect("expected second target");
assert_eq!(0xaa998877, { target.header.hwmp_seqno });
assert!(target.ext_addr.is_none());
assert_eq!(0xccbb, target.reason_code.get().0);
}
assert_eq!(0, iter.bytes_remaining());
assert!(iter.next().is_none());
assert_eq!(0, iter.bytes_remaining());
}
#[test]
fn perr_iter_too_short_for_header() {
#[rustfmt::skip]
let data = [
0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, ];
let mut iter = PerrDestinationListView(&data[..]).into_iter();
assert_eq!(data.len(), iter.bytes_remaining());
assert!(iter.next().is_none());
assert_eq!(data.len(), iter.bytes_remaining());
}
#[test]
fn perr_iter_too_short_for_ext_addr() {
#[rustfmt::skip]
let data = [
0x40, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, 0x44, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, ];
let mut iter = PerrDestinationListView(&data[..]).into_iter();
assert_eq!(data.len(), iter.bytes_remaining());
assert!(iter.next().is_none());
assert_eq!(data.len(), iter.bytes_remaining());
}
#[test]
fn perr_iter_too_short_for_reason_code() {
#[rustfmt::skip]
let data = [
0x40, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x11, 0x22, 0x33, 0x44, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x55, ];
let mut iter = PerrDestinationListView(&data[..]).into_iter();
assert_eq!(data.len(), iter.bytes_remaining());
assert!(iter.next().is_none());
assert_eq!(data.len(), iter.bytes_remaining());
}
#[test]
fn vht_mcs_nss_map_accessor() {
let mut map = VhtMcsNssMap(0x00ff);
assert_eq!(map.ss(1), Ok(VhtMcsSet(3)));
assert_eq!(map.ss(5), Ok(VhtMcsSet(0)));
assert_eq!(map.set_ss(1, VhtMcsSet(2)), Ok(()));
assert_eq!(map.set_ss(8, VhtMcsSet(3)), Ok(()));
assert_eq!(map.ss(1), Ok(VhtMcsSet(2)));
assert_eq!(map.ss(8), Ok(VhtMcsSet(3)));
assert_eq!(map.0, 0xc0fe);
}
#[test]
fn vht_mcs_nss_map_accssor_error() {
let mut map = VhtMcsNssMap(0);
assert_eq!(
map.ss(0),
Err("spatial stream number must be between 1 and 8, 0 invalid".to_string())
);
assert_eq!(
map.ss(9),
Err("spatial stream number must be between 1 and 8, 9 invalid".to_string())
);
assert_eq!(
map.set_ss(0, VhtMcsSet(3)),
Err("spatial stream number must be between 1 and 8, 0 invalid".to_string())
);
assert_eq!(
map.set_ss(9, VhtMcsSet(3)),
Err("spatial stream number must be between 1 and 8, 9 invalid".to_string())
);
assert_eq!(
map.set_ss(1, VhtMcsSet(4)),
Err("bitfield is only 2 bit wide, 4 invalid".to_string())
);
}
#[test]
fn successfully_convert_ht_operation_to_fidl() {
let ht_op = crate::ie::fake_ies::fake_ht_operation();
let ddk: fidl_ieee80211::HtOperation = ht_op.into();
assert_eq!(ht_op.as_bytes(), ddk.bytes);
}
#[test]
fn successfully_convert_vht_operation_to_fidl() {
let vht_op = crate::ie::fake_ies::fake_vht_operation();
let ddk: fidl_ieee80211::VhtOperation = vht_op.into();
assert_eq!(vht_op.as_bytes(), ddk.bytes);
}
}