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