sl4f_lib/wlan_policy/
facade.rs1use crate::common_utils::common::macros::with_line;
6use crate::wlan_policy::types::{ClientStateSummary, NetworkConfig};
7use anyhow::{Error, format_err};
8use fidl::endpoints::Proxy as _;
9use fidl_fuchsia_wlan_policy as fidl_policy;
10use fuchsia_async::{self as fasync, DurationExt as _};
11use fuchsia_component::client::connect_to_protocol;
12use fuchsia_sync::RwLock;
13use futures::TryStreamExt;
14use log::*;
15use std::cell::Cell;
16use std::collections::HashSet;
17use std::fmt::{self, Debug};
18
19pub struct WlanPolicyFacade {
20 controller: RwLock<InnerController>,
21 update_listener: Cell<Option<fidl_policy::ClientStateUpdatesRequestStream>>,
22}
23
24#[derive(Debug)]
25pub struct InnerController {
26 inner: Option<fidl_policy::ClientControllerProxy>,
27}
28
29impl Debug for WlanPolicyFacade {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 let listener = self.update_listener.take();
32 let update_listener =
33 if listener.is_some() { "Some(ClientStateUpdatesRequestStream)" } else { "None" }
34 .to_string();
35 self.update_listener.set(listener);
36
37 f.debug_struct("InnerWlanPolicyFacade")
38 .field("controller", &self.controller)
39 .field("update_listener", &update_listener)
40 .finish()
41 }
42}
43
44impl WlanPolicyFacade {
45 pub fn new() -> Result<WlanPolicyFacade, Error> {
46 Ok(Self {
47 controller: RwLock::new(InnerController { inner: None }),
48 update_listener: Cell::new(None),
49 })
50 }
51
52 pub async fn create_client_controller(&self) -> Result<(), Error> {
59 let tag = "WlanPolicyFacade::create_client_controller";
60
61 {
62 let mut controller_guard = self.controller.write();
63 controller_guard.inner = None;
64 }
65
66 let (controller, update_stream) = Self::init_client_controller().await.map_err(|e| {
67 info!(tag = &with_line!(tag); "Error getting client controller: {}", e);
68 format_err!("Error getting client controller: {}", e)
69 })?;
70
71 {
72 let mut controller_guard = self.controller.write();
73 controller_guard.inner = Some(controller);
74 }
75
76 self.update_listener.set(Some(update_stream));
77
78 Ok(())
79 }
80
81 async fn init_client_controller() -> Result<
84 (fidl_policy::ClientControllerProxy, fidl_policy::ClientStateUpdatesRequestStream),
85 Error,
86 > {
87 let provider = connect_to_protocol::<fidl_policy::ClientProviderMarker>()?;
88 let (controller, req) =
89 fidl::endpoints::create_proxy::<fidl_policy::ClientControllerMarker>();
90 let (update_sink, update_stream) =
91 fidl::endpoints::create_request_stream::<fidl_policy::ClientStateUpdatesMarker>();
92 provider.get_controller(req, update_sink)?;
93
94 let sleep_duration = zx::MonotonicDuration::from_millis(10);
98 fasync::Timer::new(sleep_duration.after_now()).await;
99 if controller.is_closed() {
100 return Err(format_err!(
101 "Policy layer closed channel, client controller is likely already in use."
102 ));
103 }
104
105 Ok((controller, update_stream))
106 }
107
108 pub fn drop_client_controller(&self) {
110 let mut controller_guard = self.controller.write();
111 controller_guard.inner = None;
112 }
113
114 fn init_listener() -> Result<fidl_policy::ClientStateUpdatesRequestStream, Error> {
116 let listener = connect_to_protocol::<fidl_policy::ClientListenerMarker>()?;
117 let (client_end, server_end) =
118 fidl::endpoints::create_endpoints::<fidl_policy::ClientStateUpdatesMarker>();
119 listener.get_listener(client_end)?;
120 Ok(server_end.into_stream())
121 }
122
123 pub fn set_new_listener(&self) -> Result<(), Error> {
128 self.update_listener.set(Some(Self::init_listener()?));
129 Ok(())
130 }
131
132 pub async fn scan_for_networks(&self) -> Result<Vec<String>, Error> {
134 let controller = self
135 .controller
136 .read()
137 .inner
138 .clone()
139 .ok_or_else(|| format_err!("client controller has not been initialized"))?;
140
141 let (iter, server) =
143 fidl::endpoints::create_proxy::<fidl_policy::ScanResultIteratorMarker>();
144 controller.scan_for_networks(server)?;
146
147 let mut scan_results = HashSet::new();
150 loop {
151 let results = iter.get_next().await?.map_err(|e| format_err!("{:?}", e))?;
152 if results.is_empty() {
153 break;
154 }
155
156 let results = Self::stringify_scan_results(results);
158 scan_results.extend(results);
159 }
160 Ok(scan_results.into_iter().collect())
161 }
162
163 pub async fn connect(
173 &self,
174 target_ssid: Vec<u8>,
175 type_: fidl_policy::SecurityType,
176 ) -> Result<String, Error> {
177 let controller = self
178 .controller
179 .read()
180 .inner
181 .clone()
182 .ok_or_else(|| format_err!("client controller has not been initialized"))?;
183
184 let network_id = fidl_policy::NetworkIdentifier { ssid: target_ssid, type_ };
185 let response = controller
186 .connect(&network_id)
187 .await
188 .map_err(|e| format_err!("Connect: failed to connect: {}", e))?;
189 Ok(Self::request_status_as_string(response))
190 }
191
192 fn request_status_as_string(response: fidl_policy::RequestStatus) -> String {
193 match response {
194 fidl_policy::RequestStatus::Acknowledged => "Acknowledged",
195 fidl_policy::RequestStatus::RejectedNotSupported => "RejectedNotSupported",
196 fidl_policy::RequestStatus::RejectedIncompatibleMode => "RejectedIncompatibleMode",
197 fidl_policy::RequestStatus::RejectedAlreadyInUse => "RejectedAlreadyInUse",
198 fidl_policy::RequestStatus::RejectedDuplicateRequest => "RejectedDuplicateRequest",
199 }
200 .to_string()
201 }
202
203 pub async fn remove_network(
211 &self,
212 target_ssid: Vec<u8>,
213 type_: fidl_policy::SecurityType,
214 ) -> Result<(), Error> {
215 let controller = self
216 .controller
217 .read()
218 .inner
219 .clone()
220 .ok_or_else(|| format_err!("client controller has not been initialized"))?;
221 info!(
222 tag = &with_line!("WlanPolicyFacade::remove_network");
223 "Removing network: ({}{:?})",
224 String::from_utf8_lossy(&target_ssid),
225 type_
226 );
227
228 let id = fidl_policy::NetworkIdentifier { ssid: target_ssid, type_ };
229 controller
230 .forget_network(&id)
231 .await
232 .map_err(|err| format_err!("{:?}", err))? .map_err(|err| format_err!("{:?}", err)) }
235
236 pub async fn remove_all_networks(&self) -> Result<(), Error> {
238 let controller = self
239 .controller
240 .read()
241 .inner
242 .clone()
243 .ok_or_else(|| format_err!("client controller has not been initialized"))?;
244
245 let saved_networks = self.get_saved_networks().await?;
247 for network_config in saved_networks {
248 let id = network_config.id.as_ref().ok_or_else(|| format_err!("missing network ID"))?;
249 controller
250 .forget_network(id)
251 .await
252 .map_err(|err| format_err!("{:?}", err))? .map_err(|err| format_err!("{:?}", err))?; }
255 Ok(())
256 }
257
258 pub async fn start_client_connections(&self) -> Result<(), Error> {
260 let controller = self
261 .controller
262 .read()
263 .inner
264 .clone()
265 .ok_or_else(|| format_err!("client controller has not been initialized"))?;
266
267 let req_status = controller.start_client_connections().await?;
268 if fidl_policy::RequestStatus::Acknowledged == req_status {
269 Ok(())
270 } else {
271 bail!("{:?}", req_status);
272 }
273 }
274
275 pub async fn get_update(&self) -> Result<ClientStateSummary, Error> {
285 let listener = self.update_listener.take();
287 let mut update_listener = if listener.is_none() {
288 Self::init_listener()
289 } else {
290 listener.ok_or_else(|| format_err!("failed to set update listener of facade"))
291 }?;
292
293 if let Some(update_request) = update_listener.try_next().await? {
294 let update = update_request.into_on_client_state_update();
295 let (update, responder) = match update {
296 Some((update, responder)) => (update, responder),
297 None => return Err(format_err!("Client provider produced invalid update.")),
298 };
299 responder.send().map_err(|e| format_err!("failed to ack update: {}", e))?;
301 self.update_listener.set(Some(update_listener));
303 Ok(update.into())
304 } else {
305 self.update_listener.set(Some(update_listener));
306 Err(format_err!("update listener's next update is None"))
307 }
308 }
309
310 pub async fn stop_client_connections(&self) -> Result<(), Error> {
312 let controller = self
313 .controller
314 .read()
315 .inner
316 .clone()
317 .ok_or_else(|| format_err!("client controller has not been initialized"))?;
318
319 let req_status = controller.stop_client_connections().await?;
320 if fidl_policy::RequestStatus::Acknowledged == req_status {
321 Ok(())
322 } else {
323 bail!("{:?}", req_status);
324 }
325 }
326
327 pub async fn save_network(
335 &self,
336 target_ssid: Vec<u8>,
337 type_: fidl_policy::SecurityType,
338 credential: fidl_policy::Credential,
339 ) -> Result<(), Error> {
340 let controller = self
341 .controller
342 .read()
343 .inner
344 .clone()
345 .ok_or_else(|| format_err!("client controller has not been initialized"))?;
346
347 let network_id = fidl_policy::NetworkIdentifier { ssid: target_ssid.clone(), type_: type_ };
348
349 controller
350 .save_network(&fidl_policy::NetworkConfig {
351 id: Some(network_id),
352 credential: Some(credential),
353 ..Default::default()
354 })
355 .await?
356 .map_err(|e| format_err!("{:?}", e))
357 }
358
359 pub async fn get_saved_networks_json(&self) -> Result<Vec<NetworkConfig>, Error> {
360 let saved_networks = self.get_saved_networks().await?;
361 Ok(saved_networks.into_iter().map(|cfg| cfg.into()).collect::<Vec<_>>())
363 }
364
365 async fn get_saved_networks(&self) -> Result<Vec<fidl_policy::NetworkConfig>, Error> {
368 let controller = self
369 .controller
370 .read()
371 .inner
372 .clone()
373 .ok_or_else(|| format_err!("client controller has not been initialized"))?;
374
375 let (iter, server) =
377 fidl::endpoints::create_proxy::<fidl_policy::NetworkConfigIteratorMarker>();
378 controller
379 .get_saved_networks(server)
380 .map_err(|e| format_err!("Get saved networks: fidl error {:?}", e))?;
381
382 let mut networks = vec![];
384 loop {
385 let cfgs = iter.get_next().await?;
386 if cfgs.is_empty() {
387 break;
388 }
389 networks.extend(cfgs);
390 }
391 Ok(networks)
392 }
393
394 fn stringify_scan_results(results: Vec<fidl_policy::ScanResult>) -> Vec<String> {
395 results
396 .into_iter()
397 .filter_map(|result| result.id)
398 .map(|id| String::from_utf8_lossy(&id.ssid).into_owned())
399 .collect()
400 }
401}