sl4f_lib/wlan_policy/
ap_facade.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::wlan_policy::types::AccessPointState;
6use anyhow::Error;
7use fidl::endpoints::{create_endpoints, create_proxy};
8use fidl_fuchsia_wlan_policy::{
9    AccessPointControllerMarker, AccessPointControllerProxy, AccessPointListenerMarker,
10    AccessPointProviderMarker, AccessPointStateUpdatesMarker, AccessPointStateUpdatesRequestStream,
11    ConnectivityMode, Credential, NetworkConfig, NetworkIdentifier, OperatingBand, OperatingState,
12    RequestStatus, SecurityType,
13};
14use fuchsia_component::client::connect_to_protocol;
15use futures::TryStreamExt;
16use std::cell::Cell;
17use std::fmt::{self, Debug};
18
19pub struct WlanApPolicyFacade {
20    ap_controller: AccessPointControllerProxy,
21    update_listener: Cell<Option<AccessPointStateUpdatesRequestStream>>,
22}
23
24impl Debug for WlanApPolicyFacade {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        let listener = self.update_listener.take();
27        let update_listener =
28            if listener.is_some() { "Some(AccessPointStateUpdatesRequestStream)" } else { "None" }
29                .to_string();
30        self.update_listener.set(listener);
31
32        f.debug_struct("WlanApPolicyFacade")
33            .field("controller", &self.ap_controller)
34            .field("update_listener", &update_listener)
35            .finish()
36    }
37}
38
39impl WlanApPolicyFacade {
40    pub fn new() -> Result<WlanApPolicyFacade, Error> {
41        let policy_provider = connect_to_protocol::<AccessPointProviderMarker>()?;
42        let (ap_controller, server_end) = create_proxy::<AccessPointControllerMarker>();
43
44        let (update_client_end, update_listener) =
45            create_endpoints::<AccessPointStateUpdatesMarker>();
46        let () = policy_provider.get_controller(server_end, update_client_end)?;
47        let update_stream = update_listener.into_stream();
48        Ok(WlanApPolicyFacade { ap_controller, update_listener: Cell::new(Some(update_stream)) })
49    }
50
51    pub async fn start_access_point(
52        &self,
53        target_ssid: Vec<u8>,
54        type_: SecurityType,
55        credential: Credential,
56        mode: ConnectivityMode,
57        band: OperatingBand,
58    ) -> Result<(), Error> {
59        let listener = connect_to_protocol::<AccessPointListenerMarker>()?;
60        let (client_end, server_end) = create_endpoints::<AccessPointStateUpdatesMarker>();
61        listener.get_listener(client_end)?;
62        let mut server_stream = server_end.into_stream();
63
64        match server_stream.try_next().await? {
65            Some(update) => {
66                let update = update.into_on_access_point_state_update();
67                let (_, responder) = match update {
68                    Some((update, responder)) => (update, responder),
69                    None => return Err(format_err!("AP provider produced invalid update.")),
70                };
71                let _ = responder.send();
72            }
73            None => return Err(format_err!("initial steam already busted")),
74        }
75
76        let network_id = NetworkIdentifier { ssid: target_ssid.clone(), type_: type_ };
77
78        match self
79            .ap_controller
80            .start_access_point(
81                &NetworkConfig {
82                    id: Some(network_id),
83                    credential: Some(credential),
84                    ..Default::default()
85                },
86                mode,
87                band,
88            )
89            .await?
90        {
91            RequestStatus::Acknowledged => {}
92            RequestStatus::RejectedNotSupported => {
93                return Err(format_err!("failed to start AP (not supported)"))
94            }
95            RequestStatus::RejectedIncompatibleMode => {
96                return Err(format_err!("failed to start AP (incompatible mode)"))
97            }
98            RequestStatus::RejectedAlreadyInUse => {
99                return Err(format_err!("failed to start AP (already in use)"))
100            }
101            RequestStatus::RejectedDuplicateRequest => {
102                return Err(format_err!("failed to start AP (duplicate request)"))
103            }
104        }
105
106        while let Some(update_request) = server_stream.try_next().await.unwrap() {
107            let update = update_request.into_on_access_point_state_update();
108            let (updates, responder) = match update {
109                Some((update, responder)) => (update, responder),
110                None => return Err(format_err!("AP provider produced invalid update.")),
111            };
112            let _ = responder.send();
113
114            for update in updates {
115                match update.state {
116                    Some(state) => match state {
117                        OperatingState::Failed => {
118                            return Err(format_err!("Failed to start AP."));
119                        }
120                        OperatingState::Starting => {
121                            continue;
122                        }
123                        OperatingState::Active => return Ok(()),
124                    },
125                    None => continue,
126                }
127            }
128        }
129        return Err(format_err!("AP update stream failed unexpectedly"));
130    }
131
132    pub async fn stop_access_point(
133        &self,
134        target_ssid: Vec<u8>,
135        type_: SecurityType,
136        credential: Credential,
137    ) -> Result<(), Error> {
138        let network_id = NetworkIdentifier { ssid: target_ssid.clone(), type_: type_ };
139        match self
140            .ap_controller
141            .stop_access_point(&NetworkConfig {
142                id: Some(network_id),
143                credential: Some(credential),
144                ..Default::default()
145            })
146            .await?
147        {
148            RequestStatus::Acknowledged => Ok(()),
149            RequestStatus::RejectedNotSupported => {
150                Err(format_err!("Failed to stop AP (not supported)"))
151            }
152            RequestStatus::RejectedIncompatibleMode => {
153                Err(format_err!("Failed to stop AP (incompatible mode)"))
154            }
155            RequestStatus::RejectedAlreadyInUse => {
156                Err(format_err!("Failed to stop AP (already in use)"))
157            }
158            RequestStatus::RejectedDuplicateRequest => {
159                Err(format_err!("Failed to stop AP (duplicate request)"))
160            }
161        }
162    }
163
164    pub async fn stop_all_access_points(&self) -> Result<(), Error> {
165        self.ap_controller.stop_all_access_points()?;
166        Ok(())
167    }
168
169    /// Creates a listener update stream for getting status updates.
170    fn init_listener() -> Result<AccessPointStateUpdatesRequestStream, Error> {
171        let listener = connect_to_protocol::<AccessPointListenerMarker>()?;
172        let (client_end, server_end) =
173            fidl::endpoints::create_endpoints::<AccessPointStateUpdatesMarker>();
174        listener.get_listener(client_end)?;
175        Ok(server_end.into_stream())
176    }
177
178    /// This function will set a new listener even if there is one because new listeners will get
179    /// the most recent update immediately without waiting.
180    pub fn set_new_listener(&self) -> Result<(), Error> {
181        self.update_listener.set(Some(Self::init_listener()?));
182        Ok(())
183    }
184
185    /// Wait for and return an AP update. If this is the first update gotten from the facade
186    /// since the AP controller or a new update listener has been created, it will get an
187    /// immediate status. After that, it will wait for a change and return a status when there has
188    /// been a change since the last call to get_update. This call will hang if there are no
189    /// updates.
190    /// This function is not thread safe, so there should not be multiple get_update calls at the
191    /// same time unless a new listener is set between them. There is no lock around the
192    /// update_listener field of the facade in order to prevent a hanging get_update from blocking
193    /// all future get_updates.
194    pub async fn get_update(&self) -> Result<Vec<AccessPointState>, Error> {
195        // Initialize the update listener if it has not been initialized.
196        let listener = self.update_listener.take();
197        let mut update_listener = if listener.is_none() {
198            Self::init_listener()
199        } else {
200            listener.ok_or_else(|| format_err!("failed to set update listener of facade"))
201        }?;
202
203        if let Some(update_request) = update_listener.try_next().await? {
204            let update = update_request.into_on_access_point_state_update();
205            let (update, responder) = match update {
206                Some((update, responder)) => (update, responder),
207                None => return Err(format_err!("Client provider produced invalid update.")).into(),
208            };
209            // Ack the update.
210            responder.send().map_err(|e| format_err!("failed to ack update: {}", e))?;
211            // Put the update listener back in the facade
212            self.update_listener.set(Some(update_listener));
213
214            let update = update.into_iter().map(|update| AccessPointState::from(update)).collect();
215            Ok(update)
216        } else {
217            self.update_listener.set(Some(update_listener));
218            Err(format_err!("update listener's next update is None"))
219        }
220    }
221}