Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more wireless options to network model #1014

Merged
merged 6 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions rust/agama-dbus-server/src/network/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ pub enum NetworkStateError {
NotControllerConnection(String),
#[error("Unexpected configuration")]
UnexpectedConfiguration,
#[error("Invalid WEP authentication algorithm: '{0}'")]
InvalidWEPAuthAlg(String),
#[error("Invalid WEP key type: '{0}'")]
InvalidWEPKeyType(u32),
}

impl From<NetworkStateError> for zbus::fdo::Error {
Expand Down
96 changes: 96 additions & 0 deletions rust/agama-dbus-server/src/network/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,10 @@ pub struct WirelessConfig {
pub ssid: SSID,
pub password: Option<String>,
pub security: SecurityProtocol,
pub band: Option<WirelessBand>,
pub channel: Option<u32>,
pub bssid: Option<macaddr::MacAddr6>,
pub wep_security: Option<WEPSecurity>,
}

impl TryFrom<ConnectionConfig> for WirelessConfig {
Expand Down Expand Up @@ -837,6 +841,98 @@ impl TryFrom<&str> for SecurityProtocol {
}
}

#[derive(Debug, Default, PartialEq, Clone)]
pub struct WEPSecurity {
pub auth_alg: WEPAuthAlg,
pub wep_key_type: WEPKeyType,
pub keys: Vec<String>,
pub wep_key_index: u32,
}

#[derive(Debug, Default, PartialEq, Clone)]
pub enum WEPKeyType {
#[default]
Unknown = 0,
Key = 1,
Passphrase = 2,
}

impl TryFrom<u32> for WEPKeyType {
type Error = NetworkStateError;

fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
0 => Ok(WEPKeyType::Unknown),
1 => Ok(WEPKeyType::Key),
2 => Ok(WEPKeyType::Passphrase),
_ => Err(NetworkStateError::InvalidWEPKeyType(value)),
}
}
}

#[derive(Debug, Default, PartialEq, Clone)]
pub enum WEPAuthAlg {
#[default]
Unset,
Open,
Shared,
Leap,
}

impl TryFrom<&str> for WEPAuthAlg {
type Error = NetworkStateError;

fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"open" => Ok(WEPAuthAlg::Open),
"shared" => Ok(WEPAuthAlg::Shared),
"leap" => Ok(WEPAuthAlg::Leap),
"" => Ok(WEPAuthAlg::Unset),
_ => Err(NetworkStateError::InvalidWEPAuthAlg(value.to_string())),
}
}
}

impl fmt::Display for WEPAuthAlg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match &self {
WEPAuthAlg::Open => "open",
WEPAuthAlg::Shared => "shared",
WEPAuthAlg::Leap => "shared",
WEPAuthAlg::Unset => "",
};
write!(f, "{}", name)
}
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum WirelessBand {
A, // 5GHz
BG, // 2.4GHz
}

impl fmt::Display for WirelessBand {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let value = match &self {
WirelessBand::A => "a",
WirelessBand::BG => "bg",
};
write!(f, "{}", value)
}
}

impl TryFrom<&str> for WirelessBand {
type Error = anyhow::Error;

fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"a" => Ok(WirelessBand::A),
"bg" => Ok(WirelessBand::BG),
_ => Err(anyhow::anyhow!("Invalid band: {}", value)),
}
}
}

#[derive(Debug, Default, Clone, PartialEq)]
pub struct BondOptions(pub HashMap<String, String>);

Expand Down
167 changes: 163 additions & 4 deletions rust/agama-dbus-server/src/network/nm/dbus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use agama_lib::{
network::types::{BondMode, SSID},
};
use cidr::IpInet;
use macaddr::MacAddr6;
use std::{collections::HashMap, net::IpAddr, str::FromStr};
use uuid::Uuid;
use zbus::zvariant::{self, OwnedValue, Value};
Expand Down Expand Up @@ -321,18 +322,53 @@ fn wireless_config_to_dbus<'a>(
config: &'a WirelessConfig,
mac_address: &MacAddress,
) -> NestedHash<'a> {
let wireless: HashMap<&str, zvariant::Value> = HashMap::from([
let mut wireless: HashMap<&str, zvariant::Value> = HashMap::from([
("mode", Value::new(config.mode.to_string())),
("ssid", Value::new(config.ssid.to_vec())),
("assigned-mac-address", Value::new(mac_address.to_string())),
]);

if let Some(band) = &config.band {
wireless.insert("band", band.to_string().into());
if let Some(channel) = config.channel {
wireless.insert("channel", channel.into());
}
}
if let Some(bssid) = &config.bssid {
wireless.insert("bssid", bssid.as_bytes().into());
}

let mut security: HashMap<&str, zvariant::Value> =
HashMap::from([("key-mgmt", config.security.to_string().into())]);

if let Some(password) = &config.password {
security.insert("psk", password.to_string().into());
}
if let Some(wep_security) = &config.wep_security {
security.insert(
"wep-key-type",
(wep_security.wep_key_type.clone() as u32).into(),
);
security.insert("auth-alg", wep_security.auth_alg.to_string().into());
for (i, wep_key) in wep_security.keys.clone().into_iter().enumerate() {
security.insert(
// FIXME: lifetimes are fun
if i == 0 {
"wep-key0"
} else if i == 1 {
"wep-key1"
} else if i == 2 {
"wep-key2"
} else if i == 3 {
"wep-key3"
} else {
break;
},
wep_key.into(),
);
}
security.insert("wep-tx-keyidx", wep_security.wep_key_index.into());
}

NestedHash::from([(WIRELESS_KEY, wireless), (WIRELESS_SECURITY_KEY, security)])
}
Expand Down Expand Up @@ -668,9 +704,51 @@ fn wireless_config_from_dbus(conn: &OwnedNestedHash) -> Option<WirelessConfig> {
..Default::default()
};

if let Some(band) = wireless.get("band") {
wireless_config.band = Some(band.downcast_ref::<str>()?.try_into().ok()?)
}
if let Some(channel) = wireless.get("channel") {
wireless_config.channel = Some(*channel.downcast_ref()?);
}
if let Some(bssid) = wireless.get("bssid") {
let bssid: &zvariant::Array = bssid.downcast_ref()?;
let bssid: Vec<u8> = bssid
.get()
.iter()
.map(|u| *u.downcast_ref::<u8>().unwrap())
.collect();
wireless_config.bssid = Some(MacAddr6::new(
*bssid.first()?,
*bssid.get(1)?,
*bssid.get(2)?,
*bssid.get(3)?,
*bssid.get(4)?,
*bssid.get(5)?,
));
}

if let Some(security) = conn.get(WIRELESS_SECURITY_KEY) {
let key_mgmt: &str = security.get("key-mgmt")?.downcast_ref()?;
wireless_config.security = NmKeyManagement(key_mgmt.to_string()).try_into().ok()?;

let wep_key_type = security
.get("wep-key-type")
.and_then(|alg| WEPKeyType::try_from(*alg.downcast_ref::<u32>()?).ok())
.unwrap_or_default();
let auth_alg = security
.get("auth-alg")
.and_then(|alg| WEPAuthAlg::try_from(alg.downcast_ref()?).ok())
.unwrap_or_default();
let wep_key_index = security
.get("wep-tx-keyidx")
.and_then(|idx| idx.downcast_ref::<u32>().cloned())
.unwrap_or_default();
wireless_config.wep_security = Some(WEPSecurity {
wep_key_type,
auth_alg,
wep_key_index,
..Default::default()
});
}

Some(wireless_config)
Expand Down Expand Up @@ -917,10 +995,23 @@ mod test {
"assigned-mac-address".to_string(),
Value::new("13:45:67:89:AB:CD").to_owned(),
),
("band".to_string(), Value::new("a").to_owned()),
("channel".to_string(), Value::new(32_u32).to_owned()),
(
"bssid".to_string(),
Value::new(vec![18_u8, 52_u8, 86_u8, 120_u8, 154_u8, 188_u8]).to_owned(),
),
]);

let security_section =
HashMap::from([("key-mgmt".to_string(), Value::new("wpa-psk").to_owned())]);
let security_section = HashMap::from([
("key-mgmt".to_string(), Value::new("wpa-psk").to_owned()),
(
"wep-key-type".to_string(),
Value::new(WEPKeyType::Key as u32).to_owned(),
),
("auth-alg".to_string(), Value::new("open").to_owned()),
("wep-tx-keyidx".to_string(), Value::new(1_u32).to_owned()),
]);

let dbus_conn = HashMap::from([
("connection".to_string(), connection_section),
Expand All @@ -934,7 +1025,17 @@ mod test {
if let ConnectionConfig::Wireless(wireless) = &connection.config {
assert_eq!(wireless.ssid, SSID(vec![97, 103, 97, 109, 97]));
assert_eq!(wireless.mode, WirelessMode::Infra);
assert_eq!(wireless.security, SecurityProtocol::WPA2)
assert_eq!(wireless.security, SecurityProtocol::WPA2);
assert_eq!(wireless.band, Some(WirelessBand::A));
assert_eq!(wireless.channel, Some(32_u32));
assert_eq!(
wireless.bssid,
Some(macaddr::MacAddr6::from_str("12:34:56:78:9A:BC").unwrap())
);
let wep_security = wireless.wep_security.as_ref().unwrap();
assert_eq!(wep_security.wep_key_type, WEPKeyType::Key);
assert_eq!(wep_security.auth_alg, WEPAuthAlg::Open);
assert_eq!(wep_security.wep_key_index, 1);
}
}

Expand Down Expand Up @@ -967,7 +1068,20 @@ mod test {
let config = WirelessConfig {
mode: WirelessMode::Infra,
security: SecurityProtocol::WPA2,
password: Some("wpa-password".to_string()),
ssid: SSID(vec![97, 103, 97, 109, 97]),
band: Some(WirelessBand::BG),
channel: Some(10),
bssid: Some(macaddr::MacAddr6::from_str("12:34:56:78:9A:BC").unwrap()),
wep_security: Some(WEPSecurity {
auth_alg: WEPAuthAlg::Open,
wep_key_type: WEPKeyType::Key,
wep_key_index: 1,
keys: vec![
"5b73215e232f4c577c5073455d".to_string(),
"hello".to_string(),
],
}),
..Default::default()
};
let mut wireless = build_base_connection();
Expand All @@ -992,9 +1106,54 @@ mod test {
.collect();
assert_eq!(ssid, "agama".as_bytes());

let band: &str = wireless.get("band").unwrap().downcast_ref().unwrap();
assert_eq!(band, "bg");

let channel: u32 = *wireless.get("channel").unwrap().downcast_ref().unwrap();
assert_eq!(channel, 10);

let bssid: &zvariant::Array = wireless.get("bssid").unwrap().downcast_ref().unwrap();
let bssid: Vec<u8> = bssid
.get()
.iter()
.map(|u| *u.downcast_ref::<u8>().unwrap())
.collect();
assert_eq!(bssid, vec![18, 52, 86, 120, 154, 188]);

let security = wireless_dbus.get(WIRELESS_SECURITY_KEY).unwrap();
let key_mgmt: &str = security.get("key-mgmt").unwrap().downcast_ref().unwrap();
assert_eq!(key_mgmt, "wpa-psk");

let password: &str = security.get("psk").unwrap().downcast_ref().unwrap();
assert_eq!(password, "wpa-password");

let auth_alg: WEPAuthAlg = security
.get("auth-alg")
.unwrap()
.downcast_ref::<str>()
.unwrap()
.try_into()
.unwrap();
assert_eq!(auth_alg, WEPAuthAlg::Open);

let wep_key_type: u32 = *security
.get("wep-key-type")
.unwrap()
.downcast_ref::<u32>()
.unwrap();
assert_eq!(wep_key_type, WEPKeyType::Key as u32);

let wep_key_index: u32 = *security
.get("wep-tx-keyidx")
.unwrap()
.downcast_ref()
.unwrap();
assert_eq!(wep_key_index, 1);

let wep_key0: &str = security.get("wep-key0").unwrap().downcast_ref().unwrap();
assert_eq!(wep_key0, "5b73215e232f4c577c5073455d");
let wep_key1: &str = security.get("wep-key1").unwrap().downcast_ref().unwrap();
assert_eq!(wep_key1, "hello");
}

#[test]
Expand Down
6 changes: 6 additions & 0 deletions rust/package/agama-cli.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
-------------------------------------------------------------------
Mon Jan 29 10:22:49 UTC 2024 - Jorik Cronenberg <jorik.cronenberg@suse.com>

- Add more wireless options to network model
(gh#openSUSE/agama#1014).

-------------------------------------------------------------------
Thu Jan 23 18:00:00 UTC 2024 - Clemens Famulla-Conrad <cfamullaconrad@suse.de>

Expand Down