1use 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#[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
34const MAX_CONCURRENT_LISTENERS: usize = 1000;
36
37type ApRequests = fidl::endpoints::ServerEnd<fidl_policy::AccessPointControllerMarker>;
38
39impl AccessPoint {
40 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 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 _ = provider_reqs.select_next_some() => (),
74 req = requests.select_next_some() => match req {
76 Ok(req) => {
77 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 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 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 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 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 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 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
283struct 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 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
341fn 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 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 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 #[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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
526
527 let (controller, _) = request_controller(&test_values.provider);
529 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
530
531 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 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 #[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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
566
567 let (controller, _) = request_controller(&test_values.provider);
569 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
570
571 {
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 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 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 #[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 {
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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
629
630 let (controller, _) = request_controller(&test_values.provider);
632 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
633
634 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 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 #[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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
662
663 let (controller, _) = request_controller(&test_values.provider);
665 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
666
667 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 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 #[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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
700
701 let (controller, _) = request_controller(&test_values.provider);
703 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
704
705 {
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 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 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 #[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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
749
750 let (controller, _) = request_controller(&test_values.provider);
752 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
753
754 let stop_result = controller.stop_all_access_points();
756 assert!(stop_result.is_ok());
757
758 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
760 }
761
762 #[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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
773
774 {
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 let (controller, _) = request_controller(&test_values.provider);
787 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
788
789 let stop_result = controller.stop_all_access_points();
791 assert!(stop_result.is_ok());
792
793 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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
806
807 let (_controller1, _) = request_controller(&test_values.provider);
809 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
810
811 let (controller2, _) = request_controller(&test_values.provider);
813 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
814
815 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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
837
838 let (controller1, _) = request_controller(&test_values.provider);
840 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
841
842 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 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(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 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 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 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 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 let _ = controller.stop_all_access_points();
934 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
935
936 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}