Skip to content

Commit

Permalink
Add more wireless options to network model (#1014)
Browse files Browse the repository at this point in the history
## Problem

For the migration there are a few wireless options that yast2lan has
that are missing in agama.

## Solution

Add the missing options.

## Testing

- *Added new unit tests*
- *Tested manually*
- *Tested with the migration:
jcronenberg#69
  • Loading branch information
imobachgs authored Jan 29, 2024
2 parents df521d7 + 2489a9a commit 709f9aa
Show file tree
Hide file tree
Showing 4 changed files with 269 additions and 4 deletions.
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 <[email protected]>

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

-------------------------------------------------------------------
Thu Jan 23 18:00:00 UTC 2024 - Clemens Famulla-Conrad <[email protected]>

Expand Down

0 comments on commit 709f9aa

Please sign in to comment.