Skip to main content

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 fidl_fuchsia_wlan_common as fidl_common;
8use fidl_fuchsia_wlan_sme as fidl_sme;
9use fidl_fuchsia_wlan_softmac as fidl_softmac;
10use fuchsia_async::{MonotonicDuration, Task};
11use fuchsia_inspect::Inspector;
12use futures::channel::mpsc;
13use futures::channel::oneshot::{self, Canceled};
14use futures::{Future, FutureExt, StreamExt};
15use log::{error, info, warn};
16use std::pin::Pin;
17use wlan_ffi_transport::completers::Completer;
18use wlan_ffi_transport::{EthernetTx, WlanRx};
19use wlan_fidl_ext::{ResponderExt, SendResultExt, WithName};
20use wlan_mlme::device::DeviceOps;
21use wlan_mlme::{DriverEvent, DriverEventSink};
22use wlan_sme::serve::create_sme;
23use wlan_trace as wtrace;
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            fidl_softmac::WlanSoftmacIfcBridgeRequest::_UnknownMethod { .. } => {
524                warn!("Received unknown request on WlanSoftmacIfcBridge channel");
525            }
526        }
527    }
528}
529
530#[cfg(test)]
531mod tests {
532    use super::*;
533    use anyhow::format_err;
534    use assert_matches::assert_matches;
535    use diagnostics_assertions::assert_data_tree;
536    use fuchsia_async::TestExecutor;
537    use fuchsia_inspect::InspectorConfig;
538    use futures::stream::FuturesUnordered;
539    use futures::task::Poll;
540    use std::pin::pin;
541    use test_case::test_case;
542    use wlan_mlme::device::test_utils::{FakeDevice, FakeDeviceConfig};
543    use zx::Vmo;
544
545    struct BootstrapGenericSmeTestHarness {
546        _softmac_ifc_bridge_request_stream: fidl_softmac::WlanSoftmacIfcBridgeRequestStream,
547    }
548
549    // We could implement BootstrapGenericSmeTestHarness::new() instead of a macro, but doing so requires
550    // pinning the FakeDevice and WlanSoftmacIfcProtocol (and its associated DriverEventSink). While the
551    // pinning itself is feasible, it leads to a complex harness implementation that outweighs the benefit
552    // of using a harness to begin with.
553    macro_rules! make_bootstrap_generic_sme_test_harness {
554        (&mut $fake_device:ident, $driver_event_sink:ident $(,)?) => {{
555            let (softmac_ifc_bridge_proxy, _softmac_ifc_bridge_request_stream) =
556                fidl::endpoints::create_proxy_and_stream::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
557            (
558                Box::pin(bootstrap_generic_sme(
559                    &mut $fake_device,
560                    $driver_event_sink,
561                    softmac_ifc_bridge_proxy,
562                )),
563                BootstrapGenericSmeTestHarness {
564                    _softmac_ifc_bridge_request_stream,
565                }
566            )
567        }};
568    }
569
570    #[fuchsia::test(allow_stalls = false)]
571    async fn bootstrap_generic_sme_fails_to_retrieve_usme_bootstrap_handle() {
572        let (mut fake_device, _fake_device_state) = FakeDevice::new_with_config(
573            FakeDeviceConfig::default().with_mock_start_result(Err(zx::Status::INTERRUPTED_RETRY)),
574        )
575        .await;
576        let (driver_event_sink, _driver_event_stream) = DriverEventSink::new();
577
578        let (mut bootstrap_generic_sme_fut, _harness) =
579            make_bootstrap_generic_sme_test_harness!(&mut fake_device, driver_event_sink);
580        match TestExecutor::poll_until_stalled(&mut bootstrap_generic_sme_fut).await {
581            Poll::Ready(Err(zx::Status::INTERRUPTED_RETRY)) => (),
582            Poll::Ready(Err(status)) => panic!("Failed with wrong status: {}", status),
583            Poll::Ready(Ok(_)) => panic!("Succeeded unexpectedly"),
584            Poll::Pending => panic!("bootstrap_generic_sme() unexpectedly stalled"),
585        }
586    }
587
588    #[fuchsia::test(allow_stalls = false)]
589    async fn boostrap_generic_sme_fails_on_error_from_bootstrap_stream() {
590        let (mut fake_device, fake_device_state) =
591            FakeDevice::new_with_config(FakeDeviceConfig::default()).await;
592        let (driver_event_sink, _driver_event_stream) = DriverEventSink::new();
593
594        let (mut bootstrap_generic_sme_fut, _harness) =
595            make_bootstrap_generic_sme_test_harness!(&mut fake_device, driver_event_sink);
596        assert!(matches!(
597            TestExecutor::poll_until_stalled(&mut bootstrap_generic_sme_fut).await,
598            Poll::Pending
599        ));
600
601        // Write an invalid FIDL message to the USME bootstrap channel.
602        let usme_bootstrap_channel =
603            fake_device_state.lock().usme_bootstrap_client_end.take().unwrap().into_channel();
604        usme_bootstrap_channel.write(&[], &mut []).unwrap();
605
606        assert!(matches!(
607            TestExecutor::poll_until_stalled(&mut bootstrap_generic_sme_fut).await,
608            Poll::Ready(Err(zx::Status::BAD_STATE))
609        ));
610    }
611
612    #[fuchsia::test(allow_stalls = false)]
613    async fn boostrap_generic_sme_fails_on_closed_bootstrap_stream() {
614        let (mut fake_device, fake_device_state) =
615            FakeDevice::new_with_config(FakeDeviceConfig::default()).await;
616        let (driver_event_sink, _driver_event_stream) = DriverEventSink::new();
617
618        let (mut bootstrap_generic_sme_fut, _harness) =
619            make_bootstrap_generic_sme_test_harness!(&mut fake_device, driver_event_sink);
620        assert!(matches!(
621            TestExecutor::poll_until_stalled(&mut bootstrap_generic_sme_fut).await,
622            Poll::Pending
623        ));
624
625        // Drop the client end of USME bootstrap channel.
626        let _ = fake_device_state.lock().usme_bootstrap_client_end.take().unwrap();
627
628        assert!(matches!(
629            TestExecutor::poll_until_stalled(&mut bootstrap_generic_sme_fut).await,
630            Poll::Ready(Err(zx::Status::BAD_STATE))
631        ));
632    }
633
634    #[fuchsia::test(allow_stalls = false)]
635    async fn boostrap_generic_sme_succeeds() {
636        let (mut fake_device, fake_device_state) =
637            FakeDevice::new_with_config(FakeDeviceConfig::default()).await;
638        let (driver_event_sink, _driver_event_stream) = DriverEventSink::new();
639
640        let (mut bootstrap_generic_sme_fut, _harness) =
641            make_bootstrap_generic_sme_test_harness!(&mut fake_device, driver_event_sink);
642        assert!(matches!(
643            TestExecutor::poll_until_stalled(&mut bootstrap_generic_sme_fut).await,
644            Poll::Pending
645        ));
646
647        let usme_bootstrap_proxy =
648            fake_device_state.lock().usme_bootstrap_client_end.take().unwrap().into_proxy();
649
650        let sent_legacy_privacy_support =
651            fidl_sme::LegacyPrivacySupport { wep_supported: false, wpa1_supported: false };
652        let (generic_sme_proxy, generic_sme_server) =
653            fidl::endpoints::create_proxy::<fidl_sme::GenericSmeMarker>();
654        let inspect_vmo_fut =
655            usme_bootstrap_proxy.start(generic_sme_server, &sent_legacy_privacy_support);
656        let mut inspect_vmo_fut = pin!(inspect_vmo_fut);
657        assert!(matches!(
658            TestExecutor::poll_until_stalled(&mut inspect_vmo_fut).await,
659            Poll::Pending
660        ));
661
662        let BootstrappedGenericSme {
663            mut generic_sme_request_stream,
664            legacy_privacy_support: received_legacy_privacy_support,
665            inspector,
666        } = match TestExecutor::poll_until_stalled(&mut bootstrap_generic_sme_fut).await {
667            Poll::Pending => panic!("bootstrap_generic_sme_fut() did not complete!"),
668            Poll::Ready(x) => x.unwrap(),
669        };
670        let inspect_vmo = match TestExecutor::poll_until_stalled(&mut inspect_vmo_fut).await {
671            Poll::Pending => panic!("Failed to receive an inspect VMO."),
672            Poll::Ready(x) => x.unwrap(),
673        };
674
675        // Send a GenericSme.Query() to check the generic_sme_proxy
676        // and generic_sme_stream are connected.
677        let query_fut = generic_sme_proxy.query();
678        let mut query_fut = pin!(query_fut);
679        assert!(matches!(TestExecutor::poll_until_stalled(&mut query_fut).await, Poll::Pending));
680        let next_generic_sme_request_fut = generic_sme_request_stream.next();
681        let mut next_generic_sme_request_fut = pin!(next_generic_sme_request_fut);
682        assert!(matches!(
683            TestExecutor::poll_until_stalled(&mut next_generic_sme_request_fut).await,
684            Poll::Ready(Some(Ok(fidl_sme::GenericSmeRequest::Query { .. })))
685        ));
686
687        assert_eq!(received_legacy_privacy_support, sent_legacy_privacy_support);
688
689        // Add a child node through the bootstrapped inspector and verify the node appears inspect_vmo.
690        let returned_inspector = Inspector::new(InspectorConfig::default().vmo(inspect_vmo));
691        let _a = inspector.root().create_child("a");
692        assert_data_tree!(returned_inspector, root: {
693            a: {},
694        });
695    }
696
697    struct StartTestHarness {
698        pub mlme_init_receiver: Pin<Box<oneshot::Receiver<()>>>,
699        // TODO(https://fxbug.dev/335283785): Remove or explain unused code.
700        #[allow(dead_code)]
701        pub driver_event_sink: DriverEventSink,
702    }
703
704    impl StartTestHarness {
705        fn new(
706            fake_device: FakeDevice,
707        ) -> (
708            impl Future<
709                Output = Result<
710                    StartedDriver<
711                        Pin<Box<dyn Future<Output = Result<(), Error>>>>,
712                        Pin<Box<impl Future<Output = Result<(), Error>>>>,
713                    >,
714                    zx::Status,
715                >,
716            >,
717            Self,
718        ) {
719            let (mlme_init_sender, mlme_init_receiver) = oneshot::channel();
720            let (driver_event_sink, driver_event_stream) = DriverEventSink::new();
721
722            (
723                Box::pin(start(
724                    mlme_init_sender,
725                    driver_event_sink.clone(),
726                    driver_event_stream,
727                    fake_device,
728                )),
729                Self { mlme_init_receiver: Box::pin(mlme_init_receiver), driver_event_sink },
730            )
731        }
732    }
733
734    #[fuchsia::test(allow_stalls = false)]
735    async fn start_fails_on_bad_bootstrap() {
736        let (fake_device, _fake_device_state) = FakeDevice::new_with_config(
737            FakeDeviceConfig::default().with_mock_start_result(Err(zx::Status::INTERRUPTED_RETRY)),
738        )
739        .await;
740        let (mut start_fut, _harness) = StartTestHarness::new(fake_device);
741
742        assert!(matches!(
743            TestExecutor::poll_until_stalled(&mut start_fut).await,
744            Poll::Ready(Err(zx::Status::INTERRUPTED_RETRY))
745        ));
746    }
747
748    fn bootstrap_generic_sme_proxy_and_inspect_vmo(
749        usme_bootstrap_client_end: fidl::endpoints::ClientEnd<fidl_sme::UsmeBootstrapMarker>,
750    ) -> (fidl_sme::GenericSmeProxy, impl Future<Output = Result<Vmo, fidl::Error>>) {
751        let usme_client_proxy = usme_bootstrap_client_end.into_proxy();
752
753        let legacy_privacy_support =
754            fidl_sme::LegacyPrivacySupport { wep_supported: false, wpa1_supported: false };
755        let (generic_sme_proxy, generic_sme_server) =
756            fidl::endpoints::create_proxy::<fidl_sme::GenericSmeMarker>();
757        (generic_sme_proxy, usme_client_proxy.start(generic_sme_server, &legacy_privacy_support))
758    }
759
760    #[test_case(FakeDeviceConfig::default().with_mock_query_response(Err(zx::Status::IO_DATA_INTEGRITY)), zx::Status::IO_DATA_INTEGRITY)]
761    #[test_case(FakeDeviceConfig::default().with_mock_security_support(Err(zx::Status::IO_DATA_INTEGRITY)), zx::Status::IO_DATA_INTEGRITY)]
762    #[test_case(FakeDeviceConfig::default().with_mock_spectrum_management_support(Err(zx::Status::IO_DATA_INTEGRITY)), zx::Status::IO_DATA_INTEGRITY)]
763    #[test_case(FakeDeviceConfig::default().with_mock_mac_role(fidl_common::WlanMacRole::__SourceBreaking { unknown_ordinal: 0 }), zx::Status::INTERNAL)]
764    #[fuchsia::test(allow_stalls = false)]
765    async fn start_fails_on_query_error(
766        fake_device_config: FakeDeviceConfig,
767        expected_status: zx::Status,
768    ) {
769        let (fake_device, fake_device_state) =
770            FakeDevice::new_with_config(fake_device_config).await;
771        let (mut start_fut, _harness) = StartTestHarness::new(fake_device);
772
773        let usme_bootstrap_client_end =
774            fake_device_state.lock().usme_bootstrap_client_end.take().unwrap();
775        let (_generic_sme_proxy, _inspect_vmo_fut) =
776            bootstrap_generic_sme_proxy_and_inspect_vmo(usme_bootstrap_client_end);
777
778        match TestExecutor::poll_until_stalled(&mut start_fut).await {
779            Poll::Ready(Err(status)) => assert_eq!(status, expected_status),
780            Poll::Pending => panic!("start_fut still pending!"),
781            Poll::Ready(Ok(_)) => panic!("start_fut completed with Ok value"),
782        }
783    }
784
785    #[fuchsia::test(allow_stalls = false)]
786    async fn start_fail_on_dropped_mlme_event_stream() {
787        let (fake_device, fake_device_state) = FakeDevice::new().await;
788        let (mut start_fut, _harness) = StartTestHarness::new(fake_device);
789
790        let usme_bootstrap_client_end =
791            fake_device_state.lock().usme_bootstrap_client_end.take().unwrap();
792        let (_generic_sme_proxy, _inspect_vmo_fut) =
793            bootstrap_generic_sme_proxy_and_inspect_vmo(usme_bootstrap_client_end);
794
795        let _ = fake_device_state.lock().mlme_event_stream.take();
796        match TestExecutor::poll_until_stalled(&mut start_fut).await {
797            Poll::Ready(Err(status)) => assert_eq!(status, zx::Status::INTERNAL),
798            Poll::Pending => panic!("start_fut still pending!"),
799            Poll::Ready(Ok(_)) => panic!("start_fut completed with Ok value"),
800        }
801    }
802
803    #[fuchsia::test(allow_stalls = false)]
804    async fn start_succeeds() {
805        let (fake_device, fake_device_state) = FakeDevice::new_with_config(
806            FakeDeviceConfig::default()
807                .with_mock_sta_addr([2u8; 6])
808                .with_mock_mac_role(fidl_common::WlanMacRole::Client),
809        )
810        .await;
811        let (mut start_fut, mut harness) = StartTestHarness::new(fake_device);
812
813        let usme_bootstrap_client_end =
814            fake_device_state.lock().usme_bootstrap_client_end.take().unwrap();
815        let (generic_sme_proxy, _inspect_vmo_fut) =
816            bootstrap_generic_sme_proxy_and_inspect_vmo(usme_bootstrap_client_end);
817
818        let StartedDriver {
819            softmac_ifc_bridge_request_stream: _softmac_ifc_bridge_request_stream,
820            mut mlme,
821            sme,
822        } = match TestExecutor::poll_until_stalled(&mut start_fut).await {
823            Poll::Ready(Ok(x)) => x,
824            Poll::Ready(Err(status)) => {
825                panic!("start_fut unexpectedly failed; {}", status)
826            }
827            Poll::Pending => panic!("start_fut still pending!"),
828        };
829
830        assert_matches!(TestExecutor::poll_until_stalled(&mut mlme).await, Poll::Pending);
831        assert!(matches!(
832            TestExecutor::poll_until_stalled(&mut harness.mlme_init_receiver).await,
833            Poll::Ready(Ok(()))
834        ));
835
836        let resp_fut = generic_sme_proxy.query();
837        let mut resp_fut = pin!(resp_fut);
838        assert_matches!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Pending);
839
840        let sme_and_mlme = [sme, mlme].into_iter().collect::<FuturesUnordered<_>>();
841        let mut sme_and_mlme = pin!(sme_and_mlme);
842        assert!(matches!(
843            TestExecutor::poll_until_stalled(&mut sme_and_mlme.next()).await,
844            Poll::Pending
845        ));
846
847        assert!(matches!(
848            TestExecutor::poll_until_stalled(&mut resp_fut).await,
849            Poll::Ready(Ok(fidl_sme::GenericSmeQuery {
850                role: fidl_common::WlanMacRole::Client,
851                sta_addr: [2, 2, 2, 2, 2, 2],
852                factory_addr: [2, 2, 2, 2, 2, 2],
853            }))
854        ));
855    }
856
857    #[fuchsia::test(allow_stalls = false)]
858    async fn serve_wlansoftmac_ifc_bridge_fails_on_request_stream_error() {
859        let (driver_event_sink, _driver_event_stream) = DriverEventSink::new();
860        let (softmac_ifc_bridge_client, softmac_ifc_bridge_server) =
861            fidl::endpoints::create_endpoints::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
862        let softmac_ifc_bridge_request_stream = softmac_ifc_bridge_server.into_stream();
863        let softmac_ifc_bridge_channel = softmac_ifc_bridge_client.into_channel();
864
865        let server_fut =
866            serve_wlan_softmac_ifc_bridge(driver_event_sink, softmac_ifc_bridge_request_stream);
867        let mut server_fut = pin!(server_fut);
868        assert_matches!(TestExecutor::poll_until_stalled(&mut server_fut).await, Poll::Pending);
869
870        softmac_ifc_bridge_channel.write(&[], &mut []).unwrap();
871        assert_matches!(
872            TestExecutor::poll_until_stalled(&mut server_fut).await,
873            Poll::Ready(Err(_))
874        );
875    }
876
877    #[fuchsia::test(allow_stalls = false)]
878    async fn serve_wlansoftmac_ifc_bridge_exits_on_request_stream_end() {
879        let (driver_event_sink, _driver_event_stream) = DriverEventSink::new();
880        let (softmac_ifc_bridge_client, softmac_ifc_bridge_server) =
881            fidl::endpoints::create_endpoints::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
882        let softmac_ifc_bridge_request_stream = softmac_ifc_bridge_server.into_stream();
883
884        let server_fut =
885            serve_wlan_softmac_ifc_bridge(driver_event_sink, softmac_ifc_bridge_request_stream);
886        let mut server_fut = pin!(server_fut);
887        assert_matches!(TestExecutor::poll_until_stalled(&mut server_fut).await, Poll::Pending);
888
889        drop(softmac_ifc_bridge_client);
890        assert_matches!(
891            TestExecutor::poll_until_stalled(&mut server_fut).await,
892            Poll::Ready(Err(_))
893        );
894    }
895
896    #[test_case(fidl_softmac::WlanSoftmacIfcBaseNotifyScanCompleteRequest {
897                status: None,
898                scan_id: Some(754),
899                ..Default::default()
900    })]
901    #[test_case(fidl_softmac::WlanSoftmacIfcBaseNotifyScanCompleteRequest {
902                status: Some(zx::Status::OK.into_raw()),
903                scan_id: None,
904                ..Default::default()
905            })]
906    #[fuchsia::test(allow_stalls = false)]
907    async fn serve_wlansoftmac_ifc_bridge_exits_on_invalid_notify_scan_complete_request(
908        request: fidl_softmac::WlanSoftmacIfcBaseNotifyScanCompleteRequest,
909    ) {
910        let (driver_event_sink, mut driver_event_stream) = DriverEventSink::new();
911        let (softmac_ifc_bridge_proxy, softmac_ifc_bridge_server) =
912            fidl::endpoints::create_proxy::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
913        let softmac_ifc_bridge_request_stream = softmac_ifc_bridge_server.into_stream();
914
915        let server_fut =
916            serve_wlan_softmac_ifc_bridge(driver_event_sink, softmac_ifc_bridge_request_stream);
917        let mut server_fut = pin!(server_fut);
918
919        let resp_fut = softmac_ifc_bridge_proxy.notify_scan_complete(&request);
920        let mut resp_fut = pin!(resp_fut);
921        assert_matches!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Pending);
922        assert_matches!(
923            TestExecutor::poll_until_stalled(&mut server_fut).await,
924            Poll::Ready(Err(_))
925        );
926        assert_matches!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Ready(Ok(())));
927        assert!(matches!(driver_event_stream.try_next(), Ok(None)));
928    }
929
930    #[fuchsia::test(allow_stalls = false)]
931    async fn serve_wlansoftmac_ifc_bridge_enqueues_notify_scan_complete() {
932        let (driver_event_sink, mut driver_event_stream) = DriverEventSink::new();
933        let (softmac_ifc_bridge_proxy, softmac_ifc_bridge_server) =
934            fidl::endpoints::create_proxy::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
935        let softmac_ifc_bridge_request_stream = softmac_ifc_bridge_server.into_stream();
936
937        let server_fut =
938            serve_wlan_softmac_ifc_bridge(driver_event_sink, softmac_ifc_bridge_request_stream);
939        let mut server_fut = pin!(server_fut);
940
941        let resp_fut = softmac_ifc_bridge_proxy.notify_scan_complete(
942            &fidl_softmac::WlanSoftmacIfcBaseNotifyScanCompleteRequest {
943                status: Some(zx::Status::OK.into_raw()),
944                scan_id: Some(754),
945                ..Default::default()
946            },
947        );
948        let mut resp_fut = pin!(resp_fut);
949        assert_matches!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Pending);
950        assert_matches!(TestExecutor::poll_until_stalled(&mut server_fut).await, Poll::Pending);
951        assert_matches!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Ready(Ok(())));
952
953        assert!(matches!(
954            driver_event_stream.try_next(),
955            Ok(Some(DriverEvent::ScanComplete { status: zx::Status::OK, scan_id: 754 }))
956        ));
957    }
958
959    struct ServeTestHarness {
960        pub mlme_init_sender: oneshot::Sender<()>,
961        pub driver_event_stream: mpsc::UnboundedReceiver<DriverEvent>,
962        pub softmac_ifc_bridge_proxy: fidl_softmac::WlanSoftmacIfcBridgeProxy,
963        pub complete_mlme_sender: oneshot::Sender<Result<(), anyhow::Error>>,
964        pub complete_sme_sender: oneshot::Sender<Result<(), anyhow::Error>>,
965    }
966
967    impl ServeTestHarness {
968        fn new() -> (Pin<Box<impl Future<Output = Result<(), zx::Status>>>>, ServeTestHarness) {
969            let (mlme_init_sender, mlme_init_receiver) = oneshot::channel();
970            let (driver_event_sink, driver_event_stream) = DriverEventSink::new();
971            let (softmac_ifc_bridge_proxy, softmac_ifc_bridge_server) =
972                fidl::endpoints::create_proxy::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
973            let softmac_ifc_bridge_request_stream = softmac_ifc_bridge_server.into_stream();
974            let (complete_mlme_sender, complete_mlme_receiver) = oneshot::channel();
975            let mlme = Box::pin(async { complete_mlme_receiver.await.unwrap() });
976            let (complete_sme_sender, complete_sme_receiver) = oneshot::channel();
977            let sme = Box::pin(async { complete_sme_receiver.await.unwrap() });
978
979            (
980                Box::pin(serve(
981                    mlme_init_receiver,
982                    driver_event_sink,
983                    softmac_ifc_bridge_request_stream,
984                    mlme,
985                    sme,
986                )),
987                ServeTestHarness {
988                    mlme_init_sender,
989                    driver_event_stream,
990                    softmac_ifc_bridge_proxy,
991                    complete_mlme_sender,
992                    complete_sme_sender,
993                },
994            )
995        }
996    }
997
998    #[fuchsia::test(allow_stalls = false)]
999    async fn serve_wlansoftmac_ifc_bridge_enqueues_report_tx_result() {
1000        let (driver_event_sink, mut driver_event_stream) = DriverEventSink::new();
1001        let (softmac_ifc_bridge_proxy, softmac_ifc_bridge_server) =
1002            fidl::endpoints::create_proxy::<fidl_softmac::WlanSoftmacIfcBridgeMarker>();
1003        let softmac_ifc_bridge_request_stream = softmac_ifc_bridge_server.into_stream();
1004
1005        let server_fut =
1006            serve_wlan_softmac_ifc_bridge(driver_event_sink, softmac_ifc_bridge_request_stream);
1007        let mut server_fut = pin!(server_fut);
1008
1009        let resp_fut = softmac_ifc_bridge_proxy.report_tx_result(&fidl_softmac::WlanTxResult {
1010            tx_result_entry: [fidl_softmac::WlanTxResultEntry {
1011                tx_vector_idx: fidl_softmac::WLAN_TX_VECTOR_IDX_INVALID,
1012                attempts: 0,
1013            }; fidl_softmac::WLAN_TX_RESULT_MAX_ENTRY as usize],
1014            peer_addr: [3; 6],
1015            result_code: fidl_softmac::WlanTxResultCode::Failed,
1016        });
1017        let mut resp_fut = pin!(resp_fut);
1018        assert_matches!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Pending);
1019        assert_matches!(TestExecutor::poll_until_stalled(&mut server_fut).await, Poll::Pending);
1020        assert_matches!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Ready(Ok(())));
1021
1022        match driver_event_stream.try_next().unwrap().unwrap() {
1023            DriverEvent::TxResultReport { tx_result } => {
1024                assert_eq!(
1025                    tx_result,
1026                    fidl_softmac::WlanTxResult {
1027                        tx_result_entry: [fidl_softmac::WlanTxResultEntry {
1028                            tx_vector_idx: fidl_softmac::WLAN_TX_VECTOR_IDX_INVALID,
1029                            attempts: 0
1030                        };
1031                            fidl_softmac::WLAN_TX_RESULT_MAX_ENTRY as usize],
1032                        peer_addr: [3; 6],
1033                        result_code: fidl_softmac::WlanTxResultCode::Failed,
1034                    }
1035                );
1036            }
1037            _ => panic!("Unexpected DriverEvent!"),
1038        }
1039    }
1040
1041    #[fuchsia::test(allow_stalls = false)]
1042    async fn serve_exits_with_error_if_mlme_init_sender_dropped() {
1043        let (mut serve_fut, harness) = ServeTestHarness::new();
1044
1045        assert_matches!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1046        drop(harness.mlme_init_sender);
1047        assert_matches!(
1048            TestExecutor::poll_until_stalled(&mut serve_fut).await,
1049            Poll::Ready(Err(zx::Status::INTERNAL))
1050        );
1051    }
1052
1053    #[fuchsia::test(allow_stalls = false)]
1054    async fn serve_exits_successfully_if_mlme_completes_just_before_init_sender_dropped() {
1055        let (mut serve_fut, harness) = ServeTestHarness::new();
1056
1057        harness.complete_mlme_sender.send(Ok(())).unwrap();
1058        drop(harness.mlme_init_sender);
1059        assert_matches!(
1060            TestExecutor::poll_until_stalled(&mut serve_fut).await,
1061            Poll::Ready(Err(zx::Status::INTERNAL))
1062        );
1063    }
1064
1065    #[fuchsia::test(allow_stalls = false)]
1066    async fn serve_exits_successfully_if_mlme_completes_just_before_init() {
1067        let (mut serve_fut, harness) = ServeTestHarness::new();
1068
1069        harness.complete_mlme_sender.send(Ok(())).unwrap();
1070        harness.mlme_init_sender.send(()).unwrap();
1071        assert_matches!(
1072            TestExecutor::poll_until_stalled(&mut serve_fut).await,
1073            Poll::Ready(Ok(()))
1074        );
1075    }
1076
1077    #[test_case(Ok(()))]
1078    #[test_case(Err(format_err!("")))]
1079    #[fuchsia::test(allow_stalls = false)]
1080    async fn serve_exits_with_error_if_mlme_completes_before_init(
1081        early_mlme_result: Result<(), Error>,
1082    ) {
1083        let (mut serve_fut, harness) = ServeTestHarness::new();
1084
1085        assert_matches!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1086        harness.complete_mlme_sender.send(early_mlme_result).unwrap();
1087        assert_matches!(
1088            TestExecutor::poll_until_stalled(&mut serve_fut).await,
1089            Poll::Ready(Err(zx::Status::INTERNAL))
1090        );
1091    }
1092
1093    #[test_case(Ok(()))]
1094    #[test_case(Err(format_err!("")))]
1095    #[fuchsia::test(allow_stalls = false)]
1096    async fn serve_exits_with_error_if_sme_shuts_down_before_mlme(
1097        early_sme_result: Result<(), Error>,
1098    ) {
1099        let (mut serve_fut, harness) = ServeTestHarness::new();
1100
1101        assert_matches!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1102        harness.mlme_init_sender.send(()).unwrap();
1103        assert_matches!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1104        harness.complete_sme_sender.send(early_sme_result).unwrap();
1105        assert_matches!(
1106            TestExecutor::poll_until_stalled(&mut serve_fut).await,
1107            Poll::Ready(Err(zx::Status::INTERNAL))
1108        );
1109    }
1110
1111    #[fuchsia::test(allow_stalls = false)]
1112    async fn serve_exits_with_error_if_mlme_completes_with_error() {
1113        let (mut serve_fut, harness) = ServeTestHarness::new();
1114
1115        assert_matches!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1116        harness.mlme_init_sender.send(()).unwrap();
1117        assert_matches!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1118        harness.complete_mlme_sender.send(Err(format_err!("mlme error"))).unwrap();
1119        assert_eq!(
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_sme_shuts_down_with_error() {
1127        let (mut serve_fut, harness) = ServeTestHarness::new();
1128
1129        assert_matches!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1130        harness.mlme_init_sender.send(()).unwrap();
1131        assert_matches!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1132        harness.complete_mlme_sender.send(Ok(())).unwrap();
1133        harness.complete_sme_sender.send(Err(format_err!("sme error"))).unwrap();
1134        assert_eq!(
1135            TestExecutor::poll_until_stalled(&mut serve_fut).await,
1136            Poll::Ready(Err(zx::Status::INTERNAL))
1137        );
1138    }
1139
1140    #[fuchsia::test(allow_stalls = false)]
1141    async fn serve_exits_with_error_if_bridge_exits_early_with_error() {
1142        let (mut serve_fut, harness) = ServeTestHarness::new();
1143
1144        assert_matches!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1145        harness.mlme_init_sender.send(()).unwrap();
1146        assert_matches!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1147
1148        // Cause the bridge to encounter an error when the client drops its endpoint.
1149        drop(harness.softmac_ifc_bridge_proxy);
1150        assert_eq!(serve_fut.await, Err(zx::Status::INTERNAL));
1151    }
1152
1153    #[fuchsia::test(allow_stalls = false)]
1154    async fn serve_exits_with_error_if_bridge_cannot_queue_stop() {
1155        let (mut serve_fut, harness) = ServeTestHarness::new();
1156
1157        assert_matches!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1158        harness.mlme_init_sender.send(()).unwrap();
1159        assert_matches!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1160
1161        // Cause the bridge to encounter an error when the bridge cannot queue the DriverEvent::Stop.
1162        drop(harness.driver_event_stream);
1163        harness.softmac_ifc_bridge_proxy.stop_bridged_driver().await.unwrap();
1164        assert_eq!(serve_fut.await, Err(zx::Status::INTERNAL));
1165    }
1166
1167    #[test_case(true)]
1168    #[test_case(false)]
1169    #[fuchsia::test(allow_stalls = false)]
1170    async fn serve_shuts_down_gracefully(bridge_shutdown_before_mlme: bool) {
1171        let (mut serve_fut, mut harness) = ServeTestHarness::new();
1172
1173        assert_matches!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1174        harness.mlme_init_sender.send(()).unwrap();
1175        assert_matches!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1176        let mut stop_response_fut = harness.softmac_ifc_bridge_proxy.stop_bridged_driver();
1177
1178        // The server should not fail if the MLME future completes before or after the bridge futures
1179        // completes. This is because the bridge server sends the message for MLME to shutdown just
1180        // before completing. And so it's possible for MLME to shutdown before the bridge server completes.
1181        //
1182        // Note that both orderings are possible even with a single threaded executor. This is because
1183        // the bridge futures actually sends two messages before completing. The first to MLME to shutdown
1184        // and the second to the bridge exit receiver with the result from the bridge completing. Thus,
1185        // there is a race between the MLME and bridge exit receiver, either of which could run first
1186        // depending on the executor.
1187        if bridge_shutdown_before_mlme {
1188            assert_matches!(
1189                TestExecutor::poll_until_stalled(&mut stop_response_fut).await,
1190                Poll::Pending
1191            );
1192            let responder = assert_matches!(harness.driver_event_stream.next().await,
1193                Some(DriverEvent::Stop{ responder }) => responder);
1194            responder.send().unwrap();
1195            assert_matches!(
1196                TestExecutor::poll_until_stalled(&mut stop_response_fut).await,
1197                Poll::Ready(Ok(()))
1198            );
1199
1200            harness.complete_mlme_sender.send(Ok(())).unwrap();
1201        } else {
1202            harness.complete_mlme_sender.send(Ok(())).unwrap();
1203            assert_eq!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1204
1205            assert_matches!(
1206                TestExecutor::poll_until_stalled(&mut stop_response_fut).await,
1207                Poll::Pending
1208            );
1209            let responder = assert_matches!(harness.driver_event_stream.next().await,
1210                Some(DriverEvent::Stop{ responder }) => responder);
1211            responder.send().unwrap();
1212            assert_matches!(
1213                TestExecutor::poll_until_stalled(&mut stop_response_fut).await,
1214                Poll::Ready(Ok(()))
1215            );
1216        }
1217
1218        assert_eq!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Pending);
1219        harness.complete_sme_sender.send(Ok(())).unwrap();
1220        assert_eq!(TestExecutor::poll_until_stalled(&mut serve_fut).await, Poll::Ready(Ok(())));
1221    }
1222
1223    #[derive(Debug)]
1224    struct StartAndServeTestHarness<F> {
1225        pub start_and_serve_fut: F,
1226        pub start_complete_receiver: oneshot::Receiver<zx::sys::zx_status_t>,
1227        pub generic_sme_proxy: fidl_sme::GenericSmeProxy,
1228    }
1229
1230    /// This function wraps start_and_serve() with a FakeDevice provided by a test.
1231    ///
1232    /// The returned start_and_serve() future will run the WlanSoftmacIfcBridge, MLME, and SME servers when
1233    /// run on an executor.
1234    ///
1235    /// An Err value will be returned if start_and_serve() encounters an error completing the bootstrap
1236    /// of the SME server.
1237    async fn start_and_serve_with_device(
1238        fake_device: FakeDevice,
1239    ) -> Result<StartAndServeTestHarness<impl Future<Output = Result<(), zx::Status>>>, zx::Status>
1240    {
1241        let (start_complete_sender, mut start_complete_receiver) =
1242            oneshot::channel::<zx::sys::zx_status_t>();
1243        let start_and_serve_fut = start_and_serve(
1244            Completer::new(move |status| {
1245                start_complete_sender.send(status).expect("Failed to signal start complete.")
1246            }),
1247            fake_device.clone(),
1248        );
1249        let mut start_and_serve_fut = Box::pin(start_and_serve_fut);
1250
1251        let usme_bootstrap_client_end = fake_device.state().lock().usme_bootstrap_client_end.take();
1252        match usme_bootstrap_client_end {
1253            // Simulate an errant initialization case where the UsmeBootstrap client end has been dropped
1254            // during initialization.
1255            None => match TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await {
1256                Poll::Pending => panic!(
1257                    "start_and_serve() failed to exit when the UsmeBootstrap client was dropped."
1258                ),
1259                Poll::Ready(result) => {
1260                    assert_matches!(
1261                        TestExecutor::poll_until_stalled(&mut start_complete_receiver).await,
1262                        Poll::Ready(Ok(status)) => assert_ne!(status, zx::Status::OK.into_raw())
1263                    );
1264                    return Err(result.unwrap_err());
1265                }
1266            },
1267            // Simulate the normal initialization case where the the UsmeBootstrap client end is active
1268            // during initialization.
1269            Some(usme_bootstrap_client_end) => {
1270                let (generic_sme_proxy, inspect_vmo_fut) =
1271                    bootstrap_generic_sme_proxy_and_inspect_vmo(usme_bootstrap_client_end);
1272                let start_and_serve_fut = match TestExecutor::poll_until_stalled(
1273                    &mut start_and_serve_fut,
1274                )
1275                .await
1276                {
1277                    Poll::Pending => start_and_serve_fut,
1278                    Poll::Ready(result) => {
1279                        assert_matches!(
1280                            TestExecutor::poll_until_stalled(&mut start_complete_receiver)
1281                                .await,
1282                            Poll::Ready(Ok(status)) => assert_ne!(status, zx::Status::OK.into_raw())
1283                        );
1284                        return Err(result.unwrap_err());
1285                    }
1286                };
1287
1288                inspect_vmo_fut.await.expect("Failed to bootstrap USME.");
1289
1290                Ok(StartAndServeTestHarness {
1291                    start_and_serve_fut,
1292                    start_complete_receiver,
1293                    generic_sme_proxy,
1294                })
1295            }
1296        }
1297    }
1298
1299    #[fuchsia::test(allow_stalls = false)]
1300    async fn start_and_serve_fails_on_dropped_usme_bootstrap_client() {
1301        let (fake_device, fake_device_state) = FakeDevice::new().await;
1302        fake_device_state.lock().usme_bootstrap_client_end = None;
1303        match start_and_serve_with_device(fake_device.clone()).await {
1304            Ok(_) => panic!(
1305                "start_and_serve() does not fail when the UsmeBootstrap client end is dropped."
1306            ),
1307            Err(status) => assert_eq!(status, zx::Status::BAD_STATE),
1308        }
1309    }
1310
1311    // Exhaustive feature tests are unit tested on start()
1312    #[fuchsia::test(allow_stalls = false)]
1313    async fn start_and_serve_fails_on_dropped_mlme_event_stream() {
1314        let (mut fake_device, _fake_device_state) = FakeDevice::new().await;
1315        let _ = fake_device.take_mlme_event_stream();
1316        match start_and_serve_with_device(fake_device.clone()).await {
1317            Ok(_) => {
1318                panic!("start_and_serve() does not fail when the MLME event stream is missing.")
1319            }
1320            Err(status) => assert_eq!(status, zx::Status::INTERNAL),
1321        }
1322    }
1323
1324    #[fuchsia::test(allow_stalls = false)]
1325    async fn start_and_serve_fails_on_dropped_generic_sme_client() {
1326        let (fake_device, _fake_device_state) = FakeDevice::new().await;
1327        let StartAndServeTestHarness {
1328            mut start_and_serve_fut,
1329            mut start_complete_receiver,
1330            generic_sme_proxy,
1331        } = start_and_serve_with_device(fake_device)
1332            .await
1333            .expect("Failed to initiate wlansoftmac setup.");
1334        assert_matches!(
1335            TestExecutor::poll_until_stalled(&mut start_complete_receiver).await,
1336            Poll::Ready(Ok(status)) => assert_eq!(zx::Status::OK.into_raw(), status)
1337        );
1338        assert_eq!(TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await, Poll::Pending);
1339
1340        drop(generic_sme_proxy);
1341
1342        assert_eq!(
1343            TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await,
1344            Poll::Ready(Err(zx::Status::INTERNAL))
1345        );
1346    }
1347
1348    #[fuchsia::test(allow_stalls = false)]
1349    async fn start_and_serve_shuts_down_gracefully() {
1350        let (fake_device, fake_device_state) = FakeDevice::new().await;
1351        let StartAndServeTestHarness {
1352            mut start_and_serve_fut,
1353            mut start_complete_receiver,
1354            generic_sme_proxy: _generic_sme_proxy,
1355        } = start_and_serve_with_device(fake_device)
1356            .await
1357            .expect("Failed to initiate wlansoftmac setup.");
1358        assert_eq!(TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await, Poll::Pending);
1359        assert_matches!(
1360            TestExecutor::poll_until_stalled(&mut start_complete_receiver).await,
1361            Poll::Ready(Ok(status)) => assert_eq!(zx::Status::OK.into_raw(), status)
1362        );
1363
1364        let wlan_softmac_ifc_bridge_proxy =
1365            fake_device_state.lock().wlan_softmac_ifc_bridge_proxy.take().unwrap();
1366        let stop_response_fut = wlan_softmac_ifc_bridge_proxy.stop_bridged_driver();
1367        assert_matches!(futures::join!(start_and_serve_fut, stop_response_fut), (Ok(()), Ok(())));
1368    }
1369
1370    #[fuchsia::test(allow_stalls = false)]
1371    async fn start_and_serve_responds_to_generic_sme_requests() {
1372        let (fake_device, fake_device_state) = FakeDevice::new().await;
1373        let StartAndServeTestHarness {
1374            mut start_and_serve_fut,
1375            mut start_complete_receiver,
1376            generic_sme_proxy,
1377        } = start_and_serve_with_device(fake_device)
1378            .await
1379            .expect("Failed to initiate wlansoftmac setup.");
1380        assert_matches!(
1381            TestExecutor::poll_until_stalled(&mut start_complete_receiver).await,
1382            Poll::Ready(Ok(status)) => assert_eq!(zx::Status::OK.into_raw(), status)
1383        );
1384
1385        let (sme_telemetry_proxy, sme_telemetry_server) = fidl::endpoints::create_proxy();
1386        let (client_sme_proxy, client_sme_server) = fidl::endpoints::create_proxy();
1387
1388        let resp_fut = generic_sme_proxy.get_sme_telemetry(sme_telemetry_server);
1389        let mut resp_fut = pin!(resp_fut);
1390
1391        // First poll `get_sme_telemetry` to send a `GetSmeTelemetry` request to the SME server, and then
1392        // poll the SME server process it. Finally, expect `get_sme_telemetry` to complete with `Ok(())`.
1393        assert_matches!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Pending);
1394        assert_eq!(TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await, Poll::Pending);
1395        assert_matches!(
1396            TestExecutor::poll_until_stalled(&mut resp_fut).await,
1397            Poll::Ready(Ok(Ok(())))
1398        );
1399
1400        let resp_fut = generic_sme_proxy.get_client_sme(client_sme_server);
1401        let mut resp_fut = pin!(resp_fut);
1402
1403        // First poll `get_client_sme` to send a `GetClientSme` request to the SME server, and then poll the
1404        // SME server process it. Finally, expect `get_client_sme` to complete with `Ok(())`.
1405        assert_matches!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Pending);
1406        assert_eq!(TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await, Poll::Pending);
1407        resp_fut.await.expect("Generic SME proxy failed").expect("Client SME request failed");
1408
1409        let wlan_softmac_ifc_bridge_proxy =
1410            fake_device_state.lock().wlan_softmac_ifc_bridge_proxy.take().unwrap();
1411        let stop_response_fut = wlan_softmac_ifc_bridge_proxy.stop_bridged_driver();
1412        assert_matches!(futures::join!(start_and_serve_fut, stop_response_fut), (Ok(()), Ok(())));
1413
1414        // All SME proxies should shutdown.
1415        assert!(generic_sme_proxy.is_closed());
1416        assert!(sme_telemetry_proxy.is_closed());
1417        assert!(client_sme_proxy.is_closed());
1418    }
1419
1420    // Mocking a passive scan verifies the path through SME, MLME, and the FFI is functional. Other paths
1421    // are much more complex to mock and sufficiently covered by other testing. For example, queueing an
1422    // Ethernet frame requires mocking an association first, and the outcome of a reported Tx result cannot
1423    // be confirmed because the Minstrel is internal to MLME.
1424    #[fuchsia::test(allow_stalls = false)]
1425    async fn start_and_serve_responds_to_passive_scan_request() {
1426        let (fake_device, fake_device_state) = FakeDevice::new().await;
1427        let StartAndServeTestHarness {
1428            mut start_and_serve_fut,
1429            mut start_complete_receiver,
1430            generic_sme_proxy,
1431        } = start_and_serve_with_device(fake_device)
1432            .await
1433            .expect("Failed to initiate wlansoftmac setup.");
1434        assert_matches!(
1435            TestExecutor::poll_until_stalled(&mut start_complete_receiver).await,
1436            Poll::Ready(Ok(status)) => assert_eq!(zx::Status::OK.into_raw(), status)
1437        );
1438
1439        let (client_sme_proxy, client_sme_server) = fidl::endpoints::create_proxy();
1440
1441        let resp_fut = generic_sme_proxy.get_client_sme(client_sme_server);
1442        let mut resp_fut = pin!(resp_fut);
1443        assert_matches!(TestExecutor::poll_until_stalled(&mut resp_fut).await, Poll::Pending);
1444        assert_eq!(TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await, Poll::Pending);
1445        assert!(matches!(
1446            TestExecutor::poll_until_stalled(&mut resp_fut).await,
1447            Poll::Ready(Ok(Ok(())))
1448        ));
1449
1450        let scan_response_fut =
1451            client_sme_proxy.scan(&fidl_sme::ScanRequest::Passive(fidl_sme::PassiveScanRequest {
1452                channels: vec![],
1453            }));
1454        let mut scan_response_fut = pin!(scan_response_fut);
1455        assert!(matches!(
1456            TestExecutor::poll_until_stalled(&mut scan_response_fut).await,
1457            Poll::Pending
1458        ));
1459
1460        assert!(fake_device_state.lock().captured_passive_scan_request.is_none());
1461        assert_eq!(TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await, Poll::Pending);
1462        assert!(fake_device_state.lock().captured_passive_scan_request.is_some());
1463
1464        let wlan_softmac_ifc_bridge_proxy =
1465            fake_device_state.lock().wlan_softmac_ifc_bridge_proxy.take().unwrap();
1466        let notify_scan_complete_fut = wlan_softmac_ifc_bridge_proxy.notify_scan_complete(
1467            &fidl_softmac::WlanSoftmacIfcBaseNotifyScanCompleteRequest {
1468                status: Some(zx::Status::OK.into_raw()),
1469                scan_id: Some(0),
1470                ..Default::default()
1471            },
1472        );
1473        notify_scan_complete_fut.await.expect("Failed to receive NotifyScanComplete response");
1474        assert_eq!(TestExecutor::poll_until_stalled(&mut start_and_serve_fut).await, Poll::Pending);
1475        assert!(matches!(
1476            TestExecutor::poll_until_stalled(&mut scan_response_fut).await,
1477            Poll::Ready(Ok(_))
1478        ));
1479
1480        let stop_response_fut = wlan_softmac_ifc_bridge_proxy.stop_bridged_driver();
1481        assert_matches!(futures::join!(start_and_serve_fut, stop_response_fut), (Ok(()), Ok(())));
1482
1483        // All SME proxies should shutdown.
1484        assert!(generic_sme_proxy.is_closed());
1485        assert!(client_sme_proxy.is_closed());
1486    }
1487}