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 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::Rng;
21use rand::distr::{Distribution, StandardUniform};
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.cbw.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, Cbw::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, Cbw::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 let mut rng = rand::rng();
494 $crate::fake_fidl_bss_description__!(
495 $crate::test_utils::fake_stas::build_random_bss_description_creator__,
496 rng.random::<$crate::test_utils::fake_stas::FakeProtectionCfg>()
497 $(, $bss_key: $bss_value)*)
498 }};
499 ($protection_name:ident $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
500 $crate::fake_fidl_bss_description__!(
501 $crate::test_utils::fake_stas::build_random_bss_description_creator__,
502 $crate::test_utils::fake_stas::FakeProtectionCfg::$protection_name
503 $(, $bss_key: $bss_value)*)
504 }};
505 (protection => $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
506 $crate::fake_fidl_bss_description__!(
507 $crate::test_utils::fake_stas::build_random_bss_description_creator__,
508 $fake_protection_cfg
509 $(, $bss_key: $bss_value)*)
510 }};
511}
512
513#[macro_export]
514macro_rules! fake_bss_description__ {
515 ($fidl_bss_description_macro:ident, $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
516 let fidl_bss = $crate::$fidl_bss_description_macro!(protection => $fake_protection_cfg $(, $bss_key: $bss_value)*);
517 let bss_description: $crate::bss::BssDescription = std::convert::TryFrom::try_from(fidl_bss)
518 .expect("expect BSS conversion to succeed");
519 bss_description
520 }}
521}
522
523#[macro_export]
524macro_rules! fake_bss_description {
525 ($protection_name:ident $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
526 $crate::fake_bss_description__!(
527 fake_fidl_bss_description,
528 $crate::test_utils::fake_stas::FakeProtectionCfg::$protection_name $(, $bss_key: $bss_value)*)
529 }};
530 (protection => $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
531 $crate::fake_bss_description__!(
532 fake_fidl_bss_description,
533 $fake_protection_cfg $(, $bss_key: $bss_value)*)
534 }};
535}
536
537#[macro_export]
538macro_rules! random_bss_description {
539 ($($bss_key:ident: $bss_value:expr),* $(,)?) => {{
540 let mut rng = rand::rng();
541 $crate::fake_bss_description__!(
542 random_fidl_bss_description,
543 rng.random::<$crate::test_utils::fake_stas::FakeProtectionCfg>()
544 $(, $bss_key: $bss_value)*)
545 }};
546 ($protection_name:ident $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
547 $crate::fake_bss_description__!(
548 random_fidl_bss_description,
549 $crate::test_utils::fake_stas::FakeProtectionCfg::$protection_name $(, $bss_key: $bss_value)*)
550 }};
551 (protection => $fake_protection_cfg:expr $(, $bss_key:ident: $bss_value:expr)* $(,)?) => {{
552 $crate::fake_bss_description__!(
553 random_fidl_bss_description,
554 $fake_protection_cfg $(, $bss_key: $bss_value)*)
555 }};
556}
557
558#[cfg(test)]
559mod tests {
560 use super::*;
561 use crate::bss::{BssDescription, Protection};
562 use crate::mac::CapabilityInfo;
563 use crate::test_utils::fake_frames::{fake_wmm_param_body, fake_wmm_param_header};
564
565 #[test]
566 fn check_simplest_macro_use() {
567 let fidl_bss_description = fake_fidl_bss_description!(Open);
568 let bss_description = fake_bss_description!(Open);
569 assert_eq!(
570 BssDescription::try_from(fidl_bss_description)
571 .expect("Failed to convert fake_fidl_bss_description value"),
572 bss_description
573 );
574
575 for i in 1..=11 {
576 if i > 10 {
577 panic!("random_bss_description is always equal to bss_description");
578 }
579
580 let random_fidl_bss_description = random_fidl_bss_description!(Open);
581 let random_bss_description =
582 BssDescription::try_from(random_fidl_bss_description.clone())
583 .expect("Failed to convert random_fidl_bss_description value");
584 if random_bss_description != bss_description {
585 break;
586 }
587 }
588
589 for i in 1..=11 {
590 if i > 10 {
591 panic!("random_bss_description is always equal to other_random_bss_description");
592 }
593
594 let random_fidl_bss_description = random_fidl_bss_description!(Open);
595 let random_bss_description =
596 BssDescription::try_from(random_fidl_bss_description.clone())
597 .expect("Failed to convert random_fidl_bss_description value");
598 let other_random_bss_description = random_bss_description!(Open);
599 if random_bss_description != other_random_bss_description {
600 break;
601 }
602 }
603 }
604
605 #[test]
606 fn fake_protection_cfg_from_primitive() {
607 assert!(
608 0 <= LAST_FAKE_PROTECTION_CFG_VALUE,
609 "LAST_FAKE_PROTECTION_CFG_VALUE is not positive: {}",
610 LAST_FAKE_PROTECTION_CFG_VALUE,
611 );
612
613 let too_low: Option<FakeProtectionCfg> = FromPrimitive::from_isize(-1);
614 assert_eq!(
615 too_low, None::<FakeProtectionCfg>,
616 "Successfully converted low out of range FakeProtectionCfg value"
617 );
618
619 for i in 0..(LAST_FAKE_PROTECTION_CFG_VALUE + 1) {
620 let _: FakeProtectionCfg = FromPrimitive::from_isize(i).unwrap_or_else(|| {
621 panic!("Failed to convert {:?} to a FakeProtectionCfg value", i)
622 });
623 }
624
625 let too_high: Option<FakeProtectionCfg> =
626 FromPrimitive::from_isize(LAST_FAKE_PROTECTION_CFG_VALUE + 1);
627 assert_eq!(
628 too_high, None::<FakeProtectionCfg>,
629 "Successfully converted high out of range FakeProtectionCfg value"
630 );
631 }
632
633 #[test]
634 fn fake_protection_cfg_expr_syntax() {
635 let fidl_bss_description =
636 fake_fidl_bss_description!(protection => FakeProtectionCfg::Open);
637 assert_eq!(
638 BssDescription::try_from(fidl_bss_description)
639 .expect("Failed to convert fake_fidl_bss_description value")
640 .protection(),
641 Protection::Open
642 );
643
644 let fidl_bss_description =
645 random_fidl_bss_description!(protection => FakeProtectionCfg::Open);
646 assert_eq!(
647 BssDescription::try_from(fidl_bss_description)
648 .expect("Failed to convert random_fidl_bss_description value")
649 .protection(),
650 Protection::Open
651 );
652
653 let bss_description = fake_bss_description!(protection => FakeProtectionCfg::Open);
654 assert_eq!(bss_description.protection(), Protection::Open);
655
656 let bss_description = random_bss_description!(protection => FakeProtectionCfg::Open);
657 assert_eq!(bss_description.protection(), Protection::Open);
658 }
659
660 #[test]
661 fn fake_protection_cfg_privacy_bit_and_protection() {
662 let bss = fake_bss_description!(Open);
663 assert!(!mac::CapabilityInfo(bss.capability_info).privacy());
664 assert_eq!(bss.protection(), Protection::Open);
665
666 let bss = fake_bss_description!(Wep);
667 assert!(mac::CapabilityInfo(bss.capability_info).privacy());
668 assert_eq!(bss.protection(), Protection::Wep);
669
670 let bss = fake_bss_description!(Wpa1);
671 assert!(mac::CapabilityInfo(bss.capability_info).privacy());
672 assert_eq!(bss.protection(), Protection::Wpa1);
673
674 let bss = fake_bss_description!(Wpa2);
675 assert!(mac::CapabilityInfo(bss.capability_info).privacy());
676 assert_eq!(bss.protection(), Protection::Wpa2Personal);
677 }
678
679 #[test]
680 fn fake_protection_cfg_privacy_bit_and_protection_in_random_bss() {
681 let bss = random_bss_description!(Open);
682 assert!(!mac::CapabilityInfo(bss.capability_info).privacy());
683 assert_eq!(bss.protection(), Protection::Open);
684
685 let bss = random_bss_description!(Wep);
686 assert!(mac::CapabilityInfo(bss.capability_info).privacy());
687 assert_eq!(bss.protection(), Protection::Wep);
688
689 let bss = random_bss_description!(Wpa1);
690 assert!(mac::CapabilityInfo(bss.capability_info).privacy());
691 assert_eq!(bss.protection(), Protection::Wpa1);
692
693 let bss = random_bss_description!(Wpa2);
694 assert!(mac::CapabilityInfo(bss.capability_info).privacy());
695 assert_eq!(bss.protection(), Protection::Wpa2Personal);
696 }
697
698 #[test]
699 fn set_capability_info_bits() {
700 macro_rules! check_bit {
701 ($bit_name:ident) => {{
702 let bss = fake_bss_description!(Open, $bit_name: true);
703 assert!(mac::CapabilityInfo(bss.capability_info).$bit_name());
704 let bss = fake_bss_description!(Open, $bit_name: false);
705 assert!(!mac::CapabilityInfo(bss.capability_info).$bit_name());
706 }}
707 }
708 check_bit!(cf_pollable);
709 check_bit!(cf_poll_req);
710 check_bit!(short_preamble);
711 check_bit!(spectrum_mgmt);
712 check_bit!(qos);
713 check_bit!(short_slot_time);
714 check_bit!(apsd);
715 check_bit!(radio_measurement);
716 check_bit!(delayed_block_ack);
717 check_bit!(immediate_block_ack);
718
719 let bss =
720 fake_bss_description!(Open, cf_pollable: true, apsd: false, immediate_block_ack: true);
721 assert!(mac::CapabilityInfo(bss.capability_info).cf_pollable());
722 assert!(!mac::CapabilityInfo(bss.capability_info).apsd());
723 assert!(mac::CapabilityInfo(bss.capability_info).immediate_block_ack());
724 }
725
726 #[test]
727 fn simple_default_override() {
728 let bss = fake_fidl_bss_description!(Open);
729 assert_eq!(bss.beacon_period, 100);
730
731 let bss = fake_fidl_bss_description!(Open, beacon_period: 50);
732 assert_eq!(bss.beacon_period, 50);
733 }
734
735 #[test]
736 #[should_panic(expected = "Personal is not supported")]
737 #[cfg_attr(feature = "variant_asan", ignore)]
739 #[cfg_attr(feature = "variant_hwasan", ignore)]
740 fn unsupported_bss_type() {
741 fake_fidl_bss_description!(Open, bss_type: fidl_ieee80211::BssType::Personal);
742 }
743
744 #[test]
745 fn any_protection_syntax() {
746 let _ = random_fidl_bss_description!();
747 let _ = random_bss_description!();
748 }
749
750 #[test]
751 fn random_fidl_bss_decription_override() {
752 let random_bss = random_bss_description!(ssid: Ssid::try_from("foo").unwrap());
753 assert_eq!(random_bss.ssid, Ssid::try_from("foo").unwrap());
754 }
755
756 #[test]
757 fn valid_random_ecw_min_max() {
758 let mut rng = rand::rng();
759 for _ in 0..100 {
760 let ecw_min_max = random_ecw_min_max(&mut rng);
761 assert!(ecw_min_max.ecw_max() >= ecw_min_max.ecw_min());
762 }
763 }
764
765 #[test]
766 fn random_bss_is_not_constant() {
767 for _ in 0..10 {
768 let random_bss_1 = BssDescription::try_from(random_fidl_bss_description!())
769 .expect("Failed to convert random_bss_description value");
770 let random_bss_2 = BssDescription::try_from(random_fidl_bss_description!())
771 .expect("Failed to convert random_bss_description value");
772 if random_bss_1 != random_bss_2 {
773 return;
774 }
775 }
776 panic!("random bss is always the same");
777 }
778
779 #[test]
780 fn random_bss_protection_is_not_constant() {
781 for _ in 0..10 {
782 let random_bss_1 = BssDescription::try_from(random_fidl_bss_description!())
783 .expect("Failed to convert random_bss_description value");
784 let random_bss_2 = BssDescription::try_from(random_fidl_bss_description!())
785 .expect("Failed to convert random_bss_description value");
786 if random_bss_1.protection() != random_bss_2.protection() {
787 return;
788 }
789 }
790 panic!("random bss protection is always the same");
791 }
792
793 #[test]
794 fn some_random_bss_bits_are_fixed() {
795 for _ in 0..5 {
796 let random_bss = random_fidl_bss_description!(Open);
797 assert_eq!(random_bss.bss_type, fidl_ieee80211::BssType::Infrastructure);
798 assert!(mac::CapabilityInfo(random_bss.capability_info).ess());
799 assert!(!mac::CapabilityInfo(random_bss.capability_info).ibss());
800 assert!(!mac::CapabilityInfo(random_bss.capability_info).privacy());
801 }
802 }
803
804 #[test]
807 fn random_bss_decription_protection_randomness() {
808 for _ in 0..10 {
809 let random_bss_1 = random_bss_description!();
810 let random_bss_2 = random_bss_description!();
811 if random_bss_1.protection() != random_bss_2.protection() {
812 return;
813 }
814 }
815 panic!("random protection is always the same");
816 }
817
818 #[test]
819 fn ies_overrides() {
820 let bss = fake_bss_description!(Wpa1Wpa2,
821 ssid: Ssid::try_from("fuchsia").unwrap(),
822 rates: vec![11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
823 ies_overrides: IesOverrides::new()
824 .remove(IeType::new_vendor6([0x00, 0x0b, 0x86, 0x01, 0x04, 0x08]))
825 .set(IeType::DSSS_PARAM_SET, [136].to_vec()),
826 );
827
828 #[rustfmt::skip]
835 let mut expected_ies = vec![
836 0x00, 0x07, b'f', b'u', b'c', b'h', b's', b'i', b'a',
838 0x01, 0x08, 11, 12, 13, 14, 15, 16, 17, 18,
840 0x03, 0x01, 136,
842 0x05, 0x04, 0x00, 0x01, 0x00, 0x02,
844 0x07, 0x10, 0x55, 0x53, 0x20, 0x24, 0x04, 0x24, 0x34, 0x04, 0x1e, 0x64, 0x0c, 0x1e, 0x95, 0x05, 0x24, 0x00, 0x20, 0x01, 0x00,
853 0x23, 0x02, 0x09, 0x00,
855 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
859 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,
871 0x3d, 0x16, 0x8c, 0x0d, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
876 0x00, 0x00, 0x7f, 0x08, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40,
879 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,
885 0xdd, 0x16, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, ];
893 expected_ies.extend(fake_wmm_param_header());
894 expected_ies.extend(fake_wmm_param_body());
895
896 assert_eq!(bss.ies(), &expected_ies[..]);
897 }
898
899 #[test]
900 fn test_bss_open_owe_transition() {
901 let bss: BssDescription = fake_bss_description!(OpenOweTransition);
902 assert!(!CapabilityInfo(bss.capability_info).privacy());
903 let expected = fake_owe_transition_ie();
904 for i in 0..=(bss.ies().len() - expected.len()) {
905 if bss.ies()[i..i + expected.len()] == expected[..] {
906 return;
908 }
909 }
910 panic!("Expected OWE Transition IE not found; ies: {:x?}", bss.ies());
911 }
912}