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