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