wlan_sme/serve/
mod.rs

1// Copyright 2018 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
5pub mod ap;
6pub mod client;
7
8use crate::{MlmeEventStream, MlmeStream, Station};
9use anyhow::format_err;
10use fidl::endpoints::ServerEnd;
11use fuchsia_sync::Mutex;
12use futures::channel::mpsc;
13use futures::future::FutureObj;
14use futures::prelude::*;
15use futures::select;
16use futures::stream::FuturesUnordered;
17use log::{error, info, warn};
18use std::convert::Infallible;
19use std::pin::Pin;
20use std::sync::Arc;
21use wlan_common::timer::{self, ScheduledEvent};
22use {
23    fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_mlme as fidl_mlme,
24    fidl_fuchsia_wlan_sme as fidl_sme,
25};
26
27pub type ClientSmeServer = mpsc::UnboundedSender<client::Endpoint>;
28pub type ApSmeServer = mpsc::UnboundedSender<ap::Endpoint>;
29
30#[derive(Clone)]
31pub enum SmeServer {
32    Client(ClientSmeServer),
33    Ap(ApSmeServer),
34}
35
36async fn serve_generic_sme(
37    mut generic_sme_request_stream: <fidl_sme::GenericSmeMarker as fidl::endpoints::ProtocolMarker>::RequestStream,
38    mlme_sink: crate::MlmeSink,
39    mut sme_server_sender: SmeServer,
40    mut telemetry_server_sender: Option<
41        mpsc::UnboundedSender<fidl::endpoints::ServerEnd<fidl_sme::TelemetryMarker>>,
42    >,
43) -> Result<(), anyhow::Error> {
44    loop {
45        match generic_sme_request_stream.next().await {
46            Some(Ok(req)) => {
47                let result = match req {
48                    fidl_sme::GenericSmeRequest::Query { responder } => {
49                        let (info_responder, info_receiver) = crate::responder::Responder::new();
50                        mlme_sink.send(crate::MlmeRequest::QueryDeviceInfo(info_responder));
51                        let info = info_receiver.await?;
52                        responder.send(&fidl_sme::GenericSmeQuery {
53                            role: info.role,
54                            sta_addr: info.sta_addr,
55                            factory_addr: info.factory_addr,
56                        })
57                    }
58                    fidl_sme::GenericSmeRequest::GetClientSme { sme_server, responder } => {
59                        let response =
60                            if let SmeServer::Client(server_sender) = &mut sme_server_sender {
61                                server_sender
62                                    .send(sme_server)
63                                    .await
64                                    .map_err(|_| zx::Status::PEER_CLOSED.into_raw())
65                            } else {
66                                Err(zx::Status::NOT_SUPPORTED.into_raw())
67                            };
68                        responder.send(response)
69                    }
70                    fidl_sme::GenericSmeRequest::GetApSme { sme_server, responder } => {
71                        let response = if let SmeServer::Ap(server_sender) = &mut sme_server_sender
72                        {
73                            server_sender
74                                .send(sme_server)
75                                .await
76                                .map_err(|_| zx::Status::PEER_CLOSED.into_raw())
77                        } else {
78                            Err(zx::Status::NOT_SUPPORTED.into_raw())
79                        };
80                        responder.send(response)
81                    }
82                    fidl_sme::GenericSmeRequest::GetSmeTelemetry {
83                        telemetry_server,
84                        responder,
85                    } => {
86                        let response = if let Some(server) = telemetry_server_sender.as_mut() {
87                            server
88                                .send(telemetry_server)
89                                .await
90                                .map_err(|_| zx::Status::PEER_CLOSED.into_raw())
91                        } else {
92                            warn!("Requested unsupported SME telemetry API");
93                            Err(zx::Status::NOT_SUPPORTED.into_raw())
94                        };
95                        responder.send(response)
96                    }
97                };
98                if let Err(e) = result {
99                    error!("Failed to respond to SME handle request: {}", e);
100                }
101            }
102            Some(Err(e)) => {
103                return Err(format_err!("Generic SME request stream failed: {}", e));
104            }
105            None => {
106                info!("Generic SME request stream terminated. Shutting down.");
107                return Ok(());
108            }
109        }
110    }
111}
112
113#[allow(
114    clippy::too_many_arguments,
115    clippy::type_complexity,
116    reason = "mass allow for https://fxbug.dev/381896734"
117)]
118pub fn create_sme(
119    cfg: crate::Config,
120    mlme_event_stream: MlmeEventStream,
121    device_info: &fidl_mlme::DeviceInfo,
122    security_support: fidl_common::SecuritySupport,
123    spectrum_management_support: fidl_common::SpectrumManagementSupport,
124    inspector: fuchsia_inspect::Inspector,
125    generic_sme_request_stream: <fidl_sme::GenericSmeMarker as fidl::endpoints::ProtocolMarker>::RequestStream,
126) -> Result<
127    (MlmeStream, Pin<Box<impl Future<Output = Result<(), anyhow::Error>> + use<>>>),
128    anyhow::Error,
129> {
130    let device_info = device_info.clone();
131    let inspect_node = inspector.root().create_child("usme");
132    let (server, mlme_req_sink, mlme_req_stream, telemetry_sender, sme_fut) = match device_info.role
133    {
134        fidl_common::WlanMacRole::Client => {
135            let (telemetry_endpoint_sender, telemetry_endpoint_receiver) = mpsc::unbounded();
136            let (sender, receiver) = mpsc::unbounded();
137            let (mlme_req_sink, mlme_req_stream, fut) = client::serve(
138                cfg,
139                device_info,
140                security_support,
141                spectrum_management_support,
142                mlme_event_stream,
143                receiver,
144                telemetry_endpoint_receiver,
145                inspector,
146                inspect_node,
147            );
148            (
149                SmeServer::Client(sender),
150                mlme_req_sink,
151                mlme_req_stream,
152                Some(telemetry_endpoint_sender),
153                FutureObj::new(Box::new(fut)),
154            )
155        }
156        fidl_common::WlanMacRole::Ap => {
157            let (sender, receiver) = mpsc::unbounded();
158            let (mlme_req_sink, mlme_req_stream, fut) =
159                ap::serve(device_info, spectrum_management_support, mlme_event_stream, receiver);
160            (
161                SmeServer::Ap(sender),
162                mlme_req_sink,
163                mlme_req_stream,
164                None,
165                FutureObj::new(Box::new(fut)),
166            )
167        }
168        fidl_common::WlanMacRole::Mesh => {
169            return Err(format_err!("Mesh mode is unsupported"));
170        }
171        fidl_common::WlanMacRoleUnknown!() => {
172            return Err(format_err!("Unknown WlanMacRole type: {:?}", device_info.role));
173        }
174    };
175    let generic_sme_fut =
176        serve_generic_sme(generic_sme_request_stream, mlme_req_sink, server, telemetry_sender);
177    let unified_fut = async move {
178        select! {
179            sme_fut = sme_fut.fuse() => sme_fut,
180            generic_sme_fut = generic_sme_fut.fuse() => generic_sme_fut,
181        }
182    };
183    Ok((mlme_req_stream, Box::pin(unified_fut)))
184}
185
186// The returned future successfully terminates when MLME closes the channel
187async fn serve_mlme_sme<STA, TS>(
188    mut event_stream: MlmeEventStream,
189    station: Arc<Mutex<STA>>,
190    time_stream: TS,
191) -> Result<(), anyhow::Error>
192where
193    STA: Station,
194    TS: Stream<Item = ScheduledEvent<<STA as crate::Station>::Event>> + Unpin,
195{
196    let mut timeout_stream = timer::make_async_timed_event_stream(time_stream).fuse();
197
198    loop {
199        select! {
200            // Fuse rationale: any `none`s in the MLME stream should result in
201            // bailing immediately, so we don't need to track if we've seen a
202            // `None` or not and can `fuse` directly in the `select` call.
203            mlme_event = event_stream.next() => match mlme_event {
204                Some(mlme_event) => station.lock().on_mlme_event(mlme_event),
205                None => return Ok(()),
206            },
207            timeout = timeout_stream.next() => match timeout {
208                Some(timed_event) => station.lock().on_timeout(timed_event),
209                None => return Err(format_err!("SME timer stream has ended unexpectedly")),
210            },
211        }
212    }
213}
214
215#[allow(clippy::extra_unused_lifetimes, reason = "mass allow for https://fxbug.dev/381896734")]
216async fn serve_fidl<
217    'a,
218    C: Clone,
219    T: fidl::endpoints::ProtocolMarker,
220    Fut: futures::Future<Output = Result<(), fidl::Error>>,
221>(
222    context: C,
223    new_fidl_clients: mpsc::UnboundedReceiver<ServerEnd<T>>,
224    event_handler: impl Fn(C, fidl::endpoints::Request<T>) -> Fut + Copy,
225) -> Result<Infallible, anyhow::Error> {
226    let mut new_fidl_clients = new_fidl_clients.fuse();
227    let mut fidl_clients = FuturesUnordered::new();
228    loop {
229        select! {
230            new_fidl_client = new_fidl_clients.next() => match new_fidl_client {
231                Some(end) => fidl_clients.push(serve_fidl_endpoint(context.clone(), end, event_handler)),
232                None => return Err(format_err!("New FIDL client stream unexpectedly ended")),
233            },
234            () = fidl_clients.select_next_some() => {},
235        }
236    }
237}
238
239#[allow(
240    clippy::extra_unused_lifetimes,
241    clippy::needless_return,
242    reason = "mass allow for https://fxbug.dev/381896734"
243)]
244async fn serve_fidl_endpoint<
245    'a,
246    C: Clone,
247    T: fidl::endpoints::ProtocolMarker,
248    Fut: futures::Future<Output = Result<(), fidl::Error>>,
249>(
250    context: C,
251    endpoint: ServerEnd<T>,
252    event_handler: impl Fn(C, fidl::endpoints::Request<T>) -> Fut + Copy,
253) {
254    let stream = endpoint.into_stream();
255    const MAX_CONCURRENT_REQUESTS: usize = 1000;
256    let handler = &event_handler;
257    let r = stream
258        .try_for_each_concurrent(MAX_CONCURRENT_REQUESTS, move |request| {
259            (*handler)(context.clone(), request)
260        })
261        .await;
262    if let Err(e) = r {
263        error!("Error serving FIDL: {}", e);
264        return;
265    }
266}
267
268#[cfg(test)]
269mod tests {
270    use super::*;
271    use crate::test_utils;
272    use assert_matches::assert_matches;
273    use fidl::endpoints::{create_proxy, create_proxy_and_stream};
274    use fuchsia_async as fasync;
275    use fuchsia_inspect::Inspector;
276    use futures::task::Poll;
277    use std::pin::pin;
278    use test_case::test_case;
279    use wlan_common::test_utils::fake_features::{
280        fake_security_support, fake_spectrum_management_support_empty,
281    };
282
283    #[test]
284    fn create_sme_fails_startup_role_unknown() {
285        let mut _exec = fasync::TestExecutor::new();
286        let inspector = Inspector::default();
287        let (_mlme_event_sender, mlme_event_stream) = mpsc::unbounded();
288        let (_generic_sme_proxy, generic_sme_stream) =
289            create_proxy_and_stream::<fidl_sme::GenericSmeMarker>();
290        let device_info = fidl_mlme::DeviceInfo {
291            role: fidl_common::WlanMacRole::unknown(),
292            ..test_utils::fake_device_info([0; 6].into())
293        };
294        let result = create_sme(
295            crate::Config::default(),
296            mlme_event_stream,
297            &device_info,
298            fake_security_support(),
299            fake_spectrum_management_support_empty(),
300            inspector,
301            generic_sme_stream,
302        );
303
304        assert!(result.is_err());
305    }
306
307    #[test]
308    fn sme_shutdown_on_generic_sme_closed() {
309        let mut exec = fasync::TestExecutor::new();
310        let (_mlme_event_sender, mlme_event_stream) = mpsc::unbounded();
311        let inspector = Inspector::default();
312        let (generic_sme_proxy, generic_sme_stream) =
313            create_proxy_and_stream::<fidl_sme::GenericSmeMarker>();
314        let (_mlme_req_stream, serve_fut) = create_sme(
315            crate::Config::default(),
316            mlme_event_stream,
317            &test_utils::fake_device_info([0; 6].into()),
318            fake_security_support(),
319            fake_spectrum_management_support_empty(),
320            inspector,
321            generic_sme_stream,
322        )
323        .unwrap();
324        let mut serve_fut = pin!(serve_fut);
325        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
326
327        // Also close secondary SME endpoint in the Generic SME.
328        drop(generic_sme_proxy);
329
330        // Verify SME future finished cleanly.
331        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Ready(Ok(())));
332    }
333
334    struct GenericSmeTestHelper {
335        proxy: fidl_sme::GenericSmeProxy,
336        mlme_req_stream: MlmeStream,
337
338        // These values must stay in scope or the SME will terminate, but they
339        // are not relevant to Generic SME tests.
340        _inspector: Inspector,
341        _mlme_event_sender: mpsc::UnboundedSender<crate::MlmeEvent>,
342        // Executor goes last to avoid test shutdown failures.
343        exec: fasync::TestExecutor,
344    }
345
346    #[allow(clippy::type_complexity, reason = "mass allow for https://fxbug.dev/381896734")]
347    fn start_generic_sme_test(
348        role: fidl_common::WlanMacRole,
349    ) -> Result<
350        (GenericSmeTestHelper, Pin<Box<impl Future<Output = Result<(), anyhow::Error>>>>),
351        anyhow::Error,
352    > {
353        let mut exec = fasync::TestExecutor::new();
354        let inspector = Inspector::default();
355        let (mlme_event_sender, mlme_event_stream) = mpsc::unbounded();
356        let (generic_sme_proxy, generic_sme_stream) =
357            create_proxy_and_stream::<fidl_sme::GenericSmeMarker>();
358        let device_info =
359            fidl_mlme::DeviceInfo { role, ..test_utils::fake_device_info([0; 6].into()) };
360        let (mlme_req_stream, serve_fut) = create_sme(
361            crate::Config::default(),
362            mlme_event_stream,
363            &device_info,
364            fake_security_support(),
365            fake_spectrum_management_support_empty(),
366            inspector.clone(),
367            generic_sme_stream,
368        )?;
369        let mut serve_fut = Box::pin(serve_fut);
370        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
371
372        Ok((
373            GenericSmeTestHelper {
374                proxy: generic_sme_proxy,
375                mlme_req_stream,
376                _inspector: inspector,
377                _mlme_event_sender: mlme_event_sender,
378                exec,
379            },
380            serve_fut,
381        ))
382    }
383
384    #[test]
385    fn generic_sme_get_client() {
386        let (mut helper, mut serve_fut) =
387            start_generic_sme_test(fidl_common::WlanMacRole::Client).unwrap();
388
389        let (client_proxy, client_server) = create_proxy();
390        let mut client_sme_fut = helper.proxy.get_client_sme(client_server);
391        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
392        assert_matches!(
393            helper.exec.run_until_stalled(&mut client_sme_fut),
394            Poll::Ready(Ok(Ok(())))
395        );
396
397        let mut status_fut = client_proxy.status();
398        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
399        assert_matches!(
400            helper.exec.run_until_stalled(&mut status_fut),
401            Poll::Ready(Ok(fidl_sme::ClientStatusResponse::Idle(_)))
402        );
403    }
404
405    #[test]
406    fn generic_sme_get_ap_from_client_fails() {
407        let (mut helper, mut serve_fut) =
408            start_generic_sme_test(fidl_common::WlanMacRole::Client).unwrap();
409
410        let (_ap_proxy, ap_server) = create_proxy();
411        let mut client_sme_fut = helper.proxy.get_ap_sme(ap_server);
412        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
413        assert_matches!(
414            helper.exec.run_until_stalled(&mut client_sme_fut),
415            Poll::Ready(Ok(Err(_)))
416        );
417    }
418
419    #[test]
420    fn generic_sme_get_ap() {
421        let (mut helper, mut serve_fut) =
422            start_generic_sme_test(fidl_common::WlanMacRole::Ap).unwrap();
423
424        let (ap_proxy, ap_server) = create_proxy();
425        let mut ap_sme_fut = helper.proxy.get_ap_sme(ap_server);
426        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
427        assert_matches!(helper.exec.run_until_stalled(&mut ap_sme_fut), Poll::Ready(Ok(Ok(()))));
428
429        let mut status_fut = ap_proxy.status();
430        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
431        assert_matches!(
432            helper.exec.run_until_stalled(&mut status_fut),
433            Poll::Ready(Ok(fidl_sme::ApStatusResponse { .. }))
434        );
435    }
436
437    #[test]
438    fn generic_sme_get_client_from_ap_fails() {
439        let (mut helper, mut serve_fut) =
440            start_generic_sme_test(fidl_common::WlanMacRole::Ap).unwrap();
441
442        let (_client_proxy, client_server) = create_proxy();
443        let mut client_sme_fut = helper.proxy.get_client_sme(client_server);
444        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
445        assert_matches!(
446            helper.exec.run_until_stalled(&mut client_sme_fut),
447            Poll::Ready(Ok(Err(_)))
448        );
449    }
450
451    fn get_telemetry_proxy(
452        helper: &mut GenericSmeTestHelper,
453        serve_fut: &mut Pin<Box<impl Future<Output = Result<(), anyhow::Error>>>>,
454    ) -> fidl_sme::TelemetryProxy {
455        let (proxy, server) = create_proxy();
456        let mut telemetry_fut = helper.proxy.get_sme_telemetry(server);
457        assert_matches!(helper.exec.run_until_stalled(serve_fut), Poll::Pending);
458        assert_matches!(helper.exec.run_until_stalled(&mut telemetry_fut), Poll::Ready(Ok(Ok(()))));
459        proxy
460    }
461
462    #[test]
463    fn generic_sme_query_telemetry_support_for_client() {
464        let (mut helper, mut serve_fut) =
465            start_generic_sme_test(fidl_common::WlanMacRole::Client).unwrap();
466        let telemetry_proxy = get_telemetry_proxy(&mut helper, &mut serve_fut);
467
468        // Forward request to MLME.
469        let mut support_fut = telemetry_proxy.query_telemetry_support();
470        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
471
472        // Mock response from MLME. Use a fake error code to make the response easily verifiable.
473        let support_req = assert_matches!(helper.exec.run_until_stalled(&mut helper.mlme_req_stream.next()), Poll::Ready(Some(req)) => req);
474        let support_responder = assert_matches!(support_req, crate::MlmeRequest::QueryTelemetrySupport(responder) => responder);
475        support_responder.respond(Err(1337));
476
477        // Verify that the response made it to us without alteration.
478        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
479        let support_result = assert_matches!(helper.exec.run_until_stalled(&mut support_fut), Poll::Ready(Ok(support_result)) => support_result);
480        assert_eq!(support_result, Err(1337));
481    }
482
483    #[test]
484    fn generic_sme_get_histogram_stats_for_client() {
485        let (mut helper, mut serve_fut) =
486            start_generic_sme_test(fidl_common::WlanMacRole::Client).unwrap();
487        let telemetry_proxy = get_telemetry_proxy(&mut helper, &mut serve_fut);
488
489        // Forward request to MLME.
490        let mut histogram_fut = telemetry_proxy.get_histogram_stats();
491        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
492
493        // Mock response from MLME. Use a fake error code to make the response easily verifiable.
494        let histogram_req = assert_matches!(helper.exec.run_until_stalled(&mut helper.mlme_req_stream.next()), Poll::Ready(Some(req)) => req);
495        let histogram_responder = assert_matches!(histogram_req, crate::MlmeRequest::GetIfaceHistogramStats(responder) => responder);
496        histogram_responder.respond(fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(1337));
497
498        // Verify that the response made it to us without alteration.
499        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
500        let histogram_result = assert_matches!(helper.exec.run_until_stalled(&mut histogram_fut), Poll::Ready(Ok(histogram_result)) => histogram_result);
501        assert_eq!(histogram_result, Err(1337));
502    }
503
504    #[test]
505    fn generic_sme_get_iface_stats_for_client() {
506        let (mut helper, mut serve_fut) =
507            start_generic_sme_test(fidl_common::WlanMacRole::Client).unwrap();
508        let telemetry_proxy = get_telemetry_proxy(&mut helper, &mut serve_fut);
509
510        // Forward request to MLME.
511        let mut counter_fut = telemetry_proxy.get_iface_stats();
512        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
513
514        // Mock response from MLME. Use a fake error code to make the response easily verifiable.
515        let counter_req = assert_matches!(helper.exec.run_until_stalled(&mut helper.mlme_req_stream.next()), Poll::Ready(Some(req)) => req);
516        let counter_responder =
517            assert_matches!(counter_req, crate::MlmeRequest::GetIfaceStats(responder) => responder);
518        counter_responder.respond(fidl_mlme::GetIfaceStatsResponse::ErrorStatus(1337));
519
520        // Verify that the response made it to us without alteration.
521        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
522        let counter_result = assert_matches!(helper.exec.run_until_stalled(&mut counter_fut), Poll::Ready(Ok(counter_result)) => counter_result);
523        assert_eq!(counter_result, Err(1337));
524    }
525
526    #[test]
527    fn generic_sme_get_signal_report_for_client() {
528        let (mut helper, mut serve_fut) =
529            start_generic_sme_test(fidl_common::WlanMacRole::Client).unwrap();
530        let telemetry_proxy = get_telemetry_proxy(&mut helper, &mut serve_fut);
531
532        // Forward request to MLME.
533        let mut report_fut = telemetry_proxy.get_signal_report();
534        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
535
536        // Mock response from MLME. Use a fake error code to make the response easily verifiable.
537        let report_req = assert_matches!(helper.exec.run_until_stalled(&mut helper.mlme_req_stream.next()), Poll::Ready(Some(req)) => req);
538        let report_responder = assert_matches!(report_req, crate::MlmeRequest::GetSignalReport(responder) => responder);
539        report_responder.respond(Err(1337));
540
541        // Verify that the response made it to us without alteration.
542        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
543        let report_result = assert_matches!(helper.exec.run_until_stalled(&mut report_fut), Poll::Ready(Ok(report_result)) => report_result);
544        assert_eq!(report_result, Err(1337));
545    }
546
547    #[test]
548    fn generic_sme_get_telemetry_for_ap_fails() {
549        let (mut helper, mut serve_fut) =
550            start_generic_sme_test(fidl_common::WlanMacRole::Ap).unwrap();
551
552        let (_telemetry_proxy, telemetry_server) = create_proxy();
553        let mut telemetry_fut = helper.proxy.get_sme_telemetry(telemetry_server);
554        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
555        assert_matches!(helper.exec.run_until_stalled(&mut telemetry_fut), Poll::Ready(Ok(Err(_))));
556    }
557
558    #[test_case(fidl_common::WlanMacRole::Client)]
559    #[test_case(fidl_common::WlanMacRole::Ap)]
560    fn generic_sme_query(mac_role: fidl_common::WlanMacRole) {
561        let (mut helper, mut serve_fut) = start_generic_sme_test(mac_role).unwrap();
562
563        let mut query_fut = helper.proxy.query();
564        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
565
566        let query_req = assert_matches!(helper.exec.run_until_stalled(&mut helper.mlme_req_stream.next()), Poll::Ready(Some(req)) => req);
567        let query_responder =
568            assert_matches!(query_req, crate::MlmeRequest::QueryDeviceInfo(responder) => responder);
569        query_responder.respond(fidl_mlme::DeviceInfo {
570            role: mac_role,
571            sta_addr: [2; 6],
572            factory_addr: [2; 6],
573            bands: vec![],
574            softmac_hardware_capability: 0,
575            qos_capable: false,
576        });
577
578        assert_matches!(helper.exec.run_until_stalled(&mut serve_fut), Poll::Pending);
579        let query_result = assert_matches!(helper.exec.run_until_stalled(&mut query_fut), Poll::Ready(Ok(result)) => result);
580        assert_eq!(query_result.role, mac_role);
581        assert_eq!(query_result.sta_addr, [2; 6]);
582    }
583}