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