wlancfg_lib/access_point/
mod.rs

1// Copyright 2021 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 crate::mode_management::iface_manager_api::IfaceManagerApi;
6use crate::util::listener;
7use anyhow::{Error, format_err};
8use fidl::epitaph::ChannelEpitaphExt;
9use futures::channel::mpsc;
10use futures::future::LocalBoxFuture;
11use futures::lock::{Mutex, MutexGuard};
12use futures::sink::SinkExt;
13use futures::stream::{FuturesUnordered, StreamExt, TryStreamExt};
14use futures::{FutureExt, TryFutureExt, select};
15use log::{error, info, warn};
16use std::sync::Arc;
17use wlan_common::RadioConfig;
18use wlan_common::channel::Cbw;
19use {fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_policy as fidl_policy};
20
21pub mod state_machine;
22pub mod types;
23
24// Wrapper around an AP interface allowing a watcher to set the underlying SME and the policy API
25// servicing routines to utilize the SME.
26#[derive(Clone)]
27pub struct AccessPoint {
28    iface_manager: Arc<Mutex<dyn IfaceManagerApi>>,
29    update_sender: listener::ApListenerMessageSender,
30    ap_provider_lock: Arc<Mutex<()>>,
31}
32
33// This number was chosen arbitrarily.
34const MAX_CONCURRENT_LISTENERS: usize = 1000;
35
36type ApRequests = fidl::endpoints::ServerEnd<fidl_policy::AccessPointControllerMarker>;
37
38impl AccessPoint {
39    /// Creates a new, empty AccessPoint. The returned AccessPoint effectively represents the state
40    /// in which no AP interface is available.
41    pub fn new(
42        iface_manager: Arc<Mutex<dyn IfaceManagerApi>>,
43        update_sender: listener::ApListenerMessageSender,
44        ap_provider_lock: Arc<Mutex<()>>,
45    ) -> Self {
46        Self { iface_manager, update_sender, ap_provider_lock }
47    }
48
49    fn send_listener_message(&self, message: listener::ApMessage) -> Result<(), Error> {
50        self.update_sender
51            .clone()
52            .unbounded_send(message)
53            .map_err(|e| format_err!("failed to send state update: {}", e))
54    }
55
56    /// Serves the AccessPointProvider protocol.  Only one caller is allowed to interact with an
57    /// AccessPointController.  This routine ensures that one active user has access at a time.
58    /// Additional requests are terminated immediately.
59    pub async fn serve_provider_requests(
60        self,
61        mut requests: fidl_policy::AccessPointProviderRequestStream,
62    ) {
63        let mut pending_response_queue =
64            FuturesUnordered::<LocalBoxFuture<'static, Result<Response, Error>>>::new();
65        let (internal_messages_sink, mut internal_messages_stream) = mpsc::channel(0);
66        let mut provider_reqs = FuturesUnordered::new();
67
68        loop {
69            select! {
70                // Progress controller requests.
71                _ = provider_reqs.select_next_some() => (),
72                // Process provider requests.
73                req = requests.select_next_some() => match req {
74                    Ok(req) => {
75                        // Reject the new provider request if another client is already using the
76                        // AccessPointProvider service.
77                        if let Some(ap_provider_guard) = self.ap_provider_lock.try_lock() {
78                            let mut ap = self.clone();
79                            let sink_copy = internal_messages_sink.clone();
80                            let fut = async move {
81                                ap.handle_provider_request(
82                                    sink_copy,
83                                    ap_provider_guard,
84                                    req
85                                ).await
86                            };
87                            provider_reqs.push(fut);
88                        } else if let Err(e) = reject_provider_request(req) {
89                            error!("error sending rejection epitaph: {:?}", e);
90                        }
91                    }
92                    Err(e) => error!("encountered and error while serving provider requests: {}", e)
93                },
94                complete => break,
95                msg = internal_messages_stream.select_next_some() => pending_response_queue.push(msg),
96                resp = pending_response_queue.select_next_some() => match resp {
97                    Ok(Response::StartResponse(result)) => {
98                        match result.result {
99                            Ok(()) => {}
100                            Err(_) => {
101                                let ssid_as_str = std::str::from_utf8(&result.config.id.ssid).unwrap_or("");
102                                error!("AP {} did not start", ssid_as_str);
103                            }
104                        };
105                    },
106                    Err(e) => error!("error while processing AP requests: {}", e)
107                }
108            }
109        }
110    }
111
112    /// Handles any incoming requests for the AccessPointProvider protocol.
113    async fn handle_provider_request(
114        &mut self,
115        internal_msg_sink: mpsc::Sender<LocalBoxFuture<'static, Result<Response, Error>>>,
116        ap_provider_guard: MutexGuard<'_, ()>,
117        req: fidl_policy::AccessPointProviderRequest,
118    ) -> Result<(), fidl::Error> {
119        match req {
120            fidl_policy::AccessPointProviderRequest::GetController {
121                requests, updates, ..
122            } => {
123                self.register_listener(updates.into_proxy());
124                self.handle_ap_requests(internal_msg_sink, ap_provider_guard, requests).await?;
125                Ok(())
126            }
127        }
128    }
129
130    /// Serves the AccessPointListener protocol.
131    pub async fn serve_listener_requests(
132        self,
133        requests: fidl_policy::AccessPointListenerRequestStream,
134    ) {
135        let serve_fut = requests
136            .try_for_each_concurrent(MAX_CONCURRENT_LISTENERS, |req| {
137                self.handle_listener_request(req)
138            })
139            .unwrap_or_else(|e| error!("error serving Client Listener API: {}", e));
140        serve_fut.await;
141    }
142
143    /// Handles all requests of the AccessPointController.
144    async fn handle_ap_requests(
145        &self,
146        mut internal_msg_sink: mpsc::Sender<LocalBoxFuture<'static, Result<Response, Error>>>,
147        ap_provider_guard: MutexGuard<'_, ()>,
148        requests: ApRequests,
149    ) -> Result<(), fidl::Error> {
150        let mut request_stream = requests.into_stream();
151        while let Some(request) = request_stream.try_next().await? {
152            log_ap_request(&request);
153            match request {
154                fidl_policy::AccessPointControllerRequest::StartAccessPoint {
155                    config,
156                    mode,
157                    band,
158                    responder,
159                } => {
160                    let ap_config = match derive_ap_config(&config, mode, band) {
161                        Ok(config) => config,
162                        Err(e) => {
163                            info!("StartAccessPoint could not derive AP config: {}", e);
164                            responder.send(fidl_policy::RequestStatus::RejectedNotSupported)?;
165                            continue;
166                        }
167                    };
168
169                    let mut iface_manager = self.iface_manager.lock().await;
170                    let receiver = match iface_manager.start_ap(ap_config.clone()).await {
171                        Ok(receiver) => receiver,
172                        Err(e) => {
173                            info!("failed to start AP: {}", e);
174                            responder.send(fidl_policy::RequestStatus::RejectedIncompatibleMode)?;
175                            continue;
176                        }
177                    };
178
179                    let fut = async move {
180                        receiver.await?;
181                        Ok(Response::StartResponse(StartParameters {
182                            config: ap_config,
183                            result: Ok(()),
184                        }))
185                    };
186                    if let Err(e) = internal_msg_sink.send(fut.boxed()).await {
187                        error!("Failed to send internal message: {:?}", e)
188                    }
189                    responder.send(fidl_policy::RequestStatus::Acknowledged)?;
190                }
191                fidl_policy::AccessPointControllerRequest::StopAccessPoint {
192                    config,
193                    responder,
194                } => {
195                    let ssid = match config.id {
196                        Some(id) => types::Ssid::from_bytes_unchecked(id.ssid),
197                        None => {
198                            warn!("received disconnect request with no SSID specified");
199                            responder.send(fidl_policy::RequestStatus::RejectedNotSupported)?;
200                            continue;
201                        }
202                    };
203                    let credential = match config.credential {
204                        Some(fidl_policy::Credential::Password(password)) => password,
205                        Some(fidl_policy::Credential::Psk(psk)) => psk,
206                        Some(fidl_policy::Credential::None(fidl_policy::Empty)) => vec![],
207                        // The compiler insists that the unknown credential variant be handled.
208                        Some(_) => vec![],
209                        None => {
210                            warn!("received disconnect request with no credential specified");
211                            responder.send(fidl_policy::RequestStatus::RejectedNotSupported)?;
212                            continue;
213                        }
214                    };
215
216                    let mut iface_manager = self.iface_manager.lock().await;
217                    match iface_manager.stop_ap(ssid, credential).await {
218                        Ok(()) => {
219                            responder.send(fidl_policy::RequestStatus::Acknowledged)?;
220                        }
221                        Err(e) => {
222                            error!("failed to stop AP: {}", e);
223                            responder.send(fidl_policy::RequestStatus::RejectedIncompatibleMode)?;
224                        }
225                    }
226                }
227                fidl_policy::AccessPointControllerRequest::StopAllAccessPoints { .. } => {
228                    let mut iface_manager = self.iface_manager.lock().await;
229                    match iface_manager.stop_all_aps().await {
230                        Ok(()) => {}
231                        Err(e) => {
232                            info!("could not cleanly stop all APs: {}", e);
233                        }
234                    }
235                }
236            }
237        }
238        drop(ap_provider_guard);
239        Ok(())
240    }
241
242    /// Registers a new update listener.
243    /// The client's current state will be send to the newly added listener immediately.
244    fn register_listener(&self, listener: fidl_policy::AccessPointStateUpdatesProxy) {
245        if let Err(e) = self.send_listener_message(listener::Message::NewListener(listener)) {
246            error!("failed to register new listener: {}", e);
247        }
248    }
249
250    /// Handle inbound requests to register an additional AccessPointStateUpdates listener.
251    async fn handle_listener_request(
252        &self,
253        req: fidl_policy::AccessPointListenerRequest,
254    ) -> Result<(), fidl::Error> {
255        match req {
256            fidl_policy::AccessPointListenerRequest::GetListener { updates, .. } => {
257                self.register_listener(updates.into_proxy());
258                Ok(())
259            }
260        }
261    }
262}
263
264fn reject_provider_request(
265    req: fidl_policy::AccessPointProviderRequest,
266) -> Result<(), fidl::Error> {
267    match req {
268        fidl_policy::AccessPointProviderRequest::GetController { requests, updates, .. } => {
269            info!("Rejecting new access point controller request because a controller is in use");
270            requests.into_channel().close_with_epitaph(zx::Status::ALREADY_BOUND)?;
271            updates.into_channel().close_with_epitaph(zx::Status::ALREADY_BOUND)?;
272            Ok(())
273        }
274    }
275}
276
277// The NetworkConfigs will be used in the future to aggregate state in crate::util::listener.
278struct StartParameters {
279    config: state_machine::ApConfig,
280    result: Result<(), Error>,
281}
282
283enum Response {
284    StartResponse(StartParameters),
285}
286
287fn derive_ap_config(
288    config: &fidl_policy::NetworkConfig,
289    mode: fidl_policy::ConnectivityMode,
290    band: fidl_policy::OperatingBand,
291) -> Result<state_machine::ApConfig, Error> {
292    let network_id = match config.id.as_ref() {
293        Some(id) => id.clone(),
294        None => return Err(format_err!("invalid NetworkIdentifier")),
295    };
296    let credential = match config.credential.as_ref() {
297        Some(credential) => match credential {
298            fidl_policy::Credential::None(fidl_policy::Empty) => b"".to_vec(),
299            fidl_policy::Credential::Password(bytes) => bytes.to_vec(),
300            fidl_policy::Credential::Psk(bytes) => bytes.to_vec(),
301            credential => {
302                return Err(format_err!("Unrecognized credential: {:?}", credential));
303            }
304        },
305        None => b"".to_vec(),
306    };
307
308    // TODO(https://fxbug.dev/42131511): Improve the channel selection algorithm.
309    let channel = match band {
310        fidl_policy::OperatingBand::Any => 11,
311        fidl_policy::OperatingBand::Only24Ghz => 11,
312        fidl_policy::OperatingBand::Only5Ghz => 36,
313    };
314
315    let radio_config = RadioConfig::new(fidl_common::WlanPhyType::Ht, Cbw::Cbw20, channel);
316
317    Ok(state_machine::ApConfig {
318        id: network_id.into(),
319        credential,
320        radio_config,
321        mode: types::ConnectivityMode::from(mode),
322        band: types::OperatingBand::from(band),
323    })
324}
325
326/// Logs incoming AccessPointController requests.
327fn log_ap_request(request: &fidl_policy::AccessPointControllerRequest) {
328    info!(
329        "Received policy AP request {}",
330        match request {
331            fidl_policy::AccessPointControllerRequest::StartAccessPoint { .. } => {
332                "StartAccessPoint"
333            }
334            fidl_policy::AccessPointControllerRequest::StopAccessPoint { .. } => {
335                "StopAccessPoint"
336            }
337            fidl_policy::AccessPointControllerRequest::StopAllAccessPoints { .. } => {
338                "StopAllAccessPoints"
339            }
340        }
341    );
342}
343
344#[cfg(test)]
345mod tests {
346    use super::*;
347    use crate::client::types as client_types;
348    use crate::mode_management::iface_manager_api::{ConnectAttemptRequest, SmeForScan};
349    use assert_matches::assert_matches;
350    use async_trait::async_trait;
351    use fidl::endpoints::{Proxy, create_proxy, create_request_stream};
352    use fuchsia_async as fasync;
353    use futures::channel::oneshot;
354    use futures::task::Poll;
355    use std::pin::pin;
356    use std::unimplemented;
357
358    #[derive(Debug)]
359    struct FakeIfaceManager {
360        pub start_response_succeeds: bool,
361        pub start_succeeds: bool,
362        pub stop_succeeds: bool,
363    }
364
365    impl FakeIfaceManager {
366        pub fn new() -> Self {
367            FakeIfaceManager {
368                start_response_succeeds: true,
369                start_succeeds: true,
370                stop_succeeds: true,
371            }
372        }
373    }
374
375    #[async_trait(?Send)]
376    impl IfaceManagerApi for FakeIfaceManager {
377        async fn disconnect(
378            &mut self,
379            _network_id: types::NetworkIdentifier,
380            _reason: client_types::DisconnectReason,
381        ) -> Result<(), Error> {
382            unimplemented!()
383        }
384
385        async fn connect(&mut self, _connect_req: ConnectAttemptRequest) -> Result<(), Error> {
386            unimplemented!()
387        }
388
389        async fn record_idle_client(&mut self, _iface_id: u16) -> Result<(), Error> {
390            unimplemented!()
391        }
392
393        async fn has_idle_client(&mut self) -> Result<bool, Error> {
394            unimplemented!()
395        }
396
397        async fn handle_added_iface(&mut self, _iface_id: u16) -> Result<(), Error> {
398            unimplemented!()
399        }
400
401        async fn handle_removed_iface(&mut self, _iface_id: u16) -> Result<(), Error> {
402            unimplemented!()
403        }
404
405        async fn get_sme_proxy_for_scan(&mut self) -> Result<SmeForScan, Error> {
406            unimplemented!()
407        }
408
409        async fn stop_client_connections(
410            &mut self,
411            _reason: client_types::DisconnectReason,
412        ) -> Result<(), Error> {
413            unimplemented!()
414        }
415
416        async fn start_client_connections(&mut self) -> Result<(), Error> {
417            unimplemented!()
418        }
419
420        async fn start_ap(
421            &mut self,
422            _config: state_machine::ApConfig,
423        ) -> Result<oneshot::Receiver<()>, Error> {
424            if self.start_succeeds {
425                let (sender, receiver) = oneshot::channel();
426
427                if self.start_response_succeeds {
428                    let _ = sender.send(());
429                }
430
431                Ok(receiver)
432            } else {
433                Err(format_err!("start_ap was configured to fail"))
434            }
435        }
436
437        async fn stop_ap(&mut self, _ssid: types::Ssid, _password: Vec<u8>) -> Result<(), Error> {
438            if self.stop_succeeds {
439                Ok(())
440            } else {
441                Err(format_err!("stop was instructed to fail"))
442            }
443        }
444
445        async fn stop_all_aps(&mut self) -> Result<(), Error> {
446            if self.stop_succeeds {
447                Ok(())
448            } else {
449                Err(format_err!("stop was instructed to fail"))
450            }
451        }
452
453        async fn set_country(
454            &mut self,
455            _country_code: Option<client_types::CountryCode>,
456        ) -> Result<(), Error> {
457            unimplemented!()
458        }
459    }
460
461    /// Requests a new AccessPointController from the given AccessPointProvider.
462    fn request_controller(
463        provider: &fidl_policy::AccessPointProviderProxy,
464    ) -> (fidl_policy::AccessPointControllerProxy, fidl_policy::AccessPointStateUpdatesRequestStream)
465    {
466        let (controller, requests) = create_proxy::<fidl_policy::AccessPointControllerMarker>();
467        let (update_sink, update_stream) =
468            create_request_stream::<fidl_policy::AccessPointStateUpdatesMarker>();
469        provider.get_controller(requests, update_sink).expect("error getting controller");
470        (controller, update_stream)
471    }
472
473    struct TestValues {
474        provider: fidl_policy::AccessPointProviderProxy,
475        requests: fidl_policy::AccessPointProviderRequestStream,
476        ap: AccessPoint,
477        iface_manager: Arc<Mutex<FakeIfaceManager>>,
478    }
479
480    /// Setup channels and proxies needed for the tests to use use the AP Provider and
481    /// AP Controller APIs in tests.
482    fn test_setup() -> TestValues {
483        let (provider, requests) = create_proxy::<fidl_policy::AccessPointProviderMarker>();
484        let requests = requests.into_stream();
485
486        let iface_manager = FakeIfaceManager::new();
487        let iface_manager = Arc::new(Mutex::new(iface_manager));
488        let (sender, _) = mpsc::unbounded();
489        let ap = AccessPoint::new(iface_manager.clone(), sender, Arc::new(Mutex::new(())));
490        TestValues { provider, requests, ap, iface_manager }
491    }
492
493    /// Tests the case where StartAccessPoint is called and there is a valid interface to service
494    /// the request and the request succeeds.
495    #[fuchsia::test]
496    fn test_start_access_point_with_iface_succeeds() {
497        let mut exec = fasync::TestExecutor::new();
498        let test_values = test_setup();
499        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
500        let mut serve_fut = pin!(serve_fut);
501
502        // No request has been sent yet. Future should be idle.
503        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
504
505        // Request a new controller.
506        let (controller, _) = request_controller(&test_values.provider);
507        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
508
509        // Issue StartAP request.
510        let network_id = fidl_policy::NetworkIdentifier {
511            ssid: b"test".to_vec(),
512            type_: fidl_policy::SecurityType::None,
513        };
514        let network_config = fidl_policy::NetworkConfig {
515            id: Some(network_id),
516            credential: None,
517            ..Default::default()
518        };
519        let connectivity_mode = fidl_policy::ConnectivityMode::LocalOnly;
520        let operating_band = fidl_policy::OperatingBand::Any;
521        let start_fut =
522            controller.start_access_point(&network_config, connectivity_mode, operating_band);
523        let mut start_fut = pin!(start_fut);
524
525        // Process start request and verify start response.
526        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
527        assert_matches!(
528            exec.run_until_stalled(&mut start_fut),
529            Poll::Ready(Ok(fidl_policy::RequestStatus::Acknowledged))
530        );
531    }
532
533    /// Tests the case where StartAccessPoint is called and there is a valid interface to service
534    /// the request, but the request fails.
535    #[fuchsia::test]
536    fn test_start_access_point_with_iface_fails() {
537        let mut exec = fasync::TestExecutor::new();
538        let test_values = test_setup();
539        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
540        let mut serve_fut = pin!(serve_fut);
541
542        // No request has been sent yet. Future should be idle.
543        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
544
545        // Request a new controller.
546        let (controller, _) = request_controller(&test_values.provider);
547        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
548
549        // Set the StartAp response.
550        {
551            let iface_manager_fut = test_values.iface_manager.lock();
552            let mut iface_manager_fut = pin!(iface_manager_fut);
553            let mut iface_manager = assert_matches!(
554                exec.run_until_stalled(&mut iface_manager_fut),
555                Poll::Ready(iface_manager) => { iface_manager }
556            );
557            iface_manager.start_response_succeeds = false;
558        }
559
560        // Issue StartAP request.
561        let network_id = fidl_policy::NetworkIdentifier {
562            ssid: b"test".to_vec(),
563            type_: fidl_policy::SecurityType::None,
564        };
565        let network_config = fidl_policy::NetworkConfig {
566            id: Some(network_id),
567            credential: None,
568            ..Default::default()
569        };
570        let connectivity_mode = fidl_policy::ConnectivityMode::LocalOnly;
571        let operating_band = fidl_policy::OperatingBand::Any;
572        let start_fut =
573            controller.start_access_point(&network_config, connectivity_mode, operating_band);
574        let mut start_fut = pin!(start_fut);
575
576        // Verify the start response is successful despite the AP's failure to start.
577        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
578        assert_matches!(
579            exec.run_until_stalled(&mut start_fut),
580            Poll::Ready(Ok(fidl_policy::RequestStatus::Acknowledged))
581        );
582    }
583
584    /// Tests the case where there are no interfaces available to handle a StartAccessPoint
585    /// request.
586    #[fuchsia::test]
587    fn test_start_access_point_no_iface() {
588        let mut exec = fasync::TestExecutor::new();
589        let test_values = test_setup();
590
591        // Set the IfaceManager to fail when asked to start an AP.
592        {
593            let iface_manager_fut = test_values.iface_manager.lock();
594            let mut iface_manager_fut = pin!(iface_manager_fut);
595            let mut iface_manager = assert_matches!(
596                exec.run_until_stalled(&mut iface_manager_fut),
597                Poll::Ready(iface_manager) => { iface_manager }
598            );
599            iface_manager.start_succeeds = false;
600        }
601
602        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
603        let mut serve_fut = pin!(serve_fut);
604
605        // No request has been sent yet. Future should be idle.
606        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
607
608        // Request a new controller.
609        let (controller, _) = request_controller(&test_values.provider);
610        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
611
612        // Issue StartAP request.
613        let connectivity_mode = fidl_policy::ConnectivityMode::LocalOnly;
614        let operating_band = fidl_policy::OperatingBand::Any;
615        let network_config =
616            fidl_policy::NetworkConfig { id: None, credential: None, ..Default::default() };
617        let start_fut =
618            controller.start_access_point(&network_config, connectivity_mode, operating_band);
619        let mut start_fut = pin!(start_fut);
620
621        // Process start request and verify start response.
622        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
623        assert_matches!(
624            exec.run_until_stalled(&mut start_fut),
625            Poll::Ready(Ok(fidl_policy::RequestStatus::RejectedNotSupported))
626        );
627    }
628
629    /// Tests the case where StopAccessPoint is called and there is a valid interface to handle the
630    /// request and the request succeeds.
631    #[fuchsia::test]
632    fn test_stop_access_point_with_iface_succeeds() {
633        let mut exec = fasync::TestExecutor::new();
634        let test_values = test_setup();
635        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
636        let mut serve_fut = pin!(serve_fut);
637
638        // No request has been sent yet. Future should be idle.
639        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
640
641        // Request a new controller.
642        let (controller, _) = request_controller(&test_values.provider);
643        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
644
645        // Issue StopAP request.
646        let network_id = fidl_policy::NetworkIdentifier {
647            ssid: b"test".to_vec(),
648            type_: fidl_policy::SecurityType::None,
649        };
650        let credential = fidl_policy::Credential::None(fidl_policy::Empty);
651        let network_config = fidl_policy::NetworkConfig {
652            id: Some(network_id),
653            credential: Some(credential),
654            ..Default::default()
655        };
656        let stop_fut = controller.stop_access_point(&network_config);
657        let mut stop_fut = pin!(stop_fut);
658
659        // Process stop request and verify stop response.
660        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
661        assert_matches!(
662            exec.run_until_stalled(&mut stop_fut),
663            Poll::Ready(Ok(fidl_policy::RequestStatus::Acknowledged))
664        );
665    }
666
667    /// Tests the case where StopAccessPoint is called and there is a valid interface to service
668    /// the request, but the request fails.
669    #[fuchsia::test]
670    fn test_stop_access_point_with_iface_fails() {
671        let mut exec = fasync::TestExecutor::new();
672        let test_values = test_setup();
673        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
674        let mut serve_fut = pin!(serve_fut);
675
676        // No request has been sent yet. Future should be idle.
677        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
678
679        // Request a new controller.
680        let (controller, _) = request_controller(&test_values.provider);
681        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
682
683        // Set the StopAp response.
684        {
685            let iface_manager_fut = test_values.iface_manager.lock();
686            let mut iface_manager_fut = pin!(iface_manager_fut);
687            let mut iface_manager = assert_matches!(
688                exec.run_until_stalled(&mut iface_manager_fut),
689                Poll::Ready(iface_manager) => { iface_manager }
690            );
691            iface_manager.stop_succeeds = false;
692        }
693
694        // Issue StopAP request.
695        let network_id = fidl_policy::NetworkIdentifier {
696            ssid: b"test".to_vec(),
697            type_: fidl_policy::SecurityType::None,
698        };
699        let credential = fidl_policy::Credential::None(fidl_policy::Empty);
700        let network_config = fidl_policy::NetworkConfig {
701            id: Some(network_id),
702            credential: Some(credential),
703            ..Default::default()
704        };
705        let stop_fut = controller.stop_access_point(&network_config);
706        let mut stop_fut = pin!(stop_fut);
707
708        // Process stop request and verify stop response.
709        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
710        assert_matches!(
711            exec.run_until_stalled(&mut stop_fut),
712            Poll::Ready(Ok(fidl_policy::RequestStatus::RejectedIncompatibleMode))
713        );
714    }
715
716    /// Tests the case where StopAccessPoints is called, there is a valid interface to handle the
717    /// request, and the request succeeds.
718    #[fuchsia::test]
719    fn test_stop_all_access_points_succeeds() {
720        let mut exec = fasync::TestExecutor::new();
721        let test_values = test_setup();
722        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
723        let mut serve_fut = pin!(serve_fut);
724
725        // No request has been sent yet. Future should be idle.
726        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
727
728        // Request a new controller.
729        let (controller, _) = request_controller(&test_values.provider);
730        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
731
732        // Issue StopAllAps request.
733        let stop_result = controller.stop_all_access_points();
734        assert!(stop_result.is_ok());
735
736        // Verify that the service is still running.
737        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
738    }
739
740    /// Tests the case where StopAccessPoints is called and there is a valid interface to handle
741    /// the request, but the request fails.
742    #[fuchsia::test]
743    fn test_stop_all_access_points_fails() {
744        let mut exec = fasync::TestExecutor::new();
745        let test_values = test_setup();
746        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
747        let mut serve_fut = pin!(serve_fut);
748
749        // No request has been sent yet. Future should be idle.
750        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
751
752        // Set the StopAp response.
753        {
754            let iface_manager_fut = test_values.iface_manager.lock();
755            let mut iface_manager_fut = pin!(iface_manager_fut);
756            let mut iface_manager = assert_matches!(
757                exec.run_until_stalled(&mut iface_manager_fut),
758                Poll::Ready(iface_manager) => { iface_manager }
759            );
760            iface_manager.stop_succeeds = false;
761        }
762
763        // Request a new controller.
764        let (controller, _) = request_controller(&test_values.provider);
765        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
766
767        // Issue StopAllAps request.
768        let stop_result = controller.stop_all_access_points();
769        assert!(stop_result.is_ok());
770
771        // Verify that the service is still running despite the call to stop failing.
772        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
773    }
774
775    #[fuchsia::test]
776    fn test_multiple_controllers() {
777        let mut exec = fasync::TestExecutor::new();
778        let test_values = test_setup();
779        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
780        let mut serve_fut = pin!(serve_fut);
781
782        // No request has been sent yet. Future should be idle.
783        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
784
785        // Request a controller.
786        let (_controller1, _) = request_controller(&test_values.provider);
787        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
788
789        // Request another controller.
790        let (controller2, _) = request_controller(&test_values.provider);
791        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
792
793        // Verify Epitaph was received.
794        let mut controller2_event_stream = controller2.take_event_stream();
795        let controller2_event_fut = controller2_event_stream.next();
796        let mut controller2_event_fut = pin!(controller2_event_fut);
797        assert_matches!(
798            exec.run_until_stalled(&mut controller2_event_fut),
799            Poll::Ready(Some(Err(fidl::Error::ClientChannelClosed {
800                status: zx::Status::ALREADY_BOUND,
801                ..
802            })))
803        );
804        assert!(controller2.is_closed());
805    }
806
807    #[fuchsia::test]
808    fn test_multiple_api_clients() {
809        let mut exec = fasync::TestExecutor::new();
810        let test_values = test_setup();
811        let serve_fut = test_values.ap.clone().serve_provider_requests(test_values.requests);
812        let mut serve_fut = pin!(serve_fut);
813
814        // No request has been sent yet. Future should be idle.
815        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
816
817        // Request a controller.
818        let (controller1, _) = request_controller(&test_values.provider);
819        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
820
821        // Create another request stream and begin serving it.  This is equivalent to the behavior
822        // that occurs when a second client connects to the AccessPointProvider service.
823        let (provider, requests) = create_proxy::<fidl_policy::AccessPointProviderMarker>();
824        let requests = requests.into_stream();
825        let second_serve_fut = test_values.ap.serve_provider_requests(requests);
826        let mut second_serve_fut = pin!(second_serve_fut);
827
828        let (controller2, _) = request_controller(&provider);
829        assert_matches!(exec.run_until_stalled(&mut second_serve_fut), Poll::Pending);
830
831        // Verify Epitaph was received.
832        let mut controller2_event_stream = controller2.take_event_stream();
833        let controller2_event_fut = controller2_event_stream.next();
834        let mut controller2_event_fut = pin!(controller2_event_fut);
835        assert_matches!(
836            exec.run_until_stalled(&mut controller2_event_fut),
837            Poll::Ready(Some(Err(fidl::Error::ClientChannelClosed {
838                status: zx::Status::ALREADY_BOUND,
839                ..
840            })))
841        );
842        assert!(controller2.is_closed());
843
844        // Drop the initial client controller and make sure the second service instance can get a
845        // client controller and make a request.
846        drop(controller1);
847        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
848
849        let (controller2, _) = request_controller(&provider);
850        assert_matches!(exec.run_until_stalled(&mut second_serve_fut), Poll::Pending);
851
852        // Issue StartAP request to make sure the new controller works.
853        let network_id = fidl_policy::NetworkIdentifier {
854            ssid: b"test".to_vec(),
855            type_: fidl_policy::SecurityType::None,
856        };
857        let network_config = fidl_policy::NetworkConfig {
858            id: Some(network_id),
859            credential: None,
860            ..Default::default()
861        };
862        let connectivity_mode = fidl_policy::ConnectivityMode::LocalOnly;
863        let operating_band = fidl_policy::OperatingBand::Any;
864        let start_fut =
865            controller2.start_access_point(&network_config, connectivity_mode, operating_band);
866        let mut start_fut = pin!(start_fut);
867
868        // Process start request and verify start response.
869        assert_matches!(exec.run_until_stalled(&mut second_serve_fut), Poll::Pending);
870        assert_matches!(
871            exec.run_until_stalled(&mut start_fut),
872            Poll::Ready(Ok(fidl_policy::RequestStatus::Acknowledged))
873        );
874    }
875}