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