1use crate::client::scanner::Scanner;
6use crate::client::{Context, TimedEvent};
7use crate::device::DeviceOps;
8use anyhow::bail;
9use futures::Future;
10use log::error;
11use wlan_common::mac::BeaconHdr;
12use wlan_common::timer::EventHandle;
13use wlan_common::{ie, TimeUnit};
14use zerocopy::SplitByteSlice;
15use {fidl_fuchsia_wlan_common as fidl_common, fuchsia_async as fasync};
16
17pub trait ChannelActions {
18 fn switch_channel(
19 &mut self,
20 new_main_channel: fidl_common::WlanChannel,
21 ) -> impl Future<Output = Result<(), zx::Status>>;
22 fn schedule_channel_switch_timeout(&mut self, time: zx::MonotonicInstant) -> EventHandle;
23 fn disable_scanning(&mut self) -> impl Future<Output = Result<(), zx::Status>>;
24 fn enable_scanning(&mut self);
25 fn disable_tx(&mut self) -> Result<(), zx::Status>;
26 fn enable_tx(&mut self);
27}
28
29pub struct ChannelActionHandle<'a, D> {
30 ctx: &'a mut Context<D>,
31 scanner: &'a mut Scanner,
32}
33
34impl<'a, D: DeviceOps> ChannelActions for ChannelActionHandle<'a, D> {
35 async fn switch_channel(
36 &mut self,
37 new_main_channel: fidl_common::WlanChannel,
38 ) -> Result<(), zx::Status> {
39 self.ctx.device.set_channel(new_main_channel).await
40 }
41 fn schedule_channel_switch_timeout(&mut self, time: zx::MonotonicInstant) -> EventHandle {
42 self.ctx.timer.schedule_at(time, TimedEvent::ChannelSwitch)
43 }
44 async fn disable_scanning(&mut self) -> Result<(), zx::Status> {
45 let mut bound_scanner = self.scanner.bind(self.ctx);
46 bound_scanner.disable_scanning().await
47 }
48 fn enable_scanning(&mut self) {
49 let mut bound_scanner = self.scanner.bind(self.ctx);
50 bound_scanner.enable_scanning()
51 }
52 fn disable_tx(&mut self) -> Result<(), zx::Status> {
53 Err(zx::Status::NOT_SUPPORTED)
55 }
56 fn enable_tx(&mut self) {}
57}
58
59#[derive(Default)]
60pub struct ChannelState {
61 main_channel: Option<fidl_common::WlanChannel>,
64 pending_channel_switch: Option<(ChannelSwitch, EventHandle)>,
65 beacon_interval: Option<TimeUnit>,
66 last_beacon_timestamp: Option<fasync::MonotonicInstant>,
67}
68
69pub struct BoundChannelState<'a, T> {
70 channel_state: &'a mut ChannelState,
71 actions: T,
72}
73
74impl ChannelState {
75 #[cfg(test)]
76 pub fn new_with_main_channel(main_channel: fidl_common::WlanChannel) -> Self {
77 Self { main_channel: Some(main_channel), ..Default::default() }
78 }
79
80 pub fn get_main_channel(&self) -> Option<fidl_common::WlanChannel> {
81 self.main_channel
82 }
83
84 pub fn bind<'a, D>(
85 &'a mut self,
86 ctx: &'a mut Context<D>,
87 scanner: &'a mut Scanner,
88 ) -> BoundChannelState<'a, ChannelActionHandle<'a, D>> {
89 BoundChannelState { channel_state: self, actions: ChannelActionHandle { ctx, scanner } }
90 }
91
92 #[cfg(test)]
93 pub fn test_bind<'a, T: ChannelActions>(&'a mut self, actions: T) -> BoundChannelState<'a, T> {
94 BoundChannelState { channel_state: self, actions }
95 }
96
97 fn channel_switch_time_from_count(&self, channel_switch_count: u8) -> fasync::MonotonicInstant {
98 let beacon_interval =
99 self.beacon_interval.clone().unwrap_or(TimeUnit::DEFAULT_BEACON_INTERVAL);
100 let beacon_duration = fasync::MonotonicDuration::from(beacon_interval);
101 let duration = beacon_duration * channel_switch_count;
102 let now = fasync::MonotonicInstant::now();
103 let mut last_beacon =
104 self.last_beacon_timestamp.unwrap_or_else(|| fasync::MonotonicInstant::now());
105 while now - last_beacon > beacon_duration {
108 last_beacon += beacon_duration;
109 }
110 last_beacon + duration
111 }
112}
113
114impl<'a, T: ChannelActions> BoundChannelState<'a, T> {
115 pub async fn set_main_channel(
117 &mut self,
118 new_main_channel: fidl_common::WlanChannel,
119 ) -> Result<(), zx::Status> {
120 self.channel_state.pending_channel_switch.take();
121 let result = self.actions.switch_channel(new_main_channel).await;
122 match result {
123 Ok(()) => {
124 log::info!("Switched to new main channel {:?}", new_main_channel);
125 self.channel_state.main_channel.replace(new_main_channel);
126 }
127 Err(e) => {
128 log::error!("Failed to switch to new main channel {:?}: {}", new_main_channel, e);
129 }
130 }
131 self.actions.enable_scanning();
132 self.actions.enable_tx();
133 result
134 }
135
136 pub fn clear_main_channel(&mut self) {
140 self.channel_state.main_channel.take();
141 self.channel_state.pending_channel_switch.take();
142 self.channel_state.last_beacon_timestamp.take();
143 self.channel_state.beacon_interval.take();
144 self.actions.enable_scanning();
145 self.actions.enable_tx();
146 }
147
148 pub async fn handle_beacon(
149 &mut self,
150 header: &BeaconHdr,
151 elements: &[u8],
152 ) -> Result<(), anyhow::Error> {
153 self.channel_state.last_beacon_timestamp.replace(fasync::MonotonicInstant::now());
154 self.channel_state.beacon_interval.replace(header.beacon_interval);
155 self.handle_channel_switch_elements_if_present(elements, false).await
156 }
157
158 pub async fn handle_announcement_frame(
159 &mut self,
160 elements: &[u8],
161 ) -> Result<(), anyhow::Error> {
162 self.handle_channel_switch_elements_if_present(elements, true).await
163 }
164
165 async fn handle_channel_switch_elements_if_present(
166 &mut self,
167 elements: &[u8],
168 action_frame: bool,
169 ) -> Result<(), anyhow::Error> {
170 let mut csa_builder = ChannelSwitchBuilder::<&[u8]>::default();
171 for (ie_type, range) in ie::IeSummaryIter::new(elements) {
172 match ie_type {
173 ie::IeType::CHANNEL_SWITCH_ANNOUNCEMENT => {
174 let csa = ie::parse_channel_switch_announcement(&elements[range])?;
175 csa_builder.add_channel_switch_announcement((*csa).clone());
176 }
177 ie::IeType::SECONDARY_CHANNEL_OFFSET => {
178 let sco = ie::parse_sec_chan_offset(&elements[range])?;
179 csa_builder.add_secondary_channel_offset((*sco).clone());
180 }
181 ie::IeType::EXTENDED_CHANNEL_SWITCH_ANNOUNCEMENT => {
182 let ecsa = ie::parse_extended_channel_switch_announcement(&elements[range])?;
183 csa_builder.add_extended_channel_switch_announcement((*ecsa).clone());
184 }
185 ie::IeType::CHANNEL_SWITCH_WRAPPER => {
186 let csw = ie::parse_channel_switch_wrapper(&elements[range])?;
187 csa_builder.add_channel_switch_wrapper(csw);
188 }
189 ie::IeType::WIDE_BANDWIDTH_CHANNEL_SWITCH if action_frame => {
190 let wbcs = ie::parse_wide_bandwidth_channel_switch(&elements[range])?;
191 csa_builder.add_wide_bandwidth_channel_switch((*wbcs).clone());
192 }
193 ie::IeType::TRANSMIT_POWER_ENVELOPE if action_frame => {
194 let tpe = ie::parse_transmit_power_envelope(&elements[range])?;
195 csa_builder.add_transmit_power_envelope(tpe);
196 }
197 _ => (),
198 }
199 }
200 match csa_builder.build() {
201 ChannelSwitchResult::ChannelSwitch(cs) => self.handle_channel_switch(cs).await,
202 ChannelSwitchResult::NoChannelSwitch => Ok(()),
203 ChannelSwitchResult::Error(err) => Err(err.into()),
204 }
205 }
206
207 async fn handle_channel_switch(
208 &mut self,
209 channel_switch: ChannelSwitch,
210 ) -> Result<(), anyhow::Error> {
211 if !channel_switch.compatible() {
212 bail!("Incompatible channel switch announcement received.");
213 }
214
215 self.actions.disable_scanning().await?;
216 if channel_switch.channel_switch_count == 0 {
217 self.set_main_channel(channel_switch.new_channel).await.map_err(|e| e.into())
218 } else {
219 if channel_switch.pause_transmission {
220 self.actions.disable_tx()?;
222 }
223 let time = self
224 .channel_state
225 .channel_switch_time_from_count(channel_switch.channel_switch_count);
226 let event_id = self.actions.schedule_channel_switch_timeout(time.into());
227 self.channel_state.pending_channel_switch.replace((channel_switch, event_id));
228 Ok(())
229 }
230 }
231
232 pub async fn handle_channel_switch_timeout(&mut self) -> Result<(), anyhow::Error> {
233 if let Some((channel_switch, _handle)) = self.channel_state.pending_channel_switch.take() {
234 self.set_main_channel(channel_switch.new_channel).await?;
235 }
236 Ok(())
237 }
238}
239
240#[derive(Debug, PartialEq)]
241pub struct ChannelSwitch {
242 pub channel_switch_count: u8,
243 pub new_channel: fidl_common::WlanChannel,
244 pub pause_transmission: bool,
245 pub new_operating_class: Option<u8>,
246 pub new_transmit_power_envelope_specified: bool,
248}
249
250impl ChannelSwitch {
251 fn compatible(&self) -> bool {
254 self.new_operating_class.is_none()
255 && !self.new_transmit_power_envelope_specified
256 && !self.pause_transmission
257 }
258}
259
260#[derive(Default)]
261pub struct ChannelSwitchBuilder<B> {
262 channel_switch: Option<ie::ChannelSwitchAnnouncement>,
263 secondary_channel_offset: Option<ie::SecChanOffset>,
264 extended_channel_switch: Option<ie::ExtendedChannelSwitchAnnouncement>,
265 new_country: Option<ie::CountryView<B>>,
266 wide_bandwidth_channel_switch: Option<ie::WideBandwidthChannelSwitch>,
267 transmit_power_envelope: Option<ie::TransmitPowerEnvelopeView<B>>,
268}
269
270#[derive(Debug)]
271pub enum ChannelSwitchResult {
272 ChannelSwitch(ChannelSwitch),
273 NoChannelSwitch,
274 Error(ChannelSwitchError),
275}
276
277#[derive(Debug, thiserror::Error)]
278pub enum ChannelSwitchError {
279 #[error("Frame contains multiple channel switch elements with conflicting information.")]
280 ConflictingElements,
281 #[error("Invalid channel switch mode {}", _0)]
282 InvalidChannelSwitchMode(u8),
283}
284
285impl<B: SplitByteSlice> ChannelSwitchBuilder<B> {
286 pub fn build(self) -> ChannelSwitchResult {
290 let (mode, new_channel_number, channel_switch_count, new_operating_class) =
295 if let Some(csa) = self.channel_switch {
296 if let Some(ecsa) = self.extended_channel_switch {
297 if csa.new_channel_number != ecsa.new_channel_number {
299 return ChannelSwitchResult::Error(ChannelSwitchError::ConflictingElements);
300 }
301 }
302 (csa.mode, csa.new_channel_number, csa.channel_switch_count, None)
304 } else if let Some(ecsa) = self.extended_channel_switch {
305 (
307 ecsa.mode,
308 ecsa.new_channel_number,
309 ecsa.channel_switch_count,
310 Some(ecsa.new_operating_class),
311 )
312 } else {
313 return ChannelSwitchResult::NoChannelSwitch;
314 };
315
316 let pause_transmission = match mode {
317 1 => true,
318 0 => false,
319 other => {
320 return ChannelSwitchResult::Error(ChannelSwitchError::InvalidChannelSwitchMode(
321 other,
322 ))
323 }
324 };
325
326 let vht_cbw_and_segs = self
329 .wide_bandwidth_channel_switch
330 .map(|wbcs| (wbcs.new_width, wbcs.new_center_freq_seg0, wbcs.new_center_freq_seg1));
331 let sec_chan_offset =
332 self.secondary_channel_offset.unwrap_or(ie::SecChanOffset::SECONDARY_NONE);
333 let (cbw, secondary80) =
334 wlan_common::channel::derive_wide_channel_bandwidth(vht_cbw_and_segs, sec_chan_offset)
335 .to_fidl();
336
337 ChannelSwitchResult::ChannelSwitch(ChannelSwitch {
338 channel_switch_count: channel_switch_count,
339 new_channel: fidl_common::WlanChannel { primary: new_channel_number, cbw, secondary80 },
340 pause_transmission,
341 new_operating_class,
342 new_transmit_power_envelope_specified: self.transmit_power_envelope.is_some(),
343 })
344 }
345
346 pub fn add_channel_switch_announcement(&mut self, csa: ie::ChannelSwitchAnnouncement) {
347 self.channel_switch.replace(csa);
348 }
349
350 pub fn add_secondary_channel_offset(&mut self, sco: ie::SecChanOffset) {
351 self.secondary_channel_offset.replace(sco);
352 }
353
354 pub fn add_extended_channel_switch_announcement(
355 &mut self,
356 ecsa: ie::ExtendedChannelSwitchAnnouncement,
357 ) {
358 self.extended_channel_switch.replace(ecsa);
359 }
360
361 pub fn add_wide_bandwidth_channel_switch(&mut self, wbcs: ie::WideBandwidthChannelSwitch) {
362 self.wide_bandwidth_channel_switch.replace(wbcs);
363 }
364
365 pub fn add_transmit_power_envelope(&mut self, tpe: ie::TransmitPowerEnvelopeView<B>) {
366 self.transmit_power_envelope.replace(tpe);
367 }
368
369 pub fn add_channel_switch_wrapper(&mut self, csw: ie::ChannelSwitchWrapperView<B>) {
370 csw.new_country.map(|new_country| self.new_country.replace(new_country));
371 csw.new_transmit_power_envelope.map(|tpe| self.add_transmit_power_envelope(tpe));
372 csw.wide_bandwidth_channel_switch.map(|wbcs| self.add_wide_bandwidth_channel_switch(*wbcs));
373 }
374}
375
376#[cfg(test)]
377mod tests {
378 use super::*;
379 use futures::task::Poll;
380 use std::pin::pin;
381 use test_case::test_case;
382 use wlan_common::assert_variant;
383 use wlan_common::mac::CapabilityInfo;
384 use wlan_common::timer::EventId;
385 use zerocopy::IntoBytes;
386
387 const NEW_CHANNEL: u8 = 10;
388 const NEW_OPERATING_CLASS: u8 = 20;
389 const COUNT: u8 = 30;
390
391 const CHANNEL_SWITCH_ANNOUNCEMENT_HEADER: &[u8] = &[37, 3];
392
393 fn csa(
394 mode: u8,
395 new_channel_number: u8,
396 channel_switch_count: u8,
397 ) -> ie::ChannelSwitchAnnouncement {
398 ie::ChannelSwitchAnnouncement { mode, new_channel_number, channel_switch_count }
399 }
400
401 fn csa_bytes(mode: u8, new_channel_number: u8, channel_switch_count: u8) -> Vec<u8> {
402 let mut elements = vec![];
403 elements.extend(CHANNEL_SWITCH_ANNOUNCEMENT_HEADER);
404 elements.extend(csa(mode, new_channel_number, channel_switch_count).as_bytes());
405 elements
406 }
407
408 fn ecsa(
409 mode: u8,
410 new_operating_class: u8,
411 new_channel_number: u8,
412 channel_switch_count: u8,
413 ) -> ie::ExtendedChannelSwitchAnnouncement {
414 ie::ExtendedChannelSwitchAnnouncement {
415 mode,
416 new_operating_class,
417 new_channel_number,
418 channel_switch_count,
419 }
420 }
421
422 fn wbcs(seg0: u8, seg1: u8) -> ie::WideBandwidthChannelSwitch {
423 ie::WideBandwidthChannelSwitch {
424 new_width: ie::VhtChannelBandwidth::CBW_80_160_80P80,
425 new_center_freq_seg0: seg0,
426 new_center_freq_seg1: seg1,
427 }
428 }
429
430 #[test_case(Some(NEW_OPERATING_CLASS), false, false ; "when operating class present")]
431 #[test_case(None, true, false ; "when new TPE present")]
432 #[test_case(Some(NEW_OPERATING_CLASS), true, false ; "when operating class and new TPE present")]
433 #[test_case(None, false, true ; "when operating class and new TPE absent")]
434 #[fuchsia::test]
435 fn channel_switch_compatible(
436 new_operating_class: Option<u8>,
437 new_transmit_power_envelope_specified: bool,
438 expected_compatible: bool,
439 ) {
440 let channel_switch = ChannelSwitch {
441 channel_switch_count: COUNT,
442 new_channel: fidl_common::WlanChannel {
443 primary: NEW_CHANNEL,
444 cbw: fidl_common::ChannelBandwidth::Cbw20,
445 secondary80: 0,
446 },
447 pause_transmission: false,
448 new_operating_class,
449 new_transmit_power_envelope_specified,
450 };
451 assert_eq!(channel_switch.compatible(), expected_compatible);
452 }
453
454 #[test]
455 fn empty_builder_returns_no_csa() {
456 let builder = ChannelSwitchBuilder::<&[u8]>::default();
457 assert_variant!(builder.build(), ChannelSwitchResult::NoChannelSwitch);
458 }
459
460 #[test_case(0, false ; "when transmission is not paused")]
461 #[test_case(1, true ; "when transmission is paused")]
462 #[fuchsia::test]
463 fn basic_csa_20mhz(mode: u8, pause_transmission: bool) {
464 let mut builder = ChannelSwitchBuilder::<&[u8]>::default();
465 builder.add_channel_switch_announcement(csa(mode, NEW_CHANNEL, COUNT));
466 let channel_switch =
467 assert_variant!(builder.build(), ChannelSwitchResult::ChannelSwitch(cs) => cs);
468 let expected_channel_switch = ChannelSwitch {
469 channel_switch_count: COUNT,
470 new_channel: fidl_common::WlanChannel {
471 primary: NEW_CHANNEL,
472 cbw: fidl_common::ChannelBandwidth::Cbw20,
473 secondary80: 0,
474 },
475 pause_transmission,
476 new_operating_class: None,
477 new_transmit_power_envelope_specified: false,
478 };
479 assert_eq!(channel_switch, expected_channel_switch);
480 }
481
482 #[test_case(0, false ; "when transmission is not paused")]
483 #[test_case(1, true ; "when transmission is paused")]
484 #[fuchsia::test]
485 fn basic_ecsa_20mhz(mode: u8, pause_transmission: bool) {
486 let mut builder = ChannelSwitchBuilder::<&[u8]>::default();
487 builder.add_extended_channel_switch_announcement(ecsa(
488 mode,
489 NEW_OPERATING_CLASS,
490 NEW_CHANNEL,
491 COUNT,
492 ));
493 let channel_switch =
494 assert_variant!(builder.build(), ChannelSwitchResult::ChannelSwitch(cs) => cs);
495 let expected_channel_switch = ChannelSwitch {
496 channel_switch_count: COUNT,
497 new_channel: fidl_common::WlanChannel {
498 primary: NEW_CHANNEL,
499 cbw: fidl_common::ChannelBandwidth::Cbw20,
500 secondary80: 0,
501 },
502 pause_transmission,
503 new_operating_class: Some(NEW_OPERATING_CLASS),
504 new_transmit_power_envelope_specified: false,
505 };
506 assert_eq!(channel_switch, expected_channel_switch);
507 }
508
509 #[test]
510 fn basic_csa_40mhz() {
511 let mut builder = ChannelSwitchBuilder::<&[u8]>::default();
512 builder.add_channel_switch_announcement(csa(0, NEW_CHANNEL, COUNT));
513 builder.add_secondary_channel_offset(ie::SecChanOffset::SECONDARY_ABOVE);
514 let channel_switch =
515 assert_variant!(builder.build(), ChannelSwitchResult::ChannelSwitch(cs) => cs);
516 let expected_channel_switch = ChannelSwitch {
517 channel_switch_count: COUNT,
518 new_channel: fidl_common::WlanChannel {
519 primary: NEW_CHANNEL,
520 cbw: fidl_common::ChannelBandwidth::Cbw40,
521 secondary80: 0,
522 },
523 pause_transmission: false,
524 new_operating_class: None,
525 new_transmit_power_envelope_specified: false,
526 };
527 assert_eq!(channel_switch, expected_channel_switch);
528 }
529
530 #[test]
531 fn basic_csa_80mhz() {
532 let mut builder = ChannelSwitchBuilder::<&[u8]>::default();
533 builder.add_channel_switch_announcement(csa(0, NEW_CHANNEL, COUNT));
534 builder.add_secondary_channel_offset(ie::SecChanOffset::SECONDARY_ABOVE);
535 builder.add_wide_bandwidth_channel_switch(wbcs(NEW_CHANNEL + 8, 0));
536 let channel_switch =
537 assert_variant!(builder.build(), ChannelSwitchResult::ChannelSwitch(cs) => cs);
538 let expected_channel_switch = ChannelSwitch {
539 channel_switch_count: COUNT,
540 new_channel: fidl_common::WlanChannel {
541 primary: NEW_CHANNEL,
542 cbw: fidl_common::ChannelBandwidth::Cbw80,
543 secondary80: 0,
544 },
545 pause_transmission: false,
546 new_operating_class: None,
547 new_transmit_power_envelope_specified: false,
548 };
549 assert_eq!(channel_switch, expected_channel_switch);
550 }
551
552 #[test]
553 fn basic_csa_160mhz() {
554 let mut builder = ChannelSwitchBuilder::<&[u8]>::default();
555 builder.add_channel_switch_announcement(csa(0, NEW_CHANNEL, COUNT));
556 builder.add_secondary_channel_offset(ie::SecChanOffset::SECONDARY_ABOVE);
557 builder.add_wide_bandwidth_channel_switch(wbcs(NEW_CHANNEL + 8, NEW_CHANNEL + 16));
558 let channel_switch =
559 assert_variant!(builder.build(), ChannelSwitchResult::ChannelSwitch(cs) => cs);
560 let expected_channel_switch = ChannelSwitch {
561 channel_switch_count: COUNT,
562 new_channel: fidl_common::WlanChannel {
563 primary: NEW_CHANNEL,
564 cbw: fidl_common::ChannelBandwidth::Cbw160,
565 secondary80: 0,
566 },
567 pause_transmission: false,
568 new_operating_class: None,
569 new_transmit_power_envelope_specified: false,
570 };
571 assert_eq!(channel_switch, expected_channel_switch);
572 }
573
574 #[test]
575 fn basic_csa_80p80mhz() {
576 let mut builder = ChannelSwitchBuilder::<&[u8]>::default();
577 builder.add_channel_switch_announcement(csa(0, NEW_CHANNEL, COUNT));
578 builder.add_secondary_channel_offset(ie::SecChanOffset::SECONDARY_ABOVE);
579 builder.add_wide_bandwidth_channel_switch(wbcs(NEW_CHANNEL + 8, NEW_CHANNEL + 100));
580 let channel_switch =
581 assert_variant!(builder.build(), ChannelSwitchResult::ChannelSwitch(cs) => cs);
582 let expected_channel_switch = ChannelSwitch {
583 channel_switch_count: COUNT,
584 new_channel: fidl_common::WlanChannel {
585 primary: NEW_CHANNEL,
586 cbw: fidl_common::ChannelBandwidth::Cbw80P80,
587 secondary80: NEW_CHANNEL + 100,
588 },
589 pause_transmission: false,
590 new_operating_class: None,
591 new_transmit_power_envelope_specified: false,
592 };
593 assert_eq!(channel_switch, expected_channel_switch);
594 }
595
596 #[test_case(0, false ; "when transmission is not paused")]
597 #[test_case(1, true ; "when transmission is paused")]
598 #[fuchsia::test]
599 fn mixed_csa_ecsa_20mhz(mode: u8, pause_transmission: bool) {
600 let mut builder = ChannelSwitchBuilder::<&[u8]>::default();
601 builder.add_channel_switch_announcement(csa(mode, NEW_CHANNEL, COUNT));
602 builder.add_extended_channel_switch_announcement(ecsa(
603 mode,
604 NEW_OPERATING_CLASS,
605 NEW_CHANNEL,
606 COUNT,
607 ));
608 let channel_switch =
609 assert_variant!(builder.build(), ChannelSwitchResult::ChannelSwitch(cs) => cs);
610 let expected_channel_switch = ChannelSwitch {
611 channel_switch_count: COUNT,
612 new_channel: fidl_common::WlanChannel {
613 primary: NEW_CHANNEL,
614 cbw: fidl_common::ChannelBandwidth::Cbw20,
615 secondary80: 0,
616 },
617 pause_transmission,
618 new_operating_class: None,
619 new_transmit_power_envelope_specified: false,
620 };
621 assert_eq!(channel_switch, expected_channel_switch);
622 }
623
624 #[test]
625 fn mixed_csa_ecsa_mismatch_20mhz() {
626 let mut builder = ChannelSwitchBuilder::<&[u8]>::default();
627 builder.add_channel_switch_announcement(csa(0, NEW_CHANNEL, COUNT));
628 let mut ecsa = ecsa(0, NEW_OPERATING_CLASS, NEW_CHANNEL, COUNT);
629 ecsa.new_channel_number += 1;
630 builder.add_extended_channel_switch_announcement(ecsa);
631 let err = assert_variant!(builder.build(), ChannelSwitchResult::Error(err) => err);
632 assert_variant!(err, ChannelSwitchError::ConflictingElements);
633 }
634
635 #[test]
636 fn basic_csa_invalid_mode_20mhz() {
637 let mut builder = ChannelSwitchBuilder::<&[u8]>::default();
638 builder.add_channel_switch_announcement(csa(123, NEW_CHANNEL, COUNT));
639 let err = assert_variant!(builder.build(), ChannelSwitchResult::Error(err) => err);
640 assert_variant!(err, ChannelSwitchError::InvalidChannelSwitchMode(123));
641 }
642
643 #[derive(Default)]
644 struct MockChannelActions {
645 actions: Vec<ChannelAction>,
646 event_id_ctr: EventId,
647 }
648
649 #[derive(Debug, Copy, Clone)]
650 enum ChannelAction {
651 SwitchChannel(fidl_common::WlanChannel),
652 Timeout(EventId, fasync::MonotonicInstant),
653 DisableScanning,
654 EnableScanning,
655 DisableTx,
656 EnableTx,
657 }
658
659 impl ChannelActions for &mut MockChannelActions {
660 async fn switch_channel(
661 &mut self,
662 new_main_channel: fidl_common::WlanChannel,
663 ) -> Result<(), zx::Status> {
664 self.actions.push(ChannelAction::SwitchChannel(new_main_channel));
665 Ok(())
666 }
667 fn schedule_channel_switch_timeout(&mut self, time: zx::MonotonicInstant) -> EventHandle {
668 self.event_id_ctr += 1;
669 self.actions.push(ChannelAction::Timeout(self.event_id_ctr, time.into()));
670 EventHandle::new_test(self.event_id_ctr)
671 }
672 async fn disable_scanning(&mut self) -> Result<(), zx::Status> {
673 self.actions.push(ChannelAction::DisableScanning);
674 Ok(())
675 }
676 fn enable_scanning(&mut self) {
677 self.actions.push(ChannelAction::EnableScanning);
678 }
679 fn disable_tx(&mut self) -> Result<(), zx::Status> {
680 self.actions.push(ChannelAction::DisableTx);
681 Ok(())
682 }
683 fn enable_tx(&mut self) {
684 self.actions.push(ChannelAction::EnableTx);
685 }
686 }
687
688 #[fuchsia::test(allow_stalls = false)]
689 async fn channel_state_ignores_empty_beacon_frame() {
690 let mut channel_state = ChannelState::default();
691 let mut actions = MockChannelActions::default();
692 let header = BeaconHdr::new(TimeUnit(10), CapabilityInfo(0));
693 let elements = [];
694 channel_state
695 .test_bind(&mut actions)
696 .handle_beacon(&header, &elements[..])
697 .await
698 .expect("Failed to handle beacon");
699
700 assert!(actions.actions.is_empty());
701 }
702
703 #[fuchsia::test(allow_stalls = false)]
704 async fn channel_state_handles_immediate_csa_in_beacon_frame() {
705 let mut channel_state = ChannelState::default();
706
707 let mut actions = MockChannelActions::default();
708 let header = BeaconHdr::new(TimeUnit(10), CapabilityInfo(0));
709 let mut elements = vec![];
710 elements.extend(csa_bytes(0, NEW_CHANNEL, 0));
711 channel_state
712 .test_bind(&mut actions)
713 .handle_beacon(&header, &elements[..])
714 .await
715 .expect("Failed to handle beacon");
716
717 assert_eq!(actions.actions.len(), 4);
718 assert_variant!(actions.actions[0], ChannelAction::DisableScanning);
719 let new_channel =
720 assert_variant!(actions.actions[1], ChannelAction::SwitchChannel(chan) => chan);
721 assert_eq!(new_channel.primary, NEW_CHANNEL);
722 assert_variant!(actions.actions[2], ChannelAction::EnableScanning);
723 assert_variant!(actions.actions[3], ChannelAction::EnableTx);
724 }
725
726 #[test]
727 fn channel_state_handles_delayed_csa_in_beacon_frame() {
728 let mut exec = fasync::TestExecutor::new_with_fake_time();
729 let mut channel_state = ChannelState::default();
730 let bcn_header = BeaconHdr::new(TimeUnit(10), CapabilityInfo(0));
731 let mut time = fasync::MonotonicInstant::from_nanos(0);
732 exec.set_fake_time(time);
733 let mut actions = MockChannelActions::default();
734
735 {
737 let mut bound_channel_state = channel_state.test_bind(&mut actions);
738 let elements = csa_bytes(0, NEW_CHANNEL, 2);
739 let fut = bound_channel_state.handle_beacon(&bcn_header, &elements[..]);
740 let mut fut = pin!(fut);
741 assert_variant!(
742 exec.run_until_stalled(&mut fut),
743 Poll::Ready(Ok(_)),
744 "Failed to handle beacon"
745 );
746 }
747 assert_eq!(actions.actions.len(), 2);
748 assert_variant!(actions.actions[0], ChannelAction::DisableScanning);
749 let (_first_event_id, event_time) =
750 assert_variant!(actions.actions[1], ChannelAction::Timeout(eid, time) => (eid, time));
751 assert_eq!(event_time, (time + (bcn_header.beacon_interval * 2u16).into()).into());
752 actions.actions.clear();
753
754 time += bcn_header.beacon_interval.into();
755 exec.set_fake_time(time);
756
757 {
759 let mut bound_channel_state = channel_state.test_bind(&mut actions);
760 let elements = csa_bytes(0, NEW_CHANNEL, 1);
761 let fut = bound_channel_state.handle_beacon(&bcn_header, &elements[..]);
762 let mut fut = pin!(fut);
763 assert_variant!(
764 exec.run_until_stalled(&mut fut),
765 Poll::Ready(Ok(_)),
766 "Failed to handle beacon"
767 );
768 }
769 assert_eq!(actions.actions.len(), 2);
770 assert_variant!(actions.actions[0], ChannelAction::DisableScanning);
771 let (_second_event_id, event_time) =
772 assert_variant!(actions.actions[1], ChannelAction::Timeout(eid, time) => (eid, time));
773 assert_eq!(event_time, (time + bcn_header.beacon_interval.into()).into());
774 actions.actions.clear();
775
776 time += bcn_header.beacon_interval.into();
777 exec.set_fake_time(time);
778
779 {
781 let mut bound_channel_state = channel_state.test_bind(&mut actions);
782 let fut = bound_channel_state.handle_channel_switch_timeout();
783 let mut fut = pin!(fut);
784 assert_variant!(
785 exec.run_until_stalled(&mut fut),
786 Poll::Ready(Ok(_)),
787 "Failed to handle channel switch timeout"
788 );
789 }
790
791 assert_eq!(actions.actions.len(), 3);
792 let new_channel =
793 assert_variant!(actions.actions[0], ChannelAction::SwitchChannel(chan) => chan);
794 assert_eq!(new_channel.primary, NEW_CHANNEL);
795 assert_variant!(actions.actions[1], ChannelAction::EnableScanning);
796 assert_variant!(actions.actions[2], ChannelAction::EnableTx);
797 }
798
799 #[fuchsia::test(allow_stalls = false)]
800 async fn channel_state_cannot_pause_tx() {
801 let mut channel_state = ChannelState::default();
802 let bcn_header = BeaconHdr::new(TimeUnit(10), CapabilityInfo(0));
803 let mut actions = MockChannelActions::default();
804
805 channel_state
806 .test_bind(&mut actions)
807 .handle_beacon(&bcn_header, &csa_bytes(1, NEW_CHANNEL, 2)[..])
808 .await
809 .expect_err("Shouldn't handle channel switch with tx pause");
810 assert_eq!(actions.actions.len(), 0);
811 }
812
813 #[fuchsia::test(allow_stalls = false)]
814 async fn channel_state_cannot_parse_malformed_csa() {
815 let mut channel_state = ChannelState::default();
816 let bcn_header = BeaconHdr::new(TimeUnit(10), CapabilityInfo(0));
817 let mut actions = MockChannelActions::default();
818
819 let mut element = vec![];
820 element.extend(CHANNEL_SWITCH_ANNOUNCEMENT_HEADER);
821 element.extend(&[10, 0, 0][..]); channel_state
823 .test_bind(&mut actions)
824 .handle_beacon(&bcn_header, &element[..])
825 .await
826 .expect_err("Should not handle malformed beacon");
827 assert_eq!(actions.actions.len(), 0);
828 }
829
830 #[fuchsia::test(allow_stalls = false)]
831 async fn channel_state_handles_immediate_csa_in_action_frame() {
832 let mut channel_state = ChannelState::default();
833
834 let mut actions = MockChannelActions::default();
835 channel_state
836 .test_bind(&mut actions)
837 .handle_announcement_frame(&csa_bytes(0, NEW_CHANNEL, 0)[..])
838 .await
839 .expect("Failed to handle beacon");
840
841 assert_eq!(actions.actions.len(), 4);
842 assert_variant!(actions.actions[0], ChannelAction::DisableScanning);
843 let new_channel =
844 assert_variant!(actions.actions[1], ChannelAction::SwitchChannel(chan) => chan);
845 assert_eq!(new_channel.primary, NEW_CHANNEL);
846 assert_variant!(actions.actions[2], ChannelAction::EnableScanning);
847 assert_variant!(actions.actions[3], ChannelAction::EnableTx);
848 }
849
850 #[test]
851 fn channel_state_handles_delayed_csa_in_announcement_frame() {
852 let mut exec = fasync::TestExecutor::new_with_fake_time();
853 let mut channel_state = ChannelState::default();
854 let bcn_header = BeaconHdr::new(TimeUnit(100), CapabilityInfo(0));
855 let bcn_time: fasync::MonotonicInstant =
856 fasync::MonotonicInstant::from_nanos(0) + bcn_header.beacon_interval.into();
857 exec.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
858 let mut actions = MockChannelActions::default();
859
860 {
862 let mut bound_channel_state = channel_state.test_bind(&mut actions);
863 let elements = [];
864 let fut = bound_channel_state.handle_beacon(&bcn_header, &elements[..]);
865 let mut fut = pin!(fut);
866 assert_variant!(
867 exec.run_until_stalled(&mut fut),
868 Poll::Ready(Ok(_)),
869 "Failed to handle beacon"
870 );
871 }
872 assert!(actions.actions.is_empty());
873
874 exec.set_fake_time(bcn_time - fasync::MonotonicDuration::from_micros(500));
876 {
877 let mut bound_channel_state = channel_state.test_bind(&mut actions);
878 let elements = csa_bytes(0, NEW_CHANNEL, 1);
879 let fut = bound_channel_state.handle_announcement_frame(&elements[..]);
880 let mut fut = pin!(fut);
881 assert_variant!(
882 exec.run_until_stalled(&mut fut),
883 Poll::Ready(Ok(_)),
884 "Failed to handle announcement"
885 );
886 }
887 assert_eq!(actions.actions.len(), 2);
888 assert_variant!(actions.actions[0], ChannelAction::DisableScanning);
889 let (_event_id, event_time) =
890 assert_variant!(actions.actions[1], ChannelAction::Timeout(eid, time) => (eid, time));
891 assert_eq!(event_time, bcn_time);
892 actions.actions.clear();
893
894 exec.set_fake_time(bcn_time);
896 {
897 let mut bound_channel_state = channel_state.test_bind(&mut actions);
898 let fut = bound_channel_state.handle_channel_switch_timeout();
899 let mut fut = pin!(fut);
900 assert_variant!(
901 exec.run_until_stalled(&mut fut),
902 Poll::Ready(Ok(_)),
903 "Failed to handle channel switch timeout"
904 );
905 }
906 assert_eq!(actions.actions.len(), 3);
907 let new_channel =
908 assert_variant!(actions.actions[0], ChannelAction::SwitchChannel(chan) => chan);
909 assert_eq!(new_channel.primary, NEW_CHANNEL);
910 assert_variant!(actions.actions[1], ChannelAction::EnableScanning);
911 assert_variant!(actions.actions[2], ChannelAction::EnableTx);
912 }
913
914 #[test]
915 fn channel_state_handles_delayed_csa_in_announcement_frame_with_missed_beacon() {
916 let mut exec = fasync::TestExecutor::new_with_fake_time();
917 let mut channel_state = ChannelState::default();
918 let bcn_header = BeaconHdr::new(TimeUnit(100), CapabilityInfo(0));
919 exec.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
920 let mut actions = MockChannelActions::default();
921
922 {
924 let mut bound_channel_state = channel_state.test_bind(&mut actions);
925 let elements = [];
926 let fut = bound_channel_state.handle_beacon(&bcn_header, &elements[..]);
927 let mut fut = pin!(fut);
928 assert_variant!(
929 exec.run_until_stalled(&mut fut),
930 Poll::Ready(Ok(_)),
931 "Failed to handle beacon"
932 );
933 }
934 assert!(actions.actions.is_empty());
935
936 exec.set_fake_time(
938 fasync::MonotonicInstant::from_nanos(0)
939 + bcn_header.beacon_interval.into()
940 + fasync::MonotonicDuration::from_micros(500),
941 );
942
943 {
945 let mut bound_channel_state = channel_state.test_bind(&mut actions);
946 let elements = csa_bytes(0, NEW_CHANNEL, 1);
947 let fut = bound_channel_state.handle_announcement_frame(&elements[..]);
948 let mut fut = pin!(fut);
949 assert_variant!(
950 exec.run_until_stalled(&mut fut),
951 Poll::Ready(Ok(_)),
952 "Failed to handle announcement"
953 );
954 }
955 assert_eq!(actions.actions.len(), 2);
956 assert_variant!(actions.actions[0], ChannelAction::DisableScanning);
957 let (_event_id, event_time) =
958 assert_variant!(actions.actions[1], ChannelAction::Timeout(eid, time) => (eid, time));
959 assert_eq!(
961 event_time,
962 fasync::MonotonicInstant::from_nanos(0) + (bcn_header.beacon_interval * 2u16).into()
963 );
964 }
965}