Skip to main content

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 fidl_fuchsia_wlan_policy as fidl_policy;
10use futures::channel::mpsc;
11use futures::future::LocalBoxFuture;
12use futures::lock::{Mutex, MutexGuard};
13use futures::sink::SinkExt;
14use futures::stream::{FuturesUnordered, StreamExt, TryStreamExt};
15use futures::{FutureExt, TryFutureExt, select};
16use log::{error, info, warn};
17use std::sync::Arc;
18use wlan_common::RadioConfig;
19use wlan_common::channel::Cbw;
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, wlan_band) = match band {
310        fidl_policy::OperatingBand::Any => (11, fidl_fuchsia_wlan_ieee80211::WlanBand::TwoGhz),
311        fidl_policy::OperatingBand::Only24Ghz => {
312            (11, fidl_fuchsia_wlan_ieee80211::WlanBand::TwoGhz)
313        }
314        fidl_policy::OperatingBand::Only5Ghz => {
315            (36, fidl_fuchsia_wlan_ieee80211::WlanBand::FiveGhz)
316        }
317    };
318
319    let radio_config = RadioConfig::new(
320        fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht,
321        Cbw::Cbw20,
322        channel,
323        wlan_band,
324    );
325
326    Ok(state_machine::ApConfig {
327        id: network_id.into(),
328        credential,
329        radio_config,
330        mode: types::ConnectivityMode::from(mode),
331        band: types::OperatingBand::from(band),
332    })
333}
334
335/// Logs incoming AccessPointController requests.
336fn log_ap_request(request: &fidl_policy::AccessPointControllerRequest) {
337    info!(
338        "Received policy AP request {}",
339        match request {
340            fidl_policy::AccessPointControllerRequest::StartAccessPoint { .. } => {
341                "StartAccessPoint"
342            }
343            fidl_policy::AccessPointControllerRequest::StopAccessPoint { .. } => {
344                "StopAccessPoint"
345            }
346            fidl_policy::AccessPointControllerRequest::StopAllAccessPoints { .. } => {
347                "StopAllAccessPoints"
348            }
349        }
350    );
351}
352
353#[cfg(test)]
354mod tests {
355    use super::*;
356    use crate::client::types as client_types;
357    use crate::mode_management::iface_manager_api::{ConnectAttemptRequest, SmeForScan};
358    use assert_matches::assert_matches;
359    use async_trait::async_trait;
360    use fidl::endpoints::{Proxy, create_proxy, create_request_stream};
361    use fuchsia_async as fasync;
362    use futures::channel::oneshot;
363    use futures::task::Poll;
364    use std::pin::pin;
365    use std::unimplemented;
366
367    #[derive(Debug)]
368    struct FakeIfaceManager {
369        pub start_response_succeeds: bool,
370        pub start_succeeds: bool,
371        pub stop_succeeds: bool,
372    }
373
374    impl FakeIfaceManager {
375        pub fn new() -> Self {
376            FakeIfaceManager {
377                start_response_succeeds: true,
378                start_succeeds: true,
379                stop_succeeds: true,
380            }
381        }
382    }
383
384    #[async_trait(?Send)]
385    impl IfaceManagerApi for FakeIfaceManager {
386        async fn disconnect(
387            &mut self,
388            _network_id: types::NetworkIdentifier,
389            _reason: client_types::DisconnectReason,
390        ) -> Result<(), Error> {
391            unimplemented!()
392        }
393
394        async fn connect(&mut self, _connect_req: ConnectAttemptRequest) -> Result<(), Error> {
395            unimplemented!()
396        }
397
398        async fn record_idle_client(&mut self, _iface_id: u16) -> Result<(), Error> {
399            unimplemented!()
400        }
401
402        async fn has_idle_client(&mut self) -> Result<bool, Error> {
403            unimplemented!()
404        }
405
406        async fn handle_added_iface(&mut self, _iface_id: u16) -> Result<(), Error> {
407            unimplemented!()
408        }
409
410        async fn handle_removed_iface(&mut self, _iface_id: u16) -> Result<(), Error> {
411            unimplemented!()
412        }
413
414        async fn get_sme_proxy_for_scan(&mut self) -> Result<SmeForScan, Error> {
415            unimplemented!()
416        }
417
418        async fn stop_client_connections(
419            &mut self,
420            _reason: client_types::DisconnectReason,
421        ) -> Result<(), Error> {
422            unimplemented!()
423        }
424
425        async fn start_client_connections(&mut self) -> Result<(), Error> {
426            unimplemented!()
427        }
428
429        async fn start_ap(
430            &mut self,
431            _config: state_machine::ApConfig,
432        ) -> Result<oneshot::Receiver<()>, Error> {
433            if self.start_succeeds {
434                let (sender, receiver) = oneshot::channel();
435
436                if self.start_response_succeeds {
437                    let _ = sender.send(());
438                }
439
440                Ok(receiver)
441            } else {
442                Err(format_err!("start_ap was configured to fail"))
443            }
444        }
445
446        async fn stop_ap(&mut self, _ssid: types::Ssid, _password: Vec<u8>) -> Result<(), Error> {
447            if self.stop_succeeds {
448                Ok(())
449            } else {
450                Err(format_err!("stop was instructed to fail"))
451            }
452        }
453
454        async fn stop_all_aps(&mut self) -> Result<(), Error> {
455            if self.stop_succeeds {
456                Ok(())
457            } else {
458                Err(format_err!("stop was instructed to fail"))
459            }
460        }
461
462        async fn set_country(
463            &mut self,
464            _country_code: Option<client_types::CountryCode>,
465        ) -> Result<(), Error> {
466            unimplemented!()
467        }
468    }
469
470    /// Requests a new AccessPointController from the given AccessPointProvider.
471    fn request_controller(
472        provider: &fidl_policy::AccessPointProviderProxy,
473    ) -> (fidl_policy::AccessPointControllerProxy, fidl_policy::AccessPointStateUpdatesRequestStream)
474    {
475        let (controller, requests) = create_proxy::<fidl_policy::AccessPointControllerMarker>();
476        let (update_sink, update_stream) =
477            create_request_stream::<fidl_policy::AccessPointStateUpdatesMarker>();
478        provider.get_controller(requests, update_sink).expect("error getting controller");
479        (controller, update_stream)
480    }
481
482    struct TestValues {
483        provider: fidl_policy::AccessPointProviderProxy,
484        requests: fidl_policy::AccessPointProviderRequestStream,
485        ap: AccessPoint,
486        iface_manager: Arc<Mutex<FakeIfaceManager>>,
487    }
488
489    /// Setup channels and proxies needed for the tests to use use the AP Provider and
490    /// AP Controller APIs in tests.
491    fn test_setup() -> TestValues {
492        let (provider, requests) = create_proxy::<fidl_policy::AccessPointProviderMarker>();
493        let requests = requests.into_stream();
494
495        let iface_manager = FakeIfaceManager::new();
496        let iface_manager = Arc::new(Mutex::new(iface_manager));
497        let (sender, _) = mpsc::unbounded();
498        let ap = AccessPoint::new(iface_manager.clone(), sender, Arc::new(Mutex::new(())));
499        TestValues { provider, requests, ap, iface_manager }
500    }
501
502    /// Tests the case where StartAccessPoint is called and there is a valid interface to service
503    /// the request and the request succeeds.
504    #[fuchsia::test]
505    fn test_start_access_point_with_iface_succeeds() {
506        let mut exec = fasync::TestExecutor::new();
507        let test_values = test_setup();
508        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
509        let mut serve_fut = pin!(serve_fut);
510
511        // No request has been sent yet. Future should be idle.
512        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
513
514        // Request a new controller.
515        let (controller, _) = request_controller(&test_values.provider);
516        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
517
518        // Issue StartAP request.
519        let network_id = fidl_policy::NetworkIdentifier {
520            ssid: b"test".to_vec(),
521            type_: fidl_policy::SecurityType::None,
522        };
523        let network_config = fidl_policy::NetworkConfig {
524            id: Some(network_id),
525            credential: None,
526            ..Default::default()
527        };
528        let connectivity_mode = fidl_policy::ConnectivityMode::LocalOnly;
529        let operating_band = fidl_policy::OperatingBand::Any;
530        let start_fut =
531            controller.start_access_point(&network_config, connectivity_mode, operating_band);
532        let mut start_fut = pin!(start_fut);
533
534        // Process start request and verify start response.
535        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
536        assert_matches!(
537            exec.run_until_stalled(&mut start_fut),
538            Poll::Ready(Ok(fidl_policy::RequestStatus::Acknowledged))
539        );
540    }
541
542    /// Tests the case where StartAccessPoint is called and there is a valid interface to service
543    /// the request, but the request fails.
544    #[fuchsia::test]
545    fn test_start_access_point_with_iface_fails() {
546        let mut exec = fasync::TestExecutor::new();
547        let test_values = test_setup();
548        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
549        let mut serve_fut = pin!(serve_fut);
550
551        // No request has been sent yet. Future should be idle.
552        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
553
554        // Request a new controller.
555        let (controller, _) = request_controller(&test_values.provider);
556        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
557
558        // Set the StartAp response.
559        {
560            let iface_manager_fut = test_values.iface_manager.lock();
561            let mut iface_manager_fut = pin!(iface_manager_fut);
562            let mut iface_manager = assert_matches!(
563                exec.run_until_stalled(&mut iface_manager_fut),
564                Poll::Ready(iface_manager) => { iface_manager }
565            );
566            iface_manager.start_response_succeeds = false;
567        }
568
569        // Issue StartAP request.
570        let network_id = fidl_policy::NetworkIdentifier {
571            ssid: b"test".to_vec(),
572            type_: fidl_policy::SecurityType::None,
573        };
574        let network_config = fidl_policy::NetworkConfig {
575            id: Some(network_id),
576            credential: None,
577            ..Default::default()
578        };
579        let connectivity_mode = fidl_policy::ConnectivityMode::LocalOnly;
580        let operating_band = fidl_policy::OperatingBand::Any;
581        let start_fut =
582            controller.start_access_point(&network_config, connectivity_mode, operating_band);
583        let mut start_fut = pin!(start_fut);
584
585        // Verify the start response is successful despite the AP's failure to start.
586        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
587        assert_matches!(
588            exec.run_until_stalled(&mut start_fut),
589            Poll::Ready(Ok(fidl_policy::RequestStatus::Acknowledged))
590        );
591    }
592
593    /// Tests the case where there are no interfaces available to handle a StartAccessPoint
594    /// request.
595    #[fuchsia::test]
596    fn test_start_access_point_no_iface() {
597        let mut exec = fasync::TestExecutor::new();
598        let test_values = test_setup();
599
600        // Set the IfaceManager to fail when asked to start an AP.
601        {
602            let iface_manager_fut = test_values.iface_manager.lock();
603            let mut iface_manager_fut = pin!(iface_manager_fut);
604            let mut iface_manager = assert_matches!(
605                exec.run_until_stalled(&mut iface_manager_fut),
606                Poll::Ready(iface_manager) => { iface_manager }
607            );
608            iface_manager.start_succeeds = false;
609        }
610
611        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
612        let mut serve_fut = pin!(serve_fut);
613
614        // No request has been sent yet. Future should be idle.
615        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
616
617        // Request a new controller.
618        let (controller, _) = request_controller(&test_values.provider);
619        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
620
621        // Issue StartAP request.
622        let connectivity_mode = fidl_policy::ConnectivityMode::LocalOnly;
623        let operating_band = fidl_policy::OperatingBand::Any;
624        let network_config =
625            fidl_policy::NetworkConfig { id: None, credential: None, ..Default::default() };
626        let start_fut =
627            controller.start_access_point(&network_config, connectivity_mode, operating_band);
628        let mut start_fut = pin!(start_fut);
629
630        // Process start request and verify start response.
631        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
632        assert_matches!(
633            exec.run_until_stalled(&mut start_fut),
634            Poll::Ready(Ok(fidl_policy::RequestStatus::RejectedNotSupported))
635        );
636    }
637
638    /// Tests the case where StopAccessPoint is called and there is a valid interface to handle the
639    /// request and the request succeeds.
640    #[fuchsia::test]
641    fn test_stop_access_point_with_iface_succeeds() {
642        let mut exec = fasync::TestExecutor::new();
643        let test_values = test_setup();
644        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
645        let mut serve_fut = pin!(serve_fut);
646
647        // No request has been sent yet. Future should be idle.
648        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
649
650        // Request a new controller.
651        let (controller, _) = request_controller(&test_values.provider);
652        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
653
654        // Issue StopAP request.
655        let network_id = fidl_policy::NetworkIdentifier {
656            ssid: b"test".to_vec(),
657            type_: fidl_policy::SecurityType::None,
658        };
659        let credential = fidl_policy::Credential::None(fidl_policy::Empty);
660        let network_config = fidl_policy::NetworkConfig {
661            id: Some(network_id),
662            credential: Some(credential),
663            ..Default::default()
664        };
665        let stop_fut = controller.stop_access_point(&network_config);
666        let mut stop_fut = pin!(stop_fut);
667
668        // Process stop request and verify stop response.
669        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
670        assert_matches!(
671            exec.run_until_stalled(&mut stop_fut),
672            Poll::Ready(Ok(fidl_policy::RequestStatus::Acknowledged))
673        );
674    }
675
676    /// Tests the case where StopAccessPoint is called and there is a valid interface to service
677    /// the request, but the request fails.
678    #[fuchsia::test]
679    fn test_stop_access_point_with_iface_fails() {
680        let mut exec = fasync::TestExecutor::new();
681        let test_values = test_setup();
682        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
683        let mut serve_fut = pin!(serve_fut);
684
685        // No request has been sent yet. Future should be idle.
686        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
687
688        // Request a new controller.
689        let (controller, _) = request_controller(&test_values.provider);
690        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
691
692        // Set the StopAp response.
693        {
694            let iface_manager_fut = test_values.iface_manager.lock();
695            let mut iface_manager_fut = pin!(iface_manager_fut);
696            let mut iface_manager = assert_matches!(
697                exec.run_until_stalled(&mut iface_manager_fut),
698                Poll::Ready(iface_manager) => { iface_manager }
699            );
700            iface_manager.stop_succeeds = false;
701        }
702
703        // Issue StopAP request.
704        let network_id = fidl_policy::NetworkIdentifier {
705            ssid: b"test".to_vec(),
706            type_: fidl_policy::SecurityType::None,
707        };
708        let credential = fidl_policy::Credential::None(fidl_policy::Empty);
709        let network_config = fidl_policy::NetworkConfig {
710            id: Some(network_id),
711            credential: Some(credential),
712            ..Default::default()
713        };
714        let stop_fut = controller.stop_access_point(&network_config);
715        let mut stop_fut = pin!(stop_fut);
716
717        // Process stop request and verify stop response.
718        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
719        assert_matches!(
720            exec.run_until_stalled(&mut stop_fut),
721            Poll::Ready(Ok(fidl_policy::RequestStatus::RejectedIncompatibleMode))
722        );
723    }
724
725    /// Tests the case where StopAccessPoints is called, there is a valid interface to handle the
726    /// request, and the request succeeds.
727    #[fuchsia::test]
728    fn test_stop_all_access_points_succeeds() {
729        let mut exec = fasync::TestExecutor::new();
730        let test_values = test_setup();
731        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
732        let mut serve_fut = pin!(serve_fut);
733
734        // No request has been sent yet. Future should be idle.
735        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
736
737        // Request a new controller.
738        let (controller, _) = request_controller(&test_values.provider);
739        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
740
741        // Issue StopAllAps request.
742        let stop_result = controller.stop_all_access_points();
743        assert!(stop_result.is_ok());
744
745        // Verify that the service is still running.
746        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
747    }
748
749    /// Tests the case where StopAccessPoints is called and there is a valid interface to handle
750    /// the request, but the request fails.
751    #[fuchsia::test]
752    fn test_stop_all_access_points_fails() {
753        let mut exec = fasync::TestExecutor::new();
754        let test_values = test_setup();
755        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
756        let mut serve_fut = pin!(serve_fut);
757
758        // No request has been sent yet. Future should be idle.
759        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
760
761        // Set the StopAp response.
762        {
763            let iface_manager_fut = test_values.iface_manager.lock();
764            let mut iface_manager_fut = pin!(iface_manager_fut);
765            let mut iface_manager = assert_matches!(
766                exec.run_until_stalled(&mut iface_manager_fut),
767                Poll::Ready(iface_manager) => { iface_manager }
768            );
769            iface_manager.stop_succeeds = false;
770        }
771
772        // Request a new controller.
773        let (controller, _) = request_controller(&test_values.provider);
774        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
775
776        // Issue StopAllAps request.
777        let stop_result = controller.stop_all_access_points();
778        assert!(stop_result.is_ok());
779
780        // Verify that the service is still running despite the call to stop failing.
781        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
782    }
783
784    #[fuchsia::test]
785    fn test_multiple_controllers() {
786        let mut exec = fasync::TestExecutor::new();
787        let test_values = test_setup();
788        let serve_fut = test_values.ap.serve_provider_requests(test_values.requests);
789        let mut serve_fut = pin!(serve_fut);
790
791        // No request has been sent yet. Future should be idle.
792        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
793
794        // Request a controller.
795        let (_controller1, _) = request_controller(&test_values.provider);
796        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
797
798        // Request another controller.
799        let (controller2, _) = request_controller(&test_values.provider);
800        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
801
802        // Verify Epitaph was received.
803        let mut controller2_event_stream = controller2.take_event_stream();
804        let controller2_event_fut = controller2_event_stream.next();
805        let mut controller2_event_fut = pin!(controller2_event_fut);
806        assert_matches!(
807            exec.run_until_stalled(&mut controller2_event_fut),
808            Poll::Ready(Some(Err(fidl::Error::ClientChannelClosed {
809                status: zx::Status::ALREADY_BOUND,
810                ..
811            })))
812        );
813        assert!(controller2.is_closed());
814    }
815
816    #[fuchsia::test]
817    fn test_multiple_api_clients() {
818        let mut exec = fasync::TestExecutor::new();
819        let test_values = test_setup();
820        let serve_fut = test_values.ap.clone().serve_provider_requests(test_values.requests);
821        let mut serve_fut = pin!(serve_fut);
822
823        // No request has been sent yet. Future should be idle.
824        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
825
826        // Request a controller.
827        let (controller1, _) = request_controller(&test_values.provider);
828        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
829
830        // Create another request stream and begin serving it.  This is equivalent to the behavior
831        // that occurs when a second client connects to the AccessPointProvider service.
832        let (provider, requests) = create_proxy::<fidl_policy::AccessPointProviderMarker>();
833        let requests = requests.into_stream();
834        let second_serve_fut = test_values.ap.serve_provider_requests(requests);
835        let mut second_serve_fut = pin!(second_serve_fut);
836
837        let (controller2, _) = request_controller(&provider);
838        assert_matches!(exec.run_until_stalled(&mut second_serve_fut), Poll::Pending);
839
840        // Verify Epitaph was received.
841        let mut controller2_event_stream = controller2.take_event_stream();
842        let controller2_event_fut = controller2_event_stream.next();
843        let mut controller2_event_fut = pin!(controller2_event_fut);
844        assert_matches!(
845            exec.run_until_stalled(&mut controller2_event_fut),
846            Poll::Ready(Some(Err(fidl::Error::ClientChannelClosed {
847                status: zx::Status::ALREADY_BOUND,
848                ..
849            })))
850        );
851        assert!(controller2.is_closed());
852
853        // Drop the initial client controller and make sure the second service instance can get a
854        // client controller and make a request.
855        drop(controller1);
856        assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
857
858        let (controller2, _) = request_controller(&provider);
859        assert_matches!(exec.run_until_stalled(&mut second_serve_fut), Poll::Pending);
860
861        // Issue StartAP request to make sure the new controller works.
862        let network_id = fidl_policy::NetworkIdentifier {
863            ssid: b"test".to_vec(),
864            type_: fidl_policy::SecurityType::None,
865        };
866        let network_config = fidl_policy::NetworkConfig {
867            id: Some(network_id),
868            credential: None,
869            ..Default::default()
870        };
871        let connectivity_mode = fidl_policy::ConnectivityMode::LocalOnly;
872        let operating_band = fidl_policy::OperatingBand::Any;
873        let start_fut =
874            controller2.start_access_point(&network_config, connectivity_mode, operating_band);
875        let mut start_fut = pin!(start_fut);
876
877        // Process start request and verify start response.
878        assert_matches!(exec.run_until_stalled(&mut second_serve_fut), Poll::Pending);
879        assert_matches!(
880            exec.run_until_stalled(&mut start_fut),
881            Poll::Ready(Ok(fidl_policy::RequestStatus::Acknowledged))
882        );
883    }
884}