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