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