about summary refs log tree commit diff
path: root/src/core/nm-l3-config-data.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2026-07-03 19:53:23 +0200
committerMichael Biebl <biebl@debian.org>2026-07-03 19:53:23 +0200
commitaa308069bebf2d5a3200728caa69a76137c03d8b (patch)
treec0ba2281e801c4720a0d8a5e5ee943688234f088 /src/core/nm-l3-config-data.c
parent0a4b2c29da4ccf259bbcea3298d15abebb94348f (diff)
parent537bfce2bda471c92caabd388589230200891509 (diff)
Update upstream source from tag 'upstream/1.58_rc1'
Update to upstream version '1.58~rc1'
with Debian dir 451489c9234e2b6b7c2f41ca6670287ea3ac3efd
Diffstat (limited to 'src/core/nm-l3-config-data.c')
-rw-r--r--src/core/nm-l3-config-data.c297
1 files changed, 271 insertions, 26 deletions
diff --git a/src/core/nm-l3-config-data.c b/src/core/nm-l3-config-data.c
index 7500337e..849da7f4 100644
--- a/src/core/nm-l3-config-data.c
+++ b/src/core/nm-l3-config-data.c
@@ -50,6 +50,9 @@ struct _NML3ConfigData {
         const NMPObject *best_default_route_x[2];
     };
 
+    struct in6_addr pref64_prefix;
+    guint32         pref64_plen;
+
     GArray *wins;
     GArray *nis_servers;
 
@@ -122,6 +125,19 @@ struct _NML3ConfigData {
     NMSettingConnectionDnsOverTls dns_over_tls;
     NMSettingConnectionDnssec     dnssec;
     NMUtilsIPv6IfaceId            ip6_token;
+    NMRefString                  *network_id;
+    NMSettingIp4ConfigClat        clat_config; /* this indicates the 'administrative' CLAT
+                                                * state, i.e. whether CLAT will be started
+                                                * once we receive a PREF64 */
+
+    /* The runtime CLAT state */
+    struct {
+        struct in6_addr ip6;
+        struct in6_addr pref64;
+        in_addr_t       ip4;
+        guint8          pref64_plen;
+        bool            enabled;
+    } clat_state;
 
     NML3ConfigDatFlags flags;
 
@@ -130,7 +146,8 @@ struct _NML3ConfigData {
     int ndisc_hop_limit_val;
 
     guint32 mtu;
-    guint32 ip6_mtu;
+    guint32 ip6_mtu_static; /* IPv6 MTU from the connection profile */
+    guint32 ip6_mtu_ra;     /* IPv6 MTU from Router Advertisement */
     guint32 ndisc_reachable_time_msec_val;
     guint32 ndisc_retrans_timer_msec_val;
 
@@ -167,6 +184,8 @@ struct _NML3ConfigData {
 
     bool routed_dns_4 : 1;
     bool routed_dns_6 : 1;
+
+    bool pref64_valid : 1;
 };
 
 /*****************************************************************************/
@@ -390,8 +409,11 @@ nm_l3_config_data_log(const NML3ConfigData *self,
            : "",
        !self->is_sealed ? ", not-sealed" : "");
 
-    if (self->mtu != 0 || self->ip6_mtu != 0) {
-        _L("mtu: %u, ip6-mtu: %u", self->mtu, self->ip6_mtu);
+    if (self->mtu != 0 || self->ip6_mtu_static != 0 || self->ip6_mtu_ra != 0) {
+        _L("mtu: %u, ip6-mtu-static: %u, ip6-mtu-ra %u",
+           self->mtu,
+           self->ip6_mtu_static,
+           self->ip6_mtu_ra);
     }
 
     for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
@@ -519,6 +541,27 @@ nm_l3_config_data_log(const NML3ConfigData *self,
                 _L("nis-domain: %s", self->nis_domain->str);
         }
 
+        if (!IS_IPv4) {
+            if (self->clat_config == NM_SETTING_IP4_CONFIG_CLAT_AUTO)
+                _L("clat-config: auto");
+            else if (self->clat_config == NM_SETTING_IP4_CONFIG_CLAT_FORCE)
+                _L("clat-config: force");
+
+            if (self->clat_state.enabled) {
+                _L("clat-state: ip4=%s/32, pref64=%s/%u, ip6=%s/64",
+                   nm_inet4_ntop(self->clat_state.ip4, sbuf + NM_INET_ADDRSTRLEN),
+                   nm_inet6_ntop(&self->clat_state.pref64, sbuf),
+                   self->clat_state.pref64_plen,
+                   nm_inet6_ntop(&self->clat_state.ip6, sbuf_addr));
+            }
+        }
+
+        if (!IS_IPv4 && self->pref64_valid) {
+            _L("pref64_prefix: %s/%d",
+               nm_utils_inet6_ntop(&self->pref64_prefix, sbuf_addr),
+               self->pref64_plen);
+        }
+
         if (self->dhcp_lease_x[IS_IPv4]) {
             gs_free NMUtilsNamedValue *options_free = NULL;
             NMUtilsNamedValue          options_buffer[30];
@@ -603,6 +646,10 @@ nm_l3_config_data_log(const NML3ConfigData *self,
            nm_utils_inet6_interface_identifier_to_token(&self->ip6_token, sbuf_addr));
     }
 
+    if (self->network_id) {
+        _L("network-id: %s", self->network_id->str);
+    }
+
     if (self->metered != NM_TERNARY_DEFAULT)
         _L("metered: %s", self->metered ? "yes" : "no");
 
@@ -709,6 +756,7 @@ nm_l3_config_data_new(NMDedupMultiIndex *multi_idx, int ifindex, NMIPConfigSourc
         .flags                          = NM_L3_CONFIG_DAT_FLAGS_NONE,
         .metered                        = NM_TERNARY_DEFAULT,
         .proxy_browser_only             = NM_TERNARY_DEFAULT,
+        .clat_config                    = NM_SETTING_IP4_CONFIG_CLAT_NO,
         .proxy_method                   = NM_PROXY_CONFIG_METHOD_UNKNOWN,
         .route_table_sync_4             = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE,
         .route_table_sync_6             = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE,
@@ -722,6 +770,7 @@ nm_l3_config_data_new(NMDedupMultiIndex *multi_idx, int ifindex, NMIPConfigSourc
         .ndisc_retrans_timer_msec_set   = FALSE,
         .allow_routes_without_address_4 = TRUE,
         .allow_routes_without_address_6 = TRUE,
+        .pref64_valid                   = FALSE,
     };
 
     _idx_type_init(&self->idx_addresses_4, NMP_OBJECT_TYPE_IP4_ADDRESS);
@@ -822,6 +871,7 @@ nm_l3_config_data_unref(const NML3ConfigData *self)
     nm_ref_string_unref(mutable->nis_domain);
     nm_ref_string_unref(mutable->proxy_pac_url);
     nm_ref_string_unref(mutable->proxy_pac_script);
+    nm_ref_string_unref(mutable->network_id);
 
     nm_g_slice_free(mutable);
 }
@@ -1890,22 +1940,42 @@ nm_l3_config_data_set_mtu(NML3ConfigData *self, guint32 mtu)
 }
 
 guint32
-nm_l3_config_data_get_ip6_mtu(const NML3ConfigData *self)
+nm_l3_config_data_get_ip6_mtu_static(const NML3ConfigData *self)
+{
+    nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
+
+    return self->ip6_mtu_static;
+}
+
+gboolean
+nm_l3_config_data_set_ip6_mtu_static(NML3ConfigData *self, guint32 ip6_mtu)
+{
+    nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
+
+    if (self->ip6_mtu_static == ip6_mtu)
+        return FALSE;
+
+    self->ip6_mtu_static = ip6_mtu;
+    return TRUE;
+}
+
+guint32
+nm_l3_config_data_get_ip6_mtu_ra(const NML3ConfigData *self)
 {
     nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
 
-    return self->ip6_mtu;
+    return self->ip6_mtu_ra;
 }
 
 gboolean
-nm_l3_config_data_set_ip6_mtu(NML3ConfigData *self, guint32 ip6_mtu)
+nm_l3_config_data_set_ip6_mtu_ra(NML3ConfigData *self, guint32 ip6_mtu)
 {
     nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
 
-    if (self->ip6_mtu == ip6_mtu)
+    if (self->ip6_mtu_ra == ip6_mtu)
         return FALSE;
 
-    self->ip6_mtu = ip6_mtu;
+    self->ip6_mtu_ra = ip6_mtu;
     return TRUE;
 }
 
@@ -1957,6 +2027,132 @@ nm_l3_config_data_set_ip6_token(NML3ConfigData *self, NMUtilsIPv6IfaceId ipv6_to
     return TRUE;
 }
 
+const char *
+nm_l3_config_data_get_network_id(const NML3ConfigData *self)
+{
+    nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
+
+    return nm_ref_string_get_str(self->network_id);
+}
+
+gboolean
+nm_l3_config_data_set_network_id(NML3ConfigData *self, const char *value)
+{
+    nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
+
+    return nm_ref_string_reset_str(&self->network_id, value);
+}
+
+gboolean
+nm_l3_config_data_set_clat_config(NML3ConfigData *self, NMSettingIp4ConfigClat val)
+{
+    nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
+    nm_assert(NM_IN_SET(val,
+                        NM_SETTING_IP4_CONFIG_CLAT_NO,
+                        NM_SETTING_IP4_CONFIG_CLAT_FORCE,
+                        NM_SETTING_IP4_CONFIG_CLAT_AUTO));
+
+    if (self->clat_config == val)
+        return FALSE;
+    self->clat_config = val;
+    return TRUE;
+}
+
+NMSettingIp4ConfigClat
+nm_l3_config_data_get_clat_config(const NML3ConfigData *self)
+{
+    nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
+
+    return self->clat_config;
+}
+
+gboolean
+nm_l3_config_data_get_clat_state(const NML3ConfigData *self,
+                                 struct in6_addr      *out_ip6,
+                                 struct in6_addr      *out_pref64,
+                                 guint8               *out_pref64_plen,
+                                 in_addr_t            *out_ip4)
+{
+    if (!self || !self->clat_state.enabled)
+        return FALSE;
+    NM_SET_OUT(out_ip6, self->clat_state.ip6);
+    NM_SET_OUT(out_pref64, self->clat_state.pref64);
+    NM_SET_OUT(out_pref64_plen, self->clat_state.pref64_plen);
+    NM_SET_OUT(out_ip4, self->clat_state.ip4);
+    return TRUE;
+}
+
+void
+nm_l3_config_data_set_clat_state(NML3ConfigData        *self,
+                                 gboolean               enabled,
+                                 const struct in6_addr *ip6,
+                                 const struct in6_addr *pref64,
+                                 guint8                 pref64_plen,
+                                 in_addr_t              ip4)
+{
+    nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
+
+    self->clat_state.enabled = enabled;
+    if (enabled) {
+        self->clat_state.ip6         = *ip6;
+        self->clat_state.pref64      = *pref64;
+        self->clat_state.pref64_plen = pref64_plen;
+        self->clat_state.ip4         = ip4;
+    } else {
+        self->clat_state.ip6         = in6addr_any;
+        self->clat_state.pref64      = in6addr_any;
+        self->clat_state.pref64_plen = 0;
+        self->clat_state.ip4         = 0;
+    }
+}
+
+gboolean
+nm_l3_config_data_set_pref64_valid(NML3ConfigData *self, gboolean val)
+{
+    if (self->pref64_valid == val)
+        return FALSE;
+    self->pref64_valid = val;
+    return TRUE;
+}
+
+gboolean
+nm_l3_config_data_get_pref64_valid(const NML3ConfigData *self)
+{
+    nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
+
+    return self->pref64_valid;
+}
+
+gboolean
+nm_l3_config_data_get_pref64(const NML3ConfigData *self,
+                             struct in6_addr      *out_prefix,
+                             guint32              *out_plen)
+{
+    nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
+
+    if (!self->pref64_valid)
+        return FALSE;
+    NM_SET_OUT(out_prefix, self->pref64_prefix);
+    NM_SET_OUT(out_plen, self->pref64_plen);
+    return TRUE;
+}
+
+gboolean
+nm_l3_config_data_set_pref64(NML3ConfigData *self, struct in6_addr prefix, guint32 plen)
+{
+    if (self->pref64_valid) {
+        if (self->pref64_plen == plen
+            && nm_ip6_addr_same_prefix(&self->pref64_prefix, &prefix, plen)) {
+            return FALSE;
+        }
+    } else {
+        self->pref64_valid = TRUE;
+    }
+    self->pref64_prefix = prefix;
+    self->pref64_plen   = plen;
+    return TRUE;
+}
+
 NMMptcpFlags
 nm_l3_config_data_get_mptcp_flags(const NML3ConfigData *self)
 {
@@ -2294,8 +2490,8 @@ _dedup_multi_index_cmp(const NML3ConfigData *a,
             switch (obj_type) {
             case NMP_OBJECT_TYPE_IP4_ADDRESS:
                 NM_CMP_DIRECT(obj_a->ip4_address.plen, obj_b->ip4_address.plen);
-                NM_CMP_DIRECT(obj_b->ip4_address.address, obj_b->ip4_address.address);
-                NM_CMP_DIRECT(obj_b->ip4_address.peer_address, obj_b->ip4_address.peer_address);
+                NM_CMP_DIRECT(obj_a->ip4_address.address, obj_b->ip4_address.address);
+                NM_CMP_DIRECT(obj_a->ip4_address.peer_address, obj_b->ip4_address.peer_address);
                 break;
             case NMP_OBJECT_TYPE_IP6_ADDRESS:
                 NM_CMP_DIRECT(obj_a->ip6_address.plen, obj_b->ip6_address.plen);
@@ -2408,15 +2604,15 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a,
         const NMPObject *def_route_a = a->best_default_route_x[IS_IPv4];
         const NMPObject *def_route_b = b->best_default_route_x[IS_IPv4];
 
-        if (def_route_a != def_route_b) {
-            if (NM_FLAGS_HAS(flags, NM_L3_CONFIG_CMP_FLAGS_ROUTES)) {
-                NM_CMP_RETURN(
-                    nmp_object_cmp_full(def_route_a,
-                                        def_route_b,
-                                        NM_FLAGS_HAS(flags, NM_L3_CONFIG_CMP_FLAGS_IFINDEX)
-                                            ? NMP_OBJECT_CMP_FLAGS_NONE
-                                            : NMP_OBJECT_CMP_FLAGS_IGNORE_IFINDEX));
-            } else if (NM_FLAGS_HAS(flags, NM_L3_CONFIG_CMP_FLAGS_ROUTES_ID)) {
+        if (NM_FLAGS_HAS(flags, NM_L3_CONFIG_CMP_FLAGS_ROUTES)) {
+            NM_CMP_RETURN(nmp_object_cmp_full(def_route_a,
+                                              def_route_b,
+                                              NM_FLAGS_HAS(flags, NM_L3_CONFIG_CMP_FLAGS_IFINDEX)
+                                                  ? NMP_OBJECT_CMP_FLAGS_NONE
+                                                  : NMP_OBJECT_CMP_FLAGS_IGNORE_IFINDEX));
+        } else if (NM_FLAGS_HAS(flags, NM_L3_CONFIG_CMP_FLAGS_ROUTES_ID)) {
+            NM_CMP_DIRECT(!!def_route_a, !!def_route_b);
+            if (def_route_a && def_route_b) {
                 if (NM_FLAGS_HAS(flags, NM_L3_CONFIG_CMP_FLAGS_IFINDEX)) {
                     NM_CMP_DIRECT(def_route_a->obj_with_ifindex.ifindex,
                                   def_route_b->obj_with_ifindex.ifindex);
@@ -2484,8 +2680,10 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a,
     if (NM_FLAGS_HAS(flags, NM_L3_CONFIG_CMP_FLAGS_OTHER)) {
         NM_CMP_DIRECT(a->flags, b->flags);
         NM_CMP_DIRECT(a->ip6_token.id, b->ip6_token.id);
+        NM_CMP_DIRECT_REF_STRING(a->network_id, b->network_id);
         NM_CMP_DIRECT(a->mtu, b->mtu);
-        NM_CMP_DIRECT(a->ip6_mtu, b->ip6_mtu);
+        NM_CMP_DIRECT(a->ip6_mtu_static, b->ip6_mtu_static);
+        NM_CMP_DIRECT(a->ip6_mtu_ra, b->ip6_mtu_ra);
         NM_CMP_DIRECT_UNSAFE(a->metered, b->metered);
         NM_CMP_DIRECT_UNSAFE(a->proxy_browser_only, b->proxy_browser_only);
         NM_CMP_DIRECT_UNSAFE(a->proxy_method, b->proxy_method);
@@ -2509,6 +2707,23 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a,
         NM_CMP_DIRECT_UNSAFE(a->routed_dns_4, b->routed_dns_4);
         NM_CMP_DIRECT_UNSAFE(a->routed_dns_6, b->routed_dns_6);
 
+        NM_CMP_DIRECT_UNSAFE(a->clat_config, b->clat_config);
+
+        NM_CMP_DIRECT(!!a->clat_state.enabled, !!b->clat_state.enabled);
+        if (a->clat_state.enabled) {
+            NM_CMP_DIRECT_IN6ADDR(&a->clat_state.ip6, &b->clat_state.ip6);
+            NM_CMP_DIRECT_IN6ADDR(&a->clat_state.pref64, &b->clat_state.pref64);
+            NM_CMP_DIRECT(a->clat_state.pref64_plen, b->clat_state.pref64_plen);
+            NM_CMP_DIRECT(a->clat_state.ip4, b->clat_state.ip4);
+        }
+
+        NM_CMP_DIRECT(!!a->pref64_valid, !!b->pref64_valid);
+        if (a->pref64_valid) {
+            NM_CMP_DIRECT(a->pref64_plen, b->pref64_plen);
+            NM_CMP_RETURN_DIRECT(
+                nm_ip6_addr_same_prefix_cmp(&a->pref64_prefix, &b->pref64_prefix, a->pref64_plen));
+        }
+
         NM_CMP_FIELD(a, b, source);
     }
 
@@ -2524,8 +2739,10 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a,
 
 /*****************************************************************************/
 
-static const NMPObject *
-_data_get_direct_route_for_host(const NML3ConfigData *self, int addr_family, gconstpointer host)
+const NMPObject *
+nm_l3_config_data_get_direct_route_for_host(const NML3ConfigData *self,
+                                            int                   addr_family,
+                                            gconstpointer         host)
 {
     const int                 IS_IPv4        = NM_IS_IPv4(addr_family);
     const NMPObject          *best_route_obj = NULL;
@@ -2556,7 +2773,8 @@ _data_get_direct_route_for_host(const NML3ConfigData *self, int addr_family, gco
         if (!nm_ip_addr_same_prefix(addr_family, host, item->rx.network_ptr, item->rx.plen))
             continue;
 
-        if (best_route && best_route->rx.metric <= item->rx.metric)
+        if (best_route && best_route->rx.plen == item->rx.plen
+            && best_route->rx.metric <= item->rx.metric)
             continue;
 
         best_route_obj = item_obj;
@@ -2683,7 +2901,7 @@ nm_l3_config_data_add_dependent_onlink_routes(NML3ConfigData *self, int addr_fam
         if (NM_FLAGS_HAS(route_src->rx.r_rtm_flags, (unsigned) RTNH_F_ONLINK))
             continue;
 
-        if (_data_get_direct_route_for_host(self, addr_family, p_gateway))
+        if (nm_l3_config_data_get_direct_route_for_host(self, addr_family, p_gateway))
             continue;
 
         new_route = nmp_object_clone(obj_src, FALSE);
@@ -3027,6 +3245,9 @@ _init_from_connection_ip(NML3ConfigData *self, int addr_family, NMConnection *co
         nm_l3_config_data_set_ip6_privacy(
             self,
             nm_setting_ip6_config_get_ip6_privacy(NM_SETTING_IP6_CONFIG(s_ip)));
+        nm_l3_config_data_set_ip6_mtu_static(
+            self,
+            nm_setting_ip6_config_get_mtu(NM_SETTING_IP6_CONFIG(s_ip)));
     }
 }
 
@@ -3503,6 +3724,9 @@ nm_l3_config_data_merge(NML3ConfigData       *self,
     if (self->ip6_token.id == 0)
         self->ip6_token.id = src->ip6_token.id;
 
+    if (!self->network_id)
+        self->network_id = nm_ref_string_ref(src->network_id);
+
     self->metered = NM_MAX((NMTernary) self->metered, (NMTernary) src->metered);
 
     if (self->proxy_method == NM_PROXY_CONFIG_METHOD_UNKNOWN)
@@ -3541,8 +3765,11 @@ nm_l3_config_data_merge(NML3ConfigData       *self,
     if (self->mtu == 0u)
         self->mtu = src->mtu;
 
-    if (self->ip6_mtu == 0u)
-        self->ip6_mtu = src->ip6_mtu;
+    if (self->ip6_mtu_static == 0u)
+        self->ip6_mtu_static = src->ip6_mtu_static;
+
+    if (self->ip6_mtu_ra == 0u)
+        self->ip6_mtu_ra = src->ip6_mtu_ra;
 
     if (NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_CLONE)) {
         _nm_unused nm_auto_unref_dhcplease NMDhcpLease *dhcp_lease_6 =
@@ -3564,6 +3791,24 @@ nm_l3_config_data_merge(NML3ConfigData       *self,
         self->routed_dns_4 = TRUE;
     if (src->routed_dns_6)
         self->routed_dns_6 = TRUE;
+
+    if (self->clat_config == NM_SETTING_IP4_CONFIG_CLAT_NO) {
+        /* 'no' always loses to 'force' and 'auto' */
+        self->clat_config = src->clat_config;
+    } else if (src->clat_config == NM_SETTING_IP4_CONFIG_CLAT_FORCE) {
+        /* 'force' always takes precedence */
+        self->clat_config = src->clat_config;
+    }
+
+    if (!self->clat_state.enabled && src->clat_state.enabled) {
+        self->clat_state = src->clat_state;
+    }
+
+    if (src->pref64_valid) {
+        self->pref64_prefix = src->pref64_prefix;
+        self->pref64_plen   = src->pref64_plen;
+        self->pref64_valid  = src->pref64_valid;
+    }
 }
 
 NML3ConfigData *