wlansoftmac_rust/
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
5use anyhow::{format_err, Error};
6use fidl::endpoints::{ProtocolMarker, Proxy};
7use fuchsia_async::{MonotonicDuration, Task};
8use fuchsia_inspect::Inspector;
9use futures::channel::mpsc;
10use futures::channel::oneshot::{self, Canceled};
11use futures::{Future, FutureExt, StreamExt};
12use log::{error, info, warn};
13use std::pin::Pin;
14use wlan_ffi_transport::completers::Completer;
15use wlan_ffi_transport::{EthernetTx, WlanRx};
16use wlan_fidl_ext::{ResponderExt, SendResultExt, WithName};
17use wlan_mlme::device::DeviceOps;
18use wlan_mlme::{DriverEvent, DriverEventSink};
19use wlan_sme::serve::create_sme;
20use {
21    fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_sme as fidl_sme,
22    fidl_fuchsia_wlan_softmac as fidl_softmac, fuchsia_inspect_auto_persist as auto_persist,
23    wlan_trace as wtrace,
24};
25
26const INSPECT_VMO_SIZE_BYTES: usize = 1000 * 1024;
27
28/// Run the bridged wlansoftmac driver composed of the following servers:
29///
30///   - WlanSoftmacIfcBridge server
31///   - MLME server
32///   - SME server
33///
34/// The WlanSoftmacIfcBridge server future executes on a parallel thread because otherwise
35/// synchronous calls from the MLME server into the vendor driver could deadlock if the vendor
36/// driver calls a WlanSoftmacIfcBridge method before returning from a synchronous call. For
37/// example, when the MLME server synchronously calls WlanSoftmac.StartActiveScan(), the vendor
38/// driver may call WlanSoftmacIfc.NotifyScanComplete() before returning from
39/// WlanSoftmac.StartActiveScan(). This can occur when the scan request results in immediate
40/// cancellation despite the request having valid arguments.
41///
42/// This function calls `start_completer()` when MLME initialization completes successfully, and
43/// will return in one of four cases:
44///
45///   - An error occurred during initialization.
46///   - An error occurred while running.
47///   - An error occurred during shutdown.
48///   - Shutdown completed successfully.
49///
50/// If an error occurs during the bridge driver's initialization, `start_completer()` will not be
51/// called.
52pub async fn start_and_serve<F, D: DeviceOps + 'static>(
53    start_completer: Completer<F>,
54    device: D,
55) -> Result<(), zx::Status>
56where
57    F: FnOnce(zx::sys::zx_status_t) + 'static,
58{
59    wtrace::duration_begin_scope!(c"rust_driver::start_and_serve");
60    let (driver_event_sink, driver_event_stream) = DriverEventSink::new();
61
62    let (mlme_init_sender, mlme_init_receiver) = oneshot::channel();
63    let StartedDriver { softmac_ifc_bridge_request_stream, mlme, sme } =
64        match start(mlme_init_sender, driver_event_sink.clone(), driver_event_stream, device).await
65        {
66            Err(status) => {
67                start_completer.reply(Err(status));
68                return Err(status);
69            }
70            Ok(x) => x,
71        };
72
73    start_completer.reply(Ok(()));
74
75    serve(mlme_init_receiver, driver_event_sink, softmac_ifc_bridge_request_stream, mlme, sme).await
76}
77
78struct StartedDriver<Mlme, Sme> {
79    pub softmac_ifc_bridge_request_stream: fidl_softmac::WlanSoftmacIfcBridgeRequestStream,
80    pub mlme: Mlme,
81    pub sme: Sme,
82}
83
84/// Start the bridged wlansoftmac driver by creating components to run two futures:
85///
86///   - MLME server
87///   - SME server
88///
89/// This function will use the provided |device| to make various calls into the vendor driver
90/// necessary to configure and create the components to run the futures.
91async fn start<D: DeviceOps + 'static>(
92    mlme_init_sender: oneshot::Sender<()>,
93    driver_event_sink: DriverEventSink,
94    driver_event_stream: mpsc::UnboundedReceiver<DriverEvent>,
95    mut device: D,
96) -> Result<
97    StartedDriver<
98        Pin<Box<dyn Future<Output = Result<(), Error>>>>,
99        Pin<Box<impl Future<Output = Result<(), Error>>>>,
100    >,
101    zx::Status,
102> {
103    wtrace::duration!(c"rust_driver::start");
104
105    let (softmac_ifc_bridge_proxy, softmac_ifc_bridge_request_stream) =
106        fidl::endpoints::create_proxy_and_stream::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
107
108    // Bootstrap USME
109    let BootstrappedGenericSme { generic_sme_request_stream, legacy_privacy_support, inspector } =
110        bootstrap_generic_sme(&mut device, driver_event_sink, softmac_ifc_bridge_proxy).await?;
111
112    info!("Querying device information...");
113
114    // Make a series of queries to gather device information from the vendor driver.
115    let softmac_info = device.wlan_softmac_query_response().await?;
116    let sta_addr = softmac_info.sta_addr;
117    let device_info = match wlan_mlme::mlme_device_info_from_softmac(softmac_info) {
118        Ok(info) => info,
119        Err(e) => {
120            error!("Failed to get MLME device info: {}", e);
121            return Err(zx::Status::INTERNAL);
122        }
123    };
124
125    let security_support = device.security_support().await?;
126    let spectrum_management_support = device.spectrum_management_support().await?;
127
128    info!("Querying complete!");
129
130    // TODO(https://fxbug.dev/42064968): Get persistence working by adding the appropriate configs
131    //                         in *.cml files
132    let (persistence_proxy, _persistence_server_end) =
133        fidl::endpoints::create_proxy::<fidl_fuchsia_diagnostics_persist::DataPersistenceMarker>();
134    let (persistence_req_sender, _persistence_req_forwarder_fut) =
135        auto_persist::create_persistence_req_sender(persistence_proxy);
136
137    let config = wlan_sme::Config {
138        wep_supported: legacy_privacy_support.wep_supported,
139        wpa1_supported: legacy_privacy_support.wpa1_supported,
140    };
141
142    // TODO(https://fxbug.dev/42077094): The MLME event stream should be moved out of DeviceOps
143    // entirely.
144    let mlme_event_stream = match device.take_mlme_event_stream() {
145        Some(mlme_event_stream) => mlme_event_stream,
146        None => {
147            error!("Failed to take MLME event stream.");
148            return Err(zx::Status::INTERNAL);
149        }
150    };
151
152    // Create an SME future to serve
153    let (mlme_request_stream, sme) = match create_sme(
154        config,
155        mlme_event_stream,
156        &device_info,
157        security_support,
158        spectrum_management_support,
159        inspector,
160        persistence_req_sender,
161        generic_sme_request_stream,
162    ) {
163        Ok((mlme_request_stream, sme)) => (mlme_request_stream, sme),
164        Err(e) => {
165            error!("Failed to create sme: {}", e);
166            return Err(zx::Status::INTERNAL);
167        }
168    };
169
170    // Create an MLME future to serve
171    let mlme: Pin<Box<dyn Future<Output = Result<(), Error>>>> = match device_info.role {
172        fidl_common::WlanMacRole::Client => {
173            info!("Running wlansoftmac with client role");
174            let config = wlan_mlme::client::ClientConfig {
175                ensure_on_channel_time: MonotonicDuration::from_millis(500).into_nanos(),
176            };
177            Box::pin(wlan_mlme::mlme_main_loop::<wlan_mlme::client::ClientMlme<D>>(
178                mlme_init_sender,
179                config,
180                device,
181                mlme_request_stream,
182                driver_event_stream,
183            ))
184        }
185        fidl_common::WlanMacRole::Ap => {
186            info!("Running wlansoftmac with AP role");
187            let sta_addr = match sta_addr {
188                Some(sta_addr) => sta_addr,
189                None => {
190                    error!("Driver provided no STA address.");
191                    return Err(zx::Status::INTERNAL);
192                }
193            };
194            let config = ieee80211::Bssid::from(sta_addr);
195            Box::pin(wlan_mlme::mlme_main_loop::<wlan_mlme::ap::Ap<D>>(
196                mlme_init_sender,
197                config,
198                device,
199                mlme_request_stream,
200                driver_event_stream,
201            ))
202        }
203        unsupported => {
204            error!("Unsupported mac role: {:?}", unsupported);
205            return Err(zx::Status::INTERNAL);
206        }
207    };
208
209    Ok(StartedDriver { softmac_ifc_bridge_request_stream, mlme, sme })
210}
211
212/// Await on futures hosting the following three servers:
213///
214///   - WlanSoftmacIfcBridge server
215///   - MLME server
216///   - SME server
217///
218/// The WlanSoftmacIfcBridge server runs on a parallel thread but will be shut down before this
219/// function returns. This is true even if this function exits with an error.
220///
221/// Upon receiving a DriverEvent::Stop, the MLME server will shut down first. Then this function
222/// will await the completion of WlanSoftmacIfcBridge server and SME server. Both will shut down as
223/// a consequence of MLME server shut down.
224async fn serve(
225    mlme_init_receiver: oneshot::Receiver<()>,
226    driver_event_sink: DriverEventSink,
227    softmac_ifc_bridge_request_stream: fidl_softmac::WlanSoftmacIfcBridgeRequestStream,
228    mlme: Pin<Box<dyn Future<Output = Result<(), Error>>>>,
229    sme: Pin<Box<impl Future<Output = Result<(), Error>>>>,
230) -> Result<(), zx::Status> {
231    wtrace::duration_begin_scope!(c"rust_driver::serve");
232
233    // Create a oneshot::channel to signal to this executor when WlanSoftmacIfcBridge
234    // server exits.
235    let (bridge_exit_sender, bridge_exit_receiver) = oneshot::channel();
236    // Spawn a Task to host the WlanSoftmacIfcBridge server.
237    let bridge = Task::local(async move {
238        let _: Result<(), ()> = bridge_exit_sender
239            .send(
240                serve_wlan_softmac_ifc_bridge(driver_event_sink, softmac_ifc_bridge_request_stream)
241                    .await,
242            )
243            .map_err(|result| {
244                error!("Failed to send serve_wlan_softmac_ifc_bridge() result: {:?}", result)
245            });
246    });
247
248    let mut mlme = mlme.fuse();
249    let mut sme = sme.fuse();
250
251    // oneshot::Receiver implements FusedFuture incorrectly, so we must call .fuse()
252    // to get the right behavior in the select!().
253    //
254    // See https://github.com/rust-lang/futures-rs/issues/2455 for more details.
255    let mut bridge_exit_receiver = bridge_exit_receiver.fuse();
256    let mut mlme_init_receiver = mlme_init_receiver.fuse();
257
258    info!("Starting MLME and waiting on MLME initialization to complete...");
259    // Run the MLME server and wait for the MLME to signal initialization completion.
260    //
261    // The order of the futures in this select is not arbitrary. During initialization, there is
262    // an edge case where MLME could be stopped before initialization completes. By polling
263    // the MLME future first, we can unit test handling this edge case by completing the MLME
264    // future and initialization, in that order, and then polling the future returned by
265    // serve() (i.e., this function).
266    {
267        wtrace::duration_begin_scope!(c"initialize MLME");
268        futures::select! {
269            mlme_result = mlme => {
270                match mlme_result {
271                    Err(e) => {
272                        error!("MLME future completed with error during initialization: {:?}", e);
273                        std::mem::drop(bridge);
274                        return Err(zx::Status::INTERNAL);
275                    }
276                    Ok(()) => {
277
278                        // It's possible MLME received a DriverEvent::Stop and returned after
279                        // signaling initialization completed and before mlme_init_receiver being
280                        // polled. If that's the case, then log a warning that SME never started and
281                        // return Ok. Exiting the server in this way should be considered okay
282                        // because MLME signaled initialization completed and exited successfully.
283                        match mlme_init_receiver.now_or_never() {
284                            None | Some(Err(Canceled)) => {
285                                error!("MLME future completed before signaling initialization complete.");
286                                std::mem::drop(bridge);
287                                return Err(zx::Status::INTERNAL);
288                            }
289                            Some(Ok(())) => {
290                                warn!("SME never started. MLME future completed successfully just after initialization.");
291                                std::mem::drop(bridge);
292                                return Ok(());
293                            }
294                        }
295                    }
296                }
297            }
298            init_result = mlme_init_receiver => {
299                match init_result {
300                    Ok(()) => (),
301                    Err(e) => {
302                        error!("MLME dropped the initialization signaler: {}", e);
303                        std::mem::drop(bridge);
304                        return Err(zx::Status::INTERNAL);
305                    }
306                }
307            },
308        }
309    }
310
311    info!("Starting SME and WlanSoftmacIfc servers...");
312
313    // Run the SME and MLME servers.
314    {
315        wtrace::duration_begin_scope!(c"run MLME and SME");
316        // This loop-select has two phases.
317        //
318        // In the first phase, all three futures are running. The first phase will break
319        // the loop with an error if any of the following events occurs:
320        //
321        //   - SME future completes before MLME.
322        //   - Any future completes with an error.
323        //
324        // If the bridge_exit_receiver completes successfully, the MLME and SME futures continue.
325        // It's possible for bridge_exit_receiver to complete before MLME because
326        // the bridge server exits upon receiving the StopBridgedDriver message while the MLME
327        // future consumes the StopBridgedDriver message and responds asynchronously.
328        //
329        // The first phase ends successfully only if the MLME future completes successfully.
330        //
331        // The second phase runs the SME future and, if not complete, the
332        // bridge_exit_receiver future. The second phase ends with an error if either the
333        // SME future or bridge_exit_receiver future return an error.  Otherwise, the
334        // second phase ends successfully.
335        let mut mlme_future_complete = false;
336        loop {
337            futures::select! {
338                mlme_result = mlme => {
339                    match mlme_result {
340                        Ok(()) => {
341                            info!("MLME shut down gracefully.");
342                            mlme_future_complete = true;
343                        },
344                        Err(e) => {
345                            error!("MLME shut down with error: {}", e);
346                            break Err(zx::Status::INTERNAL)
347                        }
348                    }
349                }
350                bridge_result = bridge_exit_receiver => {
351                    // We expect the bridge to shut itself down immediately upon receiving a
352                    // StopBridgedDriver message, so it's often the case that the bridge task
353                    // will exit before MLME. When the bridge task completes first, both
354                    // the `mlme` and `sme` futures should continue to run.
355                    match bridge_result {
356                        Err(Canceled) => {
357                            error!("SoftmacIfcBridge result sender dropped unexpectedly.");
358                            break Err(zx::Status::INTERNAL)
359                        }
360                        Ok(Err(e)) => {
361                            error!("SoftmacIfcBridge server shut down with error: {}", e);
362                            break Err(zx::Status::INTERNAL)
363                        }
364                        Ok(Ok(())) => info!("SoftmacIfcBridge server shut down gracefully"),
365                    }
366                }
367                sme_result = sme => {
368                    if mlme_future_complete {
369                        match sme_result {
370                            Err(e) => {
371                                error!("SME shut down with error: {}", e);
372                                break Err(zx::Status::INTERNAL)
373                            }
374                            Ok(()) => info!("SME shut down gracefully"),
375                        }
376                    } else {
377                        error!("SME shut down before MLME: {:?}", sme_result);
378                        break Err(zx::Status::INTERNAL)
379                    }
380                }
381                complete => break Ok(())
382            }
383        }
384    }
385}
386
387struct BootstrappedGenericSme {
388    pub generic_sme_request_stream: fidl_sme::GenericSmeRequestStream,
389    pub legacy_privacy_support: fidl_sme::LegacyPrivacySupport,
390    pub inspector: Inspector,
391}
392
393/// Call WlanSoftmac.Start() to retrieve the server end of UsmeBootstrap channel and wait
394/// for a UsmeBootstrap.Start() message to provide the server end of a GenericSme channel.
395///
396/// Any errors encountered in this function are fatal for the wlansoftmac driver. Failure to
397/// bootstrap GenericSme request stream will result in a driver no other component can communicate
398/// with.
399async fn bootstrap_generic_sme<D: DeviceOps>(
400    device: &mut D,
401    driver_event_sink: DriverEventSink,
402    softmac_ifc_bridge_proxy: fidl_softmac::WlanSoftmacIfcBridgeProxy,
403) -> Result<BootstrappedGenericSme, zx::Status> {
404    wtrace::duration!(c"rust_driver::bootstrap_generic_sme");
405    info!("Bootstrapping GenericSme...");
406
407    let ifc_bridge = softmac_ifc_bridge_proxy.into_client_end().map_err(|_| {
408        error!(
409            "Failed to convert {} into client end.",
410            fidl_softmac::WlanSoftmacIfcBridgeMarker::DEBUG_NAME
411        );
412        zx::Status::INTERNAL
413    })?;
414
415    // Calling WlanSoftmac.Start() indicates to the vendor driver that this driver (wlansoftmac) is
416    // ready to receive WlanSoftmacIfc messages. wlansoftmac will buffer all WlanSoftmacIfc messages
417    // in an mpsc::UnboundedReceiver<DriverEvent> sink until the MLME server drains them.
418    let usme_bootstrap_channel_via_iface_creation = match device
419        .start(
420            ifc_bridge,
421            EthernetTx::new(Box::new(driver_event_sink.clone())),
422            WlanRx::new(Box::new(driver_event_sink)),
423        )
424        .await
425    {
426        Ok(channel) => channel,
427        Err(status) => {
428            error!("Failed to receive a UsmeBootstrap handle: {}", status);
429            return Err(status);
430        }
431    };
432    info!("Bootstrap complete!");
433
434    let server = fidl::endpoints::ServerEnd::<fidl_sme::UsmeBootstrapMarker>::new(
435        usme_bootstrap_channel_via_iface_creation,
436    );
437    let mut usme_bootstrap_stream = server.into_stream();
438
439    let (generic_sme_server, legacy_privacy_support, responder) =
440        match usme_bootstrap_stream.next().await {
441            Some(Ok(fidl_sme::UsmeBootstrapRequest::Start {
442                generic_sme_server,
443                legacy_privacy_support,
444                responder,
445                ..
446            })) => (generic_sme_server, legacy_privacy_support, responder),
447            Some(Err(e)) => {
448                error!("Received an error on USME bootstrap request stream: {}", e);
449                return Err(zx::Status::BAD_STATE);
450            }
451            None => {
452                // This is always an error because the SME server should not drop
453                // the USME client endpoint until MLME shut down first.
454                error!("USME bootstrap stream terminated unexpectedly");
455                return Err(zx::Status::BAD_STATE);
456            }
457        };
458
459    let inspector =
460        Inspector::new(fuchsia_inspect::InspectorConfig::default().size(INSPECT_VMO_SIZE_BYTES));
461
462    let inspect_vmo = match inspector.duplicate_vmo() {
463        Some(vmo) => vmo,
464        None => {
465            error!("Failed to duplicate inspect VMO");
466            return Err(zx::Status::INTERNAL);
467        }
468    };
469    if let Err(e) = responder.send(inspect_vmo).into() {
470        error!("Failed to respond to UsmeBootstrap.Start(): {}", e);
471        return Err(zx::Status::INTERNAL);
472    }
473    let generic_sme_request_stream = generic_sme_server.into_stream();
474
475    Ok(BootstrappedGenericSme { generic_sme_request_stream, legacy_privacy_support, inspector })
476}
477
478async fn serve_wlan_softmac_ifc_bridge(
479    driver_event_sink: DriverEventSink,
480    mut softmac_ifc_bridge_request_stream: fidl_softmac::WlanSoftmacIfcBridgeRequestStream,
481) -> Result<(), anyhow::Error> {
482    loop {
483        let request = match softmac_ifc_bridge_request_stream.next().await {
484            Some(Ok(request)) => request,
485            Some(Err(e)) => {
486                return Err(format_err!("WlanSoftmacIfcBridge stream failed: {}", e));
487            }
488            None => {
489                return Err(format_err!(
490                    "WlanSoftmacIfcBridge stream terminated unexpectedly by client"
491                ));
492            }
493        };
494        match request {
495            fidl_softmac::WlanSoftmacIfcBridgeRequest::ReportTxResult { tx_result, responder } => {
496                let responder = driver_event_sink.unbounded_send_or_respond(
497                    DriverEvent::TxResultReport { tx_result },
498                    responder,
499                    (),
500                )?;
501                responder.send().format_send_err_with_context("ReportTxResult")?;
502            }
503            fidl_softmac::WlanSoftmacIfcBridgeRequest::NotifyScanComplete {
504                payload,
505                responder,
506            } => {
507                let ((status, scan_id), responder) = responder.unpack_fields_or_respond((
508                    payload.status.with_name("status"),
509                    payload.scan_id.with_name("scan_id"),
510                ))?;
511                let status = zx::Status::from_raw(status);
512                let responder = driver_event_sink.unbounded_send_or_respond(
513                    DriverEvent::ScanComplete { status, scan_id },
514                    responder,
515                    (),
516                )?;
517                responder.send().format_send_err_with_context("NotifyScanComplete")?;
518            }
519            fidl_softmac::WlanSoftmacIfcBridgeRequest::StopBridgedDriver { responder } => {
520                if let Err(e) = driver_event_sink.unbounded_send(DriverEvent::Stop { responder }) {
521                    let error_string = e.to_string();
522                    let event = e.into_inner();
523                    let e = format_err!("Failed to queue {}: {}", event, error_string);
524                    let DriverEvent::Stop { responder } = event else {
525                        unreachable!();
526                    };
527                    responder.send().format_send_err_with_context("StopBridgedDriver")?;
528                    return Err(e);
529                }
530                return Ok(());
531            }
532        }
533    }
534}
535
536#[cfg(test)]
537mod tests {
538    use super::*;
539    use anyhow::format_err;
540    use diagnostics_assertions::assert_data_tree;
541    use fuchsia_async::TestExecutor;
542    use fuchsia_inspect::InspectorConfig;
543    use futures::stream::FuturesUnordered;
544    use futures::task::Poll;
545    use std::pin::pin;
546    use test_case::test_case;
547    use wlan_common::assert_variant;
548    use wlan_mlme::device::test_utils::{FakeDevice, FakeDeviceConfig};
549    use zx::Vmo;
550
551    struct BootstrapGenericSmeTestHarness {
552        _softmac_ifc_bridge_request_stream: fidl_softmac::WlanSoftmacIfcBridgeRequestStream,
553    }
554
555    // We could implement BootstrapGenericSmeTestHarness::new() instead of a macro, but doing so requires
556    // pinning the FakeDevice and WlanSoftmacIfcProtocol (and its associated DriverEventSink). While the
557    // pinning itself is feasible, it leads to a complex harness implementation that outweighs the benefit
558    // of using a harness to begin with.
559    macro_rules! make_bootstrap_generic_sme_test_harness {
560        (&mut $fake_device:ident, $driver_event_sink:ident $(,)?) => {{
561            let (softmac_ifc_bridge_proxy, _softmac_ifc_bridge_request_stream) =
562                fidl::endpoints::create_proxy_and_stream::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
563            (
564                Box::pin(bootstrap_generic_sme(
565                    &mut $fake_device,
566                    $driver_event_sink,
567                    softmac_ifc_bridge_proxy,
568                )),
569                BootstrapGenericSmeTestHarness {
570                    _softmac_ifc_bridge_request_stream,
571                }
572            )
573        }};
574    }
575
576    #[fuchsia::test(allow_stalls = false)]
577    async fn bootstrap_generic_sme_fails_to_retrieve_usme_bootstrap_handle() {
578        let (mut fake_device, _fake_device_state) = FakeDevice::new_with_config(
579            FakeDeviceConfig::default().with_mock_start_result(Err(zx::Status::INTERRUPTED_RETRY)),
580        )
581        .await;
582        let (driver_event_sink, _driver_event_stream) = DriverEventSink::new();
583
584        let (mut bootstrap_generic_sme_fut, _harness) =
585            make_bootstrap_generic_sme_test_harness!(&mut fake_device, driver_event_sink);
586        match TestExecutor::poll_until_stalled(&mut bootstrap_generic_sme_fut).await {
587            Poll::Ready(Err(zx::Status::INTERRUPTED_RETRY)) => (),
588            Poll::Ready(Err(status)) => panic!("Failed with wrong status: {}", status),
589            Poll::Ready(Ok(_)) => panic!("Succeeded unexpectedly"),
590            Poll::Pending => panic!("bootstrap_generic_sme() unexpectedly stalled"),
591        }
592    }
593
594    #[fuchsia::test(allow_stalls = false)]
595    async fn boostrap_generic_sme_fails_on_error_from_bootstrap_stream() {
596        let (mut fake_device, fake_device_state) =
597            FakeDevice::new_with_config(FakeDeviceConfig::default()).await;
598        let (driver_event_sink, _driver_event_stream) = DriverEventSink::new();
599
600        let (mut bootstrap_generic_sme_fut, _harness) =
601            make_bootstrap_generic_sme_test_harness!(&mut fake_device, driver_event_sink);
602        assert!(matches!(
603            TestExecutor::poll_until_stalled(&mut bootstrap_generic_sme_fut).await,
604            Poll::Pending
605        ));
606
607        // Write an invalid FIDL message to the USME bootstrap channel.
608        let usme_bootstrap_channel =
609            fake_device_state.lock().usme_bootstrap_client_end.take().unwrap().into_channel();
610        usme_bootstrap_channel.write(&[], &mut []).unwrap();
611
612        assert!(matches!(
613            TestExecutor::poll_until_stalled(&mut bootstrap_generic_sme_fut).await,
614            Poll::Ready(Err(zx::Status::BAD_STATE))
615        ));
616    }
617
618    #[fuchsia::test(allow_stalls = false)]
619    async fn boostrap_generic_sme_fails_on_closed_bootstrap_stream() {
620        let (mut fake_device, fake_device_state) =
621            FakeDevice::new_with_config(FakeDeviceConfig::default()).await;
622        let (driver_event_sink, _driver_event_stream) = DriverEventSink::new();
623
624        let (mut bootstrap_generic_sme_fut, _harness) =
625            make_bootstrap_generic_sme_test_harness!(&mut fake_device, driver_event_sink);
626        assert!(matches!(
627            TestExecutor::poll_until_stalled(&mut bootstrap_generic_sme_fut).await,
628            Poll::Pending
629        ));
630
631        // Drop the client end of USME bootstrap channel.
632        let _ = fake_device_state.lock().usme_bootstrap_client_end.take().unwrap();
633
634        assert!(matches!(
635            TestExecutor::poll_until_stalled(&mut bootstrap_generic_sme_fut).await,
636            Poll::Ready(Err(zx::Status::BAD_STATE))
637        ));
638    }
639
640    #[fuchsia::test(allow_stalls = false)]
641    async fn boostrap_generic_sme_succeeds() {
642        let (mut fake_device, fake_device_state) =
643            FakeDevice::new_with_config(FakeDeviceConfig::default()).await;
644        let (driver_event_sink, _driver_event_stream) = DriverEventSink::new();
645
646        let (mut bootstrap_generic_sme_fut, _harness) =
647            make_bootstrap_generic_sme_test_harness!(&mut fake_device, driver_event_sink);
648        assert!(matches!(
649            TestExecutor::poll_until_stalled(&mut bootstrap_generic_sme_fut).await,
650            Poll::Pending
651        ));
652
653        let usme_bootstrap_proxy =
654            fake_device_state.lock().usme_bootstrap_client_end.take().unwrap().into_proxy();
655
656        let sent_legacy_privacy_support =
657            fidl_sme::LegacyPrivacySupport { wep_supported: false, wpa1_supported: false };
658        let (generic_sme_proxy, generic_sme_server) =
659            fidl::endpoints::create_proxy::<fidl_sme::GenericSmeMarker>();
660        let inspect_vmo_fut =
661            usme_bootstrap_proxy.start(generic_sme_server, &sent_legacy_privacy_support);
662        let mut inspect_vmo_fut = pin!(inspect_vmo_fut);
663        assert!(matches!(
664            TestExecutor::poll_until_stalled(&mut inspect_vmo_fut).await,
665            Poll::Pending
666        ));
667
668        let BootstrappedGenericSme {
669            mut generic_sme_request_stream,
670            legacy_privacy_support: received_legacy_privacy_support,
671            inspector,
672        } = match TestExecutor::poll_until_stalled(&mut bootstrap_generic_sme_fut).await {
673            Poll::Pending => panic!("bootstrap_generic_sme_fut() did not complete!"),
674            Poll::Ready(x) => x.unwrap(),
675        };
676        let inspect_vmo = match TestExecutor::poll_until_stalled(&mut inspect_vmo_fut).await {
677            Poll::Pending => panic!("Failed to receive an inspect VMO."),
678            Poll::Ready(x) => x.unwrap(),
679        };
680
681        // Send a GenericSme.Query() to check the generic_sme_proxy
682        // and generic_sme_stream are connected.
683        let query_fut = generic_sme_proxy.query();
684        let mut query_fut = pin!(query_fut);
685        assert!(matches!(TestExecutor::poll_until_stalled(&mut query_fut).await, Poll::Pending));
686        let next_generic_sme_request_fut = generic_sme_request_stream.next();
687        let mut next_generic_sme_request_fut = pin!(next_generic_sme_request_fut);
688        assert!(matches!(
689            TestExecutor::poll_until_stalled(&mut next_generic_sme_request_fut).await,
690            Poll::Ready(Some(Ok(fidl_sme::GenericSmeRequest::Query { .. })))
691        ));
692
693        assert_eq!(received_legacy_privacy_support, sent_legacy_privacy_support);
694
695        // Add a child node through the bootstrapped inspector and verify the node appears inspect_vmo.
696        let returned_inspector = Inspector::new(InspectorConfig::default().vmo(inspect_vmo));
697        let _a = inspector.root().create_child("a");
698        assert_data_tree!(returned_inspector, root: {
699            a: {},
700        });
701    }
702
703    struct StartTestHarness {
704        pub mlme_init_receiver: Pin<Box<oneshot::Receiver<()>>>,
705        // TODO(https://fxbug.dev/335283785): Remove or explain unused code.
706        #[allow(dead_code)]
707        pub driver_event_sink: DriverEventSink,
708    }
709
710    impl StartTestHarness {
711        fn new(
712            fake_device: FakeDevice,
713        ) -> (
714            impl Future<
715                Output = Result<
716                    StartedDriver<
717                        Pin<Box<dyn Future<Output = Result<(), Error>>>>,
718                        Pin<Box<impl Future<Output = Result<(), Error>>>>,
719                    >,
720                    zx::Status,
721                >,
722            >,
723            Self,
724        ) {
725            let (mlme_init_sender, mlme_init_receiver) = oneshot::channel();
726            let (driver_event_sink, driver_event_stream) = DriverEventSink::new();
727
728            (
729                Box::pin(start(
730                    mlme_init_sender,
731                    driver_event_sink.clone(),
732                    driver_event_stream,
733                    fake_device,
734                )),
735                Self { mlme_init_receiver: Box::pin(mlme_init_receiver), driver_event_sink },
736            )
737        }
738    }
739
740    #[fuchsia::test(allow_stalls = false)]
741    async fn start_fails_on_bad_bootstrap() {
742        let (fake_device, _fake_device_state) = FakeDevice::new_with_config(
743            FakeDeviceConfig::default().with_mock_start_result(Err(zx::Status::INTERRUPTED_RETRY)),
744        )
745        .await;
746        let (mut start_fut, _harness) = StartTestHarness::new(fake_device);
747
748        assert!(matches!(
749            TestExecutor::poll_until_stalled(&mut start_fut).await,
750            Poll::Ready(Err(zx::Status::INTERRUPTED_RETRY))
751        ));
752    }
753
754    fn bootstrap_generic_sme_proxy_and_inspect_vmo(
755        usme_bootstrap_client_end: fidl::endpoints::ClientEnd<fidl_sme::UsmeBootstrapMarker>,
756    ) -> (fidl_sme::GenericSmeProxy, impl Future<Output = Result<Vmo, fidl::Error>>) {
757        let usme_client_proxy = usme_bootstrap_client_end.into_proxy();
758
759        let legacy_privacy_support =
760            fidl_sme::LegacyPrivacySupport { wep_supported: false, wpa1_supported: false };
761        let (generic_sme_proxy, generic_sme_server) =
762            fidl::endpoints::create_proxy::<fidl_sme::GenericSmeMarker>();
763        (generic_sme_proxy, usme_client_proxy.start(generic_sme_server, &legacy_privacy_support))
764    }
765
766    #[test_case(FakeDeviceConfig::default().with_mock_query_response(Err(zx::Status::IO_DATA_INTEGRITY)), zx::Status::IO_DATA_INTEGRITY)]
767    #[test_case(FakeDeviceConfig::default().with_mock_security_support(Err(zx::Status::IO_DATA_INTEGRITY)), zx::Status::IO_DATA_INTEGRITY)]
768    #[test_case(FakeDeviceConfig::default().with_mock_spectrum_management_support(Err(zx::Status::IO_DATA_INTEGRITY)), zx::Status::IO_DATA_INTEGRITY)]
769    #[test_case(FakeDeviceConfig::default().with_mock_mac_role(fidl_common::WlanMacRole::__SourceBreaking { unknown_ordinal: 0 }), zx::Status::INTERNAL)]
770    #[fuchsia::test(allow_stalls = false)]
771    async fn start_fails_on_query_error(
772        fake_device_config: FakeDeviceConfig,
773        expected_status: zx::Status,
774    ) {
775        let (fake_device, fake_device_state) =
776            FakeDevice::new_with_config(fake_device_config).await;
777        let (mut start_fut, _harness) = StartTestHarness::new(fake_device);
778
779        let usme_bootstrap_client_end =
780            fake_device_state.lock().usme_bootstrap_client_end.take().unwrap();
781        let (_generic_sme_proxy, _inspect_vmo_fut) =
782            bootstrap_generic_sme_proxy_and_inspect_vmo(usme_bootstrap_client_end);
783
784        match TestExecutor::poll_until_stalled(&mut start_fut).await {
785            Poll::Ready(Err(status)) => assert_eq!(status, expected_status),
786            Poll::Pending => panic!("start_fut still pending!"),
787            Poll::Ready(Ok(_)) => panic!("start_fut completed with Ok value"),
788        }
789    }
790
791    #[fuchsia::test(allow_stalls = false)]
792    async fn start_fail_on_dropped_mlme_event_stream() {
793        let (fake_device, fake_device_state) = FakeDevice::new().await;
794        let (mut start_fut, _harness) = StartTestHarness::new(fake_device);
795
796        let usme_bootstrap_client_end =
797            fake_device_state.lock().usme_bootstrap_client_end.take().unwrap();
798        let (_generic_sme_proxy, _inspect_vmo_fut) =
799            bootstrap_generic_sme_proxy_and_inspect_vmo(usme_bootstrap_client_end);
800
801        let _ = fake_device_state.lock().mlme_event_stream.take();
802        match TestExecutor::poll_until_stalled(&mut start_fut).await {
803            Poll::Ready(Err(status)) => assert_eq!(status, zx::Status::INTERNAL),
804            Poll::Pending => panic!("start_fut still pending!"),
805            Poll::Ready(Ok(_)) => panic!("start_fut completed with Ok value"),
806        }
807    }
808
809    #[fuchsia::test(allow_stalls = false)]
810    async fn start_succeeds() {
811        let (fake_device, fake_device_state) = FakeDevice::new_with_config(
812            FakeDeviceConfig::default()
813                .with_mock_sta_addr([2u8; 6])
814                .with_mock_mac_role(fidl_common::WlanMacRole::Client),
815        )
816        .await;
817        let (mut start_fut, mut harness) = StartTestHarness::new(fake_device);
818
819        let usme_bootstrap_client_end =
820            fake_device_state.lock().usme_bootstrap_client_end.take().unwrap();
821        let (generic_sme_proxy, _inspect_vmo_fut) =
822            bootstrap_generic_sme_proxy_and_inspect_vmo(usme_bootstrap_client_end);
823
824        let StartedDriver {
825            softmac_ifc_bridge_request_stream: _softmac_ifc_bridge_request_stream,
826            mut mlme,
827            sme,
828        } = match TestExecutor::poll_until_stalled(&mut start_fut).await {
829            Poll::Ready(Ok(x)) => x,
830            Poll::Ready(Err(status)) => {
831                panic!("start_fut unexpectedly failed; {}", status)
832            }
833            Poll::Pending => panic!("start_fut still pending!"),
834        };
835
836        assert_variant!(TestExecutor::poll_until_stalled(&mut mlme).await, Poll::Pending);
837        assert!(matches!(
838            TestExecutor::poll_until_stalled(&mut harness.mlme_init_receiver).await,
839            Poll::Ready(Ok(()))
840        ));
841
842        let resp_fut = generic_sme_proxy.query();
843        let mut resp_fut = pin!(resp_fut);
844        assert_variant!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Pending);
845
846        let sme_and_mlme = [sme, mlme].into_iter().collect::<FuturesUnordered<_>>();
847        let mut sme_and_mlme = pin!(sme_and_mlme);
848        assert!(matches!(
849            TestExecutor::poll_until_stalled(&mut sme_and_mlme.next()).await,
850            Poll::Pending
851        ));
852
853        assert!(matches!(
854            TestExecutor::poll_until_stalled(&mut resp_fut).await,
855            Poll::Ready(Ok(fidl_sme::GenericSmeQuery {
856                role: fidl_common::WlanMacRole::Client,
857                sta_addr: [2, 2, 2, 2, 2, 2],
858            }))
859        ));
860    }
861
862    #[fuchsia::test(allow_stalls = false)]
863    async fn serve_wlansoftmac_ifc_bridge_fails_on_request_stream_error() {
864        let (driver_event_sink, _driver_event_stream) = DriverEventSink::new();
865        let (softmac_ifc_bridge_client, softmac_ifc_bridge_server) =
866            fidl::endpoints::create_endpoints::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
867        let softmac_ifc_bridge_request_stream = softmac_ifc_bridge_server.into_stream();
868        let softmac_ifc_bridge_channel = softmac_ifc_bridge_client.into_channel();
869
870        let server_fut =
871            serve_wlan_softmac_ifc_bridge(driver_event_sink, softmac_ifc_bridge_request_stream);
872        let mut server_fut = pin!(server_fut);
873        assert_variant!(TestExecutor::poll_until_stalled(&mut server_fut).await, Poll::Pending);
874
875        softmac_ifc_bridge_channel.write(&[], &mut []).unwrap();
876        assert_variant!(
877            TestExecutor::poll_until_stalled(&mut server_fut).await,
878            Poll::Ready(Err(_))
879        );
880    }
881
882    #[fuchsia::test(allow_stalls = false)]
883    async fn serve_wlansoftmac_ifc_bridge_exits_on_request_stream_end() {
884        let (driver_event_sink, _driver_event_stream) = DriverEventSink::new();
885        let (softmac_ifc_bridge_client, softmac_ifc_bridge_server) =
886            fidl::endpoints::create_endpoints::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
887        let softmac_ifc_bridge_request_stream = softmac_ifc_bridge_server.into_stream();
888
889        let server_fut =
890            serve_wlan_softmac_ifc_bridge(driver_event_sink, softmac_ifc_bridge_request_stream);
891        let mut server_fut = pin!(server_fut);
892        assert_variant!(TestExecutor::poll_until_stalled(&mut server_fut).await, Poll::Pending);
893
894        drop(softmac_ifc_bridge_client);
895        assert_variant!(
896            TestExecutor::poll_until_stalled(&mut server_fut).await,
897            Poll::Ready(Err(_))
898        );
899    }
900
901    #[test_case(fidl_softmac::WlanSoftmacIfcBaseNotifyScanCompleteRequest {
902                status: None,
903                scan_id: Some(754),
904                ..Default::default()
905    })]
906    #[test_case(fidl_softmac::WlanSoftmacIfcBaseNotifyScanCompleteRequest {
907                status: Some(zx::Status::OK.into_raw()),
908                scan_id: None,
909                ..Default::default()
910            })]
911    #[fuchsia::test(allow_stalls = false)]
912    async fn serve_wlansoftmac_ifc_bridge_exits_on_invalid_notify_scan_complete_request(
913        request: fidl_softmac::WlanSoftmacIfcBaseNotifyScanCompleteRequest,
914    ) {
915        let (driver_event_sink, mut driver_event_stream) = DriverEventSink::new();
916        let (softmac_ifc_bridge_proxy, softmac_ifc_bridge_server) =
917            fidl::endpoints::create_proxy::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
918        let softmac_ifc_bridge_request_stream = softmac_ifc_bridge_server.into_stream();
919
920        let server_fut =
921            serve_wlan_softmac_ifc_bridge(driver_event_sink, softmac_ifc_bridge_request_stream);
922        let mut server_fut = pin!(server_fut);
923
924        let resp_fut = softmac_ifc_bridge_proxy.notify_scan_complete(&request);
925        let mut resp_fut = pin!(resp_fut);
926        assert_variant!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Pending);
927        assert_variant!(
928            TestExecutor::poll_until_stalled(&mut server_fut).await,
929            Poll::Ready(Err(_))
930        );
931        assert_variant!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Ready(Ok(())));
932        assert!(matches!(driver_event_stream.try_next(), Ok(None)));
933    }
934
935    #[fuchsia::test(allow_stalls = false)]
936    async fn serve_wlansoftmac_ifc_bridge_enqueues_notify_scan_complete() {
937        let (driver_event_sink, mut driver_event_stream) = DriverEventSink::new();
938        let (softmac_ifc_bridge_proxy, softmac_ifc_bridge_server) =
939            fidl::endpoints::create_proxy::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
940        let softmac_ifc_bridge_request_stream = softmac_ifc_bridge_server.into_stream();
941
942        let server_fut =
943            serve_wlan_softmac_ifc_bridge(driver_event_sink, softmac_ifc_bridge_request_stream);
944        let mut server_fut = pin!(server_fut);
945
946        let resp_fut = softmac_ifc_bridge_proxy.notify_scan_complete(
947            &fidl_softmac::WlanSoftmacIfcBaseNotifyScanCompleteRequest {
948                status: Some(zx::Status::OK.into_raw()),
949                scan_id: Some(754),
950                ..Default::default()
951            },
952        );
953        let mut resp_fut = pin!(resp_fut);
954        assert_variant!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Pending);
955        assert_variant!(TestExecutor::poll_until_stalled(&mut server_fut).await, Poll::Pending);
956        assert_variant!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Ready(Ok(())));
957
958        assert!(matches!(
959            driver_event_stream.try_next(),
960            Ok(Some(DriverEvent::ScanComplete { status: zx::Status::OK, scan_id: 754 }))
961        ));
962    }
963
964    struct ServeTestHarness {
965        pub mlme_init_sender: oneshot::Sender<()>,
966        pub driver_event_stream: mpsc::UnboundedReceiver<DriverEvent>,
967        pub softmac_ifc_bridge_proxy: fidl_softmac::WlanSoftmacIfcBridgeProxy,
968        pub complete_mlme_sender: oneshot::Sender<Result<(), anyhow::Error>>,
969        pub complete_sme_sender: oneshot::Sender<Result<(), anyhow::Error>>,
970    }
971
972    impl ServeTestHarness {
973        fn new() -> (Pin<Box<impl Future<Output = Result<(), zx::Status>>>>, ServeTestHarness) {
974            let (mlme_init_sender, mlme_init_receiver) = oneshot::channel();
975            let (driver_event_sink, driver_event_stream) = DriverEventSink::new();
976            let (softmac_ifc_bridge_proxy, softmac_ifc_bridge_server) =
977                fidl::endpoints::create_proxy::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
978            let softmac_ifc_bridge_request_stream = softmac_ifc_bridge_server.into_stream();
979            let (complete_mlme_sender, complete_mlme_receiver) = oneshot::channel();
980            let mlme = Box::pin(async { complete_mlme_receiver.await.unwrap() });
981            let (complete_sme_sender, complete_sme_receiver) = oneshot::channel();
982            let sme = Box::pin(async { complete_sme_receiver.await.unwrap() });
983
984            (
985                Box::pin(serve(
986                    mlme_init_receiver,
987                    driver_event_sink,
988                    softmac_ifc_bridge_request_stream,
989                    mlme,
990                    sme,
991                )),
992                ServeTestHarness {
993                    mlme_init_sender,
994                    driver_event_stream,
995                    softmac_ifc_bridge_proxy,
996                    complete_mlme_sender,
997                    complete_sme_sender,
998                },
999            )
1000        }
1001    }
1002
1003    #[fuchsia::test(allow_stalls = false)]
1004    async fn serve_wlansoftmac_ifc_bridge_enqueues_report_tx_result() {
1005        let (driver_event_sink, mut driver_event_stream) = DriverEventSink::new();
1006        let (softmac_ifc_bridge_proxy, softmac_ifc_bridge_server) =
1007            fidl::endpoints::create_proxy::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
1008        let softmac_ifc_bridge_request_stream = softmac_ifc_bridge_server.into_stream();
1009
1010        let server_fut =
1011            serve_wlan_softmac_ifc_bridge(driver_event_sink, softmac_ifc_bridge_request_stream);
1012        let mut server_fut = pin!(server_fut);
1013
1014        let resp_fut = softmac_ifc_bridge_proxy.report_tx_result(&fidl_common::WlanTxResult {
1015            tx_result_entry: [fidl_common::WlanTxResultEntry {
1016                tx_vector_idx: fidl_common::WLAN_TX_VECTOR_IDX_INVALID,
1017                attempts: 0,
1018            }; fidl_common::WLAN_TX_RESULT_MAX_ENTRY as usize],
1019            peer_addr: [3; 6],
1020            result_code: fidl_common::WlanTxResultCode::Failed,
1021        });
1022        let mut resp_fut = pin!(resp_fut);
1023        assert_variant!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Pending);
1024        assert_variant!(TestExecutor::poll_until_stalled(&mut server_fut).await, Poll::Pending);
1025        assert_variant!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Ready(Ok(())));
1026
1027        match driver_event_stream.try_next().unwrap().unwrap() {
1028            DriverEvent::TxResultReport { tx_result } => {
1029                assert_eq!(
1030                    tx_result,
1031                    fidl_common::WlanTxResult {
1032                        tx_result_entry: [fidl_common::WlanTxResultEntry {
1033                            tx_vector_idx: fidl_common::WLAN_TX_VECTOR_IDX_INVALID,
1034                            attempts: 0
1035                        };
1036                            fidl_common::WLAN_TX_RESULT_MAX_ENTRY as usize],
1037                        peer_addr: [3; 6],
1038                        result_code: fidl_common::WlanTxResultCode::Failed,
1039                    }
1040                );
1041            }
1042            _ => panic!("Unexpected DriverEvent!"),
1043        }
1044    }
1045
1046    #[fuchsia::test(allow_stalls = false)]
1047    async fn serve_exits_with_error_if_mlme_init_sender_dropped() {
1048        let (mut serve_fut, harness) = ServeTestHarness::new();
1049
1050        assert_variant!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1051        drop(harness.mlme_init_sender);
1052        assert_variant!(
1053            TestExecutor::poll_until_stalled(&mut serve_fut).await,
1054            Poll::Ready(Err(zx::Status::INTERNAL))
1055        );
1056    }
1057
1058    #[fuchsia::test(allow_stalls = false)]
1059    async fn serve_exits_successfully_if_mlme_completes_just_before_init_sender_dropped() {
1060        let (mut serve_fut, harness) = ServeTestHarness::new();
1061
1062        harness.complete_mlme_sender.send(Ok(())).unwrap();
1063        drop(harness.mlme_init_sender);
1064        assert_variant!(
1065            TestExecutor::poll_until_stalled(&mut serve_fut).await,
1066            Poll::Ready(Err(zx::Status::INTERNAL))
1067        );
1068    }
1069
1070    #[fuchsia::test(allow_stalls = false)]
1071    async fn serve_exits_successfully_if_mlme_completes_just_before_init() {
1072        let (mut serve_fut, harness) = ServeTestHarness::new();
1073
1074        harness.complete_mlme_sender.send(Ok(())).unwrap();
1075        harness.mlme_init_sender.send(()).unwrap();
1076        assert_variant!(
1077            TestExecutor::poll_until_stalled(&mut serve_fut).await,
1078            Poll::Ready(Ok(()))
1079        );
1080    }
1081
1082    #[test_case(Ok(()))]
1083    #[test_case(Err(format_err!("")))]
1084    #[fuchsia::test(allow_stalls = false)]
1085    async fn serve_exits_with_error_if_mlme_completes_before_init(
1086        early_mlme_result: Result<(), Error>,
1087    ) {
1088        let (mut serve_fut, harness) = ServeTestHarness::new();
1089
1090        assert_variant!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1091        harness.complete_mlme_sender.send(early_mlme_result).unwrap();
1092        assert_variant!(
1093            TestExecutor::poll_until_stalled(&mut serve_fut).await,
1094            Poll::Ready(Err(zx::Status::INTERNAL))
1095        );
1096    }
1097
1098    #[test_case(Ok(()))]
1099    #[test_case(Err(format_err!("")))]
1100    #[fuchsia::test(allow_stalls = false)]
1101    async fn serve_exits_with_error_if_sme_shuts_down_before_mlme(
1102        early_sme_result: Result<(), Error>,
1103    ) {
1104        let (mut serve_fut, harness) = ServeTestHarness::new();
1105
1106        assert_variant!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1107        harness.mlme_init_sender.send(()).unwrap();
1108        assert_variant!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1109        harness.complete_sme_sender.send(early_sme_result).unwrap();
1110        assert_variant!(
1111            TestExecutor::poll_until_stalled(&mut serve_fut).await,
1112            Poll::Ready(Err(zx::Status::INTERNAL))
1113        );
1114    }
1115
1116    #[fuchsia::test(allow_stalls = false)]
1117    async fn serve_exits_with_error_if_mlme_completes_with_error() {
1118        let (mut serve_fut, harness) = ServeTestHarness::new();
1119
1120        assert_variant!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1121        harness.mlme_init_sender.send(()).unwrap();
1122        assert_variant!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1123        harness.complete_mlme_sender.send(Err(format_err!("mlme error"))).unwrap();
1124        assert_eq!(
1125            TestExecutor::poll_until_stalled(&mut serve_fut).await,
1126            Poll::Ready(Err(zx::Status::INTERNAL))
1127        );
1128    }
1129
1130    #[fuchsia::test(allow_stalls = false)]
1131    async fn serve_exits_with_error_if_sme_shuts_down_with_error() {
1132        let (mut serve_fut, harness) = ServeTestHarness::new();
1133
1134        assert_variant!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1135        harness.mlme_init_sender.send(()).unwrap();
1136        assert_variant!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1137        harness.complete_mlme_sender.send(Ok(())).unwrap();
1138        harness.complete_sme_sender.send(Err(format_err!("sme error"))).unwrap();
1139        assert_eq!(
1140            TestExecutor::poll_until_stalled(&mut serve_fut).await,
1141            Poll::Ready(Err(zx::Status::INTERNAL))
1142        );
1143    }
1144
1145    #[fuchsia::test(allow_stalls = false)]
1146    async fn serve_exits_with_error_if_bridge_exits_early_with_error() {
1147        let (mut serve_fut, harness) = ServeTestHarness::new();
1148
1149        assert_variant!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1150        harness.mlme_init_sender.send(()).unwrap();
1151        assert_variant!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1152
1153        // Cause the bridge to encounter an error when the client drops its endpoint.
1154        drop(harness.softmac_ifc_bridge_proxy);
1155        assert_eq!(serve_fut.await, Err(zx::Status::INTERNAL));
1156    }
1157
1158    #[fuchsia::test(allow_stalls = false)]
1159    async fn serve_exits_with_error_if_bridge_cannot_queue_stop() {
1160        let (mut serve_fut, harness) = ServeTestHarness::new();
1161
1162        assert_variant!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1163        harness.mlme_init_sender.send(()).unwrap();
1164        assert_variant!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1165
1166        // Cause the bridge to encounter an error when the bridge cannot queue the DriverEvent::Stop.
1167        drop(harness.driver_event_stream);
1168        harness.softmac_ifc_bridge_proxy.stop_bridged_driver().await.unwrap();
1169        assert_eq!(serve_fut.await, Err(zx::Status::INTERNAL));
1170    }
1171
1172    #[test_case(true)]
1173    #[test_case(false)]
1174    #[fuchsia::test(allow_stalls = false)]
1175    async fn serve_shuts_down_gracefully(bridge_shutdown_before_mlme: bool) {
1176        let (mut serve_fut, mut harness) = ServeTestHarness::new();
1177
1178        assert_variant!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1179        harness.mlme_init_sender.send(()).unwrap();
1180        assert_variant!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1181        let mut stop_response_fut = harness.softmac_ifc_bridge_proxy.stop_bridged_driver();
1182
1183        // The server should not fail if the MLME future completes before or after the bridge futures
1184        // completes. This is because the bridge server sends the message for MLME to shutdown just
1185        // before completing. And so it's possible for MLME to shutdown before the bridge server completes.
1186        //
1187        // Note that both orderings are possible even with a single threaded executor. This is because
1188        // the bridge futures actually sends two messages before completing. The first to MLME to shutdown
1189        // and the second to the bridge exit receiver with the result from the bridge completing. Thus,
1190        // there is a race between the MLME and bridge exit receiver, either of which could run first
1191        // depending on the executor.
1192        if bridge_shutdown_before_mlme {
1193            assert_variant!(
1194                TestExecutor::poll_until_stalled(&mut stop_response_fut).await,
1195                Poll::Pending,
1196            );
1197            let responder = assert_variant!(harness.driver_event_stream.next().await,
1198                Some(DriverEvent::Stop{ responder }) => responder);
1199            responder.send().unwrap();
1200            assert_variant!(
1201                TestExecutor::poll_until_stalled(&mut stop_response_fut).await,
1202                Poll::Ready(Ok(()))
1203            );
1204
1205            harness.complete_mlme_sender.send(Ok(())).unwrap();
1206        } else {
1207            harness.complete_mlme_sender.send(Ok(())).unwrap();
1208            assert_eq!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1209
1210            assert_variant!(
1211                TestExecutor::poll_until_stalled(&mut stop_response_fut).await,
1212                Poll::Pending,
1213            );
1214            let responder = assert_variant!(harness.driver_event_stream.next().await,
1215                Some(DriverEvent::Stop{ responder }) => responder);
1216            responder.send().unwrap();
1217            assert_variant!(
1218                TestExecutor::poll_until_stalled(&mut stop_response_fut).await,
1219                Poll::Ready(Ok(()))
1220            );
1221        }
1222
1223        assert_eq!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1224        harness.complete_sme_sender.send(Ok(())).unwrap();
1225        assert_eq!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Ready(Ok(())));
1226    }
1227
1228    #[derive(Debug)]
1229    struct StartAndServeTestHarness<F> {
1230        pub start_and_serve_fut: F,
1231        pub start_complete_receiver: oneshot::Receiver<zx::sys::zx_status_t>,
1232        pub generic_sme_proxy: fidl_sme::GenericSmeProxy,
1233    }
1234
1235    /// This function wraps start_and_serve() with a FakeDevice provided by a test.
1236    ///
1237    /// The returned start_and_serve() future will run the WlanSoftmacIfcBridge, MLME, and SME servers when
1238    /// run on an executor.
1239    ///
1240    /// An Err value will be returned if start_and_serve() encounters an error completing the bootstrap
1241    /// of the SME server.
1242    async fn start_and_serve_with_device(
1243        fake_device: FakeDevice,
1244    ) -> Result<StartAndServeTestHarness<impl Future<Output = Result<(), zx::Status>>>, zx::Status>
1245    {
1246        let (start_complete_sender, mut start_complete_receiver) =
1247            oneshot::channel::<zx::sys::zx_status_t>();
1248        let start_and_serve_fut = start_and_serve(
1249            Completer::new(move |status| {
1250                start_complete_sender.send(status).expect("Failed to signal start complete.")
1251            }),
1252            fake_device.clone(),
1253        );
1254        let mut start_and_serve_fut = Box::pin(start_and_serve_fut);
1255
1256        let usme_bootstrap_client_end = fake_device.state().lock().usme_bootstrap_client_end.take();
1257        match usme_bootstrap_client_end {
1258            // Simulate an errant initialization case where the UsmeBootstrap client end has been dropped
1259            // during initialization.
1260            None => match TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await {
1261                Poll::Pending => panic!(
1262                    "start_and_serve() failed to exit when the UsmeBootstrap client was dropped."
1263                ),
1264                Poll::Ready(result) => {
1265                    assert_variant!(
1266                        TestExecutor::poll_until_stalled(&mut start_complete_receiver).await,
1267                        Poll::Ready(Ok(status)) => assert_ne!(status, zx::Status::OK.into_raw())
1268                    );
1269                    return Err(result.unwrap_err());
1270                }
1271            },
1272            // Simulate the normal initialization case where the the UsmeBootstrap client end is active
1273            // during initialization.
1274            Some(usme_bootstrap_client_end) => {
1275                let (generic_sme_proxy, inspect_vmo_fut) =
1276                    bootstrap_generic_sme_proxy_and_inspect_vmo(usme_bootstrap_client_end);
1277                let start_and_serve_fut = match TestExecutor::poll_until_stalled(
1278                    &mut start_and_serve_fut,
1279                )
1280                .await
1281                {
1282                    Poll::Pending => start_and_serve_fut,
1283                    Poll::Ready(result) => {
1284                        assert_variant!(
1285                            TestExecutor::poll_until_stalled(&mut start_complete_receiver)
1286                                .await,
1287                            Poll::Ready(Ok(status)) => assert_ne!(status, zx::Status::OK.into_raw())
1288                        );
1289                        return Err(result.unwrap_err());
1290                    }
1291                };
1292
1293                inspect_vmo_fut.await.expect("Failed to bootstrap USME.");
1294
1295                Ok(StartAndServeTestHarness {
1296                    start_and_serve_fut,
1297                    start_complete_receiver,
1298                    generic_sme_proxy,
1299                })
1300            }
1301        }
1302    }
1303
1304    #[fuchsia::test(allow_stalls = false)]
1305    async fn start_and_serve_fails_on_dropped_usme_bootstrap_client() {
1306        let (fake_device, fake_device_state) = FakeDevice::new().await;
1307        fake_device_state.lock().usme_bootstrap_client_end = None;
1308        match start_and_serve_with_device(fake_device.clone()).await {
1309            Ok(_) => panic!(
1310                "start_and_serve() does not fail when the UsmeBootstrap client end is dropped."
1311            ),
1312            Err(status) => assert_eq!(status, zx::Status::BAD_STATE),
1313        }
1314    }
1315
1316    // Exhaustive feature tests are unit tested on start()
1317    #[fuchsia::test(allow_stalls = false)]
1318    async fn start_and_serve_fails_on_dropped_mlme_event_stream() {
1319        let (mut fake_device, _fake_device_state) = FakeDevice::new().await;
1320        let _ = fake_device.take_mlme_event_stream();
1321        match start_and_serve_with_device(fake_device.clone()).await {
1322            Ok(_) => {
1323                panic!("start_and_serve() does not fail when the MLME event stream is missing.")
1324            }
1325            Err(status) => assert_eq!(status, zx::Status::INTERNAL),
1326        }
1327    }
1328
1329    #[fuchsia::test(allow_stalls = false)]
1330    async fn start_and_serve_fails_on_dropped_generic_sme_client() {
1331        let (fake_device, _fake_device_state) = FakeDevice::new().await;
1332        let StartAndServeTestHarness {
1333            mut start_and_serve_fut,
1334            mut start_complete_receiver,
1335            generic_sme_proxy,
1336        } = start_and_serve_with_device(fake_device)
1337            .await
1338            .expect("Failed to initiate wlansoftmac setup.");
1339        assert_variant!(
1340            TestExecutor::poll_until_stalled(&mut start_complete_receiver).await,
1341            Poll::Ready(Ok(status)) => assert_eq!(zx::Status::OK.into_raw(), status)
1342        );
1343        assert_eq!(TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await, Poll::Pending);
1344
1345        drop(generic_sme_proxy);
1346
1347        assert_eq!(
1348            TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await,
1349            Poll::Ready(Err(zx::Status::INTERNAL))
1350        );
1351    }
1352
1353    #[fuchsia::test(allow_stalls = false)]
1354    async fn start_and_serve_shuts_down_gracefully() {
1355        let (fake_device, fake_device_state) = FakeDevice::new().await;
1356        let StartAndServeTestHarness {
1357            mut start_and_serve_fut,
1358            mut start_complete_receiver,
1359            generic_sme_proxy: _generic_sme_proxy,
1360        } = start_and_serve_with_device(fake_device)
1361            .await
1362            .expect("Failed to initiate wlansoftmac setup.");
1363        assert_eq!(TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await, Poll::Pending);
1364        assert_variant!(
1365            TestExecutor::poll_until_stalled(&mut start_complete_receiver).await,
1366            Poll::Ready(Ok(status)) => assert_eq!(zx::Status::OK.into_raw(), status)
1367        );
1368
1369        let wlan_softmac_ifc_bridge_proxy =
1370            fake_device_state.lock().wlan_softmac_ifc_bridge_proxy.take().unwrap();
1371        let stop_response_fut = wlan_softmac_ifc_bridge_proxy.stop_bridged_driver();
1372        assert_variant!(futures::join!(start_and_serve_fut, stop_response_fut), (Ok(()), Ok(())));
1373    }
1374
1375    #[fuchsia::test(allow_stalls = false)]
1376    async fn start_and_serve_responds_to_generic_sme_requests() {
1377        let (fake_device, fake_device_state) = FakeDevice::new().await;
1378        let StartAndServeTestHarness {
1379            mut start_and_serve_fut,
1380            mut start_complete_receiver,
1381            generic_sme_proxy,
1382        } = start_and_serve_with_device(fake_device)
1383            .await
1384            .expect("Failed to initiate wlansoftmac setup.");
1385        assert_variant!(
1386            TestExecutor::poll_until_stalled(&mut start_complete_receiver).await,
1387            Poll::Ready(Ok(status)) => assert_eq!(zx::Status::OK.into_raw(), status)
1388        );
1389
1390        let (sme_telemetry_proxy, sme_telemetry_server) = fidl::endpoints::create_proxy();
1391        let (client_sme_proxy, client_sme_server) = fidl::endpoints::create_proxy();
1392
1393        let resp_fut = generic_sme_proxy.get_sme_telemetry(sme_telemetry_server);
1394        let mut resp_fut = pin!(resp_fut);
1395
1396        // First poll `get_sme_telemetry` to send a `GetSmeTelemetry` request to the SME server, and then
1397        // poll the SME server process it. Finally, expect `get_sme_telemetry` to complete with `Ok(())`.
1398        assert_variant!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Pending);
1399        assert_eq!(TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await, Poll::Pending);
1400        assert_variant!(
1401            TestExecutor::poll_until_stalled(&mut resp_fut).await,
1402            Poll::Ready(Ok(Ok(())))
1403        );
1404
1405        let resp_fut = generic_sme_proxy.get_client_sme(client_sme_server);
1406        let mut resp_fut = pin!(resp_fut);
1407
1408        // First poll `get_client_sme` to send a `GetClientSme` request to the SME server, and then poll the
1409        // SME server process it. Finally, expect `get_client_sme` to complete with `Ok(())`.
1410        assert_variant!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Pending);
1411        assert_eq!(TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await, Poll::Pending);
1412        resp_fut.await.expect("Generic SME proxy failed").expect("Client SME request failed");
1413
1414        let wlan_softmac_ifc_bridge_proxy =
1415            fake_device_state.lock().wlan_softmac_ifc_bridge_proxy.take().unwrap();
1416        let stop_response_fut = wlan_softmac_ifc_bridge_proxy.stop_bridged_driver();
1417        assert_variant!(futures::join!(start_and_serve_fut, stop_response_fut), (Ok(()), Ok(())));
1418
1419        // All SME proxies should shutdown.
1420        assert!(generic_sme_proxy.is_closed());
1421        assert!(sme_telemetry_proxy.is_closed());
1422        assert!(client_sme_proxy.is_closed());
1423    }
1424
1425    // Mocking a passive scan verifies the path through SME, MLME, and the FFI is functional. Other paths
1426    // are much more complex to mock and sufficiently covered by other testing. For example, queueing an
1427    // Ethernet frame requires mocking an association first, and the outcome of a reported Tx result cannot
1428    // be confirmed because the Minstrel is internal to MLME.
1429    #[fuchsia::test(allow_stalls = false)]
1430    async fn start_and_serve_responds_to_passive_scan_request() {
1431        let (fake_device, fake_device_state) = FakeDevice::new().await;
1432        let StartAndServeTestHarness {
1433            mut start_and_serve_fut,
1434            mut start_complete_receiver,
1435            generic_sme_proxy,
1436        } = start_and_serve_with_device(fake_device)
1437            .await
1438            .expect("Failed to initiate wlansoftmac setup.");
1439        assert_variant!(
1440            TestExecutor::poll_until_stalled(&mut start_complete_receiver).await,
1441            Poll::Ready(Ok(status)) => assert_eq!(zx::Status::OK.into_raw(), status)
1442        );
1443
1444        let (client_sme_proxy, client_sme_server) = fidl::endpoints::create_proxy();
1445
1446        let resp_fut = generic_sme_proxy.get_client_sme(client_sme_server);
1447        let mut resp_fut = pin!(resp_fut);
1448        assert_variant!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Pending);
1449        assert_eq!(TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await, Poll::Pending);
1450        assert!(matches!(
1451            TestExecutor::poll_until_stalled(&mut resp_fut).await,
1452            Poll::Ready(Ok(Ok(())))
1453        ));
1454
1455        let scan_response_fut =
1456            client_sme_proxy.scan(&fidl_sme::ScanRequest::Passive(fidl_sme::PassiveScanRequest {}));
1457        let mut scan_response_fut = pin!(scan_response_fut);
1458        assert!(matches!(
1459            TestExecutor::poll_until_stalled(&mut scan_response_fut).await,
1460            Poll::Pending
1461        ));
1462
1463        assert!(fake_device_state.lock().captured_passive_scan_request.is_none());
1464        assert_eq!(TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await, Poll::Pending);
1465        assert!(fake_device_state.lock().captured_passive_scan_request.is_some());
1466
1467        let wlan_softmac_ifc_bridge_proxy =
1468            fake_device_state.lock().wlan_softmac_ifc_bridge_proxy.take().unwrap();
1469        let notify_scan_complete_fut = wlan_softmac_ifc_bridge_proxy.notify_scan_complete(
1470            &fidl_softmac::WlanSoftmacIfcBaseNotifyScanCompleteRequest {
1471                status: Some(zx::Status::OK.into_raw()),
1472                scan_id: Some(0),
1473                ..Default::default()
1474            },
1475        );
1476        notify_scan_complete_fut.await.expect("Failed to receive NotifyScanComplete response");
1477        assert_eq!(TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await, Poll::Pending);
1478        assert!(matches!(
1479            TestExecutor::poll_until_stalled(&mut scan_response_fut).await,
1480            Poll::Ready(Ok(_))
1481        ));
1482
1483        let stop_response_fut = wlan_softmac_ifc_bridge_proxy.stop_bridged_driver();
1484        assert_variant!(futures::join!(start_and_serve_fut, stop_response_fut), (Ok(()), Ok(())));
1485
1486        // All SME proxies should shutdown.
1487        assert!(generic_sme_proxy.is_closed());
1488        assert!(client_sme_proxy.is_closed());
1489    }
1490}