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