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