sl4f_lib/wlan_policy/
commands.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::server::Facade;
6use crate::wlan_policy::ap_facade::WlanApPolicyFacade;
7use crate::wlan_policy::facade::WlanPolicyFacade;
8use anyhow::{format_err, Error};
9use async_trait::async_trait;
10use fidl_fuchsia_wlan_policy as fidl_policy;
11use log::*;
12use serde_json::{to_value, Value};
13
14#[async_trait(?Send)]
15impl Facade for WlanPolicyFacade {
16    async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
17        match method.as_ref() {
18            "scan_for_networks" => {
19                info!(tag = "WlanPolicyFacade"; "performing scan for networks");
20                let result = self.scan_for_networks().await?;
21                to_value(result).map_err(|e| format_err!("error handling scan result: {}", e))
22            }
23            "connect" => {
24                let target_ssid = parse_target_ssid(&args)?;
25                let security_type = parse_security_type(&args)?;
26
27                info!(
28                    tag = "WlanPolicyFacade";
29                    "performing wlan connect to SSID: {:?}", target_ssid
30                );
31                let result = self.connect(target_ssid, security_type).await?;
32                to_value(result).map_err(|e| format_err!("error parsing connection result: {}", e))
33            }
34            "remove_network" => {
35                let target_ssid = parse_target_ssid(&args)?;
36                let security_type = parse_security_type(&args)?;
37                let target_pwd = parse_target_pwd(&args)?;
38
39                info!(tag = "WlanPolicyFacade"; "removing network with SSID: {:?}", target_ssid);
40                let result = self.remove_network(target_ssid, security_type, target_pwd).await?;
41                to_value(result)
42                    .map_err(|e| format_err!("error parsing remove network result: {}", e))
43            }
44            "start_client_connections" => {
45                info!(tag = "WlanPolicyFacade"; "attempting to start client connections");
46                let result = self.start_client_connections().await?;
47                to_value(result).map_err(|e| {
48                    format_err!("error handling start client connections result: {}", e)
49                })
50            }
51            "stop_client_connections" => {
52                info!(tag = "WlanPolicyFacade"; "attempting to stop client connections");
53                let result = self.stop_client_connections().await?;
54                to_value(result).map_err(|e| {
55                    format_err!("error handling stop client connections result: {}", e)
56                })
57            }
58            "save_network" => {
59                let target_ssid = parse_target_ssid(&args)?;
60                let security_type = parse_security_type(&args)?;
61                let target_pwd = parse_target_pwd(&args)?;
62
63                info!(tag = "WlanPolicyFacade"; "saving network with SSID: {:?}", target_ssid);
64                let result = self.save_network(target_ssid, security_type, target_pwd).await?;
65                to_value(result)
66                    .map_err(|e| format_err!("error parsing save network result: {}", e))
67            }
68            "get_saved_networks" => {
69                info!(tag = "WlanPolicyFacade"; "attempting to get saved networks");
70                let result = self.get_saved_networks_json().await?;
71                to_value(result)
72                    .map_err(|e| format_err!("error handling get saved networks result: {}", e))
73            }
74            "create_client_controller" => {
75                info!(tag = "WlanPolicyFacade"; "initializing client controller");
76                let result = self.create_client_controller().await?;
77                to_value(result)
78                    .map_err(|e| format_err!("error initializing client controller: {}", e))
79            }
80            "drop_client_controller" => {
81                info!(tag = "WlanPolicyFacade"; "dropping client controller");
82                let result = self.drop_client_controller();
83                to_value(result).map_err(|e| format_err!("error dropping client controller: {}", e))
84            }
85            "remove_all_networks" => {
86                info!(tag = "WlanPolicyFacade"; "Removing all saved client network configs");
87                let result = self.remove_all_networks().await?;
88                to_value(result)
89                    .map_err(|e| format_err!("error removing all saved networks: {}", e))
90            }
91            "get_update" => {
92                info!(tag = "WlanPolicyFacade"; "getting client update");
93                let result = self.get_update().await?;
94                to_value(result).map_err(|e| format_err!("error handling listener update: {}", e))
95            }
96            "set_new_update_listener" => {
97                info!(tag = "WlanPolicyFacade"; "initializing new update listener");
98                let result = self.set_new_listener()?;
99                to_value(result)
100                    .map_err(|e| format_err!("error initializing new update listener: {}", e))
101            }
102            _ => return Err(format_err!("unsupported command!")),
103        }
104    }
105}
106
107fn parse_target_ssid(args: &Value) -> Result<Vec<u8>, Error> {
108    args.get("target_ssid")
109        .and_then(|ssid| ssid.as_str().map(|ssid| ssid.as_bytes().to_vec()))
110        .ok_or_else(|| format_err!("Please provide a target ssid"))
111}
112
113/// In ACTS tests we will require a security type is specified for a call that uses a security
114/// type; none specified will not default to a none security type.
115fn parse_security_type(args: &Value) -> Result<fidl_policy::SecurityType, Error> {
116    let security_type = match args.get("security_type") {
117        Some(Value::String(security)) => security.as_bytes().to_vec(),
118        Some(value) => {
119            info!(tag = "WlanFacade"; "Please check provided security type, must be String");
120            bail!("provided security type arg is not a string, cannot parse {}", value);
121        }
122        None => {
123            info!(tag = "WlanFacade"; "Please check provided security type, none found");
124            bail!("no security type is provided");
125        }
126    };
127
128    // Parse network ID to connect to. The string is made lower case upstream in the pipeline.
129    match std::str::from_utf8(&security_type)? {
130        "none" => Ok(fidl_policy::SecurityType::None),
131        "wep" => Ok(fidl_policy::SecurityType::Wep),
132        "wpa" => Ok(fidl_policy::SecurityType::Wpa),
133        "wpa2" => Ok(fidl_policy::SecurityType::Wpa2),
134        "wpa3" => Ok(fidl_policy::SecurityType::Wpa3),
135        _ => Err(format_err!("failed to parse security type (None, WEP, WPA, WPA2, or WPA3")),
136    }
137}
138
139/// Parse the credential argument. The credential argument must be a string. No credential (for an
140/// open network) must be indicated by an empty string. Tests may omit the password argument, and
141/// if so an empty string will be provided as a default value as an argument. Tests do not need
142/// to specify the type of credential; it will be infered by the length.
143/// PSK format must be string representation of hexidecimal, not the 32 bytes representation.
144/// PSK will be distinguished from password by the length of password, if 64 bytes it will be PSK.
145fn parse_target_pwd(args: &Value) -> Result<fidl_policy::Credential, Error> {
146    let target_pwd = match args.get("target_pwd") {
147        Some(Value::String(pwd)) => pwd.as_bytes().to_vec(),
148        Some(value) => {
149            info!(tag = "WlanFacade"; "Please check provided credential, must be String");
150            bail!("provided credential is not a string, cannot parse {}", value);
151        }
152        None => {
153            info!(tag = "WlanFacade"; "Please check provided credential, none provided");
154            bail!("no credential argument provided");
155        }
156    };
157
158    const PSK_LEN: usize = 64;
159    let credential = match target_pwd.len() {
160        0 => fidl_policy::Credential::None(fidl_policy::Empty),
161        PSK_LEN => {
162            let psk = hex::decode(target_pwd).map_err(|e| {
163                info!(
164                    tag = "WlanFacade";
165                    "Please check provided credential, PSK must be valid hexadecimal string"
166                );
167                format_err!("provided credential length matches PSK, failed to decode: {:?}", e)
168            })?;
169            fidl_policy::Credential::Psk(psk)
170        }
171        _ => fidl_policy::Credential::Password(target_pwd),
172    };
173    Ok(credential)
174}
175
176fn extract_operating_band(args: &Value) -> Result<fidl_fuchsia_wlan_policy::OperatingBand, Error> {
177    match args.get("operating_band") {
178        Some(operating_band) => match operating_band.as_str() {
179            Some(operating_band) => match operating_band.to_lowercase().as_str() {
180                "any" => Ok(fidl_fuchsia_wlan_policy::OperatingBand::Any),
181                "only_2_4_ghz" => Ok(fidl_fuchsia_wlan_policy::OperatingBand::Only24Ghz),
182                "only_5_ghz" => Ok(fidl_fuchsia_wlan_policy::OperatingBand::Only5Ghz),
183                _ => Err(format_err!("invalid operating band: {:?}", operating_band)),
184            },
185            None => Err(format_err!("operating band must be a string")),
186        },
187        None => Err(format_err!("operating band was not specified")),
188    }
189}
190
191fn extract_connectivity_mode(
192    args: &Value,
193) -> Result<fidl_fuchsia_wlan_policy::ConnectivityMode, Error> {
194    match args.get("connectivity_mode") {
195        Some(connectivity_mode) => match connectivity_mode.as_str() {
196            Some(connectivity_mode) => match connectivity_mode.to_lowercase().as_str() {
197                "local_only" => Ok(fidl_fuchsia_wlan_policy::ConnectivityMode::LocalOnly),
198                "unrestricted" => Ok(fidl_fuchsia_wlan_policy::ConnectivityMode::Unrestricted),
199                _ => Err(format_err!("unsupported connectivity mode: {}", connectivity_mode)),
200            },
201            None => Err(format_err!("connectivity mode must be a string")),
202        },
203        None => Err(format_err!("no connectivity mode specified")),
204    }
205}
206
207#[async_trait(?Send)]
208impl Facade for WlanApPolicyFacade {
209    async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
210        match method.as_ref() {
211            "start_access_point" => {
212                let target_ssid = parse_target_ssid(&args)?;
213                let security_type = parse_security_type(&args)?;
214                let target_pwd = parse_target_pwd(&args)?;
215
216                let connectivity_mode = extract_connectivity_mode(&args)?;
217                let operating_band = extract_operating_band(&args)?;
218                self.start_access_point(
219                    target_ssid,
220                    security_type,
221                    target_pwd,
222                    connectivity_mode,
223                    operating_band,
224                )
225                .await?;
226                return Ok(Value::Bool(true));
227            }
228            "stop_access_point" => {
229                let target_ssid = parse_target_ssid(&args)?;
230                let security_type = parse_security_type(&args)?;
231                let target_pwd = parse_target_pwd(&args)?;
232                self.stop_access_point(target_ssid, security_type, target_pwd).await?;
233                return Ok(Value::Bool(true));
234            }
235            "stop_all_access_points" => {
236                self.stop_all_access_points().await?;
237                return Ok(Value::Bool(true));
238            }
239            "get_update" => {
240                info!(tag = "WlanApPolicyFacade"; "getting AP update");
241                let result = self.get_update().await?;
242                to_value(result).map_err(|e| format_err!("error handling listener update: {}", e))
243            }
244            "set_new_update_listener" => {
245                info!(tag = "WlanApPolicyFacade"; "initializing new update listener");
246                let result = self.set_new_listener()?;
247                to_value(result)
248                    .map_err(|e| format_err!("error initializing new update listener: {}", e))
249            }
250            _ => {
251                return Err(format_err!("Unsupported command"));
252            }
253        }
254    }
255}