blob: a540a44819c72335aa0fbd39ceee1e4393e9a77e [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
crate::{
server::Facade, wlan_policy::ap_facade::WlanApPolicyFacade,
wlan_policy::facade::WlanPolicyFacade,
},
anyhow::{format_err, Error},
async_trait::async_trait,
fidl_fuchsia_wlan_policy as fidl_policy,
serde_json::{to_value, Value},
tracing::*,
};
#[async_trait(?Send)]
impl Facade for WlanPolicyFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"scan_for_networks" => {
info!(tag = "WlanPolicyFacade", "performing scan for networks");
let result = self.scan_for_networks().await?;
to_value(result).map_err(|e| format_err!("error handling scan result: {}", e))
}
"connect" => {
let target_ssid = parse_target_ssid(&args)?;
let security_type = parse_security_type(&args)?;
info!(
tag = "WlanPolicyFacade",
"performing wlan connect to SSID: {:?}", target_ssid
);
let result = self.connect(target_ssid, security_type).await?;
to_value(result).map_err(|e| format_err!("error parsing connection result: {}", e))
}
"remove_network" => {
let target_ssid = parse_target_ssid(&args)?;
let security_type = parse_security_type(&args)?;
let target_pwd = parse_target_pwd(&args)?;
info!(tag = "WlanPolicyFacade", "removing network with SSID: {:?}", target_ssid);
let result = self.remove_network(target_ssid, security_type, target_pwd).await?;
to_value(result)
.map_err(|e| format_err!("error parsing remove network result: {}", e))
}
"start_client_connections" => {
info!(tag = "WlanPolicyFacade", "attempting to start client connections");
let result = self.start_client_connections().await?;
to_value(result).map_err(|e| {
format_err!("error handling start client connections result: {}", e)
})
}
"stop_client_connections" => {
info!(tag = "WlanPolicyFacade", "attempting to stop client connections");
let result = self.stop_client_connections().await?;
to_value(result).map_err(|e| {
format_err!("error handling stop client connections result: {}", e)
})
}
"save_network" => {
let target_ssid = parse_target_ssid(&args)?;
let security_type = parse_security_type(&args)?;
let target_pwd = parse_target_pwd(&args)?;
info!(tag = "WlanPolicyFacade", "saving network with SSID: {:?}", target_ssid);
let result = self.save_network(target_ssid, security_type, target_pwd).await?;
to_value(result)
.map_err(|e| format_err!("error parsing save network result: {}", e))
}
"get_saved_networks" => {
info!(tag = "WlanPolicyFacade", "attempting to get saved networks");
let result = self.get_saved_networks_json().await?;
to_value(result)
.map_err(|e| format_err!("error handling get saved networks result: {}", e))
}
"create_client_controller" => {
info!(tag = "WlanPolicyFacade", "initializing client controller");
let result = self.create_client_controller().await?;
to_value(result)
.map_err(|e| format_err!("error initializing client controller: {}", e))
}
"drop_client_controller" => {
info!(tag = "WlanPolicyFacade", "dropping client controller");
let result = self.drop_client_controller();
to_value(result).map_err(|e| format_err!("error dropping client controller: {}", e))
}
"remove_all_networks" => {
info!(tag = "WlanPolicyFacade", "Removing all saved client network configs");
let result = self.remove_all_networks().await?;
to_value(result)
.map_err(|e| format_err!("error removing all saved networks: {}", e))
}
"get_update" => {
info!(tag = "WlanPolicyFacade", "getting client update");
let result = self.get_update().await?;
to_value(result).map_err(|e| format_err!("error handling listener update: {}", e))
}
"set_new_update_listener" => {
info!(tag = "WlanPolicyFacade", "initializing new update listener");
let result = self.set_new_listener()?;
to_value(result)
.map_err(|e| format_err!("error initializing new update listener: {}", e))
}
_ => return Err(format_err!("unsupported command!")),
}
}
}
fn parse_target_ssid(args: &Value) -> Result<Vec<u8>, Error> {
args.get("target_ssid")
.and_then(|ssid| ssid.as_str().map(|ssid| ssid.as_bytes().to_vec()))
.ok_or(format_err!("Please provide a target ssid"))
}
/// In ACTS tests we will require a security type is specified for a call that uses a security
/// type; none specified will not default to a none security type.
fn parse_security_type(args: &Value) -> Result<fidl_policy::SecurityType, Error> {
let security_type = match args.get("security_type") {
Some(Value::String(security)) => security.as_bytes().to_vec(),
Some(value) => {
info!(tag = "WlanFacade", "Please check provided security type, must be String");
bail!("provided security type arg is not a string, cannot parse {}", value);
}
None => {
info!(tag = "WlanFacade", "Please check provided security type, none found");
bail!("no security type is provided");
}
};
// Parse network ID to connect to. The string is made lower case upstream in the pipeline.
match std::str::from_utf8(&security_type)? {
"none" => Ok(fidl_policy::SecurityType::None),
"wep" => Ok(fidl_policy::SecurityType::Wep),
"wpa" => Ok(fidl_policy::SecurityType::Wpa),
"wpa2" => Ok(fidl_policy::SecurityType::Wpa2),
"wpa3" => Ok(fidl_policy::SecurityType::Wpa3),
_ => Err(format_err!("failed to parse security type (None, WEP, WPA, WPA2, or WPA3")),
}
}
/// Parse the credential argument. The credential argument must be a string. No credential (for an
/// open network) must be indicated by an empty string. Tests may omit the password argument, and
/// if so an empty string will be provided as a default value as an argument. Tests do not need
/// to specify the type of credential; it will be infered by the length.
/// PSK format must be string representation of hexidecimal, not the 32 bytes representation.
/// PSK will be distinguished from password by the length of password, if 64 bytes it will be PSK.
fn parse_target_pwd(args: &Value) -> Result<fidl_policy::Credential, Error> {
let target_pwd = match args.get("target_pwd") {
Some(Value::String(pwd)) => pwd.as_bytes().to_vec(),
Some(value) => {
info!(tag = "WlanFacade", "Please check provided credential, must be String");
bail!("provided credential is not a string, cannot parse {}", value);
}
None => {
info!(tag = "WlanFacade", "Please check provided credential, none provided");
bail!("no credential argument provided");
}
};
const PSK_LEN: usize = 64;
let credential = match target_pwd.len() {
0 => fidl_policy::Credential::None(fidl_policy::Empty),
PSK_LEN => {
let psk = hex::decode(target_pwd).map_err(|e| {
info!(
tag = "WlanFacade",
"Please check provided credential, PSK must be valid hexadecimal string"
);
format_err!("provided credential length matches PSK, failed to decode: {:?}", e)
})?;
fidl_policy::Credential::Psk(psk)
}
_ => fidl_policy::Credential::Password(target_pwd),
};
Ok(credential)
}
fn extract_operating_band(args: &Value) -> Result<fidl_fuchsia_wlan_policy::OperatingBand, Error> {
match args.get("operating_band") {
Some(operating_band) => match operating_band.as_str() {
Some(operating_band) => match operating_band.to_lowercase().as_str() {
"any" => Ok(fidl_fuchsia_wlan_policy::OperatingBand::Any),
"only_2_4_ghz" => Ok(fidl_fuchsia_wlan_policy::OperatingBand::Only24Ghz),
"only_5_ghz" => Ok(fidl_fuchsia_wlan_policy::OperatingBand::Only5Ghz),
_ => Err(format_err!("invalid operating band: {:?}", operating_band)),
},
None => Err(format_err!("operating band must be a string")),
},
None => Err(format_err!("operating band was not specified")),
}
}
fn extract_connectivity_mode(
args: &Value,
) -> Result<fidl_fuchsia_wlan_policy::ConnectivityMode, Error> {
match args.get("connectivity_mode") {
Some(connectivity_mode) => match connectivity_mode.as_str() {
Some(connectivity_mode) => match connectivity_mode.to_lowercase().as_str() {
"local_only" => Ok(fidl_fuchsia_wlan_policy::ConnectivityMode::LocalOnly),
"unrestricted" => Ok(fidl_fuchsia_wlan_policy::ConnectivityMode::Unrestricted),
_ => Err(format_err!("unsupported connectivity mode: {}", connectivity_mode)),
},
None => Err(format_err!("connectivity mode must be a string")),
},
None => Err(format_err!("no connectivity mode specified")),
}
}
#[async_trait(?Send)]
impl Facade for WlanApPolicyFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"start_access_point" => {
let target_ssid = parse_target_ssid(&args)?;
let security_type = parse_security_type(&args)?;
let target_pwd = parse_target_pwd(&args)?;
let connectivity_mode = extract_connectivity_mode(&args)?;
let operating_band = extract_operating_band(&args)?;
self.start_access_point(
target_ssid,
security_type,
target_pwd,
connectivity_mode,
operating_band,
)
.await?;
return Ok(Value::Bool(true));
}
"stop_access_point" => {
let target_ssid = parse_target_ssid(&args)?;
let security_type = parse_security_type(&args)?;
let target_pwd = parse_target_pwd(&args)?;
self.stop_access_point(target_ssid, security_type, target_pwd).await?;
return Ok(Value::Bool(true));
}
"stop_all_access_points" => {
self.stop_all_access_points().await?;
return Ok(Value::Bool(true));
}
"get_update" => {
info!(tag = "WlanApPolicyFacade", "getting AP update");
let result = self.get_update().await?;
to_value(result).map_err(|e| format_err!("error handling listener update: {}", e))
}
"set_new_update_listener" => {
info!(tag = "WlanApPolicyFacade", "initializing new update listener");
let result = self.set_new_listener()?;
to_value(result)
.map_err(|e| format_err!("error initializing new update listener: {}", e))
}
_ => {
return Err(format_err!("Unsupported command"));
}
}
}
}