Skip to main content

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::facade::WlanPolicyFacade;
7use anyhow::{Error, format_err};
8use async_trait::async_trait;
9use fidl_fuchsia_wlan_policy as fidl_policy;
10use log::*;
11use serde_json::{Value, to_value};
12
13#[async_trait(?Send)]
14impl Facade for WlanPolicyFacade {
15    async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
16        match method.as_ref() {
17            "scan_for_networks" => {
18                info!(tag = "WlanPolicyFacade"; "performing scan for networks");
19                let result = self.scan_for_networks().await?;
20                to_value(result).map_err(|e| format_err!("error handling scan result: {}", e))
21            }
22            "connect" => {
23                let target_ssid = parse_target_ssid(&args)?;
24                let security_type = parse_security_type(&args)?;
25
26                info!(
27                    tag = "WlanPolicyFacade";
28                    "performing wlan connect to SSID: {:?}", target_ssid
29                );
30                let result = self.connect(target_ssid, security_type).await?;
31                to_value(result).map_err(|e| format_err!("error parsing connection result: {}", e))
32            }
33            "remove_network" => {
34                let target_ssid = parse_target_ssid(&args)?;
35                let security_type = parse_security_type(&args)?;
36                info!(tag = "WlanPolicyFacade"; "removing network with SSID: {:?}", target_ssid);
37                let result = self.remove_network(target_ssid, security_type).await?;
38                to_value(result)
39                    .map_err(|e| format_err!("error parsing remove network result: {}", e))
40            }
41            "start_client_connections" => {
42                info!(tag = "WlanPolicyFacade"; "attempting to start client connections");
43                let result = self.start_client_connections().await?;
44                to_value(result).map_err(|e| {
45                    format_err!("error handling start client connections result: {}", e)
46                })
47            }
48            "stop_client_connections" => {
49                info!(tag = "WlanPolicyFacade"; "attempting to stop client connections");
50                let result = self.stop_client_connections().await?;
51                to_value(result).map_err(|e| {
52                    format_err!("error handling stop client connections result: {}", e)
53                })
54            }
55            "save_network" => {
56                let target_ssid = parse_target_ssid(&args)?;
57                let security_type = parse_security_type(&args)?;
58                let target_pwd = parse_target_pwd(&args)?;
59
60                info!(tag = "WlanPolicyFacade"; "saving network with SSID: {:?}", target_ssid);
61                let result = self.save_network(target_ssid, security_type, target_pwd).await?;
62                to_value(result)
63                    .map_err(|e| format_err!("error parsing save network result: {}", e))
64            }
65            "get_saved_networks" => {
66                info!(tag = "WlanPolicyFacade"; "attempting to get saved networks");
67                let result = self.get_saved_networks_json().await?;
68                to_value(result)
69                    .map_err(|e| format_err!("error handling get saved networks result: {}", e))
70            }
71            "create_client_controller" => {
72                info!(tag = "WlanPolicyFacade"; "initializing client controller");
73                let result = self.create_client_controller().await?;
74                to_value(result)
75                    .map_err(|e| format_err!("error initializing client controller: {}", e))
76            }
77            "drop_client_controller" => {
78                info!(tag = "WlanPolicyFacade"; "dropping client controller");
79                let result = self.drop_client_controller();
80                to_value(result).map_err(|e| format_err!("error dropping client controller: {}", e))
81            }
82            "remove_all_networks" => {
83                info!(tag = "WlanPolicyFacade"; "Removing all saved client network configs");
84                let result = self.remove_all_networks().await?;
85                to_value(result)
86                    .map_err(|e| format_err!("error removing all saved networks: {}", e))
87            }
88            "get_update" => {
89                info!(tag = "WlanPolicyFacade"; "getting client update");
90                let result = self.get_update().await?;
91                to_value(result).map_err(|e| format_err!("error handling listener update: {}", e))
92            }
93            "set_new_update_listener" => {
94                info!(tag = "WlanPolicyFacade"; "initializing new update listener");
95                let result = self.set_new_listener()?;
96                to_value(result)
97                    .map_err(|e| format_err!("error initializing new update listener: {}", e))
98            }
99            _ => return Err(format_err!("unsupported command!")),
100        }
101    }
102}
103
104fn parse_target_ssid(args: &Value) -> Result<Vec<u8>, Error> {
105    args.get("target_ssid")
106        .and_then(|ssid| ssid.as_str().map(|ssid| ssid.as_bytes().to_vec()))
107        .ok_or_else(|| format_err!("Please provide a target ssid"))
108}
109
110/// In ACTS tests we will require a security type is specified for a call that uses a security
111/// type; none specified will not default to a none security type.
112fn parse_security_type(args: &Value) -> Result<fidl_policy::SecurityType, Error> {
113    let security_type = match args.get("security_type") {
114        Some(Value::String(security)) => security.as_bytes().to_vec(),
115        Some(value) => {
116            info!(tag = "WlanFacade"; "Please check provided security type, must be String");
117            bail!("provided security type arg is not a string, cannot parse {}", value);
118        }
119        None => {
120            info!(tag = "WlanFacade"; "Please check provided security type, none found");
121            bail!("no security type is provided");
122        }
123    };
124
125    // Parse network ID to connect to. The string is made lower case upstream in the pipeline.
126    match std::str::from_utf8(&security_type)? {
127        "none" => Ok(fidl_policy::SecurityType::None),
128        "wep" => Ok(fidl_policy::SecurityType::Wep),
129        "wpa" => Ok(fidl_policy::SecurityType::Wpa),
130        "wpa2" => Ok(fidl_policy::SecurityType::Wpa2),
131        "wpa3" => Ok(fidl_policy::SecurityType::Wpa3),
132        _ => Err(format_err!("failed to parse security type (None, WEP, WPA, WPA2, or WPA3")),
133    }
134}
135
136/// Parse the credential argument. The credential argument must be a string. No credential (for an
137/// open network) must be indicated by an empty string. Tests may omit the password argument, and
138/// if so an empty string will be provided as a default value as an argument. Tests do not need
139/// to specify the type of credential; it will be inferred by the length.
140/// PSK format must be string representation of hexadecimal, not the 32 bytes representation.
141/// PSK will be distinguished from password by the length of password, if 64 bytes it will be PSK.
142fn parse_target_pwd(args: &Value) -> Result<fidl_policy::Credential, Error> {
143    let target_pwd = match args.get("target_pwd") {
144        Some(Value::String(pwd)) => pwd.as_bytes().to_vec(),
145        Some(value) => {
146            info!(tag = "WlanFacade"; "Please check provided credential, must be String");
147            bail!("provided credential is not a string, cannot parse {}", value);
148        }
149        None => {
150            info!(tag = "WlanFacade"; "Please check provided credential, none provided");
151            bail!("no credential argument provided");
152        }
153    };
154
155    const PSK_LEN: usize = 64;
156    let credential = match target_pwd.len() {
157        0 => fidl_policy::Credential::None(fidl_policy::Empty),
158        PSK_LEN => {
159            let psk = hex::decode(target_pwd).map_err(|e| {
160                info!(
161                    tag = "WlanFacade";
162                    "Please check provided credential, PSK must be valid hexadecimal string"
163                );
164                format_err!("provided credential length matches PSK, failed to decode: {:?}", e)
165            })?;
166            fidl_policy::Credential::Psk(psk)
167        }
168        _ => fidl_policy::Credential::Password(target_pwd),
169    };
170    Ok(credential)
171}