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