wlan_fullmac_mlme/
lib.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
5// Turn on additional lints that could lead to unexpected crashes in production code
6#![warn(clippy::indexing_slicing)]
7#![cfg_attr(test, allow(clippy::indexing_slicing))]
8#![warn(clippy::unwrap_used)]
9#![cfg_attr(test, allow(clippy::unwrap_used))]
10#![warn(clippy::expect_used)]
11#![cfg_attr(test, allow(clippy::expect_used))]
12#![warn(clippy::unreachable)]
13#![cfg_attr(test, allow(clippy::unreachable))]
14#![warn(clippy::unimplemented)]
15#![cfg_attr(test, allow(clippy::unimplemented))]
16
17mod convert;
18pub mod device;
19mod logger;
20mod mlme_main_loop;
21mod wlan_fullmac_impl_ifc_request_handler;
22
23use crate::convert::fullmac_to_mlme;
24use crate::device::DeviceOps;
25use crate::mlme_main_loop::create_mlme_main_loop;
26use anyhow::bail;
27use fuchsia_inspect::Inspector;
28use futures::channel::{mpsc, oneshot};
29use futures::future::BoxFuture;
30use futures::StreamExt;
31use log::{error, info, warn};
32use wlan_common::sink::UnboundedSink;
33use wlan_ffi_transport::completers::Completer;
34use wlan_sme::serve::create_sme;
35use {
36    fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_internal as fidl_internal,
37    fidl_fuchsia_wlan_mlme as fidl_mlme, fidl_fuchsia_wlan_sme as fidl_sme,
38    fuchsia_async as fasync, fuchsia_inspect_auto_persist as auto_persist,
39};
40
41#[derive(thiserror::Error, Debug)]
42pub enum FullmacMlmeError {
43    #[error("device.start failed: {0}")]
44    DeviceStartFailed(zx::Status),
45    #[error("Failed to get usme bootstrap stream: {0}")]
46    FailedToGetUsmeBootstrapStream(fidl::Error),
47    #[error("USME bootstrap stream failed: {0}")]
48    UsmeBootstrapStreamFailed(fidl::Error),
49    #[error("USME bootstrap stream terminated")]
50    UsmeBootstrapStreamTerminated,
51    #[error("Failed to duplicate inspect VMO")]
52    FailedToDuplicateInspectVmo,
53    #[error("Failed to respond to usme bootstrap request: {0}")]
54    FailedToRespondToUsmeBootstrapRequest(fidl::Error),
55    #[error("Failed to get generic SME stream: {0}")]
56    FailedToGetGenericSmeStream(fidl::Error),
57    #[error("Invalid MAC implementation type: {0:?}")]
58    InvalidMacImplementationType(fidl_common::MacImplementationType),
59    #[error("Invalid data plane type: {0:?}")]
60    InvalidDataPlaneType(fidl_common::DataPlaneType),
61    #[error("Failed to query vendor driver: {0:?}")]
62    FailedToQueryVendorDriver(anyhow::Error),
63    #[error("Failed to convert query from vendor driver: {0:?}")]
64    FailedToConvertVendorDriverQuery(anyhow::Error),
65    #[error("Failed to create persistence proxy: {0}")]
66    FailedToCreatePersistenceProxy(fidl::Error),
67    #[error("Failed to create sme: {0}")]
68    FailedToCreateSme(anyhow::Error),
69    #[error("Failed to create WlanFullmacImplIfcRequestStream: {0}")]
70    FailedToCreateIfcRequestStream(fidl::Error),
71}
72
73#[derive(Debug)]
74struct FullmacDriverEventSink(pub UnboundedSink<FullmacDriverEvent>);
75
76#[derive(Debug)]
77enum FullmacDriverEvent {
78    Stop,
79    OnScanResult { result: fidl_mlme::ScanResult },
80    OnScanEnd { end: fidl_mlme::ScanEnd },
81    ConnectConf { resp: fidl_mlme::ConnectConfirm },
82    RoamConf { conf: fidl_mlme::RoamConfirm },
83    RoamStartInd { ind: fidl_mlme::RoamStartIndication },
84    RoamResultInd { ind: fidl_mlme::RoamResultIndication },
85    AuthInd { ind: fidl_mlme::AuthenticateIndication },
86    DeauthConf { resp: fidl_mlme::DeauthenticateConfirm },
87    DeauthInd { ind: fidl_mlme::DeauthenticateIndication },
88    AssocInd { ind: fidl_mlme::AssociateIndication },
89    DisassocConf { resp: fidl_mlme::DisassociateConfirm },
90    DisassocInd { ind: fidl_mlme::DisassociateIndication },
91    StartConf { resp: fidl_mlme::StartConfirm },
92    StopConf { resp: fidl_mlme::StopConfirm },
93    EapolConf { resp: fidl_mlme::EapolConfirm },
94    OnChannelSwitch { resp: fidl_internal::ChannelSwitchInfo },
95    SignalReport { ind: fidl_internal::SignalReportIndication },
96    EapolInd { ind: fidl_mlme::EapolIndication },
97    OnPmkAvailable { info: fidl_mlme::PmkInfo },
98    SaeHandshakeInd { ind: fidl_mlme::SaeHandshakeIndication },
99    SaeFrameRx { frame: fidl_mlme::SaeFrame },
100    OnWmmStatusResp { status: i32, resp: fidl_internal::WmmStatusResponse },
101}
102
103enum DriverState {
104    Running,
105    Stopping,
106}
107
108pub struct FullmacMlmeHandle {
109    driver_event_sender: mpsc::UnboundedSender<FullmacDriverEvent>,
110    mlme_loop_join_handle: Option<std::thread::JoinHandle<()>>,
111    stop_requested: bool,
112}
113
114impl FullmacMlmeHandle {
115    pub fn request_stop(&mut self) {
116        info!("Requesting MLME stop...");
117        if let Err(e) = self.driver_event_sender.unbounded_send(FullmacDriverEvent::Stop) {
118            error!("Cannot signal MLME event loop thread: {}", e);
119        } else {
120            // Only set this to true if sending the Stop event succeeded. Most likely, this means
121            // that the receiver was dropped and the MLME thread has already exited. But just in
122            // case sending can result in a different error, this will let us retry sending the
123            // Stop event in |Self::delete|. If it fails again, then we only emit another error
124            // log.
125            self.stop_requested = true;
126        }
127    }
128
129    pub fn delete(mut self) {
130        if !self.stop_requested {
131            warn!("Called delete on FullmacMlmeHandle before calling stop.");
132            self.request_stop()
133        }
134
135        match self.mlme_loop_join_handle.take() {
136            Some(join_handle) => {
137                if let Err(e) = join_handle.join() {
138                    error!("MLME event loop thread panicked: {:?}", e);
139                }
140            }
141            None => warn!("Called stop on already stopped MLME"),
142        }
143        info!("MLME main loop thread has shutdown.");
144    }
145}
146
147const INSPECT_VMO_SIZE_BYTES: usize = 1000 * 1024;
148
149/// Starts and serves the FullMAC MLME on a separate thread.
150///
151/// This will block until the FullMAC MLME has been initialized. MLME is considered "initialized"
152/// after it bootstraps USME, queries the vendor driver for supported hardware features, and
153/// creates the SME and MLME main loop futures. See the `start` function in this file for details.
154///
155/// Returns a handle to MLME on success, and an error if MLME failed to initialize.
156pub fn start_and_serve_on_separate_thread<F, D: DeviceOps + Send + 'static>(
157    device: D,
158    shutdown_completer: Completer<F>,
159) -> anyhow::Result<FullmacMlmeHandle>
160where
161    F: FnOnce(zx::sys::zx_status_t) + 'static,
162{
163    // Logger requires the executor to be initialized first.
164    let mut executor = fasync::LocalExecutor::new();
165    logger::init();
166
167    let (driver_event_sender, driver_event_stream) = mpsc::unbounded();
168    let driver_event_sender_clone = driver_event_sender.clone();
169    let inspector =
170        Inspector::new(fuchsia_inspect::InspectorConfig::default().size(INSPECT_VMO_SIZE_BYTES));
171
172    let (startup_sender, startup_receiver) = oneshot::channel();
173    let mlme_loop_join_handle = std::thread::spawn(move || {
174        // NOTE: Until MLME can be made async, MLME needs two threads to be able to
175        // send requests to the vendor driver and receive requests from the vendor driver
176        // simultaneously.
177        let mut executor = fasync::SendExecutor::new(2);
178
179        info!("Starting WLAN MLME main loop");
180        let future = start_and_serve(
181            device,
182            driver_event_sender_clone,
183            driver_event_stream,
184            inspector,
185            startup_sender,
186        );
187        let result = executor.run(future);
188        shutdown_completer.reply(result);
189    });
190
191    match executor.run_singlethreaded(startup_receiver) {
192        Ok(Ok(())) => (),
193        Ok(Err(err)) => bail!(
194            "MLME failed to start with error {}. MLME main loop returned {:?}.",
195            err,
196            mlme_loop_join_handle.join()
197        ),
198        Err(oneshot::Canceled) => bail!(
199            "MLME thread dropped startup_sender. MLME main loop returned {:?}",
200            mlme_loop_join_handle.join()
201        ),
202    };
203
204    Ok(FullmacMlmeHandle {
205        driver_event_sender,
206        mlme_loop_join_handle: Some(mlme_loop_join_handle),
207        stop_requested: false,
208    })
209}
210
211/// Contains the initialized MLME main loop and SME futures.
212///
213/// Both futures do not hold references, so they should satisfy the 'static lifetime.
214struct StartedDriver {
215    mlme_main_loop_fut: BoxFuture<'static, anyhow::Result<()>>,
216    sme_fut: BoxFuture<'static, anyhow::Result<()>>,
217}
218
219/// This initializes the MLME and SME, then on successful initialization runs the MLME main loop
220/// future and SME futures concurrently until completion.
221///
222/// Notifies when startup is complete through |startup_sender|.
223///
224/// If initialization fails, then this exits immediately.
225///
226/// # Panics
227///
228/// This panics if sending over |startup_sender| returns an error. This probably means the
229/// thread that owns |startup_sender| already exited to an error/panic.
230async fn start_and_serve<D: DeviceOps + Send + 'static>(
231    device: D,
232    driver_event_sender: mpsc::UnboundedSender<FullmacDriverEvent>,
233    driver_event_stream: mpsc::UnboundedReceiver<FullmacDriverEvent>,
234    inspector: Inspector,
235    startup_sender: oneshot::Sender<Result<(), FullmacMlmeError>>,
236) -> Result<(), zx::Status> {
237    let StartedDriver { mlme_main_loop_fut, sme_fut } =
238        match start(device, driver_event_stream, driver_event_sender, inspector).await {
239            Ok(initialized_mlme) => {
240                if let Err(e) = startup_sender.send(Ok(())) {
241                    error!("Failed to send startup response: {:?}", e);
242                    return Err(zx::Status::INTERNAL);
243                }
244                initialized_mlme
245            }
246            Err(e) => {
247                if let Err(e) = startup_sender.send(Err(e)) {
248                    error!("Failed to send startup response: {:?}", e);
249                }
250                return Err(zx::Status::INTERNAL);
251            }
252        };
253
254    match futures::try_join!(mlme_main_loop_fut, sme_fut) {
255        Ok(_) => {
256            info!("MLME and/or SME event loop exited gracefully");
257            Ok(())
258        }
259        Err(e) => {
260            error!("MLME and/or SME event loop exited with error: {:?}", e);
261            Err(zx::Status::INTERNAL)
262        }
263    }
264}
265
266/// Starts the MLME and SME.
267///
268/// This:
269/// - Handles the channel exchange over WlanFullmacImpl::Start().
270/// - Retrieves the generic SME channel over the USME bootstrap channel.
271/// - Creates the SME future.
272/// - Creates the MLME main loop future.
273///
274/// On success, returns a `StartedDriver` that contains the MLME main loop and SME futures.
275async fn start<D: DeviceOps + Send + 'static>(
276    mut device: D,
277    driver_event_stream: mpsc::UnboundedReceiver<FullmacDriverEvent>,
278    driver_event_sender: mpsc::UnboundedSender<FullmacDriverEvent>,
279    inspector: Inspector,
280) -> Result<StartedDriver, FullmacMlmeError> {
281    let (fullmac_ifc_client_end, fullmac_ifc_request_stream) =
282        fidl::endpoints::create_request_stream();
283
284    let usme_bootstrap_protocol_channel =
285        device.init(fullmac_ifc_client_end).map_err(FullmacMlmeError::DeviceStartFailed)?;
286
287    let server = fidl::endpoints::ServerEnd::<fidl_sme::UsmeBootstrapMarker>::new(
288        usme_bootstrap_protocol_channel,
289    );
290
291    let mut usme_bootstrap_stream = server.into_stream();
292
293    let fidl_sme::UsmeBootstrapRequest::Start {
294        generic_sme_server,
295        legacy_privacy_support,
296        responder,
297        ..
298    } = usme_bootstrap_stream
299        .next()
300        .await
301        .ok_or(FullmacMlmeError::UsmeBootstrapStreamTerminated)?
302        .map_err(FullmacMlmeError::UsmeBootstrapStreamFailed)?;
303
304    let inspect_vmo =
305        inspector.duplicate_vmo().ok_or(FullmacMlmeError::FailedToDuplicateInspectVmo)?;
306
307    responder.send(inspect_vmo).map_err(FullmacMlmeError::FailedToRespondToUsmeBootstrapRequest)?;
308
309    let generic_sme_stream = generic_sme_server.into_stream();
310
311    // Create SME
312    let cfg = wlan_sme::Config {
313        wep_supported: legacy_privacy_support.wep_supported,
314        wpa1_supported: legacy_privacy_support.wpa1_supported,
315    };
316
317    let (mlme_event_sender, mlme_event_receiver) = mpsc::unbounded();
318    let mlme_event_sink = UnboundedSink::new(mlme_event_sender);
319
320    let device_info =
321        device.query_device_info().map_err(FullmacMlmeError::FailedToQueryVendorDriver)?;
322    let device_info = fullmac_to_mlme::convert_device_info(device_info)
323        .map_err(FullmacMlmeError::FailedToConvertVendorDriverQuery)?;
324
325    let security_support =
326        device.query_security_support().map_err(FullmacMlmeError::FailedToQueryVendorDriver)?;
327
328    let spectrum_management_support = device
329        .query_spectrum_management_support()
330        .map_err(FullmacMlmeError::FailedToQueryVendorDriver)?;
331
332    // TODO(https://fxbug.dev/42064968): Get persistence working by adding the appropriate configs
333    //                         in *.cml files
334    let (persistence_proxy, _persistence_server_end) =
335        fidl::endpoints::create_proxy::<fidl_fuchsia_diagnostics_persist::DataPersistenceMarker>();
336
337    let (persistence_req_sender, _persistence_req_forwarder_fut) =
338        auto_persist::create_persistence_req_sender(persistence_proxy);
339
340    let (mlme_request_stream, sme_fut) = create_sme(
341        cfg.into(),
342        mlme_event_receiver,
343        &device_info,
344        security_support,
345        spectrum_management_support,
346        inspector,
347        persistence_req_sender,
348        generic_sme_stream,
349    )
350    .map_err(FullmacMlmeError::FailedToCreateSme)?;
351
352    let driver_event_sink = FullmacDriverEventSink(UnboundedSink::new(driver_event_sender));
353    let mlme_main_loop_fut = create_mlme_main_loop(
354        device,
355        mlme_request_stream,
356        mlme_event_sink,
357        driver_event_stream,
358        driver_event_sink,
359        fullmac_ifc_request_stream,
360    );
361
362    Ok(StartedDriver { mlme_main_loop_fut, sme_fut })
363}
364
365#[cfg(test)]
366mod tests {
367    use super::*;
368    use crate::device::test_utils::{DriverCall, FakeFullmacDevice, FakeFullmacDeviceMocks};
369    use fuchsia_async as fasync;
370    use futures::task::Poll;
371    use futures::Future;
372    use std::pin::Pin;
373    use std::sync::{Arc, Mutex};
374    use wlan_common::assert_variant;
375
376    #[test]
377    fn test_happy_path() {
378        let (mut h, mut test_fut) = TestHelper::set_up();
379        assert_variant!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
380
381        let startup_result =
382            assert_variant!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
383        assert_variant!(startup_result, Ok(()));
384
385        let (client_sme_proxy, client_sme_server) =
386            fidl::endpoints::create_proxy::<fidl_sme::ClientSmeMarker>();
387
388        let mut client_sme_response_fut =
389            h.generic_sme_proxy.as_ref().unwrap().get_client_sme(client_sme_server);
390        assert_variant!(h.exec.run_until_stalled(&mut client_sme_response_fut), Poll::Pending);
391        assert_variant!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
392        assert_variant!(
393            h.exec.run_until_stalled(&mut client_sme_response_fut),
394            Poll::Ready(Ok(Ok(())))
395        );
396
397        let mut status_fut = client_sme_proxy.status();
398        assert_variant!(h.exec.run_until_stalled(&mut status_fut), Poll::Pending);
399        assert_variant!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
400        let status_result = assert_variant!(h.exec.run_until_stalled(&mut status_fut), Poll::Ready(result) => result);
401        assert_variant!(status_result, Ok(fidl_sme::ClientStatusResponse::Idle(_)));
402    }
403
404    #[test]
405    fn test_mlme_exits_due_to_driver_event() {
406        let (mut h, mut test_fut) = TestHelper::set_up();
407        assert_variant!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
408
409        let startup_result =
410            assert_variant!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
411        assert_variant!(startup_result, Ok(()));
412
413        h.driver_event_sender
414            .unbounded_send(FullmacDriverEvent::Stop)
415            .expect("expect sending driver Stop event to succeed");
416        assert_variant!(h.exec.run_until_stalled(&mut test_fut), Poll::Ready(Ok(())));
417    }
418
419    #[test]
420    fn test_mlme_startup_fails_due_to_device_start() {
421        let (mut h, mut test_fut) = TestHelper::set_up();
422        h.fake_device.lock().unwrap().start_fn_status_mock = Some(zx::sys::ZX_ERR_BAD_STATE);
423        assert_variant!(
424            h.exec.run_until_stalled(&mut test_fut),
425            Poll::Ready(Err(zx::Status::INTERNAL))
426        );
427
428        let startup_result =
429            assert_variant!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
430        assert_variant!(startup_result, Err(FullmacMlmeError::DeviceStartFailed(_)))
431    }
432
433    #[test]
434    fn test_mlme_startup_fails_due_to_usme_bootstrap_terminated() {
435        let bootstrap = false;
436        let (mut h, mut test_fut) = TestHelper::set_up_with_usme_bootstrap(bootstrap);
437        h.usme_bootstrap_proxy.take();
438        assert_variant!(
439            h.exec.run_until_stalled(&mut test_fut),
440            Poll::Ready(Err(zx::Status::INTERNAL))
441        );
442
443        let startup_result =
444            assert_variant!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
445        assert_variant!(startup_result, Err(FullmacMlmeError::UsmeBootstrapStreamTerminated));
446    }
447
448    #[test]
449    fn test_mlme_startup_fails_due_to_query_device_info_error() {
450        let (mut h, mut test_fut) = TestHelper::set_up();
451        h.fake_device.lock().unwrap().query_device_info_mock = None;
452        assert_variant!(
453            h.exec.run_until_stalled(&mut test_fut),
454            Poll::Ready(Err(zx::Status::INTERNAL))
455        );
456
457        let startup_result =
458            assert_variant!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
459        assert_variant!(startup_result, Err(FullmacMlmeError::FailedToQueryVendorDriver(_)));
460    }
461
462    #[test]
463    fn test_mlme_startup_fails_due_to_query_security_support_error() {
464        let (mut h, mut test_fut) = TestHelper::set_up();
465        h.fake_device.lock().unwrap().query_security_support_mock = None;
466        assert_variant!(
467            h.exec.run_until_stalled(&mut test_fut),
468            Poll::Ready(Err(zx::Status::INTERNAL))
469        );
470
471        let startup_result =
472            assert_variant!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
473        assert_variant!(startup_result, Err(FullmacMlmeError::FailedToQueryVendorDriver(_)));
474    }
475
476    #[test]
477    fn test_mlme_startup_fails_due_to_query_spectrum_management_support_error() {
478        let (mut h, mut test_fut) = TestHelper::set_up();
479        h.fake_device.lock().unwrap().query_spectrum_management_support_mock = None;
480        assert_variant!(
481            h.exec.run_until_stalled(&mut test_fut),
482            Poll::Ready(Err(zx::Status::INTERNAL))
483        );
484
485        let startup_result =
486            assert_variant!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
487        assert_variant!(startup_result, Err(FullmacMlmeError::FailedToQueryVendorDriver(_)));
488    }
489
490    #[test]
491    fn test_mlme_startup_fails_due_to_failure_to_convert_query_device_info() {
492        let (mut h, mut test_fut) = TestHelper::set_up();
493        h.fake_device.lock().unwrap().query_device_info_mock.as_mut().unwrap().role = None;
494        assert_variant!(
495            h.exec.run_until_stalled(&mut test_fut),
496            Poll::Ready(Err(zx::Status::INTERNAL))
497        );
498
499        let startup_result =
500            assert_variant!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
501        assert_variant!(startup_result, Err(FullmacMlmeError::FailedToConvertVendorDriverQuery(_)));
502    }
503
504    #[test]
505    fn test_mlme_startup_exits_due_to_sme_channel_closure() {
506        let (mut h, mut test_fut) = TestHelper::set_up();
507        assert_variant!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
508        assert_variant!(h.startup_receiver.try_recv(), Ok(Some(Ok(()))));
509
510        std::mem::drop(h.generic_sme_proxy.take());
511        assert_variant!(
512            h.exec.run_until_stalled(&mut test_fut),
513            Poll::Ready(Err(zx::Status::INTERNAL))
514        );
515    }
516
517    #[test]
518    fn test_mlme_startup_exits_due_to_wlan_fullmac_impl_ifc_channel_closure() {
519        let (mut h, mut test_fut) = TestHelper::set_up();
520        assert_variant!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
521        assert_variant!(h.startup_receiver.try_recv(), Ok(Some(Ok(()))));
522
523        std::mem::drop(h.fake_device.lock().unwrap().fullmac_ifc_client_end.take());
524        assert_variant!(
525            h.exec.run_until_stalled(&mut test_fut),
526            Poll::Ready(Err(zx::Status::INTERNAL))
527        );
528    }
529
530    struct TestHelper {
531        fake_device: Arc<Mutex<FakeFullmacDeviceMocks>>,
532        driver_event_sender: mpsc::UnboundedSender<FullmacDriverEvent>,
533        usme_bootstrap_proxy: Option<fidl_sme::UsmeBootstrapProxy>,
534        _usme_bootstrap_result: Option<fidl::client::QueryResponseFut<zx::Vmo>>,
535        generic_sme_proxy: Option<fidl_sme::GenericSmeProxy>,
536        startup_receiver: oneshot::Receiver<Result<(), FullmacMlmeError>>,
537        _driver_calls: mpsc::UnboundedReceiver<DriverCall>,
538        exec: fasync::TestExecutor,
539    }
540
541    impl TestHelper {
542        pub fn set_up() -> (Self, Pin<Box<impl Future<Output = Result<(), zx::Status>>>>) {
543            let bootstrap = true;
544            Self::set_up_with_usme_bootstrap(bootstrap)
545        }
546
547        pub fn set_up_with_usme_bootstrap(
548            bootstrap: bool,
549        ) -> (Self, Pin<Box<impl Future<Output = Result<(), zx::Status>>>>) {
550            let exec = fasync::TestExecutor::new();
551
552            let (mut fake_device, _driver_calls) = FakeFullmacDevice::new();
553            let usme_bootstrap_proxy =
554                fake_device.usme_bootstrap_client_end.take().unwrap().into_proxy();
555
556            let (generic_sme_proxy, generic_sme_server_end) =
557                fidl::endpoints::create_proxy::<fidl_sme::GenericSmeMarker>();
558            let usme_bootstrap_result = if bootstrap {
559                Some(usme_bootstrap_proxy.start(
560                    generic_sme_server_end,
561                    &fidl_sme::LegacyPrivacySupport { wep_supported: false, wpa1_supported: false },
562                ))
563            } else {
564                None
565            };
566
567            let (driver_event_sender, driver_event_stream) = mpsc::unbounded();
568            let inspector = Inspector::default();
569            let (startup_sender, startup_receiver) = oneshot::channel();
570
571            let mocks = fake_device.mocks.clone();
572
573            let test_fut = Box::pin(start_and_serve(
574                fake_device,
575                driver_event_sender.clone(),
576                driver_event_stream,
577                inspector,
578                startup_sender,
579            ));
580
581            let test_helper = TestHelper {
582                fake_device: mocks,
583                driver_event_sender,
584                usme_bootstrap_proxy: Some(usme_bootstrap_proxy),
585                _usme_bootstrap_result: usme_bootstrap_result,
586                generic_sme_proxy: Some(generic_sme_proxy),
587                startup_receiver,
588                _driver_calls,
589                exec,
590            };
591            (test_helper, test_fut)
592        }
593    }
594}