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