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 start_scan(&self, req: fidl_fullmac::WlanFullmacImplStartScanRequest) -> anyhow::Result<()>;
27    fn connect(&self, req: fidl_fullmac::WlanFullmacImplConnectRequest) -> anyhow::Result<()>;
28    fn reconnect(&self, req: fidl_fullmac::WlanFullmacImplReconnectRequest) -> anyhow::Result<()>;
29    fn roam(&self, req: fidl_fullmac::WlanFullmacImplRoamRequest) -> anyhow::Result<()>;
30    fn auth_resp(&self, resp: fidl_fullmac::WlanFullmacImplAuthRespRequest) -> anyhow::Result<()>;
31    fn deauth(&self, req: fidl_fullmac::WlanFullmacImplDeauthRequest) -> anyhow::Result<()>;
32    fn assoc_resp(&self, resp: fidl_fullmac::WlanFullmacImplAssocRespRequest)
33    -> anyhow::Result<()>;
34    fn disassoc(&self, req: fidl_fullmac::WlanFullmacImplDisassocRequest) -> anyhow::Result<()>;
35    fn start_bss(&self, req: fidl_fullmac::WlanFullmacImplStartBssRequest) -> anyhow::Result<()>;
36    fn stop_bss(&self, req: fidl_fullmac::WlanFullmacImplStopBssRequest) -> anyhow::Result<()>;
37    fn set_keys(
38        &self,
39        req: fidl_fullmac::WlanFullmacImplSetKeysRequest,
40    ) -> anyhow::Result<fidl_fullmac::WlanFullmacSetKeysResp>;
41    fn eapol_tx(&self, req: fidl_fullmac::WlanFullmacImplEapolTxRequest) -> anyhow::Result<()>;
42    fn get_iface_stats(&self) -> anyhow::Result<fidl_mlme::GetIfaceStatsResponse>;
43    fn get_iface_histogram_stats(
44        &self,
45    ) -> anyhow::Result<fidl_mlme::GetIfaceHistogramStatsResponse>;
46    fn get_signal_report(&self) -> anyhow::Result<Result<fidl_stats::SignalReport, i32>>;
47    fn sae_handshake_resp(
48        &self,
49        resp: fidl_fullmac::WlanFullmacImplSaeHandshakeRespRequest,
50    ) -> anyhow::Result<()>;
51    fn sae_frame_tx(&self, frame: fidl_fullmac::SaeFrame) -> anyhow::Result<()>;
52    fn wmm_status_req(&self) -> anyhow::Result<()>;
53    fn on_link_state_changed(
54        &self,
55        req: fidl_fullmac::WlanFullmacImplOnLinkStateChangedRequest,
56    ) -> anyhow::Result<()>;
57    fn set_mac_address(
58        &self,
59        req: fidl_fullmac::WlanFullmacImplSetMacAddressRequest,
60    ) -> anyhow::Result<Result<(), i32>>;
61}
62
63pub struct FullmacDevice {
64    fullmac_impl_sync_proxy: fidl_fullmac::WlanFullmacImpl_SynchronousProxy,
65}
66
67/// TODO(https://fxbug.dev/368323681): Users should be notified when the WlanFullmacImpl channel
68/// closes.
69impl FullmacDevice {
70    pub fn new(
71        fullmac_impl_sync_proxy: fidl_fullmac::WlanFullmacImpl_SynchronousProxy,
72    ) -> FullmacDevice {
73        FullmacDevice { fullmac_impl_sync_proxy }
74    }
75}
76
77impl DeviceOps for FullmacDevice {
78    fn init(
79        &mut self,
80        fullmac_ifc_client_end: ClientEnd<fidl_fullmac::WlanFullmacImplIfcMarker>,
81    ) -> Result<fidl::Channel, zx::Status> {
82        let req = fidl_fullmac::WlanFullmacImplInitRequest {
83            ifc: Some(fullmac_ifc_client_end),
84            ..Default::default()
85        };
86        let resp = self
87            .fullmac_impl_sync_proxy
88            .init(req, zx::MonotonicInstant::INFINITE)
89            .map_err(|e| {
90                log::error!("FIDL error on Start: {}", e);
91                zx::Status::INTERNAL
92            })?
93            .map_err(|e| zx::Status::from_raw(e))?;
94
95        resp.sme_channel.ok_or(zx::Status::INVALID_ARGS)
96    }
97
98    fn query_device_info(&self) -> anyhow::Result<fidl_fullmac::WlanFullmacImplQueryResponse> {
99        self.fullmac_impl_sync_proxy
100            .query(zx::MonotonicInstant::INFINITE)
101            .context("FIDL error on QueryDeviceInfo")?
102            .map_err(|e| format_err!("Driver returned error on QueryDeviceInfo: {}", e))
103    }
104
105    fn query_security_support(&self) -> anyhow::Result<fidl_common::SecuritySupport> {
106        self.fullmac_impl_sync_proxy
107            .query_security_support(zx::MonotonicInstant::INFINITE)
108            .context("FIDL error on QuerySecuritySupport")?
109            .map_err(|e| format_err!("Driver returned error on QuerySecuritySupport: {}", e))
110    }
111
112    fn query_spectrum_management_support(
113        &self,
114    ) -> anyhow::Result<fidl_common::SpectrumManagementSupport> {
115        self.fullmac_impl_sync_proxy
116            .query_spectrum_management_support(zx::MonotonicInstant::INFINITE)
117            .context("FIDL error on QuerySpectrumManagementSupport")?
118            .map_err(|e| {
119                format_err!("Driver returned error on QuerySpectrumManagementSupport: {}", e)
120            })
121    }
122
123    fn query_telemetry_support(&self) -> anyhow::Result<Result<fidl_stats::TelemetrySupport, i32>> {
124        self.fullmac_impl_sync_proxy
125            .query_telemetry_support(zx::MonotonicInstant::INFINITE)
126            .context("FIDL error on QueryTelemetrySupport")
127    }
128
129    fn start_scan(&self, req: fidl_fullmac::WlanFullmacImplStartScanRequest) -> anyhow::Result<()> {
130        self.fullmac_impl_sync_proxy
131            .start_scan(&req, zx::MonotonicInstant::INFINITE)
132            .context("FIDL error on StartScan")
133    }
134    fn connect(&self, req: fidl_fullmac::WlanFullmacImplConnectRequest) -> anyhow::Result<()> {
135        self.fullmac_impl_sync_proxy
136            .connect(&req, zx::MonotonicInstant::INFINITE)
137            .context("FIDL error on Connect")
138    }
139    fn reconnect(&self, req: fidl_fullmac::WlanFullmacImplReconnectRequest) -> anyhow::Result<()> {
140        self.fullmac_impl_sync_proxy
141            .reconnect(&req, zx::MonotonicInstant::INFINITE)
142            .context("FIDL error on Reconnect")
143    }
144    fn roam(&self, req: fidl_fullmac::WlanFullmacImplRoamRequest) -> anyhow::Result<()> {
145        self.fullmac_impl_sync_proxy
146            .roam(&req, zx::MonotonicInstant::INFINITE)
147            .context("FIDL error on Roam")
148    }
149    fn auth_resp(&self, resp: fidl_fullmac::WlanFullmacImplAuthRespRequest) -> anyhow::Result<()> {
150        self.fullmac_impl_sync_proxy
151            .auth_resp(&resp, zx::MonotonicInstant::INFINITE)
152            .context("FIDL error on AuthResp")
153    }
154    fn deauth(&self, req: fidl_fullmac::WlanFullmacImplDeauthRequest) -> anyhow::Result<()> {
155        self.fullmac_impl_sync_proxy
156            .deauth(&req, zx::MonotonicInstant::INFINITE)
157            .context("FIDL error on Deauth")
158    }
159    fn assoc_resp(
160        &self,
161        resp: fidl_fullmac::WlanFullmacImplAssocRespRequest,
162    ) -> anyhow::Result<()> {
163        self.fullmac_impl_sync_proxy
164            .assoc_resp(&resp, zx::MonotonicInstant::INFINITE)
165            .context("FIDL error on AssocResp")
166    }
167    fn disassoc(&self, req: fidl_fullmac::WlanFullmacImplDisassocRequest) -> anyhow::Result<()> {
168        self.fullmac_impl_sync_proxy
169            .disassoc(&req, zx::MonotonicInstant::INFINITE)
170            .context("FIDL error on Disassoc")
171    }
172    fn start_bss(&self, req: fidl_fullmac::WlanFullmacImplStartBssRequest) -> anyhow::Result<()> {
173        self.fullmac_impl_sync_proxy
174            .start_bss(&req, zx::MonotonicInstant::INFINITE)
175            .context("FIDL error on StartBss")
176    }
177    fn stop_bss(&self, req: fidl_fullmac::WlanFullmacImplStopBssRequest) -> anyhow::Result<()> {
178        self.fullmac_impl_sync_proxy
179            .stop_bss(&req, zx::MonotonicInstant::INFINITE)
180            .context("FIDL error on StopBss")
181    }
182    fn set_keys(
183        &self,
184        req: fidl_fullmac::WlanFullmacImplSetKeysRequest,
185    ) -> anyhow::Result<fidl_fullmac::WlanFullmacSetKeysResp> {
186        self.fullmac_impl_sync_proxy
187            .set_keys(&req, zx::MonotonicInstant::INFINITE)
188            .context("FIDL error on SetKeysReq")
189    }
190    fn eapol_tx(&self, req: fidl_fullmac::WlanFullmacImplEapolTxRequest) -> anyhow::Result<()> {
191        self.fullmac_impl_sync_proxy
192            .eapol_tx(&req, zx::MonotonicInstant::INFINITE)
193            .context("FIDL error on EapolTx")
194    }
195    fn get_iface_stats(&self) -> anyhow::Result<fidl_mlme::GetIfaceStatsResponse> {
196        match self
197            .fullmac_impl_sync_proxy
198            .get_iface_stats(zx::MonotonicInstant::INFINITE)
199            .context("FIDL error on GetIfaceStats")?
200        {
201            Ok(stats) => Ok(fidl_mlme::GetIfaceStatsResponse::Stats(stats)),
202            Err(e) => Ok(fidl_mlme::GetIfaceStatsResponse::ErrorStatus(e)),
203        }
204    }
205    fn get_iface_histogram_stats(
206        &self,
207    ) -> anyhow::Result<fidl_mlme::GetIfaceHistogramStatsResponse> {
208        match self
209            .fullmac_impl_sync_proxy
210            .get_iface_histogram_stats(zx::MonotonicInstant::INFINITE)
211            .context("FIDL error on GetIfaceHistogramStats")?
212        {
213            Ok(stats) => Ok(fidl_mlme::GetIfaceHistogramStatsResponse::Stats(stats)),
214            Err(e) => Ok(fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(e)),
215        }
216    }
217    fn get_signal_report(&self) -> anyhow::Result<Result<fidl_stats::SignalReport, i32>> {
218        self.fullmac_impl_sync_proxy
219            .get_signal_report(zx::MonotonicInstant::INFINITE)
220            .context("FIDL error on GetSignalReport")
221    }
222
223    fn sae_handshake_resp(
224        &self,
225        resp: fidl_fullmac::WlanFullmacImplSaeHandshakeRespRequest,
226    ) -> anyhow::Result<()> {
227        self.fullmac_impl_sync_proxy
228            .sae_handshake_resp(&resp, zx::MonotonicInstant::INFINITE)
229            .context("FIDL error on SaeHandshakeResp")
230    }
231    fn sae_frame_tx(&self, frame: fidl_fullmac::SaeFrame) -> anyhow::Result<()> {
232        self.fullmac_impl_sync_proxy
233            .sae_frame_tx(&frame, zx::MonotonicInstant::INFINITE)
234            .context("FIDL error on SaeFrameTx")
235    }
236    fn wmm_status_req(&self) -> anyhow::Result<()> {
237        self.fullmac_impl_sync_proxy
238            .wmm_status_req(zx::MonotonicInstant::INFINITE)
239            .context("FIDL error on WmmStatusReq")
240    }
241    fn on_link_state_changed(
242        &self,
243        req: fidl_fullmac::WlanFullmacImplOnLinkStateChangedRequest,
244    ) -> anyhow::Result<()> {
245        self.fullmac_impl_sync_proxy
246            .on_link_state_changed(&req, zx::MonotonicInstant::INFINITE)
247            .context("FIDL error on OnLinkStateChanged")
248    }
249    fn set_mac_address(
250        &self,
251        req: fidl_fuchsia_wlan_fullmac::WlanFullmacImplSetMacAddressRequest,
252    ) -> anyhow::Result<Result<(), i32>> {
253        self.fullmac_impl_sync_proxy
254            .set_mac_address(&req.mac_addr, zx::MonotonicInstant::INFINITE)
255            .context("FIDL error on SetMacAddress")
256    }
257}
258
259#[cfg(test)]
260pub mod test_utils {
261    use super::*;
262    use fidl_fuchsia_wlan_sme as fidl_sme;
263    use fuchsia_sync::Mutex;
264    use futures::channel::mpsc;
265    use std::sync::Arc;
266    use wlan_common::sink::UnboundedSink;
267
268    #[derive(Debug)]
269    pub enum DriverCall {
270        StartScan { req: fidl_fullmac::WlanFullmacImplStartScanRequest },
271        ConnectReq { req: fidl_fullmac::WlanFullmacImplConnectRequest },
272        ReconnectReq { req: fidl_fullmac::WlanFullmacImplReconnectRequest },
273        RoamReq { req: fidl_fullmac::WlanFullmacImplRoamRequest },
274        AuthResp { resp: fidl_fullmac::WlanFullmacImplAuthRespRequest },
275        DeauthReq { req: fidl_fullmac::WlanFullmacImplDeauthRequest },
276        AssocResp { resp: fidl_fullmac::WlanFullmacImplAssocRespRequest },
277        Disassoc { req: fidl_fullmac::WlanFullmacImplDisassocRequest },
278        StartBss { req: fidl_fullmac::WlanFullmacImplStartBssRequest },
279        StopBss { req: fidl_fullmac::WlanFullmacImplStopBssRequest },
280        SetKeys { req: fidl_fullmac::WlanFullmacImplSetKeysRequest },
281        EapolTx { req: fidl_fullmac::WlanFullmacImplEapolTxRequest },
282        QueryTelemetrySupport,
283        GetIfaceStats,
284        GetIfaceHistogramStats,
285        GetSignalReport,
286        SaeHandshakeResp { resp: fidl_fullmac::WlanFullmacImplSaeHandshakeRespRequest },
287        SaeFrameTx { frame: fidl_fullmac::SaeFrame },
288        WmmStatusReq,
289        OnLinkStateChanged { req: fidl_fullmac::WlanFullmacImplOnLinkStateChangedRequest },
290        SetMacAddress { req: fidl_fullmac::WlanFullmacImplSetMacAddressRequest },
291    }
292
293    pub struct FakeFullmacDeviceMocks {
294        pub start_fn_status_mock: Option<zx::sys::zx_status_t>,
295
296        // Note: anyhow::Error isn't cloneable, so the query mocks are all optionals to make this
297        // easier to work with.
298        //
299        // If any of the query mocks are None, then an Err is returned from DeviceOps with an empty
300        // error message.
301        pub query_device_info_mock: Option<fidl_fullmac::WlanFullmacImplQueryResponse>,
302        pub query_security_support_mock: Option<fidl_common::SecuritySupport>,
303        pub query_spectrum_management_support_mock: Option<fidl_common::SpectrumManagementSupport>,
304        pub query_telemetry_support_mock: Option<Result<fidl_stats::TelemetrySupport, i32>>,
305
306        pub set_keys_resp_mock: Option<fidl_fullmac::WlanFullmacSetKeysResp>,
307        pub get_iface_stats_mock: Option<fidl_mlme::GetIfaceStatsResponse>,
308        pub get_iface_histogram_stats_mock: Option<fidl_mlme::GetIfaceHistogramStatsResponse>,
309        pub get_signal_report_mock: Option<Result<fidl_stats::SignalReport, i32>>,
310
311        pub fullmac_ifc_client_end: Option<ClientEnd<fidl_fullmac::WlanFullmacImplIfcMarker>>,
312    }
313
314    unsafe impl Send for FakeFullmacDevice {}
315    pub struct FakeFullmacDevice {
316        pub usme_bootstrap_client_end:
317            Option<fidl::endpoints::ClientEnd<fidl_sme::UsmeBootstrapMarker>>,
318        pub usme_bootstrap_server_end:
319            Option<fidl::endpoints::ServerEnd<fidl_sme::UsmeBootstrapMarker>>,
320        driver_call_sender: UnboundedSink<DriverCall>,
321
322        // This is boxed because tests want a reference to this to check captured calls, but in
323        // production we pass ownership of the DeviceOps to FullmacMlme. This avoids changing
324        // ownership semantics for tests.
325        pub mocks: Arc<Mutex<FakeFullmacDeviceMocks>>,
326    }
327
328    impl FakeFullmacDevice {
329        pub fn new() -> (Self, mpsc::UnboundedReceiver<DriverCall>) {
330            // Create a channel for SME requests, to be surfaced by init().
331            let (usme_bootstrap_client_end, usme_bootstrap_server_end) =
332                fidl::endpoints::create_endpoints::<fidl_sme::UsmeBootstrapMarker>();
333
334            let (driver_call_sender, driver_call_receiver) = mpsc::unbounded();
335
336            let device = Self {
337                usme_bootstrap_client_end: Some(usme_bootstrap_client_end),
338                usme_bootstrap_server_end: Some(usme_bootstrap_server_end),
339                driver_call_sender: UnboundedSink::new(driver_call_sender),
340                mocks: Arc::new(Mutex::new(FakeFullmacDeviceMocks {
341                    fullmac_ifc_client_end: None,
342                    start_fn_status_mock: None,
343                    query_device_info_mock: Some(fidl_fullmac::WlanFullmacImplQueryResponse {
344                        sta_addr: Some([0u8; 6]),
345                        role: Some(fidl_common::WlanMacRole::Client),
346                        band_caps: Some(vec![]),
347                        ..Default::default()
348                    }),
349                    query_security_support_mock: Some(fidl_common::SecuritySupport {
350                        sae: fidl_common::SaeFeature {
351                            driver_handler_supported: false,
352                            sme_handler_supported: true,
353                        },
354                        mfp: fidl_common::MfpFeature { supported: false },
355                    }),
356                    query_spectrum_management_support_mock: Some(
357                        fidl_common::SpectrumManagementSupport {
358                            dfs: fidl_common::DfsFeature { supported: false },
359                        },
360                    ),
361                    query_telemetry_support_mock: Some(Ok(fidl_stats::TelemetrySupport {
362                        ..Default::default()
363                    })),
364                    get_signal_report_mock: Some(Ok(fidl_stats::SignalReport {
365                        ..Default::default()
366                    })),
367                    set_keys_resp_mock: None,
368                    get_iface_stats_mock: None,
369                    get_iface_histogram_stats_mock: None,
370                })),
371            };
372
373            (device, driver_call_receiver)
374        }
375    }
376
377    impl DeviceOps for FakeFullmacDevice {
378        fn init(
379            &mut self,
380            fullmac_ifc_client_end: ClientEnd<fidl_fullmac::WlanFullmacImplIfcMarker>,
381        ) -> Result<fidl::Channel, zx::Status> {
382            let mut mocks = self.mocks.lock();
383
384            mocks.fullmac_ifc_client_end = Some(fullmac_ifc_client_end);
385            match mocks.start_fn_status_mock {
386                Some(status) => Err(zx::Status::from_raw(status)),
387
388                // Start can only be called once since this moves usme_bootstrap_server_end.
389                None => Ok(self.usme_bootstrap_server_end.take().unwrap().into_channel()),
390            }
391        }
392
393        fn query_device_info(&self) -> anyhow::Result<fidl_fullmac::WlanFullmacImplQueryResponse> {
394            self.mocks.lock().query_device_info_mock.clone().ok_or_else(|| format_err!(""))
395        }
396
397        fn query_security_support(&self) -> anyhow::Result<fidl_common::SecuritySupport> {
398            self.mocks.lock().query_security_support_mock.clone().ok_or_else(|| format_err!(""))
399        }
400
401        fn query_spectrum_management_support(
402            &self,
403        ) -> anyhow::Result<fidl_common::SpectrumManagementSupport> {
404            self.mocks
405                .lock()
406                .query_spectrum_management_support_mock
407                .clone()
408                .ok_or_else(|| format_err!(""))
409        }
410
411        fn query_telemetry_support(
412            &self,
413        ) -> anyhow::Result<Result<fidl_stats::TelemetrySupport, i32>> {
414            self.driver_call_sender.send(DriverCall::QueryTelemetrySupport);
415            self.mocks.lock().query_telemetry_support_mock.clone().ok_or_else(|| format_err!(""))
416        }
417
418        // Cannot mark fn unsafe because it has to match fn signature in FullDeviceInterface
419        fn start_scan(
420            &self,
421            req: fidl_fullmac::WlanFullmacImplStartScanRequest,
422        ) -> anyhow::Result<()> {
423            self.driver_call_sender.send(DriverCall::StartScan { req });
424            Ok(())
425        }
426
427        fn connect(&self, req: fidl_fullmac::WlanFullmacImplConnectRequest) -> anyhow::Result<()> {
428            self.driver_call_sender.send(DriverCall::ConnectReq { req });
429            Ok(())
430        }
431        fn reconnect(
432            &self,
433            req: fidl_fullmac::WlanFullmacImplReconnectRequest,
434        ) -> anyhow::Result<()> {
435            self.driver_call_sender.send(DriverCall::ReconnectReq { req });
436            Ok(())
437        }
438        fn roam(&self, req: fidl_fullmac::WlanFullmacImplRoamRequest) -> anyhow::Result<()> {
439            self.driver_call_sender.send(DriverCall::RoamReq { req });
440            Ok(())
441        }
442        fn auth_resp(
443            &self,
444            resp: fidl_fullmac::WlanFullmacImplAuthRespRequest,
445        ) -> anyhow::Result<()> {
446            self.driver_call_sender.send(DriverCall::AuthResp { resp });
447            Ok(())
448        }
449        fn deauth(&self, req: fidl_fullmac::WlanFullmacImplDeauthRequest) -> anyhow::Result<()> {
450            self.driver_call_sender.send(DriverCall::DeauthReq { req });
451            Ok(())
452        }
453        fn assoc_resp(
454            &self,
455            resp: fidl_fullmac::WlanFullmacImplAssocRespRequest,
456        ) -> anyhow::Result<()> {
457            self.driver_call_sender.send(DriverCall::AssocResp { resp });
458            Ok(())
459        }
460        fn disassoc(
461            &self,
462            req: fidl_fullmac::WlanFullmacImplDisassocRequest,
463        ) -> anyhow::Result<()> {
464            self.driver_call_sender.send(DriverCall::Disassoc { req });
465            Ok(())
466        }
467        fn start_bss(
468            &self,
469            req: fidl_fullmac::WlanFullmacImplStartBssRequest,
470        ) -> anyhow::Result<()> {
471            self.driver_call_sender.send(DriverCall::StartBss { req });
472            Ok(())
473        }
474        fn stop_bss(&self, req: fidl_fullmac::WlanFullmacImplStopBssRequest) -> anyhow::Result<()> {
475            self.driver_call_sender.send(DriverCall::StopBss { req });
476            Ok(())
477        }
478        fn set_keys(
479            &self,
480            req: fidl_fullmac::WlanFullmacImplSetKeysRequest,
481        ) -> anyhow::Result<fidl_fullmac::WlanFullmacSetKeysResp> {
482            let num_keys = req.keylist.as_ref().unwrap().len();
483            self.driver_call_sender.send(DriverCall::SetKeys { req });
484            match &self.mocks.lock().set_keys_resp_mock {
485                Some(resp) => Ok(resp.clone()),
486                None => {
487                    Ok(fidl_fullmac::WlanFullmacSetKeysResp { statuslist: vec![0i32; num_keys] })
488                }
489            }
490        }
491        fn eapol_tx(&self, req: fidl_fullmac::WlanFullmacImplEapolTxRequest) -> anyhow::Result<()> {
492            self.driver_call_sender.send(DriverCall::EapolTx { req });
493            Ok(())
494        }
495        fn get_iface_stats(&self) -> anyhow::Result<fidl_mlme::GetIfaceStatsResponse> {
496            self.driver_call_sender.send(DriverCall::GetIfaceStats);
497            Ok(self.mocks.lock().get_iface_stats_mock.clone().unwrap_or(
498                fidl_mlme::GetIfaceStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED),
499            ))
500        }
501        fn get_iface_histogram_stats(
502            &self,
503        ) -> anyhow::Result<fidl_mlme::GetIfaceHistogramStatsResponse> {
504            self.driver_call_sender.send(DriverCall::GetIfaceHistogramStats);
505            Ok(self.mocks.lock().get_iface_histogram_stats_mock.clone().unwrap_or(
506                fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(
507                    zx::sys::ZX_ERR_NOT_SUPPORTED,
508                ),
509            ))
510        }
511        fn get_signal_report(&self) -> anyhow::Result<Result<fidl_stats::SignalReport, i32>> {
512            self.driver_call_sender.send(DriverCall::GetSignalReport);
513            self.mocks.lock().get_signal_report_mock.clone().ok_or_else(|| format_err!(""))
514        }
515        fn sae_handshake_resp(
516            &self,
517            resp: fidl_fullmac::WlanFullmacImplSaeHandshakeRespRequest,
518        ) -> anyhow::Result<()> {
519            self.driver_call_sender.send(DriverCall::SaeHandshakeResp { resp });
520            Ok(())
521        }
522        fn sae_frame_tx(&self, frame: fidl_fullmac::SaeFrame) -> anyhow::Result<()> {
523            self.driver_call_sender.send(DriverCall::SaeFrameTx { frame });
524            Ok(())
525        }
526        fn wmm_status_req(&self) -> anyhow::Result<()> {
527            self.driver_call_sender.send(DriverCall::WmmStatusReq);
528            Ok(())
529        }
530        fn on_link_state_changed(
531            &self,
532            req: fidl_fullmac::WlanFullmacImplOnLinkStateChangedRequest,
533        ) -> anyhow::Result<()> {
534            self.driver_call_sender.send(DriverCall::OnLinkStateChanged { req });
535            Ok(())
536        }
537        fn set_mac_address(
538            &self,
539            req: fidl_fuchsia_wlan_fullmac::WlanFullmacImplSetMacAddressRequest,
540        ) -> anyhow::Result<Result<(), i32>> {
541            self.driver_call_sender.send(DriverCall::SetMacAddress { req });
542            Ok(Ok(()))
543        }
544    }
545}