1use crate::channel::{Bandwidth, Channel};
6use crate::ie::fake_ies::{fake_owe_transition_ie, fake_wmm_param};
7use crate::ie::{self, IeType, write_rsnxe, write_wmm_param};
8use crate::mac;
9use crate::test_utils::fake_frames::{
10 fake_eap_rsne, fake_owe_rsne, fake_wpa1_ie, fake_wpa2_enterprise_rsne, fake_wpa2_rsne,
11 fake_wpa2_tkip_ccmp_rsne, fake_wpa2_tkip_only_rsne, fake_wpa2_wpa3_rsne,
12 fake_wpa3_enterprise_192_bit_rsne, fake_wpa3_rsne, fake_wpa3_transition_rsne,
13};
14use anyhow::Context;
15use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
16use fidl_fuchsia_wlan_sme as fidl_sme;
17use ieee80211::Ssid;
18use num_derive::FromPrimitive;
19use num_traits::FromPrimitive;
20use rand::distr::{Distribution, StandardUniform};
21use rand::{Rng, RngExt as _};
22
23#[rustfmt::skip]
24const DEFAULT_MOCK_IES: &'static [u8] = &[
25 0x03, 0x01, 0x8c,
27 0x05, 0x04, 0x00, 0x01, 0x00, 0x02,
29 0x07, 0x10, 0x55, 0x53, 0x20, 0x24, 0x04, 0x24, 0x34, 0x04, 0x1e, 0x64, 0x0c, 0x1e, 0x95, 0x05, 0x24, 0x00, 0x20, 0x01, 0x00,
38 0x23, 0x02, 0x09, 0x00,
40 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x16, 0x8c, 0x0d, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53 0x00, 0x7f, 0x08, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40,
56 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, 0xc0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
61 0xc3, 0x03, 0x01, 0x24, 0x24,
63 0xdd, 0x07, 0x00, 0x0b, 0x86, 0x01, 0x04, 0x08, 0x09,
65];
66
67pub struct BssDescriptionCreator {
68 pub bssid: [u8; 6],
70 pub bss_type: fidl_ieee80211::BssType,
71 pub beacon_period: u16,
72 pub channel: Channel,
73 pub rssi_dbm: i8,
74 pub snr_db: i8,
75
76 pub protection_cfg: FakeProtectionCfg,
78 pub ssid: Ssid,
79 pub rates: Vec<u8>,
80 pub wmm_param: Option<ie::WmmParam>,
81 pub sae_hash_to_element: bool,
82
83 pub cf_pollable: bool,
88 pub cf_poll_req: bool,
89 pub short_preamble: bool,
90 pub spectrum_mgmt: bool,
91 pub qos: bool,
92 pub short_slot_time: bool,
93 pub apsd: bool,
94 pub radio_measurement: bool,
95 pub delayed_block_ack: bool,
96 pub immediate_block_ack: bool,
97
98 pub ies_overrides: IesOverrides,
99}
100
101impl BssDescriptionCreator {
102 pub fn create_bss_description(self) -> Result<fidl_ieee80211::BssDescription, anyhow::Error> {
103 let mut ies_updater = ie::IesUpdater::new(DEFAULT_MOCK_IES.to_vec());
104 ies_updater.set(IeType::SSID, &self.ssid[..]).context("set SSID")?;
105
106 let rates_writer = ie::RatesWriter::try_new(&self.rates[..]).context("set rates")?;
107 let mut rates_buf = vec![];
108 rates_writer.write_supported_rates(&mut rates_buf);
109 ies_updater.set_raw(&rates_buf[..]).context("set rates")?;
110
111 let mut ext_rates_buf = vec![];
112 rates_writer.write_extended_supported_rates(&mut ext_rates_buf);
113 ies_updater.set_raw(&ext_rates_buf[..]).context("set extended rates")?;
114
115 if let Some(rsne) = derive_rsne(self.protection_cfg) {
116 ies_updater.set_raw(&rsne[..]).context("set RSNE")?;
117 }
118 if self.sae_hash_to_element {
119 let mut octet_1 = ie::RsnxeOctet1(0);
120 octet_1.set_sae_hash_to_element(true);
121 let mut rsnxe = vec![];
122 write_rsnxe(&mut rsnxe, octet_1).context("Failed to write RSNXE to IE buffer")?;
123 ies_updater.set_raw(&rsnxe[..]).context("set RSNXE")?;
124 }
125 if let Some(wpa1_vendor_ie) = derive_wpa1_vendor_ies(self.protection_cfg) {
126 ies_updater.set_raw(&wpa1_vendor_ie[..]).context("set WPA1 vendor IE")?;
127 }
128 if let Some(owe_transition_ie) = derive_owe_transition_ie(self.protection_cfg) {
129 ies_updater.set_raw(&owe_transition_ie[..]).context("set OWE Transition IE")?;
130 }
131
132 if let Some(wmm_param) = self.wmm_param {
133 let mut wmm_param_vendor_ie = vec![];
134 write_wmm_param(&mut wmm_param_vendor_ie, &wmm_param)
135 .context("failed to write WmmParam to vendor IE buffer")?;
136 ies_updater.set_raw(&wmm_param_vendor_ie[..]).context("set WMM parameter IE")?;
137 }
138
139 let capability_info = mac::CapabilityInfo(0)
140 .with_cf_pollable(self.cf_pollable)
141 .with_cf_poll_req(self.cf_poll_req)
142 .with_short_preamble(self.short_preamble)
143 .with_spectrum_mgmt(self.spectrum_mgmt)
144 .with_qos(self.qos)
145 .with_short_slot_time(self.short_slot_time)
146 .with_apsd(self.apsd)
147 .with_radio_measurement(self.radio_measurement)
148 .with_delayed_block_ack(self.delayed_block_ack)
149 .with_immediate_block_ack(self.immediate_block_ack);
150
151 let capability_info = match self.protection_cfg {
154 FakeProtectionCfg::Open | FakeProtectionCfg::OpenOweTransition => {
155 capability_info.with_privacy(false)
156 }
157 _ => capability_info.with_privacy(true),
158 };
159 let capability_info = match self.bss_type {
160 fidl_ieee80211::BssType::Infrastructure => {
161 capability_info.with_ess(true).with_ibss(false)
162 }
163 _ => panic!("{:?} is not supported", self.bss_type),
164 };
165 let capability_info = capability_info.0;
166
167 for ovr in self.ies_overrides.overrides {
168 match ovr {
169 IeOverride::Remove(ie_type) => ies_updater.remove(&ie_type),
170 IeOverride::Set(ie_type, bytes) => {
171 ies_updater
172 .set(ie_type, &bytes[..])
173 .with_context(|| format!("set IE type: {:?}", ie_type))?;
174 }
175 IeOverride::SetRaw(bytes) => {
176 ies_updater.set_raw(&bytes[..]).context("set raw IE")?;
177 }
178 }
179 }
180
181 let (bandwidth, secondary80_num) = self.channel.bandwidth.to_fidl();
182 let secondary80 =
183 fidl_ieee80211::ChannelNumber { band: self.channel.band, number: secondary80_num };
184 Ok(fidl_ieee80211::BssDescription {
185 bssid: self.bssid,
186 bss_type: self.bss_type,
187 beacon_period: self.beacon_period,
188 capability_info,
189 ies: ies_updater.finalize(),
190 primary: self.channel.into(),
191 bandwidth,
192 vht_secondary_80_channel: secondary80,
193 rssi_dbm: self.rssi_dbm,
194 snr_db: self.snr_db,
195 })
196 }
197}
198
199pub struct IesOverrides {
200 overrides: Vec<IeOverride>,
201}
202
203impl IesOverrides {
204 pub fn new() -> Self {
205 Self { overrides: vec![] }
206 }
207
208 pub fn remove(mut self, ie_type: IeType) -> Self {
209 self.overrides.push(IeOverride::Remove(ie_type));
210 self
211 }
212
213 pub fn set(mut self, ie_type: IeType, bytes: Vec<u8>) -> Self {
214 self.overrides.push(IeOverride::Set(ie_type, bytes));
215 self
216 }
217
218 pub fn set_raw(mut self, bytes: Vec<u8>) -> Self {
219 self.overrides.push(IeOverride::SetRaw(bytes));
220 self
221 }
222}
223
224enum IeOverride {
225 Remove(IeType),
226 Set(IeType, Vec<u8>),
227 SetRaw(Vec<u8>),
228}
229
230const LAST_FAKE_PROTECTION_CFG_VALUE: isize = 16;
231
232#[derive(Debug, FromPrimitive, Copy, Clone, PartialEq)]
233pub enum FakeProtectionCfg {
234 Open = 0,
235 Owe,
236 OpenOweTransition,
237 Wep,
238 Wpa1,
239 Wpa1Enhanced,
240 Wpa1Wpa2TkipOnly,
241 Wpa2TkipOnly,
242 Wpa1Wpa2,
243 Wpa2TkipCcmp,
244 Wpa2Enterprise,
245 Wpa2,
246 Wpa2Wpa3,
247 Wpa3Transition,
248 Wpa3,
249 Wpa3Enterprise,
250 Eap = LAST_FAKE_PROTECTION_CFG_VALUE,
251}
252
253impl Distribution<FakeProtectionCfg> for StandardUniform {
254 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> FakeProtectionCfg {
255 let r = rng.random_range(0..usize::try_from(LAST_FAKE_PROTECTION_CFG_VALUE + 1).unwrap());
257 FromPrimitive::from_usize(r)
258 .unwrap_or_else(|| panic!("Out of range random value for FakeProtectionCfg: {:?}", r))
259 }
260}
261
262impl From<fidl_sme::Protection> for FakeProtectionCfg {
263 fn from(protection: fidl_sme::Protection) -> Self {
264 match protection {
265 fidl_sme::Protection::Unknown => panic!("unknown protection"),
266 fidl_sme::Protection::Open => FakeProtectionCfg::Open,
267 fidl_sme::Protection::Owe => FakeProtectionCfg::Owe,
268 fidl_sme::Protection::OpenOweTransition => FakeProtectionCfg::OpenOweTransition,
269 fidl_sme::Protection::Wep => FakeProtectionCfg::Wep,
270 fidl_sme::Protection::Wpa1 => FakeProtectionCfg::Wpa1,
271 fidl_sme::Protection::Wpa1Wpa2PersonalTkipOnly => FakeProtectionCfg::Wpa1Wpa2TkipOnly,
272 fidl_sme::Protection::Wpa2PersonalTkipOnly => FakeProtectionCfg::Wpa2TkipOnly,
273 fidl_sme::Protection::Wpa1Wpa2Personal => FakeProtectionCfg::Wpa1Wpa2,
274 fidl_sme::Protection::Wpa2Personal => FakeProtectionCfg::Wpa2,
275 fidl_sme::Protection::Wpa2Wpa3Personal => FakeProtectionCfg::Wpa2Wpa3,
276 fidl_sme::Protection::Wpa3Personal => FakeProtectionCfg::Wpa3,
277 fidl_sme::Protection::Wpa2Enterprise => FakeProtectionCfg::Wpa2Enterprise,
278 fidl_sme::Protection::Wpa3Enterprise => FakeProtectionCfg::Wpa3Enterprise,
279 }
280 }
281}
282
283pub fn build_fake_bss_description_creator__(
284 protection_cfg: FakeProtectionCfg,
285) -> BssDescriptionCreator {
286 BssDescriptionCreator {
287 bssid: [0x07, 0x01, 0x02, 0x4d, 0x35, 0x08],
288 bss_type: fidl_ieee80211::BssType::Infrastructure,
289 beacon_period: 100,
290 channel: Channel::new(3, Bandwidth::Cbw40, fidl_ieee80211::WlanBand::TwoGhz),
291 rssi_dbm: 0,
292 snr_db: 0,
293
294 protection_cfg,
295 ssid: Ssid::try_from("fake-ssid").unwrap(),
296 rates: vec![0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c],
297 wmm_param: Some(fake_wmm_param()),
298 sae_hash_to_element: false,
299
300 cf_pollable: false,
301 cf_poll_req: false,
302 short_preamble: false,
303 spectrum_mgmt: false,
304 qos: false,
305 short_slot_time: false,
306 apsd: false,
307 radio_measurement: false,
308 delayed_block_ack: false,
309 immediate_block_ack: false,
310
311 ies_overrides: IesOverrides::new(),
312 }
313}
314
315fn random_ecw_min_max(rng: &mut rand::prelude::ThreadRng) -> ie::EcwMinMax {
316 let min = rng.random_range(0x0..0xf);
317 let max = rng.random_range(min..0xf);
318 ie::EcwMinMax((max << 4) | min)
319}
320
321pub fn build_random_bss_description_creator__(
322 protection_cfg: FakeProtectionCfg,
323) -> BssDescriptionCreator {
324 let bss_type = fidl_ieee80211::BssType::Infrastructure;
326
327 let mut rng = rand::rng();
328
329 let mut rates: Vec<u8> = vec![];
331 for _ in
332 0..rng.random_range(1..ie::SUPPORTED_RATES_MAX_LEN + ie::EXTENDED_SUPPORTED_RATES_MAX_LEN)
333 {
334 rates.push(rng.random());
335 }
336 let rates = rates; let mut giant_vendor_ies = vec![];
340 for _j in 0..8 {
341 giant_vendor_ies.extend_from_slice(&[221, 250]);
342 giant_vendor_ies.extend((0..250).map(|_| rng.random::<u8>()))
343 }
344 let ies_overrides = IesOverrides::new().set_raw(giant_vendor_ies);
345
346 let qos: bool = rng.random();
347 let apsd: bool = qos && rng.random(); BssDescriptionCreator {
350 bssid: (0..6).map(|_| rng.random::<u8>()).collect::<Vec<u8>>().try_into().unwrap(),
351 bss_type,
352 beacon_period: rng.random::<u16>(),
353 channel: {
355 let primary = rng.random_range(1..255);
356 let band = if primary <= 14 {
357 fidl_ieee80211::WlanBand::TwoGhz
358 } else {
359 fidl_ieee80211::WlanBand::FiveGhz
360 };
361 Channel::new(primary, Bandwidth::Cbw20, band)
362 },
363 rssi_dbm: rng.random::<i8>(),
364 snr_db: rng.random::<i8>(),
365
366 protection_cfg,
367 ssid: Ssid::from_bytes_unchecked(
368 (0..fidl_ieee80211::MAX_SSID_BYTE_LEN).map(|_| rng.random::<u8>()).collect::<Vec<u8>>(),
369 ),
370 rates,
371
372 wmm_param: if rng.random() {
376 Some(ie::WmmParam {
377 wmm_info: ie::WmmInfo(0).with_ap_wmm_info(
378 ie::ApWmmInfo(0)
379 .with_parameter_set_count(rng.random_range(0x00..0xf))
380 .with_uapsd(rng.random()),
381 ),
382 _reserved: rng.random(),
383 ac_be_params: ie::WmmAcParams {
384 aci_aifsn: ie::WmmAciAifsn(0).with_aifsn(rng.random_range(2..0xf)).with_aci(0),
385 ecw_min_max: random_ecw_min_max(&mut rng),
386 txop_limit: rng.random(),
387 },
388 ac_bk_params: ie::WmmAcParams {
389 aci_aifsn: ie::WmmAciAifsn(0).with_aifsn(rng.random_range(2..0xf)).with_aci(1),
390 ecw_min_max: random_ecw_min_max(&mut rng),
391 txop_limit: rng.random(),
392 },
393 ac_vi_params: ie::WmmAcParams {
394 aci_aifsn: ie::WmmAciAifsn(0).with_aifsn(rng.random_range(2..0xf)).with_aci(2),
395 ecw_min_max: random_ecw_min_max(&mut rng),
396 txop_limit: rng.random(),
397 },
398 ac_vo_params: ie::WmmAcParams {
399 aci_aifsn: ie::WmmAciAifsn(0).with_aifsn(rng.random_range(2..0xf)).with_aci(3),
400 ecw_min_max: random_ecw_min_max(&mut rng),
401 txop_limit: rng.random(),
402 },
403 })
404 } else {
405 None
406 },
407 sae_hash_to_element: rng.random(),
408
409 cf_pollable: rng.random(),
410 cf_poll_req: rng.random(),
411 short_preamble: rng.random(),
412 spectrum_mgmt: rng.random(),
413 qos,
414 short_slot_time: rng.random(),
415 apsd,
416 radio_measurement: rng.random(),
417 delayed_block_ack: rng.random(),
418 immediate_block_ack: rng.random(),
419
420 ies_overrides,
423 }
424}
425
426fn derive_rsne(protection_cfg: FakeProtectionCfg) -> Option<Vec<u8>> {
427 match protection_cfg {
428 FakeProtectionCfg::Wpa3Enterprise => Some(fake_wpa3_enterprise_192_bit_rsne()),
429 FakeProtectionCfg::Wpa2Enterprise => Some(fake_wpa2_enterprise_rsne()),
430 FakeProtectionCfg::Wpa3 => Some(fake_wpa3_rsne()),
431 FakeProtectionCfg::Wpa3Transition => Some(fake_wpa3_transition_rsne()),
432 FakeProtectionCfg::Wpa2Wpa3 => Some(fake_wpa2_wpa3_rsne()),
433 FakeProtectionCfg::Wpa2TkipCcmp => Some(fake_wpa2_tkip_ccmp_rsne()),
434 FakeProtectionCfg::Wpa1Wpa2TkipOnly | FakeProtectionCfg::Wpa2TkipOnly => {
435 Some(fake_wpa2_tkip_only_rsne())
436 }
437 FakeProtectionCfg::Wpa1Wpa2 | FakeProtectionCfg::Wpa2 => Some(fake_wpa2_rsne()),
438 FakeProtectionCfg::Eap => Some(fake_eap_rsne()),
439 FakeProtectionCfg::Owe => Some(fake_owe_rsne()),
440 _ => None,
441 }
442}
443
444fn derive_wpa1_vendor_ies(protection_cfg: FakeProtectionCfg) -> Option<Vec<u8>> {
445 match protection_cfg {
446 FakeProtectionCfg::Wpa1
447 | FakeProtectionCfg::Wpa1Wpa2TkipOnly
448 | FakeProtectionCfg::Wpa1Wpa2 => Some(fake_wpa1_ie(false)),
449 FakeProtectionCfg::Wpa1Enhanced => Some(fake_wpa1_ie(true)),
450 _ => None,
451 }
452}
453
454fn derive_owe_transition_ie(protection_cfg: FakeProtectionCfg) -> Option<Vec<u8>> {
455 match protection_cfg {
456 FakeProtectionCfg::OpenOweTransition => Some(fake_owe_transition_ie()),
457 _ => None,
458 }
459}
460
461#[macro_export]
462macro_rules! fake_fidl_bss_description__ {
463 ($build_fake_bss_description_creator__:path, $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)*) => {{
464 let bss_description_creator = $crate::test_utils::fake_stas::BssDescriptionCreator {
465 $(
466 $bss_key: $bss_value,
467 )*
468 ..$build_fake_bss_description_creator__($fake_protection_cfg.into())
469 };
470 bss_description_creator.create_bss_description().expect("expect creating BSS to succeed")
471 }};
472}
473
474#[macro_export]
475macro_rules! fake_fidl_bss_description {
476 ($protection_name:ident $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
477 $crate::fake_fidl_bss_description__!(
478 $crate::test_utils::fake_stas::build_fake_bss_description_creator__,
479 $crate::test_utils::fake_stas::FakeProtectionCfg::$protection_name
480 $(, $bss_key: $bss_value)*)
481 }};
482 (protection => $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
483 $crate::fake_fidl_bss_description__!(
484 $crate::test_utils::fake_stas::build_fake_bss_description_creator__,
485 $fake_protection_cfg
486 $(, $bss_key: $bss_value)*)
487 }};
488}
489
490#[macro_export]
491macro_rules! random_fidl_bss_description {
492 ($($bss_key:ident: $bss_value:expr),* $(,)?) => {{
493 use rand::RngExt as _;
494 let mut rng = rand::rng();
495 $crate::fake_fidl_bss_description__!(
496 $crate::test_utils::fake_stas::build_random_bss_description_creator__,
497 rng.random::<$crate::test_utils::fake_stas::FakeProtectionCfg>()
498 $(, $bss_key: $bss_value)*)
499 }};
500 ($protection_name:ident $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
501 $crate::fake_fidl_bss_description__!(
502 $crate::test_utils::fake_stas::build_random_bss_description_creator__,
503 $crate::test_utils::fake_stas::FakeProtectionCfg::$protection_name
504 $(, $bss_key: $bss_value)*)
505 }};
506 (protection => $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
507 $crate::fake_fidl_bss_description__!(
508 $crate::test_utils::fake_stas::build_random_bss_description_creator__,
509 $fake_protection_cfg
510 $(, $bss_key: $bss_value)*)
511 }};
512}
513
514#[macro_export]
515macro_rules! fake_bss_description__ {
516 ($fidl_bss_description_macro:ident, $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
517 let fidl_bss = $crate::$fidl_bss_description_macro!(protection => $fake_protection_cfg $(, $bss_key: $bss_value)*);
518 let bss_description: $crate::bss::BssDescription = std::convert::TryFrom::try_from(fidl_bss)
519 .expect("expect BSS conversion to succeed");
520 bss_description
521 }}
522}
523
524#[macro_export]
525macro_rules! fake_bss_description {
526 ($protection_name:ident $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
527 $crate::fake_bss_description__!(
528 fake_fidl_bss_description,
529 $crate::test_utils::fake_stas::FakeProtectionCfg::$protection_name $(, $bss_key: $bss_value)*)
530 }};
531 (protection => $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
532 $crate::fake_bss_description__!(
533 fake_fidl_bss_description,
534 $fake_protection_cfg $(, $bss_key: $bss_value)*)
535 }};
536}
537
538#[macro_export]
539macro_rules! random_bss_description {
540 ($($bss_key:ident: $bss_value:expr),* $(,)?) => {{
541 use rand::RngExt as _;
542 let mut rng = rand::rng();
543 $crate::fake_bss_description__!(
544 random_fidl_bss_description,
545 rng.random::<$crate::test_utils::fake_stas::FakeProtectionCfg>()
546 $(, $bss_key: $bss_value)*)
547 }};
548 ($protection_name:ident $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
549 $crate::fake_bss_description__!(
550 random_fidl_bss_description,
551 $crate::test_utils::fake_stas::FakeProtectionCfg::$protection_name $(, $bss_key: $bss_value)*)
552 }};
553 (protection => $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
554 $crate::fake_bss_description__!(
555 random_fidl_bss_description,
556 $fake_protection_cfg $(, $bss_key: $bss_value)*)
557 }};
558}
559
560#[cfg(test)]
561mod tests {
562 use super::*;
563 use crate::bss::{BssDescription, Protection};
564 use crate::mac::CapabilityInfo;
565 use crate::test_utils::fake_frames::{fake_wmm_param_body, fake_wmm_param_header};
566
567 #[test]
568 fn check_simplest_macro_use() {
569 let fidl_bss_description = fake_fidl_bss_description!(Open);
570 let bss_description = fake_bss_description!(Open);
571 assert_eq!(
572 BssDescription::try_from(fidl_bss_description)
573 .expect("Failed to convert fake_fidl_bss_description value"),
574 bss_description
575 );
576
577 for i in 1..=11 {
578 if i > 10 {
579 panic!("random_bss_description is always equal to bss_description");
580 }
581
582 let random_fidl_bss_description = random_fidl_bss_description!(Open);
583 let random_bss_description =
584 BssDescription::try_from(random_fidl_bss_description.clone())
585 .expect("Failed to convert random_fidl_bss_description value");
586 if random_bss_description != bss_description {
587 break;
588 }
589 }
590
591 for i in 1..=11 {
592 if i > 10 {
593 panic!("random_bss_description is always equal to other_random_bss_description");
594 }
595
596 let random_fidl_bss_description = random_fidl_bss_description!(Open);
597 let random_bss_description =
598 BssDescription::try_from(random_fidl_bss_description.clone())
599 .expect("Failed to convert random_fidl_bss_description value");
600 let other_random_bss_description = random_bss_description!(Open);
601 if random_bss_description != other_random_bss_description {
602 break;
603 }
604 }
605 }
606
607 #[test]
608 fn fake_protection_cfg_from_primitive() {
609 assert!(
610 0 <= LAST_FAKE_PROTECTION_CFG_VALUE,
611 "LAST_FAKE_PROTECTION_CFG_VALUE is not positive: {}",
612 LAST_FAKE_PROTECTION_CFG_VALUE,
613 );
614
615 let too_low: Option<FakeProtectionCfg> = FromPrimitive::from_isize(-1);
616 assert_eq!(
617 too_low, None::<FakeProtectionCfg>,
618 "Successfully converted low out of range FakeProtectionCfg value"
619 );
620
621 for i in 0..(LAST_FAKE_PROTECTION_CFG_VALUE + 1) {
622 let _: FakeProtectionCfg = FromPrimitive::from_isize(i).unwrap_or_else(|| {
623 panic!("Failed to convert {:?} to a FakeProtectionCfg value", i)
624 });
625 }
626
627 let too_high: Option<FakeProtectionCfg> =
628 FromPrimitive::from_isize(LAST_FAKE_PROTECTION_CFG_VALUE + 1);
629 assert_eq!(
630 too_high, None::<FakeProtectionCfg>,
631 "Successfully converted high out of range FakeProtectionCfg value"
632 );
633 }
634
635 #[test]
636 fn fake_protection_cfg_expr_syntax() {
637 let fidl_bss_description =
638 fake_fidl_bss_description!(protection => FakeProtectionCfg::Open);
639 assert_eq!(
640 BssDescription::try_from(fidl_bss_description)
641 .expect("Failed to convert fake_fidl_bss_description value")
642 .protection(),
643 Protection::Open
644 );
645
646 let fidl_bss_description =
647 random_fidl_bss_description!(protection => FakeProtectionCfg::Open);
648 assert_eq!(
649 BssDescription::try_from(fidl_bss_description)
650 .expect("Failed to convert random_fidl_bss_description value")
651 .protection(),
652 Protection::Open
653 );
654
655 let bss_description = fake_bss_description!(protection => FakeProtectionCfg::Open);
656 assert_eq!(bss_description.protection(), Protection::Open);
657
658 let bss_description = random_bss_description!(protection => FakeProtectionCfg::Open);
659 assert_eq!(bss_description.protection(), Protection::Open);
660 }
661
662 #[test]
663 fn fake_protection_cfg_privacy_bit_and_protection() {
664 let bss = fake_bss_description!(Open);
665 assert!(!mac::CapabilityInfo(bss.capability_info).privacy());
666 assert_eq!(bss.protection(), Protection::Open);
667
668 let bss = fake_bss_description!(Wep);
669 assert!(mac::CapabilityInfo(bss.capability_info).privacy());
670 assert_eq!(bss.protection(), Protection::Wep);
671
672 let bss = fake_bss_description!(Wpa1);
673 assert!(mac::CapabilityInfo(bss.capability_info).privacy());
674 assert_eq!(bss.protection(), Protection::Wpa1);
675
676 let bss = fake_bss_description!(Wpa2);
677 assert!(mac::CapabilityInfo(bss.capability_info).privacy());
678 assert_eq!(bss.protection(), Protection::Wpa2Personal);
679 }
680
681 #[test]
682 fn fake_protection_cfg_privacy_bit_and_protection_in_random_bss() {
683 let bss = random_bss_description!(Open);
684 assert!(!mac::CapabilityInfo(bss.capability_info).privacy());
685 assert_eq!(bss.protection(), Protection::Open);
686
687 let bss = random_bss_description!(Wep);
688 assert!(mac::CapabilityInfo(bss.capability_info).privacy());
689 assert_eq!(bss.protection(), Protection::Wep);
690
691 let bss = random_bss_description!(Wpa1);
692 assert!(mac::CapabilityInfo(bss.capability_info).privacy());
693 assert_eq!(bss.protection(), Protection::Wpa1);
694
695 let bss = random_bss_description!(Wpa2);
696 assert!(mac::CapabilityInfo(bss.capability_info).privacy());
697 assert_eq!(bss.protection(), Protection::Wpa2Personal);
698 }
699
700 #[test]
701 fn set_capability_info_bits() {
702 macro_rules! check_bit {
703 ($bit_name:ident) => {{
704 let bss = fake_bss_description!(Open, $bit_name: true);
705 assert!(mac::CapabilityInfo(bss.capability_info).$bit_name());
706 let bss = fake_bss_description!(Open, $bit_name: false);
707 assert!(!mac::CapabilityInfo(bss.capability_info).$bit_name());
708 }}
709 }
710 check_bit!(cf_pollable);
711 check_bit!(cf_poll_req);
712 check_bit!(short_preamble);
713 check_bit!(spectrum_mgmt);
714 check_bit!(qos);
715 check_bit!(short_slot_time);
716 check_bit!(apsd);
717 check_bit!(radio_measurement);
718 check_bit!(delayed_block_ack);
719 check_bit!(immediate_block_ack);
720
721 let bss =
722 fake_bss_description!(Open, cf_pollable: true, apsd: false, immediate_block_ack: true);
723 assert!(mac::CapabilityInfo(bss.capability_info).cf_pollable());
724 assert!(!mac::CapabilityInfo(bss.capability_info).apsd());
725 assert!(mac::CapabilityInfo(bss.capability_info).immediate_block_ack());
726 }
727
728 #[test]
729 fn simple_default_override() {
730 let bss = fake_fidl_bss_description!(Open);
731 assert_eq!(bss.beacon_period, 100);
732
733 let bss = fake_fidl_bss_description!(Open, beacon_period: 50);
734 assert_eq!(bss.beacon_period, 50);
735 }
736
737 #[test]
738 #[should_panic(expected = "Personal is not supported")]
739 #[cfg_attr(feature = "variant_asan", ignore)]
741 #[cfg_attr(feature = "variant_hwasan", ignore)]
742 fn unsupported_bss_type() {
743 fake_fidl_bss_description!(Open, bss_type: fidl_ieee80211::BssType::Personal);
744 }
745
746 #[test]
747 fn any_protection_syntax() {
748 let _ = random_fidl_bss_description!();
749 let _ = random_bss_description!();
750 }
751
752 #[test]
753 fn random_fidl_bss_decription_override() {
754 let random_bss = random_bss_description!(ssid: Ssid::try_from("foo").unwrap());
755 assert_eq!(random_bss.ssid, Ssid::try_from("foo").unwrap());
756 }
757
758 #[test]
759 fn valid_random_ecw_min_max() {
760 let mut rng = rand::rng();
761 for _ in 0..100 {
762 let ecw_min_max = random_ecw_min_max(&mut rng);
763 assert!(ecw_min_max.ecw_max() >= ecw_min_max.ecw_min());
764 }
765 }
766
767 #[test]
768 fn random_bss_is_not_constant() {
769 for _ in 0..10 {
770 let random_bss_1 = BssDescription::try_from(random_fidl_bss_description!())
771 .expect("Failed to convert random_bss_description value");
772 let random_bss_2 = BssDescription::try_from(random_fidl_bss_description!())
773 .expect("Failed to convert random_bss_description value");
774 if random_bss_1 != random_bss_2 {
775 return;
776 }
777 }
778 panic!("random bss is always the same");
779 }
780
781 #[test]
782 fn random_bss_protection_is_not_constant() {
783 for _ in 0..10 {
784 let random_bss_1 = BssDescription::try_from(random_fidl_bss_description!())
785 .expect("Failed to convert random_bss_description value");
786 let random_bss_2 = BssDescription::try_from(random_fidl_bss_description!())
787 .expect("Failed to convert random_bss_description value");
788 if random_bss_1.protection() != random_bss_2.protection() {
789 return;
790 }
791 }
792 panic!("random bss protection is always the same");
793 }
794
795 #[test]
796 fn some_random_bss_bits_are_fixed() {
797 for _ in 0..5 {
798 let random_bss = random_fidl_bss_description!(Open);
799 assert_eq!(random_bss.bss_type, fidl_ieee80211::BssType::Infrastructure);
800 assert!(mac::CapabilityInfo(random_bss.capability_info).ess());
801 assert!(!mac::CapabilityInfo(random_bss.capability_info).ibss());
802 assert!(!mac::CapabilityInfo(random_bss.capability_info).privacy());
803 }
804 }
805
806 #[test]
809 fn random_bss_decription_protection_randomness() {
810 for _ in 0..10 {
811 let random_bss_1 = random_bss_description!();
812 let random_bss_2 = random_bss_description!();
813 if random_bss_1.protection() != random_bss_2.protection() {
814 return;
815 }
816 }
817 panic!("random protection is always the same");
818 }
819
820 #[test]
821 fn ies_overrides() {
822 let bss = fake_bss_description!(Wpa1Wpa2,
823 ssid: Ssid::try_from("fuchsia").unwrap(),
824 rates: vec![11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
825 ies_overrides: IesOverrides::new()
826 .remove(IeType::new_vendor6([0x00, 0x0b, 0x86, 0x01, 0x04, 0x08]))
827 .set(IeType::DSSS_PARAM_SET, [136].to_vec()),
828 );
829
830 #[rustfmt::skip]
837 let mut expected_ies = vec![
838 0x00, 0x07, b'f', b'u', b'c', b'h', b's', b'i', b'a',
840 0x01, 0x08, 11, 12, 13, 14, 15, 16, 17, 18,
842 0x03, 0x01, 136,
844 0x05, 0x04, 0x00, 0x01, 0x00, 0x02,
846 0x07, 0x10, 0x55, 0x53, 0x20, 0x24, 0x04, 0x24, 0x34, 0x04, 0x1e, 0x64, 0x0c, 0x1e, 0x95, 0x05, 0x24, 0x00, 0x20, 0x01, 0x00,
855 0x23, 0x02, 0x09, 0x00,
857 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
861 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 18, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 2, 0x32, 0x06, 19, 20, 21, 22, 23, 24,
873 0x3d, 0x16, 0x8c, 0x0d, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
878 0x00, 0x00, 0x7f, 0x08, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40,
881 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, 0xc0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x03, 0x01, 0x24, 0x24,
887 0xdd, 0x16, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, ];
895 expected_ies.extend(fake_wmm_param_header());
896 expected_ies.extend(fake_wmm_param_body());
897
898 assert_eq!(bss.ies(), &expected_ies[..]);
899 }
900
901 #[test]
902 fn test_bss_open_owe_transition() {
903 let bss: BssDescription = fake_bss_description!(OpenOweTransition);
904 assert!(!CapabilityInfo(bss.capability_info).privacy());
905 let expected = fake_owe_transition_ie();
906 for i in 0..=(bss.ies().len() - expected.len()) {
907 if bss.ies()[i..i + expected.len()] == expected[..] {
908 return;
910 }
911 }
912 panic!("Expected OWE Transition IE not found; ies: {:x?}", bss.ies());
913 }
914}