| // 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, |
| fuchsia_syslog::macros::*, |
| serde_json::{to_value, Value}, |
| }; |
| |
| #[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" => { |
| fx_log_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)?; |
| |
| fx_log_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)?; |
| |
| fx_log_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" => { |
| fx_log_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" => { |
| fx_log_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)?; |
| |
| fx_log_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" => { |
| fx_log_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" => { |
| fx_log_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)) |
| } |
| "remove_all_networks" => { |
| fx_log_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" => { |
| fx_log_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" => { |
| fx_log_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) => { |
| fx_log_info!(tag: "WlanFacade", "Please check provided security type, must be String"); |
| bail!("provided security type arg is not a string, cannot parse {}", value); |
| } |
| None => { |
| fx_log_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) => { |
| fx_log_info!(tag: "WlanFacade", "Please check provided credential, must be String"); |
| bail!("provided credential is not a string, cannot parse {}", value); |
| } |
| None => { |
| fx_log_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| { |
| fx_log_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)); |
| } |
| _ => { |
| return Err(format_err!("Unsupported command")); |
| } |
| } |
| } |
| } |