Skip to main content

wlan_fullmac_mlme/
device.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use anyhow::{Context, format_err};
6use fidl::endpoints::ClientEnd;
7use {
8    fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_fullmac as fidl_fullmac,
9    fidl_fuchsia_wlan_mlme as fidl_mlme, fidl_fuchsia_wlan_stats as fidl_stats,
10};
11
12/// This trait abstracts how Device accomplish operations. Test code
13/// can then implement trait methods instead of mocking an underlying DeviceInterface
14/// and FIDL proxy.
15pub trait DeviceOps {
16    fn init(
17        &mut self,
18        fullmac_ifc_client_end: ClientEnd<fidl_fullmac::WlanFullmacImplIfcMarker>,
19    ) -> Result<fidl::Channel, zx::Status>;
20    fn query_device_info(&self) -> anyhow::Result<fidl_fullmac::WlanFullmacImplQueryResponse>;
21    fn query_security_support(&self) -> anyhow::Result<fidl_common::SecuritySupport>;
22    fn query_spectrum_management_support(
23        &self,
24    ) -> anyhow::Result<fidl_common::SpectrumManagementSupport>;
25    fn query_telemetry_support(&self) -> anyhow::Result<Result<fidl_stats::TelemetrySupport, i32>>;
26    fn query_apf_packet_filter_support(
27        &self,
28    ) -> anyhow::Result<Result<fidl_common::ApfPacketFilterSupport, i32>>;
29    fn start_scan(&self, req: fidl_fullmac::WlanFullmacImplStartScanRequest) -> anyhow::Result<()>;
30    fn connect(&self, req: fidl_fullmac::WlanFullmacImplConnectRequest) -> anyhow::Result<()>;
31    fn reconnect(&self, req: fidl_fullmac::WlanFullmacImplReconnectRequest) -> anyhow::Result<()>;
32    fn roam(&self, req: fidl_fullmac::WlanFullmacImplRoamRequest) -> anyhow::Result<()>;
33    fn auth_resp(&self, resp: fidl_fullmac::WlanFullmacImplAuthRespRequest) -> anyhow::Result<()>;
34    fn deauth(&self, req: fidl_fullmac::WlanFullmacImplDeauthRequest) -> anyhow::Result<()>;
35    fn assoc_resp(&self, resp: fidl_fullmac::WlanFullmacImplAssocRespRequest)
36    -> anyhow::Result<()>;
37    fn disassoc(&self, req: fidl_fullmac::WlanFullmacImplDisassocRequest) -> anyhow::Result<()>;
38    fn start_bss(&self, req: fidl_fullmac::WlanFullmacImplStartBssRequest) -> anyhow::Result<()>;
39    fn stop_bss(&self, req: fidl_fullmac::WlanFullmacImplStopBssRequest) -> anyhow::Result<()>;
40    fn set_keys(
41        &self,
42        req: fidl_fullmac::WlanFullmacImplSetKeysRequest,
43    ) -> anyhow::Result<fidl_fullmac::WlanFullmacSetKeysResp>;
44    fn eapol_tx(&self, req: fidl_fullmac::WlanFullmacImplEapolTxRequest) -> anyhow::Result<()>;
45    fn get_iface_stats(&self) -> anyhow::Result<fidl_mlme::GetIfaceStatsResponse>;
46    fn get_iface_histogram_stats(
47        &self,
48    ) -> anyhow::Result<fidl_mlme::GetIfaceHistogramStatsResponse>;
49    fn get_signal_report(&self) -> anyhow::Result<Result<fidl_stats::SignalReport, i32>>;
50    fn sae_handshake_resp(
51        &self,
52        resp: fidl_fullmac::WlanFullmacImplSaeHandshakeRespRequest,
53    ) -> anyhow::Result<()>;
54    fn sae_frame_tx(&self, frame: fidl_fullmac::SaeFrame) -> anyhow::Result<()>;
55    fn wmm_status_req(&self) -> anyhow::Result<()>;
56    fn on_link_state_changed(
57        &self,
58        req: fidl_fullmac::WlanFullmacImplOnLinkStateChangedRequest,
59    ) -> anyhow::Result<()>;
60    fn set_mac_address(
61        &self,
62        req: fidl_fullmac::WlanFullmacImplSetMacAddressRequest,
63    ) -> anyhow::Result<Result<(), i32>>;
64    fn install_apf_packet_filter(
65        &self,
66        req: fidl_fullmac::WlanFullmacImplInstallApfPacketFilterRequest,
67    ) -> anyhow::Result<Result<(), i32>>;
68    fn read_apf_packet_filter_data(
69        &self,
70    ) -> anyhow::Result<Result<fidl_fullmac::WlanFullmacImplReadApfPacketFilterDataResponse, i32>>;
71    fn set_apf_packet_filter_enabled(
72        &self,
73        req: fidl_fullmac::WlanFullmacImplSetApfPacketFilterEnabledRequest,
74    ) -> anyhow::Result<Result<(), i32>>;
75    fn get_apf_packet_filter_enabled(
76        &self,
77    ) -> anyhow::Result<Result<fidl_fullmac::WlanFullmacImplGetApfPacketFilterEnabledResponse, i32>>;
78}
79
80pub struct FullmacDevice {
81    fullmac_impl_sync_proxy: fidl_fullmac::WlanFullmacImpl_SynchronousProxy,
82}
83
84/// TODO(https://fxbug.dev/368323681): Users should be notified when the WlanFullmacImpl channel
85/// closes.
86impl FullmacDevice {
87    pub fn new(
88        fullmac_impl_sync_proxy: fidl_fullmac::WlanFullmacImpl_SynchronousProxy,
89    ) -> FullmacDevice {
90        FullmacDevice { fullmac_impl_sync_proxy }
91    }
92}
93
94impl DeviceOps for FullmacDevice {
95    fn init(
96        &mut self,
97        fullmac_ifc_client_end: ClientEnd<fidl_fullmac::WlanFullmacImplIfcMarker>,
98    ) -> Result<fidl::Channel, zx::Status> {
99        let req = fidl_fullmac::WlanFullmacImplInitRequest {
100            ifc: Some(fullmac_ifc_client_end),
101            ..Default::default()
102        };
103        let resp = self
104            .fullmac_impl_sync_proxy
105            .init(req, zx::MonotonicInstant::INFINITE)
106            .map_err(|e| {
107                log::error!("FIDL error on Start: {}", e);
108                zx::Status::INTERNAL
109            })?
110            .map_err(|e| zx::Status::from_raw(e))?;
111
112        resp.sme_channel.ok_or(zx::Status::INVALID_ARGS)
113    }
114
115    fn query_device_info(&self) -> anyhow::Result<fidl_fullmac::WlanFullmacImplQueryResponse> {
116        self.fullmac_impl_sync_proxy
117            .query(zx::MonotonicInstant::INFINITE)
118            .context("FIDL error on QueryDeviceInfo")?
119            .map_err(|e| format_err!("Driver returned error on QueryDeviceInfo: {}", e))
120    }
121
122    fn query_security_support(&self) -> anyhow::Result<fidl_common::SecuritySupport> {
123        self.fullmac_impl_sync_proxy
124            .query_security_support(zx::MonotonicInstant::INFINITE)
125            .context("FIDL error on QuerySecuritySupport")?
126            .map_err(|e| format_err!("Driver returned error on QuerySecuritySupport: {}", e))
127            .and_then(|support| {
128                support.resp.ok_or_else(|| {
129                    format_err!("Driver returned empty QuerySecuritySupport response")
130                })
131            })
132    }
133
134    fn query_spectrum_management_support(
135        &self,
136    ) -> anyhow::Result<fidl_common::SpectrumManagementSupport> {
137        self.fullmac_impl_sync_proxy
138            .query_spectrum_management_support(zx::MonotonicInstant::INFINITE)
139            .context("FIDL error on QuerySpectrumManagementSupport")?
140            .map_err(|e| {
141                format_err!("Driver returned error on QuerySpectrumManagementSupport: {}", e)
142            })
143            .and_then(|support| {
144                support.resp.ok_or_else(|| {
145                    format_err!("Driver returned empty QuerySpectrumManagementSupport response")
146                })
147            })
148    }
149
150    fn query_telemetry_support(&self) -> anyhow::Result<Result<fidl_stats::TelemetrySupport, i32>> {
151        self.fullmac_impl_sync_proxy
152            .query_telemetry_support(zx::MonotonicInstant::INFINITE)
153            .context("FIDL error on QueryTelemetrySupport")
154            .and_then(|support| match support {
155                Ok(response) => response
156                    .resp
157                    .ok_or_else(|| {
158                        format_err!("Driver returned empty QueryTelemetrySupport response")
159                    })
160                    .map(Ok),
161                Err(e) => Ok(Err(e)),
162            })
163    }
164
165    fn query_apf_packet_filter_support(
166        &self,
167    ) -> anyhow::Result<Result<fidl_common::ApfPacketFilterSupport, i32>> {
168        self.fullmac_impl_sync_proxy
169            .query_apf_packet_filter_support(zx::MonotonicInstant::INFINITE)
170            .context("FIDL error on QueryApfPacketFilterSupport")
171            .and_then(|support| match support {
172                Ok(response) => response
173                    .resp
174                    .ok_or_else(|| {
175                        format_err!("Driver returned empty QueryApfPacketFilterSupport response")
176                    })
177                    .map(Ok),
178                Err(e) => Ok(Err(e)),
179            })
180    }
181
182    fn start_scan(&self, req: fidl_fullmac::WlanFullmacImplStartScanRequest) -> anyhow::Result<()> {
183        self.fullmac_impl_sync_proxy
184            .start_scan(&req, zx::MonotonicInstant::INFINITE)
185            .context("FIDL error on StartScan")
186    }
187    fn connect(&self, req: fidl_fullmac::WlanFullmacImplConnectRequest) -> anyhow::Result<()> {
188        self.fullmac_impl_sync_proxy
189            .connect(&req, zx::MonotonicInstant::INFINITE)
190            .context("FIDL error on Connect")
191    }
192    fn reconnect(&self, req: fidl_fullmac::WlanFullmacImplReconnectRequest) -> anyhow::Result<()> {
193        self.fullmac_impl_sync_proxy
194            .reconnect(&req, zx::MonotonicInstant::INFINITE)
195            .context("FIDL error on Reconnect")
196    }
197    fn roam(&self, req: fidl_fullmac::WlanFullmacImplRoamRequest) -> anyhow::Result<()> {
198        self.fullmac_impl_sync_proxy
199            .roam(&req, zx::MonotonicInstant::INFINITE)
200            .context("FIDL error on Roam")
201    }
202    fn auth_resp(&self, resp: fidl_fullmac::WlanFullmacImplAuthRespRequest) -> anyhow::Result<()> {
203        self.fullmac_impl_sync_proxy
204            .auth_resp(&resp, zx::MonotonicInstant::INFINITE)
205            .context("FIDL error on AuthResp")
206    }
207    fn deauth(&self, req: fidl_fullmac::WlanFullmacImplDeauthRequest) -> anyhow::Result<()> {
208        self.fullmac_impl_sync_proxy
209            .deauth(&req, zx::MonotonicInstant::INFINITE)
210            .context("FIDL error on Deauth")
211    }
212    fn assoc_resp(
213        &self,
214        resp: fidl_fullmac::WlanFullmacImplAssocRespRequest,
215    ) -> anyhow::Result<()> {
216        self.fullmac_impl_sync_proxy
217            .assoc_resp(&resp, zx::MonotonicInstant::INFINITE)
218            .context("FIDL error on AssocResp")
219    }
220    fn disassoc(&self, req: fidl_fullmac::WlanFullmacImplDisassocRequest) -> anyhow::Result<()> {
221        self.fullmac_impl_sync_proxy
222            .disassoc(&req, zx::MonotonicInstant::INFINITE)
223            .context("FIDL error on Disassoc")
224    }
225    fn start_bss(&self, req: fidl_fullmac::WlanFullmacImplStartBssRequest) -> anyhow::Result<()> {
226        self.fullmac_impl_sync_proxy
227            .start_bss(&req, zx::MonotonicInstant::INFINITE)
228            .context("FIDL error on StartBss")
229    }
230    fn stop_bss(&self, req: fidl_fullmac::WlanFullmacImplStopBssRequest) -> anyhow::Result<()> {
231        self.fullmac_impl_sync_proxy
232            .stop_bss(&req, zx::MonotonicInstant::INFINITE)
233            .context("FIDL error on StopBss")
234    }
235    fn set_keys(
236        &self,
237        req: fidl_fullmac::WlanFullmacImplSetKeysRequest,
238    ) -> anyhow::Result<fidl_fullmac::WlanFullmacSetKeysResp> {
239        self.fullmac_impl_sync_proxy
240            .set_keys(&req, zx::MonotonicInstant::INFINITE)
241            .context("FIDL error on SetKeysReq")
242    }
243    fn eapol_tx(&self, req: fidl_fullmac::WlanFullmacImplEapolTxRequest) -> anyhow::Result<()> {
244        self.fullmac_impl_sync_proxy
245            .eapol_tx(&req, zx::MonotonicInstant::INFINITE)
246            .context("FIDL error on EapolTx")
247    }
248    fn get_iface_stats(&self) -> anyhow::Result<fidl_mlme::GetIfaceStatsResponse> {
249        match self
250            .fullmac_impl_sync_proxy
251            .get_iface_stats(zx::MonotonicInstant::INFINITE)
252            .context("FIDL error on GetIfaceStats")?
253        {
254            Ok(stats) => Ok(fidl_mlme::GetIfaceStatsResponse::Stats(stats)),
255            Err(e) => Ok(fidl_mlme::GetIfaceStatsResponse::ErrorStatus(e)),
256        }
257    }
258    fn get_iface_histogram_stats(
259        &self,
260    ) -> anyhow::Result<fidl_mlme::GetIfaceHistogramStatsResponse> {
261        match self
262            .fullmac_impl_sync_proxy
263            .get_iface_histogram_stats(zx::MonotonicInstant::INFINITE)
264            .context("FIDL error on GetIfaceHistogramStats")?
265        {
266            Ok(stats) => Ok(fidl_mlme::GetIfaceHistogramStatsResponse::Stats(stats)),
267            Err(e) => Ok(fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(e)),
268        }
269    }
270    fn get_signal_report(&self) -> anyhow::Result<Result<fidl_stats::SignalReport, i32>> {
271        self.fullmac_impl_sync_proxy
272            .get_signal_report(zx::MonotonicInstant::INFINITE)
273            .context("FIDL error on GetSignalReport")
274    }
275
276    fn sae_handshake_resp(
277        &self,
278        resp: fidl_fullmac::WlanFullmacImplSaeHandshakeRespRequest,
279    ) -> anyhow::Result<()> {
280        self.fullmac_impl_sync_proxy
281            .sae_handshake_resp(&resp, zx::MonotonicInstant::INFINITE)
282            .context("FIDL error on SaeHandshakeResp")
283    }
284    fn sae_frame_tx(&self, frame: fidl_fullmac::SaeFrame) -> anyhow::Result<()> {
285        self.fullmac_impl_sync_proxy
286            .sae_frame_tx(&frame, zx::MonotonicInstant::INFINITE)
287            .context("FIDL error on SaeFrameTx")
288    }
289    fn wmm_status_req(&self) -> anyhow::Result<()> {
290        self.fullmac_impl_sync_proxy
291            .wmm_status_req(zx::MonotonicInstant::INFINITE)
292            .context("FIDL error on WmmStatusReq")
293    }
294    fn on_link_state_changed(
295        &self,
296        req: fidl_fullmac::WlanFullmacImplOnLinkStateChangedRequest,
297    ) -> anyhow::Result<()> {
298        self.fullmac_impl_sync_proxy
299            .on_link_state_changed(&req, zx::MonotonicInstant::INFINITE)
300            .context("FIDL error on OnLinkStateChanged")
301    }
302    fn set_mac_address(
303        &self,
304        req: fidl_fuchsia_wlan_fullmac::WlanFullmacImplSetMacAddressRequest,
305    ) -> anyhow::Result<Result<(), i32>> {
306        self.fullmac_impl_sync_proxy
307            .set_mac_address(&req.mac_addr, zx::MonotonicInstant::INFINITE)
308            .context("FIDL error on SetMacAddress")
309    }
310
311    fn install_apf_packet_filter(
312        &self,
313        req: fidl_fullmac::WlanFullmacImplInstallApfPacketFilterRequest,
314    ) -> anyhow::Result<Result<(), i32>> {
315        self.fullmac_impl_sync_proxy
316            .install_apf_packet_filter(&req, zx::MonotonicInstant::INFINITE)
317            .context("FIDL error on InstallApfPacketFilter")
318    }
319
320    fn read_apf_packet_filter_data(
321        &self,
322    ) -> anyhow::Result<Result<fidl_fullmac::WlanFullmacImplReadApfPacketFilterDataResponse, i32>>
323    {
324        self.fullmac_impl_sync_proxy
325            .read_apf_packet_filter_data(zx::MonotonicInstant::INFINITE)
326            .context("FIDL error on ReadApfPacketFilterData")
327    }
328
329    fn set_apf_packet_filter_enabled(
330        &self,
331        req: fidl_fullmac::WlanFullmacImplSetApfPacketFilterEnabledRequest,
332    ) -> anyhow::Result<Result<(), i32>> {
333        self.fullmac_impl_sync_proxy
334            .set_apf_packet_filter_enabled(&req, zx::MonotonicInstant::INFINITE)
335            .context("FIDL error on SetApfPacketFilterEnabled")
336    }
337
338    fn get_apf_packet_filter_enabled(
339        &self,
340    ) -> anyhow::Result<Result<fidl_fullmac::WlanFullmacImplGetApfPacketFilterEnabledResponse, i32>>
341    {
342        self.fullmac_impl_sync_proxy
343            .get_apf_packet_filter_enabled(zx::MonotonicInstant::INFINITE)
344            .context("FIDL error on GetApfPacketFilterEnabled")
345    }
346}
347
348#[cfg(test)]
349pub mod test_utils {
350    use super::*;
351    use fidl_fuchsia_wlan_sme as fidl_sme;
352    use fuchsia_sync::Mutex;
353    use futures::channel::mpsc;
354    use std::sync::Arc;
355    use wlan_common::sink::UnboundedSink;
356
357    #[derive(Debug)]
358    pub enum DriverCall {
359        StartScan {
360            req: fidl_fullmac::WlanFullmacImplStartScanRequest,
361        },
362        ConnectReq {
363            req: fidl_fullmac::WlanFullmacImplConnectRequest,
364        },
365        ReconnectReq {
366            req: fidl_fullmac::WlanFullmacImplReconnectRequest,
367        },
368        RoamReq {
369            req: fidl_fullmac::WlanFullmacImplRoamRequest,
370        },
371        AuthResp {
372            resp: fidl_fullmac::WlanFullmacImplAuthRespRequest,
373        },
374        DeauthReq {
375            req: fidl_fullmac::WlanFullmacImplDeauthRequest,
376        },
377        AssocResp {
378            resp: fidl_fullmac::WlanFullmacImplAssocRespRequest,
379        },
380        Disassoc {
381            req: fidl_fullmac::WlanFullmacImplDisassocRequest,
382        },
383        StartBss {
384            req: fidl_fullmac::WlanFullmacImplStartBssRequest,
385        },
386        StopBss {
387            req: fidl_fullmac::WlanFullmacImplStopBssRequest,
388        },
389        SetKeys {
390            req: fidl_fullmac::WlanFullmacImplSetKeysRequest,
391        },
392        EapolTx {
393            req: fidl_fullmac::WlanFullmacImplEapolTxRequest,
394        },
395        QueryTelemetrySupport,
396        QueryApfPacketFilterSupport,
397        GetIfaceStats,
398        GetIfaceHistogramStats,
399        GetSignalReport,
400        SaeHandshakeResp {
401            resp: fidl_fullmac::WlanFullmacImplSaeHandshakeRespRequest,
402        },
403        SaeFrameTx {
404            frame: fidl_fullmac::SaeFrame,
405        },
406        WmmStatusReq,
407        OnLinkStateChanged {
408            req: fidl_fullmac::WlanFullmacImplOnLinkStateChangedRequest,
409        },
410        SetMacAddress {
411            req: fidl_fullmac::WlanFullmacImplSetMacAddressRequest,
412        },
413        InstallApfPacketFilter {
414            req: fidl_fullmac::WlanFullmacImplInstallApfPacketFilterRequest,
415        },
416        ReadApfPacketFilterData,
417        SetApfPacketFilterEnabled {
418            req: fidl_fullmac::WlanFullmacImplSetApfPacketFilterEnabledRequest,
419        },
420        GetApfPacketFilterEnabled,
421    }
422
423    pub struct FakeFullmacDeviceMocks {
424        pub start_fn_status_mock: Option<zx::sys::zx_status_t>,
425
426        // Note: anyhow::Error isn't cloneable, so the query mocks are all optionals to make this
427        // easier to work with.
428        //
429        // If any of the query mocks are None, then an Err is returned from DeviceOps with an empty
430        // error message.
431        pub query_device_info_mock: Option<fidl_fullmac::WlanFullmacImplQueryResponse>,
432        pub query_security_support_mock: Option<fidl_common::SecuritySupport>,
433        pub query_spectrum_management_support_mock: Option<fidl_common::SpectrumManagementSupport>,
434        pub query_telemetry_support_mock: Option<Result<fidl_stats::TelemetrySupport, i32>>,
435        pub query_apf_packet_filter_support_mock:
436            Option<Result<fidl_common::ApfPacketFilterSupport, i32>>,
437
438        pub set_keys_resp_mock: Option<fidl_fullmac::WlanFullmacSetKeysResp>,
439        pub get_iface_stats_mock: Option<fidl_mlme::GetIfaceStatsResponse>,
440        pub get_iface_histogram_stats_mock: Option<fidl_mlme::GetIfaceHistogramStatsResponse>,
441        pub get_signal_report_mock: Option<Result<fidl_stats::SignalReport, i32>>,
442        pub install_apf_packet_filter_mock: Option<Result<(), i32>>,
443        pub read_apf_packet_filter_data_mock:
444            Option<Result<fidl_fullmac::WlanFullmacImplReadApfPacketFilterDataResponse, i32>>,
445        pub set_apf_packet_filter_enabled_mock: Option<Result<(), i32>>,
446        pub get_apf_packet_filter_enabled_mock:
447            Option<Result<fidl_fullmac::WlanFullmacImplGetApfPacketFilterEnabledResponse, i32>>,
448
449        pub fullmac_ifc_client_end: Option<ClientEnd<fidl_fullmac::WlanFullmacImplIfcMarker>>,
450    }
451
452    unsafe impl Send for FakeFullmacDevice {}
453    pub struct FakeFullmacDevice {
454        pub usme_bootstrap_client_end:
455            Option<fidl::endpoints::ClientEnd<fidl_sme::UsmeBootstrapMarker>>,
456        pub usme_bootstrap_server_end:
457            Option<fidl::endpoints::ServerEnd<fidl_sme::UsmeBootstrapMarker>>,
458        driver_call_sender: UnboundedSink<DriverCall>,
459
460        // This is boxed because tests want a reference to this to check captured calls, but in
461        // production we pass ownership of the DeviceOps to FullmacMlme. This avoids changing
462        // ownership semantics for tests.
463        pub mocks: Arc<Mutex<FakeFullmacDeviceMocks>>,
464    }
465
466    impl FakeFullmacDevice {
467        pub fn new() -> (Self, mpsc::UnboundedReceiver<DriverCall>) {
468            // Create a channel for SME requests, to be surfaced by init().
469            let (usme_bootstrap_client_end, usme_bootstrap_server_end) =
470                fidl::endpoints::create_endpoints::<fidl_sme::UsmeBootstrapMarker>();
471
472            let (driver_call_sender, driver_call_receiver) = mpsc::unbounded();
473
474            let device = Self {
475                usme_bootstrap_client_end: Some(usme_bootstrap_client_end),
476                usme_bootstrap_server_end: Some(usme_bootstrap_server_end),
477                driver_call_sender: UnboundedSink::new(driver_call_sender),
478                mocks: Arc::new(Mutex::new(FakeFullmacDeviceMocks {
479                    fullmac_ifc_client_end: None,
480                    start_fn_status_mock: None,
481                    query_device_info_mock: Some(fidl_fullmac::WlanFullmacImplQueryResponse {
482                        sta_addr: Some([0u8; 6]),
483                        factory_addr: Some([0u8; 6]),
484                        role: Some(fidl_common::WlanMacRole::Client),
485                        band_caps: Some(vec![]),
486                        ..Default::default()
487                    }),
488                    query_security_support_mock: Some(fidl_common::SecuritySupport {
489                        sae: Some(fidl_common::SaeFeature {
490                            driver_handler_supported: Some(false),
491                            sme_handler_supported: Some(true),
492                            hash_to_element_supported: Some(false),
493                            ..Default::default()
494                        }),
495                        mfp: Some(fidl_common::MfpFeature {
496                            supported: Some(false),
497                            ..Default::default()
498                        }),
499                        owe: Some(fidl_common::OweFeature {
500                            supported: Some(false),
501                            ..Default::default()
502                        }),
503                        ..Default::default()
504                    }),
505                    query_spectrum_management_support_mock: Some(
506                        fidl_common::SpectrumManagementSupport {
507                            dfs: Some(fidl_common::DfsFeature {
508                                supported: Some(false),
509                                ..Default::default()
510                            }),
511                            ..Default::default()
512                        },
513                    ),
514                    query_telemetry_support_mock: Some(Ok(fidl_stats::TelemetrySupport {
515                        ..Default::default()
516                    })),
517                    query_apf_packet_filter_support_mock: Some(Ok(
518                        fidl_common::ApfPacketFilterSupport {
519                            supported: Some(false),
520                            ..Default::default()
521                        },
522                    )),
523                    get_signal_report_mock: Some(Ok(fidl_stats::SignalReport {
524                        ..Default::default()
525                    })),
526                    set_keys_resp_mock: None,
527                    get_iface_stats_mock: None,
528                    get_iface_histogram_stats_mock: None,
529                    install_apf_packet_filter_mock: Some(Ok(())),
530                    read_apf_packet_filter_data_mock: Some(Ok(
531                        fidl_fullmac::WlanFullmacImplReadApfPacketFilterDataResponse {
532                            memory: Some(vec![]),
533                            ..Default::default()
534                        },
535                    )),
536                    set_apf_packet_filter_enabled_mock: Some(Ok(())),
537                    get_apf_packet_filter_enabled_mock: Some(Ok(
538                        fidl_fullmac::WlanFullmacImplGetApfPacketFilterEnabledResponse {
539                            enabled: Some(false),
540                            ..Default::default()
541                        },
542                    )),
543                })),
544            };
545
546            (device, driver_call_receiver)
547        }
548    }
549
550    impl DeviceOps for FakeFullmacDevice {
551        fn init(
552            &mut self,
553            fullmac_ifc_client_end: ClientEnd<fidl_fullmac::WlanFullmacImplIfcMarker>,
554        ) -> Result<fidl::Channel, zx::Status> {
555            let mut mocks = self.mocks.lock();
556
557            mocks.fullmac_ifc_client_end = Some(fullmac_ifc_client_end);
558            match mocks.start_fn_status_mock {
559                Some(status) => Err(zx::Status::from_raw(status)),
560
561                // Start can only be called once since this moves usme_bootstrap_server_end.
562                None => Ok(self.usme_bootstrap_server_end.take().unwrap().into_channel()),
563            }
564        }
565
566        fn query_device_info(&self) -> anyhow::Result<fidl_fullmac::WlanFullmacImplQueryResponse> {
567            self.mocks.lock().query_device_info_mock.clone().ok_or_else(|| format_err!(""))
568        }
569
570        fn query_security_support(&self) -> anyhow::Result<fidl_common::SecuritySupport> {
571            self.mocks.lock().query_security_support_mock.clone().ok_or_else(|| format_err!(""))
572        }
573
574        fn query_spectrum_management_support(
575            &self,
576        ) -> anyhow::Result<fidl_common::SpectrumManagementSupport> {
577            self.mocks
578                .lock()
579                .query_spectrum_management_support_mock
580                .clone()
581                .ok_or_else(|| format_err!(""))
582        }
583
584        fn query_telemetry_support(
585            &self,
586        ) -> anyhow::Result<Result<fidl_stats::TelemetrySupport, i32>> {
587            self.driver_call_sender.send(DriverCall::QueryTelemetrySupport);
588            self.mocks.lock().query_telemetry_support_mock.clone().ok_or_else(|| format_err!(""))
589        }
590
591        fn query_apf_packet_filter_support(
592            &self,
593        ) -> anyhow::Result<Result<fidl_common::ApfPacketFilterSupport, i32>> {
594            self.driver_call_sender.send(DriverCall::QueryApfPacketFilterSupport);
595            self.mocks.lock().query_apf_packet_filter_support_mock.clone().ok_or_else(|| {
596                format_err!("query_apf_packet_filter_support_mock is None in FakeFullmacDevice")
597            })
598        }
599
600        // Cannot mark fn unsafe because it has to match fn signature in FullDeviceInterface
601        fn start_scan(
602            &self,
603            req: fidl_fullmac::WlanFullmacImplStartScanRequest,
604        ) -> anyhow::Result<()> {
605            self.driver_call_sender.send(DriverCall::StartScan { req });
606            Ok(())
607        }
608
609        fn connect(&self, req: fidl_fullmac::WlanFullmacImplConnectRequest) -> anyhow::Result<()> {
610            self.driver_call_sender.send(DriverCall::ConnectReq { req });
611            Ok(())
612        }
613        fn reconnect(
614            &self,
615            req: fidl_fullmac::WlanFullmacImplReconnectRequest,
616        ) -> anyhow::Result<()> {
617            self.driver_call_sender.send(DriverCall::ReconnectReq { req });
618            Ok(())
619        }
620        fn roam(&self, req: fidl_fullmac::WlanFullmacImplRoamRequest) -> anyhow::Result<()> {
621            self.driver_call_sender.send(DriverCall::RoamReq { req });
622            Ok(())
623        }
624        fn auth_resp(
625            &self,
626            resp: fidl_fullmac::WlanFullmacImplAuthRespRequest,
627        ) -> anyhow::Result<()> {
628            self.driver_call_sender.send(DriverCall::AuthResp { resp });
629            Ok(())
630        }
631        fn deauth(&self, req: fidl_fullmac::WlanFullmacImplDeauthRequest) -> anyhow::Result<()> {
632            self.driver_call_sender.send(DriverCall::DeauthReq { req });
633            Ok(())
634        }
635        fn assoc_resp(
636            &self,
637            resp: fidl_fullmac::WlanFullmacImplAssocRespRequest,
638        ) -> anyhow::Result<()> {
639            self.driver_call_sender.send(DriverCall::AssocResp { resp });
640            Ok(())
641        }
642        fn disassoc(
643            &self,
644            req: fidl_fullmac::WlanFullmacImplDisassocRequest,
645        ) -> anyhow::Result<()> {
646            self.driver_call_sender.send(DriverCall::Disassoc { req });
647            Ok(())
648        }
649        fn start_bss(
650            &self,
651            req: fidl_fullmac::WlanFullmacImplStartBssRequest,
652        ) -> anyhow::Result<()> {
653            self.driver_call_sender.send(DriverCall::StartBss { req });
654            Ok(())
655        }
656        fn stop_bss(&self, req: fidl_fullmac::WlanFullmacImplStopBssRequest) -> anyhow::Result<()> {
657            self.driver_call_sender.send(DriverCall::StopBss { req });
658            Ok(())
659        }
660        fn set_keys(
661            &self,
662            req: fidl_fullmac::WlanFullmacImplSetKeysRequest,
663        ) -> anyhow::Result<fidl_fullmac::WlanFullmacSetKeysResp> {
664            let num_keys = req.keylist.as_ref().unwrap().len();
665            self.driver_call_sender.send(DriverCall::SetKeys { req });
666            match &self.mocks.lock().set_keys_resp_mock {
667                Some(resp) => Ok(resp.clone()),
668                None => {
669                    Ok(fidl_fullmac::WlanFullmacSetKeysResp { statuslist: vec![0i32; num_keys] })
670                }
671            }
672        }
673        fn eapol_tx(&self, req: fidl_fullmac::WlanFullmacImplEapolTxRequest) -> anyhow::Result<()> {
674            self.driver_call_sender.send(DriverCall::EapolTx { req });
675            Ok(())
676        }
677        fn get_iface_stats(&self) -> anyhow::Result<fidl_mlme::GetIfaceStatsResponse> {
678            self.driver_call_sender.send(DriverCall::GetIfaceStats);
679            Ok(self.mocks.lock().get_iface_stats_mock.clone().unwrap_or(
680                fidl_mlme::GetIfaceStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED),
681            ))
682        }
683        fn get_iface_histogram_stats(
684            &self,
685        ) -> anyhow::Result<fidl_mlme::GetIfaceHistogramStatsResponse> {
686            self.driver_call_sender.send(DriverCall::GetIfaceHistogramStats);
687            Ok(self.mocks.lock().get_iface_histogram_stats_mock.clone().unwrap_or(
688                fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(
689                    zx::sys::ZX_ERR_NOT_SUPPORTED,
690                ),
691            ))
692        }
693        fn get_signal_report(&self) -> anyhow::Result<Result<fidl_stats::SignalReport, i32>> {
694            self.driver_call_sender.send(DriverCall::GetSignalReport);
695            self.mocks.lock().get_signal_report_mock.clone().ok_or_else(|| format_err!(""))
696        }
697        fn sae_handshake_resp(
698            &self,
699            resp: fidl_fullmac::WlanFullmacImplSaeHandshakeRespRequest,
700        ) -> anyhow::Result<()> {
701            self.driver_call_sender.send(DriverCall::SaeHandshakeResp { resp });
702            Ok(())
703        }
704        fn sae_frame_tx(&self, frame: fidl_fullmac::SaeFrame) -> anyhow::Result<()> {
705            self.driver_call_sender.send(DriverCall::SaeFrameTx { frame });
706            Ok(())
707        }
708        fn wmm_status_req(&self) -> anyhow::Result<()> {
709            self.driver_call_sender.send(DriverCall::WmmStatusReq);
710            Ok(())
711        }
712        fn on_link_state_changed(
713            &self,
714            req: fidl_fullmac::WlanFullmacImplOnLinkStateChangedRequest,
715        ) -> anyhow::Result<()> {
716            self.driver_call_sender.send(DriverCall::OnLinkStateChanged { req });
717            Ok(())
718        }
719        fn set_mac_address(
720            &self,
721            req: fidl_fuchsia_wlan_fullmac::WlanFullmacImplSetMacAddressRequest,
722        ) -> anyhow::Result<Result<(), i32>> {
723            self.driver_call_sender.send(DriverCall::SetMacAddress { req });
724            Ok(Ok(()))
725        }
726
727        fn install_apf_packet_filter(
728            &self,
729            req: fidl_fullmac::WlanFullmacImplInstallApfPacketFilterRequest,
730        ) -> anyhow::Result<Result<(), i32>> {
731            self.driver_call_sender.send(DriverCall::InstallApfPacketFilter { req });
732            self.mocks.lock().install_apf_packet_filter_mock.clone().ok_or_else(|| {
733                format_err!("install_apf_packet_filter_mock is None in FakeFullmacDevice")
734            })
735        }
736
737        fn read_apf_packet_filter_data(
738            &self,
739        ) -> anyhow::Result<Result<fidl_fullmac::WlanFullmacImplReadApfPacketFilterDataResponse, i32>>
740        {
741            self.driver_call_sender.send(DriverCall::ReadApfPacketFilterData);
742            self.mocks.lock().read_apf_packet_filter_data_mock.clone().ok_or_else(|| {
743                format_err!("read_apf_packet_filter_data_mock is None in FakeFullmacDevice")
744            })
745        }
746
747        fn set_apf_packet_filter_enabled(
748            &self,
749            req: fidl_fullmac::WlanFullmacImplSetApfPacketFilterEnabledRequest,
750        ) -> anyhow::Result<Result<(), i32>> {
751            self.driver_call_sender.send(DriverCall::SetApfPacketFilterEnabled { req });
752            self.mocks.lock().set_apf_packet_filter_enabled_mock.clone().ok_or_else(|| {
753                format_err!("set_apf_packet_filter_enabled_mock is None in FakeFullmacDevice")
754            })
755        }
756
757        fn get_apf_packet_filter_enabled(
758            &self,
759        ) -> anyhow::Result<
760            Result<fidl_fullmac::WlanFullmacImplGetApfPacketFilterEnabledResponse, i32>,
761        > {
762            self.driver_call_sender.send(DriverCall::GetApfPacketFilterEnabled);
763            self.mocks.lock().get_apf_packet_filter_enabled_mock.clone().ok_or_else(|| {
764                format_err!("get_apf_packet_filter_enabled_mock is None in FakeFullmacDevice")
765            })
766        }
767    }
768}