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::Cbw;
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}
32
33const MAX_CONCURRENT_LISTENERS: usize = 1000;
35
36type ApRequests = fidl::endpoints::ServerEnd<fidl_policy::AccessPointControllerMarker>;
37
38impl AccessPoint {
39 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 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 _ = provider_reqs.select_next_some() => (),
72 req = requests.select_next_some() => match req {
74 Ok(req) => {
75 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 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 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 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 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 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 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
277struct 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 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
327fn 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 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 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 #[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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
505
506 let (controller, _) = request_controller(&test_values.provider);
508 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
509
510 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 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 #[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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
545
546 let (controller, _) = request_controller(&test_values.provider);
548 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
549
550 {
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 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 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 #[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 {
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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
608
609 let (controller, _) = request_controller(&test_values.provider);
611 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
612
613 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 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 #[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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
641
642 let (controller, _) = request_controller(&test_values.provider);
644 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
645
646 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 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 #[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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
679
680 let (controller, _) = request_controller(&test_values.provider);
682 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
683
684 {
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 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 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 #[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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
728
729 let (controller, _) = request_controller(&test_values.provider);
731 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
732
733 let stop_result = controller.stop_all_access_points();
735 assert!(stop_result.is_ok());
736
737 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
739 }
740
741 #[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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
752
753 {
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 let (controller, _) = request_controller(&test_values.provider);
766 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
767
768 let stop_result = controller.stop_all_access_points();
770 assert!(stop_result.is_ok());
771
772 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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
785
786 let (_controller1, _) = request_controller(&test_values.provider);
788 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
789
790 let (controller2, _) = request_controller(&test_values.provider);
792 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
793
794 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 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
817
818 let (controller1, _) = request_controller(&test_values.provider);
820 assert_matches!(exec.run_until_stalled(&mut serve_fut), Poll::Pending);
821
822 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 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(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 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 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}