blob: ffda4b83e9e6331c366c95a702905f1763a5d904 [file] [log] [blame]
// Copyright 2021 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.
use crate::channel::{Cbw, Channel};
use crate::ie::fake_ies::fake_wmm_param;
use crate::ie::{self, write_wmm_param, IeType};
use crate::mac;
use crate::test_utils::fake_frames::{
fake_eap_rsne, fake_wpa1_ie, fake_wpa2_enterprise_rsne, fake_wpa2_rsne,
fake_wpa2_tkip_ccmp_rsne, fake_wpa2_tkip_only_rsne, fake_wpa2_wpa3_rsne,
fake_wpa3_enterprise_192_bit_rsne, fake_wpa3_rsne, fake_wpa3_transition_rsne,
};
use anyhow::Context;
use ieee80211::Ssid;
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use rand::distributions::{Distribution, Standard};
use rand::Rng;
use {
fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211,
fidl_fuchsia_wlan_internal as fidl_internal, fidl_fuchsia_wlan_sme as fidl_sme,
};
#[rustfmt::skip]
const DEFAULT_MOCK_IES: &'static [u8] = &[
// DS parameter set: channel 140
0x03, 0x01, 0x8c,
// TIM - DTIM count: 0, DTIM period: 1, PVB: 2
0x05, 0x04, 0x00, 0x01, 0x00, 0x02,
// Country info
0x07, 0x10, 0x55, 0x53, 0x20, // US, Any environment
0x24, 0x04, 0x24, // 1st channel: 36, # channels: 4, maximum tx power: 36 dBm
0x34, 0x04, 0x1e, // 1st channel: 52, # channels: 4, maximum tx power: 30 dBm
0x64, 0x0c, 0x1e, // 1st channel: 100, # channels: 12, maximum tx power: 30 dBm
0x95, 0x05, 0x24, // 1st channel: 149, # channels: 5, maximum tx power: 36 dBm
0x00, // padding
// Power constraint: 0
0x20, 0x01, 0x00,
// TPC Report Transmit Power: 9, Link Margin: 0
0x23, 0x02, 0x09, 0x00,
// HT Capabilities
0x2d, 0x1a, 0xef, 0x09, // HT capabilities info
0x17, // A-MPDU parameters
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, // MCS set
0x00, 0x00, // HT extended capabilities
0x00, 0x00, 0x00, 0x00, // Transmit beamforming
0x00, // Antenna selection capabilities
// HT Operation
0x3d, 0x16, 0x8c, // Primary channel: 140
0x0d, // HT info subset - secondary channel above, any channel width, RIFS permitted
0x16, 0x00, 0x00, 0x00, // HT info subsets
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, // Basic MCS set
// Extended Capabilities: extended channel switching, BSS transition, operating mode notification
0x7f, 0x08, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40,
// VHT Capabilities
0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, // VHT capabilities info
0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, // VHT supported MCS set
// VHT Operation
0xc0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
// VHT Tx Power Envelope
0xc3, 0x03, 0x01, 0x24, 0x24,
// Aruba, Hewlett Packard vendor-specific IE
0xdd, 0x07, 0x00, 0x0b, 0x86, 0x01, 0x04, 0x08, 0x09,
];
pub struct BssDescriptionCreator {
// *** Fields already in fidl_internal::BssDescription
pub bssid: [u8; 6],
pub bss_type: fidl_common::BssType,
pub beacon_period: u16,
pub channel: Channel,
pub rssi_dbm: i8,
pub snr_db: i8,
// *** Custom arguments
pub protection_cfg: FakeProtectionCfg,
pub ssid: Ssid,
pub rates: Vec<u8>,
pub wmm_param: Option<ie::WmmParam>,
// *** Modifiable capability_info bits
// The privacy, ess, and ibss bits are reserved for the
// macro to set since they are implied by protection_cfg
// and bss_type.
pub cf_pollable: bool,
pub cf_poll_req: bool,
pub short_preamble: bool,
pub spectrum_mgmt: bool,
pub qos: bool,
pub short_slot_time: bool,
pub apsd: bool,
pub radio_measurement: bool,
pub delayed_block_ack: bool,
pub immediate_block_ack: bool,
pub ies_overrides: IesOverrides,
}
impl BssDescriptionCreator {
pub fn create_bss_description(self) -> Result<fidl_internal::BssDescription, anyhow::Error> {
let mut ies_updater = ie::IesUpdater::new(DEFAULT_MOCK_IES.to_vec());
ies_updater.set(IeType::SSID, &self.ssid[..]).context("set SSID")?;
let rates_writer = ie::RatesWriter::try_new(&self.rates[..]).context("set rates")?;
let mut rates_buf = vec![];
rates_writer.write_supported_rates(&mut rates_buf);
ies_updater.set_raw(&rates_buf[..]).context("set rates")?;
let mut ext_rates_buf = vec![];
rates_writer.write_extended_supported_rates(&mut ext_rates_buf);
ies_updater.set_raw(&ext_rates_buf[..]).context("set extended rates")?;
if let Some(rsne) = derive_rsne(self.protection_cfg) {
ies_updater.set_raw(&rsne[..]).context("set RSNE")?;
}
if let Some(wpa1_vendor_ie) = derive_wpa1_vendor_ies(self.protection_cfg) {
ies_updater.set_raw(&wpa1_vendor_ie[..]).context("set WPA1 vendor IE")?;
}
if let Some(wmm_param) = self.wmm_param {
let mut wmm_param_vendor_ie = vec![];
write_wmm_param(&mut wmm_param_vendor_ie, &wmm_param)
.context("failed to write WmmParam to vendor IE buffer")?;
ies_updater.set_raw(&wmm_param_vendor_ie[..]).context("set WMM parameter IE")?;
}
let capability_info = mac::CapabilityInfo(0)
.with_cf_pollable(self.cf_pollable)
.with_cf_poll_req(self.cf_poll_req)
.with_short_preamble(self.short_preamble)
.with_spectrum_mgmt(self.spectrum_mgmt)
.with_qos(self.qos)
.with_short_slot_time(self.short_slot_time)
.with_apsd(self.apsd)
.with_radio_measurement(self.radio_measurement)
.with_delayed_block_ack(self.delayed_block_ack)
.with_immediate_block_ack(self.immediate_block_ack);
// Some values of capability_info are not permitted to be set by
// the macro since otherwise the BssDescription will be trivially invalid.
let capability_info = match self.protection_cfg {
FakeProtectionCfg::Open => capability_info.with_privacy(false),
_ => capability_info.with_privacy(true),
};
let capability_info = match self.bss_type {
fidl_common::BssType::Infrastructure => capability_info.with_ess(true).with_ibss(false),
_ => panic!("{:?} is not supported", self.bss_type),
};
let capability_info = capability_info.0;
for ovr in self.ies_overrides.overrides {
match ovr {
IeOverride::Remove(ie_type) => ies_updater.remove(&ie_type),
IeOverride::Set(ie_type, bytes) => {
ies_updater
.set(ie_type, &bytes[..])
.with_context(|| format!("set IE type: {:?}", ie_type))?;
}
IeOverride::SetRaw(bytes) => {
ies_updater.set_raw(&bytes[..]).context("set raw IE")?;
}
}
}
Ok(fidl_internal::BssDescription {
bssid: self.bssid,
bss_type: self.bss_type,
beacon_period: self.beacon_period,
capability_info,
ies: ies_updater.finalize(),
channel: self.channel.into(),
rssi_dbm: self.rssi_dbm,
snr_db: self.snr_db,
})
}
}
pub struct IesOverrides {
overrides: Vec<IeOverride>,
}
impl IesOverrides {
pub fn new() -> Self {
Self { overrides: vec![] }
}
pub fn remove(mut self, ie_type: IeType) -> Self {
self.overrides.push(IeOverride::Remove(ie_type));
self
}
pub fn set(mut self, ie_type: IeType, bytes: Vec<u8>) -> Self {
self.overrides.push(IeOverride::Set(ie_type, bytes));
self
}
pub fn set_raw(mut self, bytes: Vec<u8>) -> Self {
self.overrides.push(IeOverride::SetRaw(bytes));
self
}
}
enum IeOverride {
Remove(IeType),
Set(IeType, Vec<u8>),
SetRaw(Vec<u8>),
}
const LAST_FAKE_PROTECTION_CFG_VALUE: isize = 14;
#[derive(Debug, FromPrimitive, Copy, Clone, PartialEq)]
pub enum FakeProtectionCfg {
Open = 0,
Wep,
Wpa1,
Wpa1Enhanced,
Wpa1Wpa2TkipOnly,
Wpa2TkipOnly,
Wpa1Wpa2,
Wpa2TkipCcmp,
Wpa2Enterprise,
Wpa2,
Wpa2Wpa3,
Wpa3Transition,
Wpa3,
Wpa3Enterprise,
Eap = LAST_FAKE_PROTECTION_CFG_VALUE,
}
impl Distribution<FakeProtectionCfg> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> FakeProtectionCfg {
let r = rng.gen_range(0..LAST_FAKE_PROTECTION_CFG_VALUE + 1);
FromPrimitive::from_isize(r)
.unwrap_or_else(|| panic!("Out of range random value for FakeProtectionCfg: {:?}", r))
}
}
impl From<fidl_sme::Protection> for FakeProtectionCfg {
fn from(protection: fidl_sme::Protection) -> Self {
match protection {
fidl_sme::Protection::Unknown => panic!("unknown protection"),
fidl_sme::Protection::Open => FakeProtectionCfg::Open,
fidl_sme::Protection::Wep => FakeProtectionCfg::Wep,
fidl_sme::Protection::Wpa1 => FakeProtectionCfg::Wpa1,
fidl_sme::Protection::Wpa1Wpa2PersonalTkipOnly => FakeProtectionCfg::Wpa1Wpa2TkipOnly,
fidl_sme::Protection::Wpa2PersonalTkipOnly => FakeProtectionCfg::Wpa2TkipOnly,
fidl_sme::Protection::Wpa1Wpa2Personal => FakeProtectionCfg::Wpa1Wpa2,
fidl_sme::Protection::Wpa2Personal => FakeProtectionCfg::Wpa2,
fidl_sme::Protection::Wpa2Wpa3Personal => FakeProtectionCfg::Wpa2Wpa3,
fidl_sme::Protection::Wpa3Personal => FakeProtectionCfg::Wpa3,
fidl_sme::Protection::Wpa2Enterprise => FakeProtectionCfg::Wpa2Enterprise,
fidl_sme::Protection::Wpa3Enterprise => FakeProtectionCfg::Wpa3Enterprise,
}
}
}
pub fn build_fake_bss_description_creator__(
protection_cfg: FakeProtectionCfg,
) -> BssDescriptionCreator {
BssDescriptionCreator {
bssid: [0x07, 0x01, 0x02, 0x4d, 0x35, 0x08],
bss_type: fidl_common::BssType::Infrastructure,
beacon_period: 100,
channel: Channel::new(3, Cbw::Cbw40),
rssi_dbm: 0,
snr_db: 0,
protection_cfg,
ssid: Ssid::try_from("fake-ssid").unwrap(),
rates: vec![0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c],
wmm_param: Some(fake_wmm_param()),
cf_pollable: false,
cf_poll_req: false,
short_preamble: false,
spectrum_mgmt: false,
qos: false,
short_slot_time: false,
apsd: false,
radio_measurement: false,
delayed_block_ack: false,
immediate_block_ack: false,
ies_overrides: IesOverrides::new(),
}
}
fn random_ecw_min_max(rng: &mut rand::prelude::ThreadRng) -> ie::EcwMinMax {
let min = rng.gen_range(0x0..0xf);
let max = rng.gen_range(min..0xf);
ie::EcwMinMax((max << 4) | min)
}
pub fn build_random_bss_description_creator__(
protection_cfg: FakeProtectionCfg,
) -> BssDescriptionCreator {
// Only the Infrastructure BSS type is supported.
let bss_type = fidl_common::BssType::Infrastructure;
let mut rng = rand::thread_rng();
// Random rates
let mut rates: Vec<u8> = vec![];
for _ in 0..rng.gen_range(1..ie::SUPPORTED_RATES_MAX_LEN + ie::EXTENDED_SUPPORTED_RATES_MAX_LEN)
{
rates.push(rng.gen());
}
let rates = rates; // shadow to make rates immutable
// Random IE bytes
let mut giant_vendor_ies = vec![];
for _j in 0..8 {
giant_vendor_ies.extend_from_slice(&[221, 250]);
giant_vendor_ies.extend((0..250).map(|_| rng.gen::<u8>()))
}
let ies_overrides = IesOverrides::new().set_raw(giant_vendor_ies);
let qos: bool = rng.gen();
let apsd: bool = qos && rng.gen(); // APSD is a QoS capability, so the AP must also be QoS capable
BssDescriptionCreator {
bssid: (0..6).map(|_| rng.gen::<u8>()).collect::<Vec<u8>>().try_into().unwrap(),
bss_type,
beacon_period: rng.gen::<u16>(),
// TODO(https://fxbug.dev/42162492): Purely random valid channel values is not implemented.
channel: Channel::new(rng.gen_range(1..255), Cbw::Cbw20),
rssi_dbm: rng.gen::<i8>(),
snr_db: rng.gen::<i8>(),
protection_cfg,
ssid: Ssid::from_bytes_unchecked(
(0..fidl_ieee80211::MAX_SSID_BYTE_LEN).map(|_| rng.gen::<u8>()).collect::<Vec<u8>>(),
),
rates,
// WMM is independent of 802.11 QoS, so the capabilities randomly indicated
// in wmm_param are not related to the QoS and APSD bits in the Capability Information
// field indicated. See WMM Specification, Section 1.3.
wmm_param: if rng.gen() {
Some(ie::WmmParam {
wmm_info: ie::WmmInfo(0).with_ap_wmm_info(
ie::ApWmmInfo(0)
.with_parameter_set_count(rng.gen_range(0x00..0xf))
.with_uapsd(rng.gen()),
),
_reserved: rng.gen(),
ac_be_params: ie::WmmAcParams {
aci_aifsn: ie::WmmAciAifsn(0).with_aifsn(rng.gen_range(2..0xf)).with_aci(0),
ecw_min_max: random_ecw_min_max(&mut rng),
txop_limit: rng.gen(),
},
ac_bk_params: ie::WmmAcParams {
aci_aifsn: ie::WmmAciAifsn(0).with_aifsn(rng.gen_range(2..0xf)).with_aci(1),
ecw_min_max: random_ecw_min_max(&mut rng),
txop_limit: rng.gen(),
},
ac_vi_params: ie::WmmAcParams {
aci_aifsn: ie::WmmAciAifsn(0).with_aifsn(rng.gen_range(2..0xf)).with_aci(2),
ecw_min_max: random_ecw_min_max(&mut rng),
txop_limit: rng.gen(),
},
ac_vo_params: ie::WmmAcParams {
aci_aifsn: ie::WmmAciAifsn(0).with_aifsn(rng.gen_range(2..0xf)).with_aci(3),
ecw_min_max: random_ecw_min_max(&mut rng),
txop_limit: rng.gen(),
},
})
} else {
None
},
cf_pollable: rng.gen(),
cf_poll_req: rng.gen(),
short_preamble: rng.gen(),
spectrum_mgmt: rng.gen(),
qos,
short_slot_time: rng.gen(),
apsd,
radio_measurement: rng.gen(),
delayed_block_ack: rng.gen(),
immediate_block_ack: rng.gen(),
// Generating completely random IEs would be chaotic at best, so we
// generate some random vendor ies instead.
ies_overrides,
}
}
fn derive_rsne(protection_cfg: FakeProtectionCfg) -> Option<Vec<u8>> {
match protection_cfg {
FakeProtectionCfg::Wpa3Enterprise => Some(fake_wpa3_enterprise_192_bit_rsne()),
FakeProtectionCfg::Wpa2Enterprise => Some(fake_wpa2_enterprise_rsne()),
FakeProtectionCfg::Wpa3 => Some(fake_wpa3_rsne()),
FakeProtectionCfg::Wpa3Transition => Some(fake_wpa3_transition_rsne()),
FakeProtectionCfg::Wpa2Wpa3 => Some(fake_wpa2_wpa3_rsne()),
FakeProtectionCfg::Wpa2TkipCcmp => Some(fake_wpa2_tkip_ccmp_rsne()),
FakeProtectionCfg::Wpa1Wpa2TkipOnly | FakeProtectionCfg::Wpa2TkipOnly => {
Some(fake_wpa2_tkip_only_rsne())
}
FakeProtectionCfg::Wpa1Wpa2 | FakeProtectionCfg::Wpa2 => Some(fake_wpa2_rsne()),
FakeProtectionCfg::Eap => Some(fake_eap_rsne()),
_ => None,
}
}
fn derive_wpa1_vendor_ies(protection_cfg: FakeProtectionCfg) -> Option<Vec<u8>> {
match protection_cfg {
FakeProtectionCfg::Wpa1
| FakeProtectionCfg::Wpa1Wpa2TkipOnly
| FakeProtectionCfg::Wpa1Wpa2 => Some(fake_wpa1_ie(false)),
FakeProtectionCfg::Wpa1Enhanced => Some(fake_wpa1_ie(true)),
_ => None,
}
}
#[macro_export]
macro_rules! fake_fidl_bss_description__ {
($build_fake_bss_description_creator__:path, $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)*) => {{
#[allow(unknown_lints, clippy::unnecessary_struct_initialization)]
let bss_description_creator = $crate::test_utils::fake_stas::BssDescriptionCreator {
$(
$bss_key: $bss_value,
)*
..$build_fake_bss_description_creator__($fake_protection_cfg.into())
};
bss_description_creator.create_bss_description().expect("expect creating BSS to succeed")
}};
}
#[macro_export]
macro_rules! fake_fidl_bss_description {
($protection_name:ident $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
$crate::fake_fidl_bss_description__!(
$crate::test_utils::fake_stas::build_fake_bss_description_creator__,
$crate::test_utils::fake_stas::FakeProtectionCfg::$protection_name
$(, $bss_key: $bss_value)*)
}};
(protection => $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
$crate::fake_fidl_bss_description__!(
$crate::test_utils::fake_stas::build_fake_bss_description_creator__,
$fake_protection_cfg
$(, $bss_key: $bss_value)*)
}};
}
#[macro_export]
macro_rules! random_fidl_bss_description {
($($bss_key:ident: $bss_value:expr),* $(,)?) => {{
let mut rng = rand::thread_rng();
$crate::fake_fidl_bss_description__!(
$crate::test_utils::fake_stas::build_random_bss_description_creator__,
rng.gen::<$crate::test_utils::fake_stas::FakeProtectionCfg>()
$(, $bss_key: $bss_value)*)
}};
($protection_name:ident $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
$crate::fake_fidl_bss_description__!(
$crate::test_utils::fake_stas::build_random_bss_description_creator__,
$crate::test_utils::fake_stas::FakeProtectionCfg::$protection_name
$(, $bss_key: $bss_value)*)
}};
(protection => $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
$crate::fake_fidl_bss_description__!(
$crate::test_utils::fake_stas::build_random_bss_description_creator__,
$fake_protection_cfg
$(, $bss_key: $bss_value)*)
}};
}
#[macro_export]
macro_rules! fake_bss_description__ {
($fidl_bss_description_macro:ident, $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
let fidl_bss = $crate::$fidl_bss_description_macro!(protection => $fake_protection_cfg $(, $bss_key: $bss_value)*);
let bss_description: $crate::bss::BssDescription = std::convert::TryFrom::try_from(fidl_bss)
.expect("expect BSS conversion to succeed");
bss_description
}}
}
#[macro_export]
macro_rules! fake_bss_description {
($protection_name:ident $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
$crate::fake_bss_description__!(
fake_fidl_bss_description,
$crate::test_utils::fake_stas::FakeProtectionCfg::$protection_name $(, $bss_key: $bss_value)*)
}};
(protection => $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
$crate::fake_bss_description__!(
fake_fidl_bss_description,
$fake_protection_cfg $(, $bss_key: $bss_value)*)
}};
}
#[macro_export]
macro_rules! random_bss_description {
($($bss_key:ident: $bss_value:expr),* $(,)?) => {{
let mut rng = rand::thread_rng();
$crate::fake_bss_description__!(
random_fidl_bss_description,
rng.gen::<$crate::test_utils::fake_stas::FakeProtectionCfg>()
$(, $bss_key: $bss_value)*)
}};
($protection_name:ident $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
$crate::fake_bss_description__!(
random_fidl_bss_description,
$crate::test_utils::fake_stas::FakeProtectionCfg::$protection_name $(, $bss_key: $bss_value)*)
}};
(protection => $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
$crate::fake_bss_description__!(
random_fidl_bss_description,
$fake_protection_cfg $(, $bss_key: $bss_value)*)
}};
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bss::{BssDescription, Protection};
use crate::test_utils::fake_frames::{fake_wmm_param_body, fake_wmm_param_header};
#[test]
fn check_simplest_macro_use() {
let fidl_bss_description = fake_fidl_bss_description!(Open);
let bss_description = fake_bss_description!(Open);
assert_eq!(
BssDescription::try_from(fidl_bss_description)
.expect("Failed to convert fake_fidl_bss_description value"),
bss_description
);
for i in 1..=11 {
if i > 10 {
panic!("random_bss_description is always equal to bss_description");
}
let random_fidl_bss_description = random_fidl_bss_description!(Open);
let random_bss_description =
BssDescription::try_from(random_fidl_bss_description.clone())
.expect("Failed to convert random_fidl_bss_description value");
if random_bss_description != bss_description {
break;
}
}
for i in 1..=11 {
if i > 10 {
panic!("random_bss_description is always equal to other_random_bss_description");
}
let random_fidl_bss_description = random_fidl_bss_description!(Open);
let random_bss_description =
BssDescription::try_from(random_fidl_bss_description.clone())
.expect("Failed to convert random_fidl_bss_description value");
let other_random_bss_description = random_bss_description!(Open);
if random_bss_description != other_random_bss_description {
break;
}
}
}
#[test]
fn fake_protection_cfg_from_primitive() {
assert!(
0 <= LAST_FAKE_PROTECTION_CFG_VALUE,
"LAST_FAKE_PROTECTION_CFG_VALUE is not positive: {}",
LAST_FAKE_PROTECTION_CFG_VALUE,
);
let too_low: Option<FakeProtectionCfg> = FromPrimitive::from_isize(-1);
assert_eq!(
too_low, None::<FakeProtectionCfg>,
"Successfully converted low out of range FakeProtectionCfg value"
);
for i in 0..(LAST_FAKE_PROTECTION_CFG_VALUE + 1) {
let _: FakeProtectionCfg = FromPrimitive::from_isize(i).unwrap_or_else(|| {
panic!("Failed to convert {:?} to a FakeProtectionCfg value", i)
});
}
let too_high: Option<FakeProtectionCfg> =
FromPrimitive::from_isize(LAST_FAKE_PROTECTION_CFG_VALUE + 1);
assert_eq!(
too_high, None::<FakeProtectionCfg>,
"Successfully converted high out of range FakeProtectionCfg value"
);
}
#[test]
fn fake_protection_cfg_expr_syntax() {
let fidl_bss_description =
fake_fidl_bss_description!(protection => FakeProtectionCfg::Open);
assert_eq!(
BssDescription::try_from(fidl_bss_description)
.expect("Failed to convert fake_fidl_bss_description value")
.protection(),
Protection::Open
);
let fidl_bss_description =
random_fidl_bss_description!(protection => FakeProtectionCfg::Open);
assert_eq!(
BssDescription::try_from(fidl_bss_description)
.expect("Failed to convert random_fidl_bss_description value")
.protection(),
Protection::Open
);
let bss_description = fake_bss_description!(protection => FakeProtectionCfg::Open);
assert_eq!(bss_description.protection(), Protection::Open);
let bss_description = random_bss_description!(protection => FakeProtectionCfg::Open);
assert_eq!(bss_description.protection(), Protection::Open);
}
#[test]
fn fake_protection_cfg_privacy_bit_and_protection() {
let bss = fake_bss_description!(Open);
assert!(!mac::CapabilityInfo(bss.capability_info).privacy());
assert_eq!(bss.protection(), Protection::Open);
let bss = fake_bss_description!(Wep);
assert!(mac::CapabilityInfo(bss.capability_info).privacy());
assert_eq!(bss.protection(), Protection::Wep);
let bss = fake_bss_description!(Wpa1);
assert!(mac::CapabilityInfo(bss.capability_info).privacy());
assert_eq!(bss.protection(), Protection::Wpa1);
let bss = fake_bss_description!(Wpa2);
assert!(mac::CapabilityInfo(bss.capability_info).privacy());
assert_eq!(bss.protection(), Protection::Wpa2Personal);
}
#[test]
fn fake_protection_cfg_privacy_bit_and_protection_in_random_bss() {
let bss = random_bss_description!(Open);
assert!(!mac::CapabilityInfo(bss.capability_info).privacy());
assert_eq!(bss.protection(), Protection::Open);
let bss = random_bss_description!(Wep);
assert!(mac::CapabilityInfo(bss.capability_info).privacy());
assert_eq!(bss.protection(), Protection::Wep);
let bss = random_bss_description!(Wpa1);
assert!(mac::CapabilityInfo(bss.capability_info).privacy());
assert_eq!(bss.protection(), Protection::Wpa1);
let bss = random_bss_description!(Wpa2);
assert!(mac::CapabilityInfo(bss.capability_info).privacy());
assert_eq!(bss.protection(), Protection::Wpa2Personal);
}
#[test]
fn set_capability_info_bits() {
macro_rules! check_bit {
($bit_name:ident) => {{
let bss = fake_bss_description!(Open, $bit_name: true);
assert!(mac::CapabilityInfo(bss.capability_info).$bit_name());
let bss = fake_bss_description!(Open, $bit_name: false);
assert!(!mac::CapabilityInfo(bss.capability_info).$bit_name());
}}
}
check_bit!(cf_pollable);
check_bit!(cf_poll_req);
check_bit!(short_preamble);
check_bit!(spectrum_mgmt);
check_bit!(qos);
check_bit!(short_slot_time);
check_bit!(apsd);
check_bit!(radio_measurement);
check_bit!(delayed_block_ack);
check_bit!(immediate_block_ack);
let bss =
fake_bss_description!(Open, cf_pollable: true, apsd: false, immediate_block_ack: true);
assert!(mac::CapabilityInfo(bss.capability_info).cf_pollable());
assert!(!mac::CapabilityInfo(bss.capability_info).apsd());
assert!(mac::CapabilityInfo(bss.capability_info).immediate_block_ack());
}
#[test]
fn simple_default_override() {
let bss = fake_fidl_bss_description!(Open);
assert_eq!(bss.beacon_period, 100);
let bss = fake_fidl_bss_description!(Open, beacon_period: 50);
assert_eq!(bss.beacon_period, 50);
}
#[test]
#[should_panic(expected = "Personal is not supported")]
// TODO(https://fxbug.dev/42169733): LeakSanitizer flags leaks caused by panic.
#[cfg_attr(feature = "variant_asan", ignore)]
fn unsupported_bss_type() {
fake_fidl_bss_description!(Open, bss_type: fidl_common::BssType::Personal);
}
#[test]
fn any_protection_syntax() {
let _ = random_fidl_bss_description!();
let _ = random_bss_description!();
}
#[test]
fn random_fidl_bss_decription_override() {
let random_bss = random_bss_description!(ssid: Ssid::try_from("foo").unwrap());
assert_eq!(random_bss.ssid, Ssid::try_from("foo").unwrap());
}
#[test]
fn valid_random_ecw_min_max() {
let mut rng = rand::thread_rng();
for _ in 0..100 {
let ecw_min_max = random_ecw_min_max(&mut rng);
assert!(ecw_min_max.ecw_max() >= ecw_min_max.ecw_min());
}
}
#[test]
fn random_bss_is_not_constant() {
for _ in 0..10 {
let random_bss_1 = BssDescription::try_from(random_fidl_bss_description!())
.expect("Failed to convert random_bss_description value");
let random_bss_2 = BssDescription::try_from(random_fidl_bss_description!())
.expect("Failed to convert random_bss_description value");
if random_bss_1 != random_bss_2 {
return;
}
}
panic!("random bss is always the same");
}
#[test]
fn random_bss_protection_is_not_constant() {
for _ in 0..10 {
let random_bss_1 = BssDescription::try_from(random_fidl_bss_description!())
.expect("Failed to convert random_bss_description value");
let random_bss_2 = BssDescription::try_from(random_fidl_bss_description!())
.expect("Failed to convert random_bss_description value");
if random_bss_1.protection() != random_bss_2.protection() {
return;
}
}
panic!("random bss protection is always the same");
}
#[test]
fn some_random_bss_bits_are_fixed() {
for _ in 0..5 {
let random_bss = random_fidl_bss_description!(Open);
assert_eq!(random_bss.bss_type, fidl_common::BssType::Infrastructure);
assert!(mac::CapabilityInfo(random_bss.capability_info).ess());
assert!(!mac::CapabilityInfo(random_bss.capability_info).ibss());
assert!(!mac::CapabilityInfo(random_bss.capability_info).privacy());
}
}
// Test random_bss_description generation of random protection since
// it doesn't rely on random_fidl_bss_description for it.
#[test]
fn random_bss_decription_protection_randomness() {
for _ in 0..10 {
let random_bss_1 = random_bss_description!();
let random_bss_2 = random_bss_description!();
if random_bss_1.protection() != random_bss_2.protection() {
return;
}
}
panic!("random protection is always the same");
}
#[test]
fn ies_overrides() {
let bss = fake_bss_description!(Wpa1Wpa2,
ssid: Ssid::try_from("fuchsia").unwrap(),
rates: vec![11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
ies_overrides: IesOverrides::new()
.remove(IeType::new_vendor([0x00, 0x0b, 0x86, 0x01, 0x04, 0x08]))
.set(IeType::DSSS_PARAM_SET, [136].to_vec()),
);
// Things to note:
// - SSID "fuchsia" is inserted.
// - Rates and extended supported rates are inserted.
// - WPA2 RSNE and WPA1 vendor IE are inserted.
// - DSSS Param set's value is changed.
// - Aruba vendor IE no longer there.
#[rustfmt::skip]
let mut expected_ies = vec![
// SSID
0x00, 0x07, b'f', b'u', b'c', b'h', b's', b'i', b'a',
// Rates
0x01, 0x08, 11, 12, 13, 14, 15, 16, 17, 18,
// DS parameter set: channel 136
0x03, 0x01, 136,
// TIM - DTIM count: 0, DTIM period: 1, PVB: 2
0x05, 0x04, 0x00, 0x01, 0x00, 0x02,
// Country info
0x07, 0x10, 0x55, 0x53, 0x20, // US, Any environment
0x24, 0x04, 0x24, // 1st channel: 36, # channels: 4, maximum tx power: 36 dBm
0x34, 0x04, 0x1e, // 1st channel: 52, # channels: 4, maximum tx power: 30 dBm
0x64, 0x0c, 0x1e, // 1st channel: 100, # channels: 12, maximum tx power: 30 dBm
0x95, 0x05, 0x24, // 1st channel: 149, # channels: 5, maximum tx power: 36 dBm
0x00, // padding
// Power constraint: 0
0x20, 0x01, 0x00,
// TPC Report Transmit Power: 9, Link Margin: 0
0x23, 0x02, 0x09, 0x00,
// HT Capabilities
0x2d, 0x1a, 0xef, 0x09, // HT capabilities info
0x17, // A-MPDU parameters
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, // MCS set
0x00, 0x00, // HT extended capabilities
0x00, 0x00, 0x00, 0x00, // Transmit beamforming
0x00, // Antenna selection capabilities
// RSNE
0x30, 18, // Element header
1, 0, // Version
0x00, 0x0F, 0xAC, 4, // Group Cipher: CCMP-128
1, 0, 0x00, 0x0F, 0xAC, 4, // 1 Pairwise Cipher: CCMP-128
1, 0, 0x00, 0x0F, 0xAC, 2, // 1 AKM: PSK
// Extended supported rates
0x32, 0x06, 19, 20, 21, 22, 23, 24,
// HT Operation
0x3d, 0x16, 0x8c, // Primary channel: 140
0x0d, // HT info subset - secondary channel above, any channel width, RIFS permitted
0x16, 0x00, 0x00, 0x00, // HT info subsets
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, // Basic MCS set
// Extended Capabilities: extended channel switching, BSS transition, operating mode notification
0x7f, 0x08, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40,
// VHT Capabilities
0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, // VHT capabilities info
0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, // VHT supported MCS set
// VHT Operation
0xc0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, // VHT Tx Power Envelope
0xc3, 0x03, 0x01, 0x24, 0x24,
// WPA1 vendor IE
0xdd, 0x16, 0x00, 0x50, 0xf2, // IE header
0x01, // MSFT specific IE type (WPA)
0x01, 0x00, // WPA version
0x00, 0x50, 0xf2, 0x02, // multicast cipher: TKIP
0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 unicast cipher
0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 AKM: PSK
];
expected_ies.extend(fake_wmm_param_header());
expected_ies.extend(fake_wmm_param_body());
assert_eq!(bss.ies(), &expected_ies[..]);
}
}