1use crate::common::mac::WlanGi;
6use crate::error::Error;
7use anyhow::format_err;
8use fdf::ArenaStaticBox;
9use fidl_fuchsia_wlan_common as fidl_common;
10use fidl_fuchsia_wlan_driver as fidl_driver_common;
11use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
12use fidl_fuchsia_wlan_mlme as fidl_mlme;
13use fidl_fuchsia_wlan_softmac as fidl_softmac;
14use fuchsia_trace as trace;
15use futures::Future;
16use futures::channel::mpsc;
17use ieee80211::MacAddr;
18use log::error;
19use std::fmt::Display;
20use std::mem;
21use std::sync::Arc;
22use trace::Id as TraceId;
23use wlan_common::mac::FrameControl;
24use wlan_common::{TimeUnit, tx_vector};
25use wlan_ffi_transport::{EthernetRx, EthernetTx, FfiEthernetTx, FfiWlanRx, WlanRx, WlanTx};
26use wlan_trace as wtrace;
27
28pub use test_utils::*;
29
30#[derive(Debug, PartialEq)]
31pub struct LinkStatus(u32);
32impl LinkStatus {
33 pub const DOWN: Self = Self(0);
34 pub const UP: Self = Self(1);
35}
36
37impl From<fidl_mlme::ControlledPortState> for LinkStatus {
38 fn from(state: fidl_mlme::ControlledPortState) -> Self {
39 match state {
40 fidl_mlme::ControlledPortState::Open => Self::UP,
41 fidl_mlme::ControlledPortState::Closed => Self::DOWN,
42 }
43 }
44}
45
46pub struct Device {
47 ethernet_rx: EthernetRx,
48 ethernet_tx: Option<EthernetTx>,
49 wlan_rx: Option<WlanRx>,
50 wlan_tx: WlanTx,
51 wlan_softmac_bridge_proxy: fidl_softmac::WlanSoftmacBridgeProxy,
52 minstrel: Option<crate::MinstrelWrapper>,
53 event_receiver: Option<mpsc::UnboundedReceiver<fidl_mlme::MlmeEvent>>,
54 event_sink: mpsc::UnboundedSender<fidl_mlme::MlmeEvent>,
55}
56
57impl Device {
58 pub fn new(
59 wlan_softmac_bridge_proxy: fidl_softmac::WlanSoftmacBridgeProxy,
60 ethernet_rx: EthernetRx,
61 wlan_tx: WlanTx,
62 ) -> Device {
63 let (event_sink, event_receiver) = mpsc::unbounded();
64 Device {
65 ethernet_rx,
66 ethernet_tx: None,
67 wlan_rx: None,
68 wlan_tx,
69 wlan_softmac_bridge_proxy,
70 minstrel: None,
71 event_receiver: Some(event_receiver),
72 event_sink,
73 }
74 }
75
76 fn flatten_and_log_error<T>(
78 method_name: impl Display,
79 result: Result<Result<T, zx::sys::zx_status_t>, fidl::Error>,
80 ) -> Result<T, zx::Status> {
81 result
82 .map_err(|fidl_error| {
83 error!("FIDL error during {}: {:?}", method_name, fidl_error);
84 zx::Status::INTERNAL
85 })?
86 .map_err(|status| {
87 error!("{} failed: {:?}", method_name, status);
88 zx::Status::from_raw(status)
89 })
90 }
91}
92
93const REQUIRED_WLAN_HEADER_LEN: usize = 10;
94const PEER_ADDR_OFFSET: usize = 4;
95
96pub trait DeviceOps {
98 fn wlan_softmac_query_response(
99 &mut self,
100 ) -> impl Future<Output = Result<fidl_softmac::WlanSoftmacQueryResponse, zx::Status>>;
101 fn discovery_support(
102 &mut self,
103 ) -> impl Future<Output = Result<fidl_softmac::DiscoverySupport, zx::Status>>;
104 fn mac_sublayer_support(
105 &mut self,
106 ) -> impl Future<Output = Result<fidl_common::MacSublayerSupport, zx::Status>>;
107 fn security_support(
108 &mut self,
109 ) -> impl Future<Output = Result<fidl_common::SecuritySupport, zx::Status>>;
110 fn spectrum_management_support(
111 &mut self,
112 ) -> impl Future<Output = Result<fidl_common::SpectrumManagementSupport, zx::Status>>;
113 fn start(
114 &mut self,
115 ifc_bridge: fidl::endpoints::ClientEnd<fidl_softmac::WlanSoftmacIfcBridgeMarker>,
116 ethernet_tx: EthernetTx,
117 wlan_rx: WlanRx,
118 ) -> impl Future<Output = Result<fidl::Channel, zx::Status>>;
119 fn deliver_eth_frame(&mut self, packet: &[u8]) -> Result<(), zx::Status>;
120 fn send_wlan_frame(
124 &mut self,
125 buffer: ArenaStaticBox<[u8]>,
126 tx_flags: fidl_softmac::WlanTxInfoFlags,
127 async_id: Option<TraceId>,
128 ) -> Result<(), zx::Status>;
129
130 fn set_ethernet_status(
131 &mut self,
132 status: LinkStatus,
133 ) -> impl Future<Output = Result<(), zx::Status>>;
134 fn set_ethernet_up(&mut self) -> impl Future<Output = Result<(), zx::Status>> {
135 self.set_ethernet_status(LinkStatus::UP)
136 }
137 fn set_ethernet_down(&mut self) -> impl Future<Output = Result<(), zx::Status>> {
138 self.set_ethernet_status(LinkStatus::DOWN)
139 }
140 fn set_channel(
141 &mut self,
142 channel: fidl_ieee80211::ChannelNumber,
143 cbw: fidl_ieee80211::ChannelBandwidth,
144 secondary80: fidl_ieee80211::ChannelNumber,
145 ) -> impl Future<Output = Result<(), zx::Status>>;
146 fn set_mac_address(
147 &mut self,
148 mac_addr: fidl_ieee80211::MacAddr,
149 ) -> impl Future<Output = Result<(), zx::Status>>;
150 fn start_passive_scan(
151 &mut self,
152 request: &fidl_softmac::WlanSoftmacBaseStartPassiveScanRequest,
153 ) -> impl Future<Output = Result<fidl_softmac::WlanSoftmacBaseStartPassiveScanResponse, zx::Status>>;
154 fn start_active_scan(
155 &mut self,
156 request: &fidl_softmac::WlanSoftmacStartActiveScanRequest,
157 ) -> impl Future<Output = Result<fidl_softmac::WlanSoftmacBaseStartActiveScanResponse, zx::Status>>;
158 fn cancel_scan(
159 &mut self,
160 request: &fidl_softmac::WlanSoftmacBaseCancelScanRequest,
161 ) -> impl Future<Output = Result<(), zx::Status>>;
162 fn join_bss(
163 &mut self,
164 request: &fidl_driver_common::JoinBssRequest,
165 ) -> impl Future<Output = Result<(), zx::Status>>;
166 fn enable_beaconing(
167 &mut self,
168 request: fidl_softmac::WlanSoftmacBaseEnableBeaconingRequest,
169 ) -> impl Future<Output = Result<(), zx::Status>>;
170 fn disable_beaconing(&mut self) -> impl Future<Output = Result<(), zx::Status>>;
171 fn install_key(
172 &mut self,
173 key_configuration: &fidl_softmac::WlanKeyConfiguration,
174 ) -> impl Future<Output = Result<(), zx::Status>>;
175 fn notify_association_complete(
176 &mut self,
177 assoc_cfg: fidl_softmac::WlanAssociationConfig,
178 ) -> impl Future<Output = Result<(), zx::Status>>;
179 fn clear_association(
180 &mut self,
181 request: &fidl_softmac::WlanSoftmacBaseClearAssociationRequest,
182 ) -> impl Future<Output = Result<(), zx::Status>>;
183 fn update_wmm_parameters(
184 &mut self,
185 request: &fidl_softmac::WlanSoftmacBaseUpdateWmmParametersRequest,
186 ) -> impl Future<Output = Result<(), zx::Status>>;
187 fn take_mlme_event_stream(&mut self) -> Option<mpsc::UnboundedReceiver<fidl_mlme::MlmeEvent>>;
188 fn send_mlme_event(&mut self, event: fidl_mlme::MlmeEvent) -> Result<(), anyhow::Error>;
189 fn set_minstrel(&mut self, minstrel: crate::MinstrelWrapper);
190 fn minstrel(&mut self) -> Option<crate::MinstrelWrapper>;
191 fn tx_vector_idx(
192 &mut self,
193 frame_control: &FrameControl,
194 peer_addr: &MacAddr,
195 flags: fidl_softmac::WlanTxInfoFlags,
196 ) -> tx_vector::TxVecIdx {
197 self.minstrel()
198 .as_ref()
199 .and_then(|minstrel| {
200 minstrel.lock().get_tx_vector_idx(frame_control, &peer_addr, flags)
201 })
202 .unwrap_or_else(|| {
203 let mcs_idx = if frame_control.is_data() { 7 } else { 3 };
211 tx_vector::TxVector::new(
212 fidl_ieee80211::WlanPhyType::Erp,
213 WlanGi::G_800NS,
214 fidl_ieee80211::ChannelBandwidth::Cbw20,
215 mcs_idx,
216 )
217 .unwrap()
218 .to_idx()
219 })
220 }
221}
222
223pub async fn try_query(
224 device: &mut impl DeviceOps,
225) -> Result<fidl_softmac::WlanSoftmacQueryResponse, Error> {
226 device
227 .wlan_softmac_query_response()
228 .await
229 .map_err(|status| Error::Status(String::from("Failed to query device."), status))
230}
231
232pub async fn try_query_iface_mac(device: &mut impl DeviceOps) -> Result<MacAddr, Error> {
233 try_query(device).await.and_then(|query_response| {
234 query_response.sta_addr.map(From::from).ok_or_else(|| {
235 Error::Internal(format_err!(
236 "Required field not set in device query response: iface MAC"
237 ))
238 })
239 })
240}
241
242pub async fn try_query_discovery_support(
243 device: &mut impl DeviceOps,
244) -> Result<fidl_softmac::DiscoverySupport, Error> {
245 device.discovery_support().await.map_err(|status| {
246 Error::Status(String::from("Failed to query discovery support for device."), status)
247 })
248}
249
250pub async fn try_query_mac_sublayer_support(
251 device: &mut impl DeviceOps,
252) -> Result<fidl_common::MacSublayerSupport, Error> {
253 device.mac_sublayer_support().await.map_err(|status| {
254 Error::Status(String::from("Failed to query MAC sublayer support for device."), status)
255 })
256}
257
258pub async fn try_query_security_support(
259 device: &mut impl DeviceOps,
260) -> Result<fidl_common::SecuritySupport, Error> {
261 device.security_support().await.map_err(|status| {
262 Error::Status(String::from("Failed to query security support for device."), status)
263 })
264}
265
266pub async fn try_query_spectrum_management_support(
267 device: &mut impl DeviceOps,
268) -> Result<fidl_common::SpectrumManagementSupport, Error> {
269 device.spectrum_management_support().await.map_err(|status| {
270 Error::Status(
271 String::from("Failed to query spectrum management support for device."),
272 status,
273 )
274 })
275}
276
277impl DeviceOps for Device {
278 async fn wlan_softmac_query_response(
279 &mut self,
280 ) -> Result<fidl_softmac::WlanSoftmacQueryResponse, zx::Status> {
281 Self::flatten_and_log_error("Query", self.wlan_softmac_bridge_proxy.query().await)
282 }
283
284 async fn discovery_support(&mut self) -> Result<fidl_softmac::DiscoverySupport, zx::Status> {
285 Self::flatten_and_log_error(
286 "QueryDiscoverySupport",
287 self.wlan_softmac_bridge_proxy.query_discovery_support().await,
288 )
289 }
290
291 async fn mac_sublayer_support(
292 &mut self,
293 ) -> Result<fidl_common::MacSublayerSupport, zx::Status> {
294 Self::flatten_and_log_error(
295 "QueryMacSublayerSupport",
296 self.wlan_softmac_bridge_proxy.query_mac_sublayer_support().await,
297 )
298 }
299
300 async fn security_support(&mut self) -> Result<fidl_common::SecuritySupport, zx::Status> {
301 Self::flatten_and_log_error(
302 "QuerySecuritySupport",
303 self.wlan_softmac_bridge_proxy.query_security_support().await,
304 )
305 }
306
307 async fn spectrum_management_support(
308 &mut self,
309 ) -> Result<fidl_common::SpectrumManagementSupport, zx::Status> {
310 Self::flatten_and_log_error(
311 "QuerySpectrumManagementSupport",
312 self.wlan_softmac_bridge_proxy.query_spectrum_management_support().await,
313 )
314 }
315
316 async fn start(
317 &mut self,
318 ifc_bridge: fidl::endpoints::ClientEnd<fidl_softmac::WlanSoftmacIfcBridgeMarker>,
319 ethernet_tx: EthernetTx,
320 wlan_rx: WlanRx,
321 ) -> Result<fidl::Channel, zx::Status> {
322 let mut ffi_ethernet_tx = unsafe { ethernet_tx.to_ffi() };
329 let mut ffi_wlan_rx = unsafe { wlan_rx.to_ffi() };
330
331 let ffi_ethernet_tx = &mut ffi_ethernet_tx;
335 let ffi_wlan_rx = &mut ffi_wlan_rx;
336
337 self.ethernet_tx = Some(ethernet_tx);
338 self.wlan_rx = Some(wlan_rx);
339
340 self.wlan_softmac_bridge_proxy
341 .start(
342 ifc_bridge,
343 ffi_ethernet_tx as *mut FfiEthernetTx as u64,
344 ffi_wlan_rx as *mut FfiWlanRx as u64,
345 )
346 .await
347 .map_err(|error| {
348 error!("Start failed with FIDL error: {:?}", error);
349 zx::Status::INTERNAL
350 })?
351 .map_err(zx::Status::from_raw)
352 }
353
354 fn deliver_eth_frame(&mut self, packet: &[u8]) -> Result<(), zx::Status> {
355 wtrace::duration!("Device::deliver_eth_frame");
356 self.ethernet_rx.transfer(&fidl_softmac::EthernetRxTransferRequest {
357 packet_address: Some(packet.as_ptr() as u64),
358 packet_size: Some(packet.len() as u64),
359 ..Default::default()
360 })
361 }
362
363 fn send_wlan_frame(
364 &mut self,
365 buffer: ArenaStaticBox<[u8]>,
366 mut tx_flags: fidl_softmac::WlanTxInfoFlags,
367 async_id: Option<TraceId>,
368 ) -> Result<(), zx::Status> {
369 let async_id_provided = async_id.is_some();
370 let async_id = async_id.unwrap_or_else(|| {
371 let async_id = TraceId::new();
372 wtrace::async_begin_wlansoftmac_tx(async_id, "mlme");
373 async_id
374 });
375 wtrace::duration!("Device::send_data_frame");
376
377 let (arena, mut buffer) = ArenaStaticBox::into_raw(buffer);
378
379 let buffer = unsafe { buffer.as_mut() };
382 if buffer.len() < REQUIRED_WLAN_HEADER_LEN {
383 let status = zx::Status::BUFFER_TOO_SMALL;
384 if !async_id_provided {
385 wtrace::async_end_wlansoftmac_tx(async_id, status);
386 }
387 return Err(status);
388 }
389 const _: () =
391 assert!(mem::size_of::<FrameControl>() == 2, "Size of FrameControl is not 2 bytes");
392 let frame_control = zerocopy::Ref::into_ref(
393 zerocopy::Ref::<&[u8], FrameControl>::from_bytes(&buffer[0..=1]).unwrap(),
394 );
395 if frame_control.protected() {
396 tx_flags |= fidl_softmac::WlanTxInfoFlags::PROTECTED;
397 }
398 let peer_addr: MacAddr = {
399 let mut peer_addr = [0u8; 6];
400 peer_addr.copy_from_slice(&buffer[PEER_ADDR_OFFSET..PEER_ADDR_OFFSET + 6]);
402 peer_addr.into()
403 };
404 let tx_vector_idx = self.tx_vector_idx(frame_control, &peer_addr, tx_flags);
405
406 let tx_info = wlan_common::tx_vector::TxVector::from_idx(tx_vector_idx)
407 .to_fidl_tx_info(tx_flags, self.minstrel.is_some());
408 let packet_address = Some(buffer.as_ptr() as *mut u8 as u64);
409 let packet_size = Some(buffer.len() as u64);
410
411 self.wlan_tx
412 .transfer(&fidl_softmac::WlanTxTransferRequest {
413 arena: Some(arena.as_ptr() as u64),
414 packet_size,
415 packet_address,
416 packet_info: Some(tx_info),
417 async_id: Some(async_id.into()),
418 ..Default::default()
419 })
420 .map_err(|s| {
421 if !async_id_provided {
422 wtrace::async_end_wlansoftmac_tx(async_id, s);
423 }
424 s
425 })
426 }
427
428 async fn set_ethernet_status(&mut self, status: LinkStatus) -> Result<(), zx::Status> {
429 self.wlan_softmac_bridge_proxy.set_ethernet_status(status.0).await.map_err(|error| {
430 error!("SetEthernetStatus failed with FIDL error: {:?}", error);
431 zx::Status::INTERNAL
432 })
433 }
434
435 async fn set_channel(
436 &mut self,
437 channel: fidl_ieee80211::ChannelNumber,
438 cbw: fidl_ieee80211::ChannelBandwidth,
439 secondary80: fidl_ieee80211::ChannelNumber,
440 ) -> Result<(), zx::Status> {
441 self.wlan_softmac_bridge_proxy
442 .set_channel(&fidl_softmac::WlanSoftmacBaseSetChannelRequest {
443 primary: Some(channel),
444 bandwidth: Some(cbw),
445 vht_secondary_80_channel: Some(secondary80),
446 ..Default::default()
447 })
448 .await
449 .map_err(|error| {
450 error!("SetChannel failed with FIDL error: {:?}", error);
451 zx::Status::INTERNAL
452 })?
453 .map_err(zx::Status::from_raw)
454 }
455
456 async fn set_mac_address(
460 &mut self,
461 _mac_addr: fidl_fuchsia_wlan_ieee80211::MacAddr,
462 ) -> Result<(), zx::Status> {
463 Err(zx::Status::NOT_SUPPORTED)
464 }
465
466 async fn start_passive_scan(
467 &mut self,
468 request: &fidl_softmac::WlanSoftmacBaseStartPassiveScanRequest,
469 ) -> Result<fidl_softmac::WlanSoftmacBaseStartPassiveScanResponse, zx::Status> {
470 Self::flatten_and_log_error(
471 "StartPassiveScan",
472 self.wlan_softmac_bridge_proxy.start_passive_scan(request).await,
473 )
474 }
475
476 async fn start_active_scan(
477 &mut self,
478 request: &fidl_softmac::WlanSoftmacStartActiveScanRequest,
479 ) -> Result<fidl_softmac::WlanSoftmacBaseStartActiveScanResponse, zx::Status> {
480 Self::flatten_and_log_error(
481 "StartActiveScan",
482 self.wlan_softmac_bridge_proxy.start_active_scan(request).await,
483 )
484 }
485
486 async fn cancel_scan(
487 &mut self,
488 request: &fidl_softmac::WlanSoftmacBaseCancelScanRequest,
489 ) -> Result<(), zx::Status> {
490 Self::flatten_and_log_error(
491 "CancelScan",
492 self.wlan_softmac_bridge_proxy.cancel_scan(request).await,
493 )
494 }
495
496 async fn join_bss(
497 &mut self,
498 request: &fidl_driver_common::JoinBssRequest,
499 ) -> Result<(), zx::Status> {
500 Self::flatten_and_log_error(
501 "JoinBss",
502 self.wlan_softmac_bridge_proxy.join_bss(request).await,
503 )
504 }
505
506 async fn enable_beaconing(
507 &mut self,
508 request: fidl_softmac::WlanSoftmacBaseEnableBeaconingRequest,
509 ) -> Result<(), zx::Status> {
510 self.wlan_softmac_bridge_proxy
511 .enable_beaconing(&request)
512 .await
513 .map_err(|error| {
514 error!("FIDL error during EnableBeaconing: {:?}", error);
515 zx::Status::INTERNAL
516 })?
517 .map_err(zx::Status::from_raw)
518 }
519
520 async fn disable_beaconing(&mut self) -> Result<(), zx::Status> {
521 self.wlan_softmac_bridge_proxy
522 .disable_beaconing()
523 .await
524 .map_err(|error| {
525 error!("DisableBeaconing failed with FIDL error: {:?}", error);
526 zx::Status::INTERNAL
527 })?
528 .map_err(zx::Status::from_raw)
529 }
530
531 async fn install_key(
532 &mut self,
533 key_configuration: &fidl_softmac::WlanKeyConfiguration,
534 ) -> Result<(), zx::Status> {
535 self.wlan_softmac_bridge_proxy
536 .install_key(&key_configuration)
537 .await
538 .map_err(|error| {
539 error!("FIDL error during InstallKey: {:?}", error);
540 zx::Status::INTERNAL
541 })?
542 .map_err(zx::Status::from_raw)
543 }
544
545 async fn notify_association_complete(
546 &mut self,
547 assoc_cfg: fidl_softmac::WlanAssociationConfig,
548 ) -> Result<(), zx::Status> {
549 if let Some(minstrel) = &self.minstrel {
550 minstrel.lock().add_peer(&assoc_cfg)?;
551 }
552 Self::flatten_and_log_error(
553 "NotifyAssociationComplete",
554 self.wlan_softmac_bridge_proxy.notify_association_complete(&assoc_cfg).await,
555 )
556 }
557
558 async fn clear_association(
559 &mut self,
560 request: &fidl_softmac::WlanSoftmacBaseClearAssociationRequest,
561 ) -> Result<(), zx::Status> {
562 let addr: MacAddr = request
563 .peer_addr
564 .ok_or_else(|| {
565 error!("ClearAssociation called with no peer_addr field.");
566 zx::Status::INVALID_ARGS
567 })?
568 .into();
569 if let Some(minstrel) = &self.minstrel {
570 minstrel.lock().remove_peer(&addr);
571 }
572 Self::flatten_and_log_error(
573 "ClearAssociation",
574 self.wlan_softmac_bridge_proxy.clear_association(request).await,
575 )
576 }
577
578 async fn update_wmm_parameters(
579 &mut self,
580 request: &fidl_softmac::WlanSoftmacBaseUpdateWmmParametersRequest,
581 ) -> Result<(), zx::Status> {
582 Self::flatten_and_log_error(
583 "UpdateWmmParameters",
584 self.wlan_softmac_bridge_proxy.update_wmm_parameters(request).await,
585 )
586 }
587
588 fn take_mlme_event_stream(&mut self) -> Option<mpsc::UnboundedReceiver<fidl_mlme::MlmeEvent>> {
589 self.event_receiver.take()
590 }
591
592 fn send_mlme_event(&mut self, event: fidl_mlme::MlmeEvent) -> Result<(), anyhow::Error> {
593 self.event_sink.unbounded_send(event).map_err(|e| e.into())
594 }
595
596 fn set_minstrel(&mut self, minstrel: crate::MinstrelWrapper) {
597 self.minstrel.replace(minstrel);
598 }
599
600 fn minstrel(&mut self) -> Option<crate::MinstrelWrapper> {
601 self.minstrel.as_ref().map(Arc::clone)
602 }
603}
604
605pub mod test_utils {
606 use super::*;
607 use crate::ddk_converter;
608 use fidl_fuchsia_wlan_common as fidl_common;
609 use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
610 use fidl_fuchsia_wlan_internal as fidl_internal;
611 use fidl_fuchsia_wlan_sme as fidl_sme;
612 use fuchsia_sync::Mutex;
613 use paste::paste;
614 use std::collections::VecDeque;
615
616 pub trait FromMlmeEvent {
617 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self>
618 where
619 Self: std::marker::Sized;
620 }
621
622 impl FromMlmeEvent for fidl_mlme::AuthenticateIndication {
623 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self> {
624 event.into_authenticate_ind()
625 }
626 }
627
628 impl FromMlmeEvent for fidl_mlme::AssociateIndication {
629 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self> {
630 event.into_associate_ind()
631 }
632 }
633
634 impl FromMlmeEvent for fidl_mlme::ConnectConfirm {
635 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self> {
636 event.into_connect_conf()
637 }
638 }
639
640 impl FromMlmeEvent for fidl_mlme::StartConfirm {
641 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self> {
642 event.into_start_conf()
643 }
644 }
645
646 impl FromMlmeEvent for fidl_mlme::StopConfirm {
647 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self> {
648 event.into_stop_conf()
649 }
650 }
651
652 impl FromMlmeEvent for fidl_mlme::ScanResult {
653 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self> {
654 event.into_on_scan_result()
655 }
656 }
657
658 impl FromMlmeEvent for fidl_mlme::ScanEnd {
659 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self> {
660 event.into_on_scan_end()
661 }
662 }
663
664 impl FromMlmeEvent for fidl_mlme::EapolConfirm {
665 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self> {
666 event.into_eapol_conf()
667 }
668 }
669
670 impl FromMlmeEvent for fidl_mlme::EapolIndication {
671 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self> {
672 event.into_eapol_ind()
673 }
674 }
675
676 impl FromMlmeEvent for fidl_mlme::DeauthenticateConfirm {
677 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self> {
678 event.into_deauthenticate_conf()
679 }
680 }
681
682 impl FromMlmeEvent for fidl_mlme::DeauthenticateIndication {
683 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self> {
684 event.into_deauthenticate_ind()
685 }
686 }
687
688 impl FromMlmeEvent for fidl_mlme::DisassociateIndication {
689 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self> {
690 event.into_disassociate_ind()
691 }
692 }
693
694 impl FromMlmeEvent for fidl_mlme::SetKeysConfirm {
695 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self> {
696 event.into_set_keys_conf()
697 }
698 }
699
700 impl FromMlmeEvent for fidl_internal::SignalReportIndication {
701 fn from_event(event: fidl_mlme::MlmeEvent) -> Option<Self> {
702 event.into_signal_report()
703 }
704 }
705
706 pub struct FakeDeviceConfig {
707 mock_query_response: Option<Result<fidl_softmac::WlanSoftmacQueryResponse, zx::Status>>,
708 mock_discovery_support: Option<Result<fidl_softmac::DiscoverySupport, zx::Status>>,
709 mock_mac_sublayer_support: Option<Result<fidl_common::MacSublayerSupport, zx::Status>>,
710 mock_security_support: Option<Result<fidl_common::SecuritySupport, zx::Status>>,
711 mock_spectrum_management_support:
712 Option<Result<fidl_common::SpectrumManagementSupport, zx::Status>>,
713 mock_start_result: Option<Result<fidl::Channel, zx::Status>>,
714 pub start_passive_scan_fails: bool,
715 pub start_active_scan_fails: bool,
716 pub send_wlan_frame_fails: bool,
717 }
718
719 impl Default for FakeDeviceConfig {
720 fn default() -> Self {
721 Self {
722 mock_start_result: None,
723 mock_query_response: None,
724 mock_discovery_support: None,
725 mock_mac_sublayer_support: None,
726 mock_security_support: None,
727 mock_spectrum_management_support: None,
728 start_passive_scan_fails: false,
729 start_active_scan_fails: false,
730 send_wlan_frame_fails: false,
731 }
732 }
733 }
734
735 macro_rules! with_mock_func {
739 ( $mock_name: ident, $mock_type: path ) => {
740 paste! {
741 pub fn [<with_mock_ $mock_name>](
742 mut self,
743 mock_value: Result<$mock_type, zx::Status>
744 ) -> Self {
745 self.[<mock_ $mock_name>] = Some(mock_value);
746 self
747 }
748 }
749 };
750 }
751
752 impl FakeDeviceConfig {
753 with_mock_func!(query_response, fidl_softmac::WlanSoftmacQueryResponse);
754 with_mock_func!(discovery_support, fidl_softmac::DiscoverySupport);
755 with_mock_func!(mac_sublayer_support, fidl_common::MacSublayerSupport);
756 with_mock_func!(security_support, fidl_common::SecuritySupport);
757 with_mock_func!(spectrum_management_support, fidl_common::SpectrumManagementSupport);
758 with_mock_func!(start_result, fidl::Channel);
759
760 pub fn with_mock_sta_addr(mut self, mock_field: [u8; 6]) -> Self {
761 if let None = self.mock_query_response {
762 let mut mock_value = Self::default_mock_query_response();
763 mock_value.as_mut().unwrap().sta_addr = Some(mock_field);
764 return self.with_mock_query_response(mock_value);
765 }
766 let mock_value = self
767 .mock_query_response
768 .as_mut()
769 .unwrap()
770 .as_mut()
771 .expect("Cannot overwrite an Err value mock");
772 mock_value.sta_addr = Some(mock_field);
773 self
774 }
775
776 pub fn with_mock_mac_role(mut self, mock_field: fidl_common::WlanMacRole) -> Self {
777 if let None = self.mock_query_response {
778 let mut mock_value = Self::default_mock_query_response();
779 mock_value.as_mut().unwrap().mac_role = Some(mock_field);
780 return self.with_mock_query_response(mock_value);
781 }
782 let mock_value = self
783 .mock_query_response
784 .as_mut()
785 .unwrap()
786 .as_mut()
787 .expect("Cannot overwrite an Err value mock");
788 mock_value.mac_role = Some(mock_field);
789 self
790 }
791
792 fn default_mock_query_response()
793 -> Result<fidl_softmac::WlanSoftmacQueryResponse, zx::Status> {
794 Ok(fidl_softmac::WlanSoftmacQueryResponse {
795 sta_addr: Some([7u8; 6]),
796 mac_role: Some(fidl_common::WlanMacRole::Client),
797 supported_phys: Some(vec![
798 fidl_ieee80211::WlanPhyType::Dsss,
799 fidl_ieee80211::WlanPhyType::Hr,
800 fidl_ieee80211::WlanPhyType::Ofdm,
801 fidl_ieee80211::WlanPhyType::Erp,
802 fidl_ieee80211::WlanPhyType::Ht,
803 fidl_ieee80211::WlanPhyType::Vht,
804 ]),
805 hardware_capability: Some(0),
806 band_caps: Some(fake_band_caps()),
807 factory_addr: Some([7u8; 6]),
808 ..Default::default()
809 })
810 }
811
812 pub fn with_mock_probe_response_offload(
813 mut self,
814 mock_field: fidl_softmac::ProbeResponseOffloadExtension,
815 ) -> Self {
816 if let None = self.mock_discovery_support {
817 let mut mock_value = Self::default_mock_discovery_support();
818 mock_value.as_mut().unwrap().probe_response_offload = Some(mock_field);
819 return self.with_mock_discovery_support(mock_value);
820 }
821 let mock_value = self
822 .mock_discovery_support
823 .as_mut()
824 .unwrap()
825 .as_mut()
826 .expect("Cannot overwrite an Err value mock");
827 mock_value.probe_response_offload = Some(mock_field);
828 self
829 }
830
831 fn default_mock_discovery_support() -> Result<fidl_softmac::DiscoverySupport, zx::Status> {
832 Ok(fidl_softmac::DiscoverySupport {
833 scan_offload: Some(fidl_softmac::ScanOffloadExtension {
834 supported: Some(true),
835 scan_cancel_supported: Some(false),
836 ..Default::default()
837 }),
838 probe_response_offload: Some(fidl_softmac::ProbeResponseOffloadExtension {
839 supported: Some(false),
840 ..Default::default()
841 }),
842 ..Default::default()
843 })
844 }
845
846 pub fn with_mock_mac_implementation_type(
847 mut self,
848 mock_field: fidl_common::MacImplementationType,
849 ) -> Self {
850 if let None = self.mock_mac_sublayer_support {
851 let mut mock_value = Self::default_mock_mac_sublayer_support();
852 mock_value.as_mut().unwrap().device.as_mut().unwrap().mac_implementation_type =
853 Some(mock_field);
854 return self.with_mock_mac_sublayer_support(mock_value);
855 }
856 let mock_value = self
857 .mock_mac_sublayer_support
858 .as_mut()
859 .unwrap()
860 .as_mut()
861 .expect("Cannot overwrite an Err value mock");
862 mock_value.device.as_mut().unwrap().mac_implementation_type = Some(mock_field);
863 self
864 }
865
866 fn default_mock_mac_sublayer_support() -> Result<fidl_common::MacSublayerSupport, zx::Status>
867 {
868 Ok(fidl_common::MacSublayerSupport {
869 rate_selection_offload: Some(fidl_common::RateSelectionOffloadExtension {
870 supported: Some(false),
871 ..Default::default()
872 }),
873 data_plane: Some(fidl_common::DataPlaneExtension {
874 data_plane_type: Some(fidl_common::DataPlaneType::EthernetDevice),
875 ..Default::default()
876 }),
877 device: Some(fidl_common::DeviceExtension {
878 is_synthetic: Some(true),
879 mac_implementation_type: Some(fidl_common::MacImplementationType::Softmac),
880 tx_status_report_supported: Some(true),
881 ..Default::default()
882 }),
883 ..Default::default()
884 })
885 }
886 }
887
888 #[derive(Clone)]
891 pub struct FakeDevice {
892 state: Arc<Mutex<FakeDeviceState>>,
893 mlme_event_sink: mpsc::UnboundedSender<fidl_mlme::MlmeEvent>,
894 }
895
896 pub struct FakeDeviceState {
897 pub config: FakeDeviceConfig,
898 pub minstrel: Option<crate::MinstrelWrapper>,
899 pub eth_queue: Vec<Vec<u8>>,
900 pub wlan_queue: Vec<(Vec<u8>, usize)>,
901 pub wlan_softmac_ifc_bridge_proxy: Option<fidl_softmac::WlanSoftmacIfcBridgeProxy>,
902 pub mlme_event_stream: Option<mpsc::UnboundedReceiver<fidl_mlme::MlmeEvent>>,
903 pub mlme_request_sink: mpsc::UnboundedSender<wlan_sme::MlmeRequest>,
904 pub mlme_request_stream: Option<mpsc::UnboundedReceiver<wlan_sme::MlmeRequest>>,
905 pub usme_bootstrap_client_end:
906 Option<fidl::endpoints::ClientEnd<fidl_sme::UsmeBootstrapMarker>>,
907 pub usme_bootstrap_server_end:
908 Option<fidl::endpoints::ServerEnd<fidl_sme::UsmeBootstrapMarker>>,
909 pub wlan_channel: fidl_ieee80211::ChannelNumber,
910 pub cbw: fidl_ieee80211::ChannelBandwidth,
911 pub secondary80: fidl_ieee80211::ChannelNumber,
912 pub keys: Vec<fidl_softmac::WlanKeyConfiguration>,
913 pub next_scan_id: u64,
914 pub captured_passive_scan_request:
915 Option<fidl_softmac::WlanSoftmacBaseStartPassiveScanRequest>,
916 pub captured_active_scan_request: Option<fidl_softmac::WlanSoftmacStartActiveScanRequest>,
917
918 pub join_bss_request: Option<fidl_driver_common::JoinBssRequest>,
919 pub beacon_config: Option<(Vec<u8>, usize, TimeUnit)>,
920 pub link_status: LinkStatus,
921 pub assocs: std::collections::HashMap<MacAddr, fidl_softmac::WlanAssociationConfig>,
922 pub install_key_results: VecDeque<Result<(), zx::Status>>,
923 pub captured_update_wmm_parameters_request:
924 Option<fidl_softmac::WlanSoftmacBaseUpdateWmmParametersRequest>,
925 }
926
927 impl FakeDevice {
928 pub async fn new() -> (FakeDevice, Arc<Mutex<FakeDeviceState>>) {
932 Self::new_with_config(FakeDeviceConfig::default()).await
933 }
934
935 pub async fn new_with_config(
939 config: FakeDeviceConfig,
940 ) -> (FakeDevice, Arc<Mutex<FakeDeviceState>>) {
941 let (usme_bootstrap_client_end, usme_bootstrap_server_end) =
943 fidl::endpoints::create_endpoints::<fidl_sme::UsmeBootstrapMarker>();
944 let (mlme_event_sink, mlme_event_stream) = mpsc::unbounded();
945 let (mlme_request_sink, mlme_request_stream) = mpsc::unbounded();
946 let state = Arc::new(Mutex::new(FakeDeviceState {
947 config,
948 minstrel: None,
949 eth_queue: vec![],
950 wlan_queue: vec![],
951 wlan_softmac_ifc_bridge_proxy: None,
952 mlme_event_stream: Some(mlme_event_stream),
953 mlme_request_sink,
954 mlme_request_stream: Some(mlme_request_stream),
955 usme_bootstrap_client_end: Some(usme_bootstrap_client_end),
956 usme_bootstrap_server_end: Some(usme_bootstrap_server_end),
957 wlan_channel: fidl_ieee80211::ChannelNumber {
958 band: fidl_ieee80211::WlanBand::TwoGhz,
959 number: 0,
960 },
961 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
962 secondary80: fidl_ieee80211::ChannelNumber {
963 band: fidl_ieee80211::WlanBand::TwoGhz,
964 number: 0,
965 },
966 next_scan_id: 0,
967 captured_passive_scan_request: None,
968 captured_active_scan_request: None,
969 keys: vec![],
970 join_bss_request: None,
971 beacon_config: None,
972 link_status: LinkStatus::DOWN,
973 assocs: std::collections::HashMap::new(),
974 install_key_results: VecDeque::new(),
975 captured_update_wmm_parameters_request: None,
976 }));
977 (FakeDevice { state: state.clone(), mlme_event_sink }, state)
978 }
979
980 pub fn state(&self) -> Arc<Mutex<FakeDeviceState>> {
981 self.state.clone()
982 }
983 }
984
985 impl FakeDeviceState {
986 #[track_caller]
987 pub fn next_mlme_msg<T: FromMlmeEvent>(&mut self) -> Result<T, Error> {
988 self.mlme_event_stream
989 .as_mut()
990 .expect("no mlme event stream available")
991 .try_next()
992 .map_err(|e| anyhow::format_err!("Failed to read mlme event stream: {}", e))
993 .and_then(|opt_next| {
994 opt_next.ok_or_else(|| anyhow::format_err!("No message available"))
995 })
996 .and_then(|evt| {
997 T::from_event(evt).ok_or_else(|| anyhow::format_err!("Unexpected mlme event"))
998 })
999 .map_err(|e| e.into())
1000 }
1001
1002 pub fn reset(&mut self) {
1003 self.eth_queue.clear();
1004 }
1005 }
1006
1007 impl DeviceOps for FakeDevice {
1008 async fn wlan_softmac_query_response(
1009 &mut self,
1010 ) -> Result<fidl_softmac::WlanSoftmacQueryResponse, zx::Status> {
1011 let state = self.state.lock();
1012 match state.config.mock_query_response.as_ref() {
1013 Some(query_response) => query_response.clone(),
1014 None => FakeDeviceConfig::default_mock_query_response(),
1015 }
1016 }
1017
1018 async fn discovery_support(
1019 &mut self,
1020 ) -> Result<fidl_softmac::DiscoverySupport, zx::Status> {
1021 let state = self.state.lock();
1022 match state.config.mock_discovery_support.as_ref() {
1023 Some(discovery_support) => discovery_support.clone(),
1024 None => FakeDeviceConfig::default_mock_discovery_support(),
1025 }
1026 }
1027
1028 async fn mac_sublayer_support(
1029 &mut self,
1030 ) -> Result<fidl_common::MacSublayerSupport, zx::Status> {
1031 let state = self.state.lock();
1032 match state.config.mock_mac_sublayer_support.as_ref() {
1033 Some(mac_sublayer_support) => mac_sublayer_support.clone(),
1034 None => FakeDeviceConfig::default_mock_mac_sublayer_support(),
1035 }
1036 }
1037
1038 async fn security_support(&mut self) -> Result<fidl_common::SecuritySupport, zx::Status> {
1039 let state = self.state.lock();
1040 match state.config.mock_security_support.as_ref() {
1041 Some(security_support) => security_support.clone(),
1042 None => Ok(fidl_common::SecuritySupport {
1043 mfp: Some(fidl_common::MfpFeature {
1044 supported: Some(false),
1045 ..Default::default()
1046 }),
1047 sae: Some(fidl_common::SaeFeature {
1048 driver_handler_supported: Some(false),
1049 sme_handler_supported: Some(false),
1050 hash_to_element_supported: Some(false),
1051 ..Default::default()
1052 }),
1053 owe: Some(fidl_common::OweFeature {
1054 supported: Some(false),
1055 ..Default::default()
1056 }),
1057 ..Default::default()
1058 }),
1059 }
1060 }
1061
1062 async fn spectrum_management_support(
1063 &mut self,
1064 ) -> Result<fidl_common::SpectrumManagementSupport, zx::Status> {
1065 let state = self.state.lock();
1066 match state.config.mock_spectrum_management_support.as_ref() {
1067 Some(spectrum_management_support) => spectrum_management_support.clone(),
1068 None => Ok(fidl_common::SpectrumManagementSupport {
1069 dfs: Some(fidl_common::DfsFeature {
1070 supported: Some(true),
1071 ..Default::default()
1072 }),
1073 ..Default::default()
1074 }),
1075 }
1076 }
1077
1078 async fn start(
1079 &mut self,
1080 ifc_bridge: fidl::endpoints::ClientEnd<fidl_softmac::WlanSoftmacIfcBridgeMarker>,
1081 _ethernet_tx: EthernetTx,
1082 _wlan_rx: WlanRx,
1083 ) -> Result<fidl::Channel, zx::Status> {
1084 let mut state = self.state.lock();
1085
1086 if let Some(mock_start_result) = state.config.mock_start_result.take() {
1087 return mock_start_result;
1088 }
1089
1090 state.wlan_softmac_ifc_bridge_proxy = Some(ifc_bridge.into_proxy());
1091 Ok(state.usme_bootstrap_server_end.take().unwrap().into_channel())
1092 }
1093
1094 fn deliver_eth_frame(&mut self, packet: &[u8]) -> Result<(), zx::Status> {
1095 self.state.lock().eth_queue.push(packet.to_vec());
1096 Ok(())
1097 }
1098
1099 fn send_wlan_frame(
1100 &mut self,
1101 buffer: ArenaStaticBox<[u8]>,
1102 _tx_flags: fidl_softmac::WlanTxInfoFlags,
1103 _async_id: Option<TraceId>,
1104 ) -> Result<(), zx::Status> {
1105 let mut state = self.state.lock();
1106 if state.config.send_wlan_frame_fails {
1107 return Err(zx::Status::IO);
1108 }
1109 state.wlan_queue.push((buffer.to_vec(), 0));
1110 Ok(())
1111 }
1112
1113 async fn set_ethernet_status(&mut self, status: LinkStatus) -> Result<(), zx::Status> {
1114 self.state.lock().link_status = status;
1115 Ok(())
1116 }
1117
1118 async fn set_channel(
1119 &mut self,
1120 wlan_channel: fidl_ieee80211::ChannelNumber,
1121 cbw: fidl_ieee80211::ChannelBandwidth,
1122 secondary80: fidl_ieee80211::ChannelNumber,
1123 ) -> Result<(), zx::Status> {
1124 let mut state = self.state.lock();
1125 state.wlan_channel = wlan_channel;
1126 state.cbw = cbw;
1127 state.secondary80 = secondary80;
1128 Ok(())
1129 }
1130
1131 async fn set_mac_address(
1132 &mut self,
1133 _mac_addr: fidl_fuchsia_wlan_ieee80211::MacAddr,
1134 ) -> Result<(), zx::Status> {
1135 Err(zx::Status::NOT_SUPPORTED)
1136 }
1137
1138 async fn start_passive_scan(
1139 &mut self,
1140 request: &fidl_softmac::WlanSoftmacBaseStartPassiveScanRequest,
1141 ) -> Result<fidl_softmac::WlanSoftmacBaseStartPassiveScanResponse, zx::Status> {
1142 let mut state = self.state.lock();
1143 if state.config.start_passive_scan_fails {
1144 return Err(zx::Status::NOT_SUPPORTED);
1145 }
1146 let scan_id = state.next_scan_id;
1147 state.next_scan_id += 1;
1148 state.captured_passive_scan_request.replace(request.clone());
1149 Ok(fidl_softmac::WlanSoftmacBaseStartPassiveScanResponse {
1150 scan_id: Some(scan_id),
1151 ..Default::default()
1152 })
1153 }
1154
1155 async fn start_active_scan(
1156 &mut self,
1157 request: &fidl_softmac::WlanSoftmacStartActiveScanRequest,
1158 ) -> Result<fidl_softmac::WlanSoftmacBaseStartActiveScanResponse, zx::Status> {
1159 let mut state = self.state.lock();
1160 if state.config.start_active_scan_fails {
1161 return Err(zx::Status::NOT_SUPPORTED);
1162 }
1163 let scan_id = state.next_scan_id;
1164 state.next_scan_id += 1;
1165 state.captured_active_scan_request.replace(request.clone());
1166 Ok(fidl_softmac::WlanSoftmacBaseStartActiveScanResponse {
1167 scan_id: Some(scan_id),
1168 ..Default::default()
1169 })
1170 }
1171
1172 async fn cancel_scan(
1173 &mut self,
1174 _request: &fidl_softmac::WlanSoftmacBaseCancelScanRequest,
1175 ) -> Result<(), zx::Status> {
1176 Err(zx::Status::NOT_SUPPORTED)
1177 }
1178
1179 async fn join_bss(
1180 &mut self,
1181 request: &fidl_driver_common::JoinBssRequest,
1182 ) -> Result<(), zx::Status> {
1183 self.state.lock().join_bss_request.replace(request.clone());
1184 Ok(())
1185 }
1186
1187 async fn enable_beaconing(
1188 &mut self,
1189 request: fidl_softmac::WlanSoftmacBaseEnableBeaconingRequest,
1190 ) -> Result<(), zx::Status> {
1191 match (request.packet_template, request.tim_ele_offset, request.beacon_interval) {
1192 (Some(packet_template), Some(tim_ele_offset), Some(beacon_interval)) => Ok({
1193 self.state.lock().beacon_config = Some((
1194 packet_template.mac_frame,
1195 usize::try_from(tim_ele_offset).map_err(|_| zx::Status::INTERNAL)?,
1196 TimeUnit(beacon_interval),
1197 ));
1198 }),
1199 _ => Err(zx::Status::INVALID_ARGS),
1200 }
1201 }
1202
1203 async fn disable_beaconing(&mut self) -> Result<(), zx::Status> {
1204 self.state.lock().beacon_config = None;
1205 Ok(())
1206 }
1207
1208 async fn install_key(
1209 &mut self,
1210 key_configuration: &fidl_softmac::WlanKeyConfiguration,
1211 ) -> Result<(), zx::Status> {
1212 let mut state = self.state.lock();
1213 state.keys.push(key_configuration.clone());
1214 state.install_key_results.pop_front().unwrap_or(Ok(()))
1215 }
1216
1217 async fn notify_association_complete(
1218 &mut self,
1219 cfg: fidl_softmac::WlanAssociationConfig,
1220 ) -> Result<(), zx::Status> {
1221 let mut state = self.state.lock();
1222 if let Some(minstrel) = &state.minstrel {
1223 minstrel.lock().add_peer(&cfg)?
1224 }
1225 state.assocs.insert(cfg.bssid.unwrap().into(), cfg);
1226 Ok(())
1227 }
1228
1229 async fn clear_association(
1230 &mut self,
1231 request: &fidl_softmac::WlanSoftmacBaseClearAssociationRequest,
1232 ) -> Result<(), zx::Status> {
1233 let addr: MacAddr = request.peer_addr.unwrap().into();
1234 let mut state = self.state.lock();
1235 if let Some(minstrel) = &state.minstrel {
1236 minstrel.lock().remove_peer(&addr);
1237 }
1238 state.assocs.remove(&addr);
1239 state.join_bss_request = None;
1240 Ok(())
1241 }
1242
1243 async fn update_wmm_parameters(
1244 &mut self,
1245 request: &fidl_softmac::WlanSoftmacBaseUpdateWmmParametersRequest,
1246 ) -> Result<(), zx::Status> {
1247 let mut state = self.state.lock();
1248 state.captured_update_wmm_parameters_request.replace(request.clone());
1249 Ok(())
1250 }
1251
1252 fn take_mlme_event_stream(
1253 &mut self,
1254 ) -> Option<mpsc::UnboundedReceiver<fidl_mlme::MlmeEvent>> {
1255 self.state.lock().mlme_event_stream.take()
1256 }
1257
1258 fn send_mlme_event(&mut self, event: fidl_mlme::MlmeEvent) -> Result<(), anyhow::Error> {
1259 self.mlme_event_sink.unbounded_send(event).map_err(|e| e.into())
1260 }
1261
1262 fn set_minstrel(&mut self, minstrel: crate::MinstrelWrapper) {
1263 self.state.lock().minstrel.replace(minstrel);
1264 }
1265
1266 fn minstrel(&mut self) -> Option<crate::MinstrelWrapper> {
1267 self.state.lock().minstrel.as_ref().map(Arc::clone)
1268 }
1269 }
1270
1271 pub fn fake_band_caps() -> Vec<fidl_softmac::WlanSoftmacBandCapability> {
1272 vec![
1273 fidl_softmac::WlanSoftmacBandCapability {
1274 band: Some(fidl_ieee80211::WlanBand::TwoGhz),
1275 basic_rates: Some(vec![
1276 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
1277 ]),
1278 primary_channels: Some(
1279 (1..=14)
1280 .map(|c| fidl_ieee80211::ChannelNumber {
1281 band: fidl_ieee80211::WlanBand::TwoGhz,
1282 number: c,
1283 })
1284 .collect(),
1285 ),
1286 ht_caps: Some(fidl_ieee80211::HtCapabilities {
1287 bytes: [
1288 0x63, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1291 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ],
1297 }),
1298 vht_caps: None,
1299 ..Default::default()
1300 },
1301 fidl_softmac::WlanSoftmacBandCapability {
1302 band: Some(fidl_ieee80211::WlanBand::FiveGhz),
1303 basic_rates: Some(vec![0x02, 0x04, 0x0b, 0x16, 0x30, 0x60, 0x7e, 0x7f]),
1304 primary_channels: Some(
1305 [36, 40, 44, 48, 149, 153, 157, 161]
1306 .into_iter()
1307 .map(|c| fidl_ieee80211::ChannelNumber {
1308 band: fidl_ieee80211::WlanBand::FiveGhz,
1309 number: c,
1310 })
1311 .collect(),
1312 ),
1313 ht_caps: Some(fidl_ieee80211::HtCapabilities {
1314 bytes: [
1315 0x63, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1318 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ],
1324 }),
1325 vht_caps: Some(fidl_ieee80211::VhtCapabilities {
1326 bytes: [0x32, 0x50, 0x80, 0x0f, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00],
1327 }),
1328 ..Default::default()
1329 },
1330 ]
1331 }
1332
1333 pub fn fake_mlme_band_caps() -> Vec<fidl_mlme::BandCapability> {
1334 fake_band_caps()
1335 .into_iter()
1336 .map(ddk_converter::mlme_band_cap_from_softmac)
1337 .collect::<Result<_, _>>()
1338 .expect("Failed to convert softmac driver band capabilities.")
1339 }
1340}
1341
1342#[cfg(test)]
1343mod tests {
1344 use super::*;
1345 use crate::{WlanTxPacketExt as _, ddk_converter};
1346 use assert_matches::assert_matches;
1347 use fdf::Arena;
1348 use fidl_fuchsia_wlan_common as fidl_common;
1349 use fidl_fuchsia_wlan_driver as fidl_driver_common;
1350 use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
1351 use ieee80211::Ssid;
1352
1353 fn make_deauth_confirm_msg() -> fidl_mlme::DeauthenticateConfirm {
1354 fidl_mlme::DeauthenticateConfirm { peer_sta_address: [1; 6] }
1355 }
1356
1357 #[fuchsia::test(allow_stalls = false)]
1358 async fn state_method_returns_correct_pointer() {
1359 let (fake_device, fake_device_state) = FakeDevice::new().await;
1360 assert_eq!(Arc::as_ptr(&fake_device.state()), Arc::as_ptr(&fake_device_state));
1361 }
1362
1363 #[fuchsia::test(allow_stalls = false)]
1364 async fn fake_device_returns_expected_wlan_softmac_query_response() {
1365 let (mut fake_device, _) = FakeDevice::new().await;
1366 let query_response = fake_device.wlan_softmac_query_response().await.unwrap();
1367 assert_eq!(query_response.sta_addr, [7u8; 6].into());
1368 assert_eq!(query_response.factory_addr, [7u8; 6].into());
1369 assert_eq!(query_response.mac_role, Some(fidl_common::WlanMacRole::Client));
1370 assert_eq!(
1371 query_response.supported_phys,
1372 Some(vec![
1373 fidl_ieee80211::WlanPhyType::Dsss,
1374 fidl_ieee80211::WlanPhyType::Hr,
1375 fidl_ieee80211::WlanPhyType::Ofdm,
1376 fidl_ieee80211::WlanPhyType::Erp,
1377 fidl_ieee80211::WlanPhyType::Ht,
1378 fidl_ieee80211::WlanPhyType::Vht,
1379 ]),
1380 );
1381 assert_eq!(query_response.hardware_capability, Some(0));
1382
1383 let expected_band_caps = [
1384 fidl_softmac::WlanSoftmacBandCapability {
1385 band: Some(fidl_ieee80211::WlanBand::TwoGhz),
1386 basic_rates: Some(vec![
1387 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
1388 ]),
1389 primary_channels: Some(
1390 (1..=14)
1391 .map(|c| fidl_ieee80211::ChannelNumber {
1392 band: fidl_ieee80211::WlanBand::TwoGhz,
1393 number: c,
1394 })
1395 .collect(),
1396 ),
1397 ht_caps: Some(fidl_ieee80211::HtCapabilities {
1398 bytes: [
1399 0x63, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1402 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ],
1408 }),
1409 vht_caps: None,
1410 ..Default::default()
1411 },
1412 fidl_softmac::WlanSoftmacBandCapability {
1413 band: Some(fidl_ieee80211::WlanBand::FiveGhz),
1414 basic_rates: Some(vec![0x02, 0x04, 0x0b, 0x16, 0x30, 0x60, 0x7e, 0x7f]),
1415 primary_channels: Some(
1416 [36, 40, 44, 48, 149, 153, 157, 161]
1417 .into_iter()
1418 .map(|c| fidl_ieee80211::ChannelNumber {
1419 band: fidl_ieee80211::WlanBand::FiveGhz,
1420 number: c,
1421 })
1422 .collect(),
1423 ),
1424 ht_caps: Some(fidl_ieee80211::HtCapabilities {
1425 bytes: [
1426 0x63, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1429 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ],
1435 }),
1436 vht_caps: Some(fidl_ieee80211::VhtCapabilities {
1437 bytes: [0x32, 0x50, 0x80, 0x0f, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00],
1438 }),
1439 ..Default::default()
1440 },
1441 ];
1442 let actual_band_caps = query_response.band_caps.as_ref().unwrap();
1443 for (actual_band_cap, expected_band_cap) in actual_band_caps.iter().zip(&expected_band_caps)
1444 {
1445 assert_eq!(actual_band_cap, expected_band_cap);
1446 }
1447 }
1448
1449 #[fuchsia::test(allow_stalls = false)]
1450 async fn fake_device_returns_expected_discovery_support() {
1451 let (mut fake_device, _) = FakeDevice::new().await;
1452 let discovery_support = fake_device.discovery_support().await.unwrap();
1453 assert_eq!(
1454 discovery_support,
1455 fidl_softmac::DiscoverySupport {
1456 scan_offload: Some(fidl_softmac::ScanOffloadExtension {
1457 supported: Some(true),
1458 scan_cancel_supported: Some(false),
1459 ..Default::default()
1460 }),
1461 probe_response_offload: Some(fidl_softmac::ProbeResponseOffloadExtension {
1462 supported: Some(false),
1463 ..Default::default()
1464 }),
1465 ..Default::default()
1466 }
1467 );
1468 }
1469
1470 #[fuchsia::test(allow_stalls = false)]
1471 async fn fake_device_returns_expected_mac_sublayer_support() {
1472 let (mut fake_device, _) = FakeDevice::new().await;
1473 let mac_sublayer_support = fake_device.mac_sublayer_support().await.unwrap();
1474 assert_eq!(
1475 mac_sublayer_support,
1476 fidl_common::MacSublayerSupport {
1477 rate_selection_offload: Some(fidl_common::RateSelectionOffloadExtension {
1478 supported: Some(false),
1479 ..Default::default()
1480 }),
1481 data_plane: Some(fidl_common::DataPlaneExtension {
1482 data_plane_type: Some(fidl_common::DataPlaneType::EthernetDevice),
1483 ..Default::default()
1484 }),
1485 device: Some(fidl_common::DeviceExtension {
1486 is_synthetic: Some(true),
1487 mac_implementation_type: Some(fidl_common::MacImplementationType::Softmac),
1488 tx_status_report_supported: Some(true),
1489 ..Default::default()
1490 }),
1491 ..Default::default()
1492 }
1493 );
1494 }
1495
1496 #[fuchsia::test(allow_stalls = false)]
1497 async fn fake_device_returns_expected_security_support() {
1498 let (mut fake_device, _) = FakeDevice::new().await;
1499 let security_support = fake_device.security_support().await.unwrap();
1500 assert_eq!(
1501 security_support,
1502 fidl_common::SecuritySupport {
1503 mfp: Some(fidl_common::MfpFeature { supported: Some(false), ..Default::default() }),
1504 sae: Some(fidl_common::SaeFeature {
1505 driver_handler_supported: Some(false),
1506 sme_handler_supported: Some(false),
1507 hash_to_element_supported: Some(false),
1508 ..Default::default()
1509 }),
1510 owe: Some(fidl_common::OweFeature { supported: Some(false), ..Default::default() }),
1511 ..Default::default()
1512 }
1513 );
1514 }
1515
1516 #[fuchsia::test(allow_stalls = false)]
1517 async fn fake_device_returns_expected_spectrum_management_support() {
1518 let (mut fake_device, _) = FakeDevice::new().await;
1519 let spectrum_management_support = fake_device.spectrum_management_support().await.unwrap();
1520 assert_eq!(
1521 spectrum_management_support,
1522 fidl_common::SpectrumManagementSupport {
1523 dfs: Some(fidl_common::DfsFeature { supported: Some(true), ..Default::default() }),
1524 ..Default::default()
1525 }
1526 );
1527 }
1528
1529 #[fuchsia::test(allow_stalls = false)]
1530 async fn test_can_dynamically_change_fake_device_state() {
1531 let (mut fake_device, fake_device_state) = FakeDevice::new_with_config(
1532 FakeDeviceConfig::default().with_mock_mac_role(fidl_common::WlanMacRole::Client),
1533 )
1534 .await;
1535 let query_response = fake_device.wlan_softmac_query_response().await.unwrap();
1536 assert_eq!(query_response.mac_role, Some(fidl_common::WlanMacRole::Client));
1537
1538 fake_device_state.lock().config =
1539 FakeDeviceConfig::default().with_mock_mac_role(fidl_common::WlanMacRole::Ap);
1540
1541 let query_response = fake_device.wlan_softmac_query_response().await.unwrap();
1542 assert_eq!(query_response.mac_role, Some(fidl_common::WlanMacRole::Ap));
1543 }
1544
1545 #[fuchsia::test(allow_stalls = false)]
1546 async fn send_mlme_message() {
1547 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1548 fake_device
1549 .send_mlme_event(fidl_mlme::MlmeEvent::DeauthenticateConf {
1550 resp: make_deauth_confirm_msg(),
1551 })
1552 .expect("error sending MLME message");
1553
1554 let msg = fake_device_state
1556 .lock()
1557 .next_mlme_msg::<fidl_mlme::DeauthenticateConfirm>()
1558 .expect("error reading message from channel");
1559 assert_eq!(msg, make_deauth_confirm_msg());
1560 }
1561
1562 #[fuchsia::test(allow_stalls = false)]
1563 async fn send_mlme_message_peer_already_closed() {
1564 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1565 fake_device_state.lock().mlme_event_stream.take();
1566
1567 fake_device
1568 .send_mlme_event(fidl_mlme::MlmeEvent::DeauthenticateConf {
1569 resp: make_deauth_confirm_msg(),
1570 })
1571 .expect_err("Mlme event should fail");
1572 }
1573
1574 #[fuchsia::test(allow_stalls = false)]
1575 async fn fake_device_deliver_eth_frame() {
1576 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1577 assert_eq!(fake_device_state.lock().eth_queue.len(), 0);
1578 let first_frame = [5; 32];
1579 let second_frame = [6; 32];
1580 assert_eq!(fake_device.deliver_eth_frame(&first_frame[..]), Ok(()));
1581 assert_eq!(fake_device.deliver_eth_frame(&second_frame[..]), Ok(()));
1582 assert_eq!(fake_device_state.lock().eth_queue.len(), 2);
1583 assert_eq!(&fake_device_state.lock().eth_queue[0], &first_frame);
1584 assert_eq!(&fake_device_state.lock().eth_queue[1], &second_frame);
1585 }
1586
1587 #[fuchsia::test(allow_stalls = false)]
1588 async fn set_channel() {
1589 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1590 let expected_channel =
1591 fidl_ieee80211::ChannelNumber { band: fidl_ieee80211::WlanBand::TwoGhz, number: 2 };
1592 let expected_cbw = fidl_ieee80211::ChannelBandwidth::Cbw80P80;
1593 let expected_secondary80 =
1594 fidl_ieee80211::ChannelNumber { band: fidl_ieee80211::WlanBand::TwoGhz, number: 4 };
1595 fake_device
1596 .set_channel(expected_channel, expected_cbw, expected_secondary80)
1597 .await
1598 .expect("set_channel failed?");
1599 assert_eq!(fake_device_state.lock().wlan_channel, expected_channel);
1601 assert_eq!(fake_device_state.lock().cbw, expected_cbw);
1602 assert_eq!(fake_device_state.lock().secondary80, expected_secondary80);
1603 }
1604
1605 #[fuchsia::test(allow_stalls = false)]
1606 async fn install_key() {
1607 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1608 fake_device
1609 .install_key(&fidl_softmac::WlanKeyConfiguration {
1610 protection: Some(fidl_softmac::WlanProtection::None),
1611 cipher_oui: Some([3, 4, 5]),
1612 cipher_type: Some(6),
1613 key_type: Some(fidl_ieee80211::KeyType::Pairwise),
1614 peer_addr: Some([8; 6]),
1615 key_idx: Some(9),
1616 key: Some(vec![11; 32]),
1617 rsc: Some(12),
1618 ..Default::default()
1619 })
1620 .await
1621 .expect("error setting key");
1622 assert_eq!(fake_device_state.lock().keys.len(), 1);
1623 }
1624
1625 #[fuchsia::test(allow_stalls = false)]
1626 async fn start_passive_scan() {
1627 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1628
1629 let result = fake_device
1630 .start_passive_scan(&fidl_softmac::WlanSoftmacBaseStartPassiveScanRequest {
1631 channels: Some(
1632 [1, 2, 3]
1633 .into_iter()
1634 .map(|c| fidl_ieee80211::ChannelNumber {
1635 band: fidl_ieee80211::WlanBand::TwoGhz,
1636 number: c,
1637 })
1638 .collect(),
1639 ),
1640 min_channel_time: Some(zx::MonotonicDuration::from_millis(0).into_nanos()),
1641 max_channel_time: Some(zx::MonotonicDuration::from_millis(200).into_nanos()),
1642 min_home_time: Some(0),
1643 ..Default::default()
1644 })
1645 .await;
1646 assert!(result.is_ok());
1647
1648 assert_eq!(
1649 fake_device_state.lock().captured_passive_scan_request,
1650 Some(fidl_softmac::WlanSoftmacBaseStartPassiveScanRequest {
1651 channels: Some(
1652 [1, 2, 3]
1653 .into_iter()
1654 .map(|c| fidl_ieee80211::ChannelNumber {
1655 band: fidl_ieee80211::WlanBand::TwoGhz,
1656 number: c,
1657 })
1658 .collect(),
1659 ),
1660 min_channel_time: Some(0),
1661 max_channel_time: Some(200_000_000),
1662 min_home_time: Some(0),
1663 ..Default::default()
1664 }),
1665 );
1666 }
1667
1668 #[fuchsia::test(allow_stalls = false)]
1669 async fn start_active_scan() {
1670 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1671
1672 let result = fake_device
1673 .start_active_scan(&fidl_softmac::WlanSoftmacStartActiveScanRequest {
1674 channels: Some(
1675 [1, 2, 3]
1676 .into_iter()
1677 .map(|c| fidl_ieee80211::ChannelNumber {
1678 band: fidl_ieee80211::WlanBand::TwoGhz,
1679 number: c,
1680 })
1681 .collect(),
1682 ),
1683 ssids: Some(vec![
1684 ddk_converter::cssid_from_ssid_unchecked(
1685 &Ssid::try_from("foo").unwrap().into(),
1686 ),
1687 ddk_converter::cssid_from_ssid_unchecked(
1688 &Ssid::try_from("bar").unwrap().into(),
1689 ),
1690 ]),
1691 mac_header: Some(vec![
1692 0x40u8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0xdc, ]),
1699 ies: Some(vec![
1700 0x01u8, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, ]),
1704 min_channel_time: Some(zx::MonotonicDuration::from_millis(0).into_nanos()),
1705 max_channel_time: Some(zx::MonotonicDuration::from_millis(200).into_nanos()),
1706 min_home_time: Some(0),
1707 min_probes_per_channel: Some(1),
1708 max_probes_per_channel: Some(3),
1709 ..Default::default()
1710 })
1711 .await;
1712 assert!(result.is_ok());
1713 assert_eq!(
1714 fake_device_state.lock().captured_active_scan_request,
1715 Some(fidl_softmac::WlanSoftmacStartActiveScanRequest {
1716 channels: Some(
1717 [1, 2, 3]
1718 .into_iter()
1719 .map(|c| fidl_ieee80211::ChannelNumber {
1720 band: fidl_ieee80211::WlanBand::TwoGhz,
1721 number: c,
1722 })
1723 .collect(),
1724 ),
1725 ssids: Some(vec![
1726 ddk_converter::cssid_from_ssid_unchecked(
1727 &Ssid::try_from("foo").unwrap().into()
1728 ),
1729 ddk_converter::cssid_from_ssid_unchecked(
1730 &Ssid::try_from("bar").unwrap().into()
1731 ),
1732 ]),
1733 mac_header: Some(vec![
1734 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0xdc, ]),
1741 ies: Some(vec![
1742 0x01, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 ]),
1746 min_channel_time: Some(0),
1747 max_channel_time: Some(200_000_000),
1748 min_home_time: Some(0),
1749 min_probes_per_channel: Some(1),
1750 max_probes_per_channel: Some(3),
1751 ..Default::default()
1752 }),
1753 "No active scan argument available."
1754 );
1755 }
1756
1757 #[fuchsia::test(allow_stalls = false)]
1758 async fn join_bss() {
1759 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1760 fake_device
1761 .join_bss(&fidl_driver_common::JoinBssRequest {
1762 bssid: Some([1, 2, 3, 4, 5, 6]),
1763 bss_type: Some(fidl_ieee80211::BssType::Personal),
1764 remote: Some(true),
1765 beacon_period: Some(100),
1766 ..Default::default()
1767 })
1768 .await
1769 .expect("error configuring bss");
1770 assert!(fake_device_state.lock().join_bss_request.is_some());
1771 }
1772
1773 #[fuchsia::test(allow_stalls = false)]
1774 async fn enable_disable_beaconing() {
1775 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1776 let arena = Arena::new();
1777 let mut buffer = arena.insert_default_slice::<u8>(4);
1778 buffer.copy_from_slice(&[1, 2, 3, 4][..]);
1779 let mac_frame = buffer.to_vec();
1780
1781 fake_device
1782 .enable_beaconing(fidl_softmac::WlanSoftmacBaseEnableBeaconingRequest {
1783 packet_template: Some(fidl_softmac::WlanTxPacket::template(mac_frame)),
1784 tim_ele_offset: Some(1),
1785 beacon_interval: Some(2),
1786 ..Default::default()
1787 })
1788 .await
1789 .expect("error enabling beaconing");
1790 assert_matches!(
1791 fake_device_state.lock().beacon_config.as_ref(),
1792 Some((buffer, tim_ele_offset, beacon_interval)) => {
1793 assert_eq!(&buffer[..], &[1, 2, 3, 4][..]);
1794 assert_eq!(*tim_ele_offset, 1);
1795 assert_eq!(*beacon_interval, TimeUnit(2));
1796 });
1797 fake_device.disable_beaconing().await.expect("error disabling beaconing");
1798 assert_matches!(fake_device_state.lock().beacon_config.as_ref(), None);
1799 }
1800
1801 #[fuchsia::test(allow_stalls = false)]
1802 async fn set_ethernet_status() {
1803 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1804 fake_device.set_ethernet_up().await.expect("failed setting status");
1805 assert_eq!(fake_device_state.lock().link_status, LinkStatus::UP);
1806
1807 fake_device.set_ethernet_down().await.expect("failed setting status");
1808 assert_eq!(fake_device_state.lock().link_status, LinkStatus::DOWN);
1809 }
1810
1811 #[fuchsia::test(allow_stalls = false)]
1812 async fn notify_association_complete() {
1813 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1814 fake_device
1815 .notify_association_complete(fidl_softmac::WlanAssociationConfig {
1816 bssid: Some([1, 2, 3, 4, 5, 6]),
1817 aid: Some(1),
1818 listen_interval: Some(2),
1819 primary: Some(fidl_ieee80211::ChannelNumber {
1820 band: fidl_ieee80211::WlanBand::TwoGhz,
1821 number: 3,
1822 }),
1823 bandwidth: Some(fidl_ieee80211::ChannelBandwidth::Cbw20),
1824 qos: Some(false),
1825 wmm_params: None,
1826 rates: None,
1827 capability_info: Some(0x0102),
1828 ht_cap: None,
1829 ht_op: None,
1830 vht_cap: None,
1831 vht_op: None,
1832 ..Default::default()
1833 })
1834 .await
1835 .expect("error configuring assoc");
1836 assert!(fake_device_state.lock().assocs.contains_key(&[1, 2, 3, 4, 5, 6].into()));
1837 }
1838
1839 #[fuchsia::test(allow_stalls = false)]
1840 async fn clear_association() {
1841 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1842 fake_device
1843 .join_bss(&fidl_driver_common::JoinBssRequest {
1844 bssid: Some([1, 2, 3, 4, 5, 6]),
1845 bss_type: Some(fidl_ieee80211::BssType::Personal),
1846 remote: Some(true),
1847 beacon_period: Some(100),
1848 ..Default::default()
1849 })
1850 .await
1851 .expect("error configuring bss");
1852
1853 let assoc_cfg = fidl_softmac::WlanAssociationConfig {
1854 bssid: Some([1, 2, 3, 4, 5, 6]),
1855 aid: Some(1),
1856 primary: Some(fidl_ieee80211::ChannelNumber {
1857 band: fidl_ieee80211::WlanBand::FiveGhz,
1858 number: 149,
1859 }),
1860 bandwidth: Some(fidl_ieee80211::ChannelBandwidth::Cbw20),
1861 ..Default::default()
1862 };
1863
1864 assert!(fake_device_state.lock().join_bss_request.is_some());
1865 fake_device.notify_association_complete(assoc_cfg).await.expect("error configuring assoc");
1866 assert_eq!(fake_device_state.lock().assocs.len(), 1);
1867 fake_device
1868 .clear_association(&fidl_softmac::WlanSoftmacBaseClearAssociationRequest {
1869 peer_addr: Some([1, 2, 3, 4, 5, 6]),
1870 ..Default::default()
1871 })
1872 .await
1873 .expect("error clearing assoc");
1874 assert_eq!(fake_device_state.lock().assocs.len(), 0);
1875 assert!(fake_device_state.lock().join_bss_request.is_none());
1876 }
1877
1878 #[fuchsia::test(allow_stalls = false)]
1879 async fn fake_device_captures_update_wmm_parameters_request() {
1880 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1881
1882 let request = fidl_softmac::WlanSoftmacBaseUpdateWmmParametersRequest {
1883 ac: Some(fidl_ieee80211::WlanAccessCategory::Background),
1884 params: Some(fidl_driver_common::WlanWmmParameters {
1885 apsd: true,
1886 ac_be_params: fidl_driver_common::WlanWmmAccessCategoryParameters {
1887 ecw_min: 10,
1888 ecw_max: 100,
1889 aifsn: 1,
1890 txop_limit: 5,
1891 acm: true,
1892 },
1893 ac_bk_params: fidl_driver_common::WlanWmmAccessCategoryParameters {
1894 ecw_min: 11,
1895 ecw_max: 100,
1896 aifsn: 1,
1897 txop_limit: 5,
1898 acm: true,
1899 },
1900 ac_vi_params: fidl_driver_common::WlanWmmAccessCategoryParameters {
1901 ecw_min: 12,
1902 ecw_max: 100,
1903 aifsn: 1,
1904 txop_limit: 5,
1905 acm: true,
1906 },
1907 ac_vo_params: fidl_driver_common::WlanWmmAccessCategoryParameters {
1908 ecw_min: 13,
1909 ecw_max: 100,
1910 aifsn: 1,
1911 txop_limit: 5,
1912 acm: true,
1913 },
1914 }),
1915 ..Default::default()
1916 };
1917 let result = fake_device.update_wmm_parameters(&request).await;
1918 assert!(result.is_ok());
1919
1920 assert_eq!(fake_device_state.lock().captured_update_wmm_parameters_request, Some(request),);
1921 }
1922}