diff --git a/rust/agama-network/src/model.rs b/rust/agama-network/src/model.rs index e5a2eb28ed..30bf944fcd 100644 --- a/rust/agama-network/src/model.rs +++ b/rust/agama-network/src/model.rs @@ -871,6 +871,36 @@ impl From for zbus::fdo::Error { } } +#[derive(Debug, Default, Copy, Clone, PartialEq, Deserialize, Serialize, utoipa::ToSchema)] +#[serde(rename_all = "camelCase")] +pub enum LinkLocal { + #[default] + Default = 0, + Auto = 1, + Disabled = 2, + Enabled = 3, + Fallback = 4, +} + +#[derive(Debug, Error)] +#[error("Invalid link-local value: {0}")] +pub struct InvalidLinkLocalValue(i32); + +impl TryFrom for LinkLocal { + type Error = InvalidLinkLocalValue; + + fn try_from(value: i32) -> Result { + match value { + 0 => Ok(LinkLocal::Default), + 1 => Ok(LinkLocal::Auto), + 2 => Ok(LinkLocal::Disabled), + 3 => Ok(LinkLocal::Enabled), + 4 => Ok(LinkLocal::Fallback), + _ => Err(InvalidLinkLocalValue(value)), + } + } +} + #[skip_serializing_none] #[derive(Default, Debug, PartialEq, Clone, Deserialize, Serialize, utoipa::ToSchema)] #[serde(rename_all = "camelCase")] @@ -899,6 +929,7 @@ pub struct IpConfig { pub ip6_privacy: Option, pub dns_priority4: Option, pub dns_priority6: Option, + pub link_local4: LinkLocal, } #[skip_serializing_none] diff --git a/rust/agama-network/src/nm/dbus.rs b/rust/agama-network/src/nm/dbus.rs index c983180840..7d80844c8d 100644 --- a/rust/agama-network/src/nm/dbus.rs +++ b/rust/agama-network/src/nm/dbus.rs @@ -434,12 +434,21 @@ fn ip_config_to_ipv4_dbus<'a>( .collect::>() .into(); + let link_local = if ip_config.link_local4 == LinkLocal::Fallback + && VersionReq::parse("<1.52.0").unwrap().matches(nm_version) + { + LinkLocal::Enabled + } else { + ip_config.link_local4 + }; + let mut ipv4_dbus = HashMap::from([ ("address-data", address_data), ("dns-data", dns_data), ("dns-search", ip_config.dns_searchlist.clone().into()), ("ignore-auto-dns", ip_config.ignore_auto_dns.into()), ("method", ip_config.method4.to_string().into()), + ("link-local", (link_local as i32).into()), ]); if !ip_config.routes4.is_empty() { @@ -1081,6 +1090,10 @@ fn ip_config_from_dbus(conn: &OwnedNestedHash) -> Result { ip_config.dns_priority4 = Some(dns_priority4); } + if let Some(link_local4) = get_optional_property::(ipv4, "link-local")? { + ip_config.link_local4 = link_local4.try_into().unwrap_or_default(); + } + let mut dhcp4_settings = Dhcp4Settings::default(); if let Some(dhcp_send_hostname) = get_optional_property(ipv4, "dhcp-send-hostname-v2")? { dhcp4_settings.send_hostname = match dhcp_send_hostname { diff --git a/rust/agama-server/src/web/docs/network.rs b/rust/agama-server/src/web/docs/network.rs index 26661f41fe..f642d99f3d 100644 --- a/rust/agama-server/src/web/docs/network.rs +++ b/rust/agama-server/src/web/docs/network.rs @@ -110,6 +110,7 @@ impl ApiDocBuilder for NetworkApiDocBuilder { .schema_from::() .schema_from::() .schema_from::() + .schema_from::() .schema_from::() .schema("IpAddr", schemas::ip_addr()) .schema("IpInet", schemas::ip_inet()) diff --git a/rust/package/agama.changes b/rust/package/agama.changes index d4db15b611..0fd20aa741 100644 --- a/rust/package/agama.changes +++ b/rust/package/agama.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Tue Oct 7 09:55:46 UTC 2025 - Clemens Famulla-Conrad + +- Add IpConfig.link_local4 to specify ZeroConf/AutoIP behavior. + (gh#agama-project/agama#2792). + ------------------------------------------------------------------- Wed Oct 1 13:45:23 UTC 2025 - Ladislav Slezák