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::err_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 primary: fidl_ieee80211::ChannelNumber,
143 bandwidth: fidl_ieee80211::ChannelBandwidth,
144 vht_secondary_80_channel: 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::err_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 primary: fidl_ieee80211::ChannelNumber,
438 bandwidth: fidl_ieee80211::ChannelBandwidth,
439 vht_secondary_80_channel: fidl_ieee80211::ChannelNumber,
440 ) -> Result<(), zx::Status> {
441 self.wlan_softmac_bridge_proxy
442 .set_channel(&fidl_softmac::WlanSoftmacBaseSetChannelRequest {
443 primary: Some(primary),
444 bandwidth: Some(bandwidth),
445 vht_secondary_80_channel: Some(vht_secondary_80_channel),
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::err_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::err_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::err_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::err_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 primary_channel: fidl_ieee80211::ChannelNumber,
910 pub bandwidth: fidl_ieee80211::ChannelBandwidth,
911 pub vht_secondary_80_channel: 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 primary_channel: fidl_ieee80211::ChannelNumber {
958 band: fidl_ieee80211::WlanBand::TwoGhz,
959 number: 0,
960 },
961 bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw20,
962 vht_secondary_80_channel: 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_recv()
992 .map_err(|e| anyhow::format_err!("Failed to read mlme event stream: {}", e))
993 .and_then(|evt| {
994 T::from_event(evt).ok_or_else(|| anyhow::format_err!("Unexpected mlme event"))
995 })
996 .map_err(|e| e.into())
997 }
998
999 pub fn reset(&mut self) {
1000 self.eth_queue.clear();
1001 }
1002 }
1003
1004 impl DeviceOps for FakeDevice {
1005 async fn wlan_softmac_query_response(
1006 &mut self,
1007 ) -> Result<fidl_softmac::WlanSoftmacQueryResponse, zx::Status> {
1008 let state = self.state.lock();
1009 match state.config.mock_query_response.as_ref() {
1010 Some(query_response) => query_response.clone(),
1011 None => FakeDeviceConfig::default_mock_query_response(),
1012 }
1013 }
1014
1015 async fn discovery_support(
1016 &mut self,
1017 ) -> Result<fidl_softmac::DiscoverySupport, zx::Status> {
1018 let state = self.state.lock();
1019 match state.config.mock_discovery_support.as_ref() {
1020 Some(discovery_support) => discovery_support.clone(),
1021 None => FakeDeviceConfig::default_mock_discovery_support(),
1022 }
1023 }
1024
1025 async fn mac_sublayer_support(
1026 &mut self,
1027 ) -> Result<fidl_common::MacSublayerSupport, zx::Status> {
1028 let state = self.state.lock();
1029 match state.config.mock_mac_sublayer_support.as_ref() {
1030 Some(mac_sublayer_support) => mac_sublayer_support.clone(),
1031 None => FakeDeviceConfig::default_mock_mac_sublayer_support(),
1032 }
1033 }
1034
1035 async fn security_support(&mut self) -> Result<fidl_common::SecuritySupport, zx::Status> {
1036 let state = self.state.lock();
1037 match state.config.mock_security_support.as_ref() {
1038 Some(security_support) => security_support.clone(),
1039 None => Ok(fidl_common::SecuritySupport {
1040 mfp: Some(fidl_common::MfpFeature {
1041 supported: Some(false),
1042 ..Default::default()
1043 }),
1044 sae: Some(fidl_common::SaeFeature {
1045 driver_handler_supported: Some(false),
1046 sme_handler_supported: Some(false),
1047 hash_to_element_supported: Some(false),
1048 ..Default::default()
1049 }),
1050 owe: Some(fidl_common::OweFeature {
1051 supported: Some(false),
1052 ..Default::default()
1053 }),
1054 ..Default::default()
1055 }),
1056 }
1057 }
1058
1059 async fn spectrum_management_support(
1060 &mut self,
1061 ) -> Result<fidl_common::SpectrumManagementSupport, zx::Status> {
1062 let state = self.state.lock();
1063 match state.config.mock_spectrum_management_support.as_ref() {
1064 Some(spectrum_management_support) => spectrum_management_support.clone(),
1065 None => Ok(fidl_common::SpectrumManagementSupport {
1066 dfs: Some(fidl_common::DfsFeature {
1067 supported: Some(true),
1068 ..Default::default()
1069 }),
1070 ..Default::default()
1071 }),
1072 }
1073 }
1074
1075 async fn start(
1076 &mut self,
1077 ifc_bridge: fidl::endpoints::ClientEnd<fidl_softmac::WlanSoftmacIfcBridgeMarker>,
1078 _ethernet_tx: EthernetTx,
1079 _wlan_rx: WlanRx,
1080 ) -> Result<fidl::Channel, zx::Status> {
1081 let mut state = self.state.lock();
1082
1083 if let Some(mock_start_result) = state.config.mock_start_result.take() {
1084 return mock_start_result;
1085 }
1086
1087 state.wlan_softmac_ifc_bridge_proxy = Some(ifc_bridge.into_proxy());
1088 Ok(state.usme_bootstrap_server_end.take().unwrap().into_channel())
1089 }
1090
1091 fn deliver_eth_frame(&mut self, packet: &[u8]) -> Result<(), zx::Status> {
1092 self.state.lock().eth_queue.push(packet.to_vec());
1093 Ok(())
1094 }
1095
1096 fn send_wlan_frame(
1097 &mut self,
1098 buffer: ArenaStaticBox<[u8]>,
1099 _tx_flags: fidl_softmac::WlanTxInfoFlags,
1100 _async_id: Option<TraceId>,
1101 ) -> Result<(), zx::Status> {
1102 let mut state = self.state.lock();
1103 if state.config.send_wlan_frame_fails {
1104 return Err(zx::Status::IO);
1105 }
1106 state.wlan_queue.push((buffer.to_vec(), 0));
1107 Ok(())
1108 }
1109
1110 async fn set_ethernet_status(&mut self, status: LinkStatus) -> Result<(), zx::Status> {
1111 self.state.lock().link_status = status;
1112 Ok(())
1113 }
1114
1115 async fn set_channel(
1116 &mut self,
1117 primary: fidl_ieee80211::ChannelNumber,
1118 bandwidth: fidl_ieee80211::ChannelBandwidth,
1119 vht_secondary_80_channel: fidl_ieee80211::ChannelNumber,
1120 ) -> Result<(), zx::Status> {
1121 let mut state = self.state.lock();
1122 state.primary_channel = primary;
1123 state.bandwidth = bandwidth;
1124 state.vht_secondary_80_channel = vht_secondary_80_channel;
1125 Ok(())
1126 }
1127
1128 async fn set_mac_address(
1129 &mut self,
1130 _mac_addr: fidl_fuchsia_wlan_ieee80211::MacAddr,
1131 ) -> Result<(), zx::Status> {
1132 Err(zx::Status::NOT_SUPPORTED)
1133 }
1134
1135 async fn start_passive_scan(
1136 &mut self,
1137 request: &fidl_softmac::WlanSoftmacBaseStartPassiveScanRequest,
1138 ) -> Result<fidl_softmac::WlanSoftmacBaseStartPassiveScanResponse, zx::Status> {
1139 let mut state = self.state.lock();
1140 if state.config.start_passive_scan_fails {
1141 return Err(zx::Status::NOT_SUPPORTED);
1142 }
1143 let scan_id = state.next_scan_id;
1144 state.next_scan_id += 1;
1145 state.captured_passive_scan_request.replace(request.clone());
1146 Ok(fidl_softmac::WlanSoftmacBaseStartPassiveScanResponse {
1147 scan_id: Some(scan_id),
1148 ..Default::default()
1149 })
1150 }
1151
1152 async fn start_active_scan(
1153 &mut self,
1154 request: &fidl_softmac::WlanSoftmacStartActiveScanRequest,
1155 ) -> Result<fidl_softmac::WlanSoftmacBaseStartActiveScanResponse, zx::Status> {
1156 let mut state = self.state.lock();
1157 if state.config.start_active_scan_fails {
1158 return Err(zx::Status::NOT_SUPPORTED);
1159 }
1160 let scan_id = state.next_scan_id;
1161 state.next_scan_id += 1;
1162 state.captured_active_scan_request.replace(request.clone());
1163 Ok(fidl_softmac::WlanSoftmacBaseStartActiveScanResponse {
1164 scan_id: Some(scan_id),
1165 ..Default::default()
1166 })
1167 }
1168
1169 async fn cancel_scan(
1170 &mut self,
1171 _request: &fidl_softmac::WlanSoftmacBaseCancelScanRequest,
1172 ) -> Result<(), zx::Status> {
1173 Err(zx::Status::NOT_SUPPORTED)
1174 }
1175
1176 async fn join_bss(
1177 &mut self,
1178 request: &fidl_driver_common::JoinBssRequest,
1179 ) -> Result<(), zx::Status> {
1180 self.state.lock().join_bss_request.replace(request.clone());
1181 Ok(())
1182 }
1183
1184 async fn enable_beaconing(
1185 &mut self,
1186 request: fidl_softmac::WlanSoftmacBaseEnableBeaconingRequest,
1187 ) -> Result<(), zx::Status> {
1188 match (request.packet_template, request.tim_ele_offset, request.beacon_interval) {
1189 (Some(packet_template), Some(tim_ele_offset), Some(beacon_interval)) => Ok({
1190 self.state.lock().beacon_config = Some((
1191 packet_template.mac_frame,
1192 usize::try_from(tim_ele_offset).map_err(|_| zx::Status::INTERNAL)?,
1193 TimeUnit(beacon_interval),
1194 ));
1195 }),
1196 _ => Err(zx::Status::INVALID_ARGS),
1197 }
1198 }
1199
1200 async fn disable_beaconing(&mut self) -> Result<(), zx::Status> {
1201 self.state.lock().beacon_config = None;
1202 Ok(())
1203 }
1204
1205 async fn install_key(
1206 &mut self,
1207 key_configuration: &fidl_softmac::WlanKeyConfiguration,
1208 ) -> Result<(), zx::Status> {
1209 let mut state = self.state.lock();
1210 state.keys.push(key_configuration.clone());
1211 state.install_key_results.pop_front().unwrap_or(Ok(()))
1212 }
1213
1214 async fn notify_association_complete(
1215 &mut self,
1216 cfg: fidl_softmac::WlanAssociationConfig,
1217 ) -> Result<(), zx::Status> {
1218 let mut state = self.state.lock();
1219 if let Some(minstrel) = &state.minstrel {
1220 minstrel.lock().add_peer(&cfg)?
1221 }
1222 state.assocs.insert(cfg.bssid.unwrap().into(), cfg);
1223 Ok(())
1224 }
1225
1226 async fn clear_association(
1227 &mut self,
1228 request: &fidl_softmac::WlanSoftmacBaseClearAssociationRequest,
1229 ) -> Result<(), zx::Status> {
1230 let addr: MacAddr = request.peer_addr.unwrap().into();
1231 let mut state = self.state.lock();
1232 if let Some(minstrel) = &state.minstrel {
1233 minstrel.lock().remove_peer(&addr);
1234 }
1235 state.assocs.remove(&addr);
1236 state.join_bss_request = None;
1237 Ok(())
1238 }
1239
1240 async fn update_wmm_parameters(
1241 &mut self,
1242 request: &fidl_softmac::WlanSoftmacBaseUpdateWmmParametersRequest,
1243 ) -> Result<(), zx::Status> {
1244 let mut state = self.state.lock();
1245 state.captured_update_wmm_parameters_request.replace(request.clone());
1246 Ok(())
1247 }
1248
1249 fn take_mlme_event_stream(
1250 &mut self,
1251 ) -> Option<mpsc::UnboundedReceiver<fidl_mlme::MlmeEvent>> {
1252 self.state.lock().mlme_event_stream.take()
1253 }
1254
1255 fn send_mlme_event(&mut self, event: fidl_mlme::MlmeEvent) -> Result<(), anyhow::Error> {
1256 self.mlme_event_sink.unbounded_send(event).map_err(|e| e.into())
1257 }
1258
1259 fn set_minstrel(&mut self, minstrel: crate::MinstrelWrapper) {
1260 self.state.lock().minstrel.replace(minstrel);
1261 }
1262
1263 fn minstrel(&mut self) -> Option<crate::MinstrelWrapper> {
1264 self.state.lock().minstrel.as_ref().map(Arc::clone)
1265 }
1266 }
1267
1268 pub fn fake_band_caps() -> Vec<fidl_softmac::WlanSoftmacBandCapability> {
1269 vec![
1270 fidl_softmac::WlanSoftmacBandCapability {
1271 band: Some(fidl_ieee80211::WlanBand::TwoGhz),
1272 basic_rates: Some(vec![
1273 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
1274 ]),
1275 primary_channels: Some(
1276 (1..=14)
1277 .map(|c| fidl_ieee80211::ChannelNumber {
1278 band: fidl_ieee80211::WlanBand::TwoGhz,
1279 number: c,
1280 })
1281 .collect(),
1282 ),
1283 ht_caps: Some(fidl_ieee80211::HtCapabilities {
1284 bytes: [
1285 0x63, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1288 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ],
1294 }),
1295 vht_caps: None,
1296 ..Default::default()
1297 },
1298 fidl_softmac::WlanSoftmacBandCapability {
1299 band: Some(fidl_ieee80211::WlanBand::FiveGhz),
1300 basic_rates: Some(vec![0x02, 0x04, 0x0b, 0x16, 0x30, 0x60, 0x7e, 0x7f]),
1301 primary_channels: Some(
1302 [36, 40, 44, 48, 149, 153, 157, 161]
1303 .into_iter()
1304 .map(|c| fidl_ieee80211::ChannelNumber {
1305 band: fidl_ieee80211::WlanBand::FiveGhz,
1306 number: c,
1307 })
1308 .collect(),
1309 ),
1310 ht_caps: Some(fidl_ieee80211::HtCapabilities {
1311 bytes: [
1312 0x63, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1315 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ],
1321 }),
1322 vht_caps: Some(fidl_ieee80211::VhtCapabilities {
1323 bytes: [0x32, 0x50, 0x80, 0x0f, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00],
1324 }),
1325 ..Default::default()
1326 },
1327 ]
1328 }
1329
1330 pub fn fake_mlme_band_caps() -> Vec<fidl_mlme::BandCapability> {
1331 fake_band_caps()
1332 .into_iter()
1333 .map(ddk_converter::mlme_band_cap_from_softmac)
1334 .collect::<Result<_, _>>()
1335 .expect("Failed to convert softmac driver band capabilities.")
1336 }
1337}
1338
1339#[cfg(test)]
1340mod tests {
1341 use super::*;
1342 use crate::{WlanTxPacketExt as _, ddk_converter};
1343 use assert_matches::assert_matches;
1344 use fdf::Arena;
1345 use fidl_fuchsia_wlan_common as fidl_common;
1346 use fidl_fuchsia_wlan_driver as fidl_driver_common;
1347 use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
1348 use ieee80211::Ssid;
1349
1350 fn make_deauth_confirm_msg() -> fidl_mlme::DeauthenticateConfirm {
1351 fidl_mlme::DeauthenticateConfirm { peer_sta_address: [1; 6] }
1352 }
1353
1354 #[fuchsia::test(allow_stalls = false)]
1355 async fn state_method_returns_correct_pointer() {
1356 let (fake_device, fake_device_state) = FakeDevice::new().await;
1357 assert_eq!(Arc::as_ptr(&fake_device.state()), Arc::as_ptr(&fake_device_state));
1358 }
1359
1360 #[fuchsia::test(allow_stalls = false)]
1361 async fn fake_device_returns_expected_wlan_softmac_query_response() {
1362 let (mut fake_device, _) = FakeDevice::new().await;
1363 let query_response = fake_device.wlan_softmac_query_response().await.unwrap();
1364 assert_eq!(query_response.sta_addr, [7u8; 6].into());
1365 assert_eq!(query_response.factory_addr, [7u8; 6].into());
1366 assert_eq!(query_response.mac_role, Some(fidl_common::WlanMacRole::Client));
1367 assert_eq!(
1368 query_response.supported_phys,
1369 Some(vec![
1370 fidl_ieee80211::WlanPhyType::Dsss,
1371 fidl_ieee80211::WlanPhyType::Hr,
1372 fidl_ieee80211::WlanPhyType::Ofdm,
1373 fidl_ieee80211::WlanPhyType::Erp,
1374 fidl_ieee80211::WlanPhyType::Ht,
1375 fidl_ieee80211::WlanPhyType::Vht,
1376 ]),
1377 );
1378 assert_eq!(query_response.hardware_capability, Some(0));
1379
1380 let expected_band_caps = [
1381 fidl_softmac::WlanSoftmacBandCapability {
1382 band: Some(fidl_ieee80211::WlanBand::TwoGhz),
1383 basic_rates: Some(vec![
1384 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
1385 ]),
1386 primary_channels: Some(
1387 (1..=14)
1388 .map(|c| fidl_ieee80211::ChannelNumber {
1389 band: fidl_ieee80211::WlanBand::TwoGhz,
1390 number: c,
1391 })
1392 .collect(),
1393 ),
1394 ht_caps: Some(fidl_ieee80211::HtCapabilities {
1395 bytes: [
1396 0x63, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1399 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ],
1405 }),
1406 vht_caps: None,
1407 ..Default::default()
1408 },
1409 fidl_softmac::WlanSoftmacBandCapability {
1410 band: Some(fidl_ieee80211::WlanBand::FiveGhz),
1411 basic_rates: Some(vec![0x02, 0x04, 0x0b, 0x16, 0x30, 0x60, 0x7e, 0x7f]),
1412 primary_channels: Some(
1413 [36, 40, 44, 48, 149, 153, 157, 161]
1414 .into_iter()
1415 .map(|c| fidl_ieee80211::ChannelNumber {
1416 band: fidl_ieee80211::WlanBand::FiveGhz,
1417 number: c,
1418 })
1419 .collect(),
1420 ),
1421 ht_caps: Some(fidl_ieee80211::HtCapabilities {
1422 bytes: [
1423 0x63, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1426 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ],
1432 }),
1433 vht_caps: Some(fidl_ieee80211::VhtCapabilities {
1434 bytes: [0x32, 0x50, 0x80, 0x0f, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00],
1435 }),
1436 ..Default::default()
1437 },
1438 ];
1439 let actual_band_caps = query_response.band_caps.as_ref().unwrap();
1440 for (actual_band_cap, expected_band_cap) in actual_band_caps.iter().zip(&expected_band_caps)
1441 {
1442 assert_eq!(actual_band_cap, expected_band_cap);
1443 }
1444 }
1445
1446 #[fuchsia::test(allow_stalls = false)]
1447 async fn fake_device_returns_expected_discovery_support() {
1448 let (mut fake_device, _) = FakeDevice::new().await;
1449 let discovery_support = fake_device.discovery_support().await.unwrap();
1450 assert_eq!(
1451 discovery_support,
1452 fidl_softmac::DiscoverySupport {
1453 scan_offload: Some(fidl_softmac::ScanOffloadExtension {
1454 supported: Some(true),
1455 scan_cancel_supported: Some(false),
1456 ..Default::default()
1457 }),
1458 probe_response_offload: Some(fidl_softmac::ProbeResponseOffloadExtension {
1459 supported: Some(false),
1460 ..Default::default()
1461 }),
1462 ..Default::default()
1463 }
1464 );
1465 }
1466
1467 #[fuchsia::test(allow_stalls = false)]
1468 async fn fake_device_returns_expected_mac_sublayer_support() {
1469 let (mut fake_device, _) = FakeDevice::new().await;
1470 let mac_sublayer_support = fake_device.mac_sublayer_support().await.unwrap();
1471 assert_eq!(
1472 mac_sublayer_support,
1473 fidl_common::MacSublayerSupport {
1474 rate_selection_offload: Some(fidl_common::RateSelectionOffloadExtension {
1475 supported: Some(false),
1476 ..Default::default()
1477 }),
1478 data_plane: Some(fidl_common::DataPlaneExtension {
1479 data_plane_type: Some(fidl_common::DataPlaneType::EthernetDevice),
1480 ..Default::default()
1481 }),
1482 device: Some(fidl_common::DeviceExtension {
1483 is_synthetic: Some(true),
1484 mac_implementation_type: Some(fidl_common::MacImplementationType::Softmac),
1485 tx_status_report_supported: Some(true),
1486 ..Default::default()
1487 }),
1488 ..Default::default()
1489 }
1490 );
1491 }
1492
1493 #[fuchsia::test(allow_stalls = false)]
1494 async fn fake_device_returns_expected_security_support() {
1495 let (mut fake_device, _) = FakeDevice::new().await;
1496 let security_support = fake_device.security_support().await.unwrap();
1497 assert_eq!(
1498 security_support,
1499 fidl_common::SecuritySupport {
1500 mfp: Some(fidl_common::MfpFeature { supported: Some(false), ..Default::default() }),
1501 sae: Some(fidl_common::SaeFeature {
1502 driver_handler_supported: Some(false),
1503 sme_handler_supported: Some(false),
1504 hash_to_element_supported: Some(false),
1505 ..Default::default()
1506 }),
1507 owe: Some(fidl_common::OweFeature { supported: Some(false), ..Default::default() }),
1508 ..Default::default()
1509 }
1510 );
1511 }
1512
1513 #[fuchsia::test(allow_stalls = false)]
1514 async fn fake_device_returns_expected_spectrum_management_support() {
1515 let (mut fake_device, _) = FakeDevice::new().await;
1516 let spectrum_management_support = fake_device.spectrum_management_support().await.unwrap();
1517 assert_eq!(
1518 spectrum_management_support,
1519 fidl_common::SpectrumManagementSupport {
1520 dfs: Some(fidl_common::DfsFeature { supported: Some(true), ..Default::default() }),
1521 ..Default::default()
1522 }
1523 );
1524 }
1525
1526 #[fuchsia::test(allow_stalls = false)]
1527 async fn test_can_dynamically_change_fake_device_state() {
1528 let (mut fake_device, fake_device_state) = FakeDevice::new_with_config(
1529 FakeDeviceConfig::default().with_mock_mac_role(fidl_common::WlanMacRole::Client),
1530 )
1531 .await;
1532 let query_response = fake_device.wlan_softmac_query_response().await.unwrap();
1533 assert_eq!(query_response.mac_role, Some(fidl_common::WlanMacRole::Client));
1534
1535 fake_device_state.lock().config =
1536 FakeDeviceConfig::default().with_mock_mac_role(fidl_common::WlanMacRole::Ap);
1537
1538 let query_response = fake_device.wlan_softmac_query_response().await.unwrap();
1539 assert_eq!(query_response.mac_role, Some(fidl_common::WlanMacRole::Ap));
1540 }
1541
1542 #[fuchsia::test(allow_stalls = false)]
1543 async fn send_mlme_message() {
1544 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1545 fake_device
1546 .send_mlme_event(fidl_mlme::MlmeEvent::DeauthenticateConf {
1547 resp: make_deauth_confirm_msg(),
1548 })
1549 .expect("error sending MLME message");
1550
1551 let msg = fake_device_state
1553 .lock()
1554 .next_mlme_msg::<fidl_mlme::DeauthenticateConfirm>()
1555 .expect("error reading message from channel");
1556 assert_eq!(msg, make_deauth_confirm_msg());
1557 }
1558
1559 #[fuchsia::test(allow_stalls = false)]
1560 async fn send_mlme_message_peer_already_closed() {
1561 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1562 fake_device_state.lock().mlme_event_stream.take();
1563
1564 fake_device
1565 .send_mlme_event(fidl_mlme::MlmeEvent::DeauthenticateConf {
1566 resp: make_deauth_confirm_msg(),
1567 })
1568 .expect_err("Mlme event should fail");
1569 }
1570
1571 #[fuchsia::test(allow_stalls = false)]
1572 async fn fake_device_deliver_eth_frame() {
1573 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1574 assert_eq!(fake_device_state.lock().eth_queue.len(), 0);
1575 let first_frame = [5; 32];
1576 let second_frame = [6; 32];
1577 assert_eq!(fake_device.deliver_eth_frame(&first_frame[..]), Ok(()));
1578 assert_eq!(fake_device.deliver_eth_frame(&second_frame[..]), Ok(()));
1579 assert_eq!(fake_device_state.lock().eth_queue.len(), 2);
1580 assert_eq!(&fake_device_state.lock().eth_queue[0], &first_frame);
1581 assert_eq!(&fake_device_state.lock().eth_queue[1], &second_frame);
1582 }
1583
1584 #[fuchsia::test(allow_stalls = false)]
1585 async fn set_channel() {
1586 let (mut fake_device, fake_device_state) = FakeDevice::new().await;
1587 let expected_primary =
1588 fidl_ieee80211::ChannelNumber { band: fidl_ieee80211::WlanBand::TwoGhz, number: 2 };
1589 let expected_bandwidth = fidl_ieee80211::ChannelBandwidth::Cbw80P80;
1590 let expected_vht_secondary_80_channel =
1591 fidl_ieee80211::ChannelNumber { band: fidl_ieee80211::WlanBand::TwoGhz, number: 4 };
1592 fake_device
1593 .set_channel(expected_primary, expected_bandwidth, expected_vht_secondary_80_channel)
1594 .await
1595 .expect("set_channel failed?");
1596 assert_eq!(fake_device_state.lock().primary_channel, expected_primary);
1598 assert_eq!(fake_device_state.lock().bandwidth, expected_bandwidth);
1599 assert_eq!(
1600 fake_device_state.lock().vht_secondary_80_channel,
1601 expected_vht_secondary_80_channel
1602 );
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}