diff --git a/LICENSE b/LICENSE index 658021b..0cf8237 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,6 @@ Copyright © 2023 Collabora Ltd. Copyright © 2024 Valve Software +Copyright © 2024 Igalia S.L. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in diff --git a/src/manager.rs b/src/manager.rs index 441df10..592ceaa 100644 --- a/src/manager.rs +++ b/src/manager.rs @@ -1,6 +1,7 @@ /* * Copyright © 2023 Collabora Ltd. * Copyright © 2024 Valve Software + * Copyright © 2024 Igalia S.L. * * SPDX-License-Identifier: MIT */ @@ -17,7 +18,10 @@ use crate::power::{ GPUPerformanceLevel, }; use crate::process::{run_script, script_output, SYSTEMCTL_PATH}; -use crate::wifi::{set_wifi_debug_mode, WifiDebugMode, WifiPowerManagement}; +use crate::wifi::{ + get_wifi_backend_from_conf, get_wifi_backend_from_script, set_wifi_backend, + set_wifi_debug_mode, WifiBackend, WifiDebugMode, WifiPowerManagement, +}; use crate::{anyhow_to_zbus, anyhow_to_zbus_fdo}; #[derive(PartialEq, Debug, Copy, Clone)] @@ -55,6 +59,7 @@ impl fmt::Display for FanControl { } pub struct SteamOSManager { + wifi_backend: WifiBackend, wifi_debug_mode: WifiDebugMode, // Whether we should use trace-cmd or not. // True on galileo devices, false otherwise @@ -64,6 +69,7 @@ pub struct SteamOSManager { impl SteamOSManager { pub async fn new() -> Result { Ok(SteamOSManager { + wifi_backend: get_wifi_backend_from_conf().await?, wifi_debug_mode: WifiDebugMode::Off, should_trace: variant().await? == HardwareVariant::Galileo, }) @@ -263,6 +269,35 @@ impl SteamOSManager { self.wifi_debug_mode as u32 } + /// WifiBackend property. + #[zbus(property)] + async fn wifi_backend(&self) -> u32 { + self.wifi_backend as u32 + } + + #[zbus(property)] + async fn set_wifi_backend(&mut self, backend: u32) -> zbus::fdo::Result<()> { + if self.wifi_debug_mode == WifiDebugMode::On { + return Err(zbus::fdo::Error::Failed(String::from( + "operation not supported when wifi_debug_mode=on", + ))); + } + let backend = match WifiBackend::try_from(backend) { + Ok(backend) => backend, + Err(e) => return Err(zbus::fdo::Error::InvalidArgs(e.to_string())), + }; + match set_wifi_backend(backend).await { + Ok(()) => { + self.wifi_backend = backend; + Ok(()) + } + Err(e) => { + error!("Setting wifi backend failed: {e}"); + Err(anyhow_to_zbus_fdo(e)) + } + } + } + async fn set_wifi_debug_mode( &mut self, mode: u32, @@ -271,6 +306,15 @@ impl SteamOSManager { // Set the wifi debug mode to mode, using an int for flexibility going forward but only // doing things on 0 or 1 for now // Return false on error + match get_wifi_backend_from_script().await { + Ok(WifiBackend::IWD) => (), + Ok(backend) => { + return Err(zbus::fdo::Error::Failed(format!( + "Setting wifi debug mode not supported when backend is {backend}", + ))); + } + Err(e) => return Err(anyhow_to_zbus_fdo(e)), + } let wanted_mode = match WifiDebugMode::try_from(mode) { Ok(mode) => mode, @@ -319,6 +363,12 @@ mod test { write(crate::path("/sys/class/dmi/id/board_name"), "Jupiter\n") .await .expect("write"); + create_dir_all(crate::path("/etc/NetworkManager/conf.d")) + .await + .expect("create_dir_all"); + write(crate::path("/etc/NetworkManager/conf.d/wifi_backend.conf"), "wifi.backend=iwd\n") + .await + .expect("write"); let manager = SteamOSManager::new().await.unwrap(); let connection = ConnectionBuilder::session() diff --git a/src/wifi.rs b/src/wifi.rs index 7882fbd..5ac9e4f 100644 --- a/src/wifi.rs +++ b/src/wifi.rs @@ -5,12 +5,14 @@ * SPDX-License-Identifier: MIT */ -use anyhow::{bail, ensure, Result}; +use anyhow::{bail, ensure, Error, Result}; use std::fmt; +use std::str::FromStr; use tokio::fs; use tracing::error; -use crate::process::{run_script, SYSTEMCTL_PATH}; +use crate::path; +use crate::process::{run_script, script_output, SYSTEMCTL_PATH}; const OVERRIDE_CONTENTS: &str = "[Service] ExecStart= @@ -26,6 +28,8 @@ const TRACE_CMD_PATH: &str = "/usr/bin/trace-cmd"; const MIN_BUFFER_SIZE: u32 = 100; +const WIFI_BACKEND_PATH: &str = "/etc/NetworkManager/conf.d/wifi_backend.conf"; + #[derive(PartialEq, Debug, Copy, Clone)] #[repr(u32)] pub enum WifiDebugMode { @@ -40,6 +44,13 @@ pub enum WifiPowerManagement { Enabled = 2, } +#[derive(PartialEq, Debug, Copy, Clone)] +#[repr(u32)] +pub enum WifiBackend { + IWD = 1, + WPASupplicant = 2, +} + impl TryFrom for WifiDebugMode { type Error = &'static str; fn try_from(v: u32) -> Result { @@ -80,6 +91,37 @@ impl fmt::Display for WifiPowerManagement { } } +impl TryFrom for WifiBackend { + type Error = &'static str; + fn try_from(v: u32) -> Result { + match v { + x if x == WifiBackend::IWD as u32 => Ok(WifiBackend::IWD), + x if x == WifiBackend::WPASupplicant as u32 => Ok(WifiBackend::WPASupplicant), + _ => Err("No enum match for WifiBackend value {v}"), + } + } +} + +impl FromStr for WifiBackend { + type Err = Error; + fn from_str(input: &str) -> Result { + Ok(match input { + "iwd" => WifiBackend::IWD, + "wpa_supplicant" => WifiBackend::WPASupplicant, + _ => bail!("Unknown backend"), + }) + } +} + +impl fmt::Display for WifiBackend { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + WifiBackend::IWD => write!(f, "iwd"), + WifiBackend::WPASupplicant => write!(f, "wpa_supplicant"), + } + } +} + pub async fn setup_iwd_config(want_override: bool) -> std::io::Result<()> { // Copy override.conf file into place or out of place depending // on install value @@ -181,3 +223,32 @@ pub async fn set_wifi_debug_mode( } Ok(()) } + +pub async fn get_wifi_backend_from_conf() -> Result { + let wifi_backend_contents = fs::read_to_string(path(WIFI_BACKEND_PATH)) + .await? + .trim() + .to_string(); + for line in wifi_backend_contents.lines() { + if line.starts_with("wifi.backend=") { + let backend = line.trim_start_matches("wifi.backend=").trim(); + return WifiBackend::from_str(backend); + } + } + + bail!("WiFi backend not found in config"); +} + +pub async fn get_wifi_backend_from_script() -> Result { + let result = script_output("/usr/bin/steamos-wifi-set-backend", &["--check"]).await?; + WifiBackend::from_str(result.trim()) +} + +pub async fn set_wifi_backend(backend: WifiBackend) -> Result<()> { + run_script( + "set wifi backend", + "/usr/bin/steamos-wifi-set-backend", + &[backend.to_string()], + ) + .await +}