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