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