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