about summary refs log tree commit diff
path: root/src/libnm-core-impl
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2022-10-04 00:56:46 +0200
committerMichael Biebl <biebl@debian.org>2022-10-04 00:56:46 +0200
commit3612e6355f3f40d264ec4657547761069baa5430 (patch)
tree768e4f5b37b66f540dd7030aa2eaff2ac7bb0168 /src/libnm-core-impl
parent7e9f00a3be8f65535e6620b344443ec4d403212b (diff)
parent6f7fcde10e47d8af865af336becf1fd8a446e62e (diff)
Merge tag 'debian/1.40.0-1' into debian/bullseye-backports
network-manager Debian release 1.40.0-1
Diffstat (limited to 'src/libnm-core-impl')
-rw-r--r--src/libnm-core-impl/nm-connection.c18
-rw-r--r--src/libnm-core-impl/nm-keyfile-utils.c6
-rw-r--r--src/libnm-core-impl/nm-keyfile.c44
-rw-r--r--src/libnm-core-impl/nm-setting-8021x.c4
-rw-r--r--src/libnm-core-impl/nm-setting-bond.c42
-rw-r--r--src/libnm-core-impl/nm-setting-bridge.c11
-rw-r--r--src/libnm-core-impl/nm-setting-connection.c218
-rw-r--r--src/libnm-core-impl/nm-setting-ethtool.c4
-rw-r--r--src/libnm-core-impl/nm-setting-ip-config.c46
-rw-r--r--src/libnm-core-impl/nm-setting-ip4-config.c115
-rw-r--r--src/libnm-core-impl/nm-setting-ip6-config.c101
-rw-r--r--src/libnm-core-impl/nm-setting-wireguard.c5
-rw-r--r--src/libnm-core-impl/nm-setting-wireless.c12
-rw-r--r--src/libnm-core-impl/nm-team-utils.c4
-rw-r--r--src/libnm-core-impl/nm-utils.c21
-rw-r--r--src/libnm-core-impl/tests/test-general.c256
-rw-r--r--src/libnm-core-impl/tests/test-setting.c10
17 files changed, 765 insertions, 152 deletions
diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c
index 27cea2cb..aed4be21 100644
--- a/src/libnm-core-impl/nm-connection.c
+++ b/src/libnm-core-impl/nm-connection.c
@@ -1708,7 +1708,7 @@ _normalize_required_settings(NMConnection *self)
     NMSetting          *s_bridge;
     gboolean            changed = FALSE;
 
-    if (nm_connection_get_setting_vlan(self)) {
+    if (nm_connection_get_setting_vlan(self) || nm_connection_get_setting_bridge(self)) {
         if (!nm_connection_get_setting_wired(self)) {
             nm_connection_add_setting(self, nm_setting_wired_new());
             changed = TRUE;
@@ -3168,22 +3168,24 @@ nm_connection_get_virtual_device_description(NMConnection *connection)
 
     iface = nm_connection_get_interface_name(connection);
 
-    if (!strcmp(type, NM_SETTING_BOND_SETTING_NAME))
+    if (nm_streq(type, NM_SETTING_BOND_SETTING_NAME))
         display_type = _("Bond");
-    else if (!strcmp(type, NM_SETTING_TEAM_SETTING_NAME))
+    else if (nm_streq(type, NM_SETTING_TEAM_SETTING_NAME))
         display_type = _("Team");
-    else if (!strcmp(type, NM_SETTING_BRIDGE_SETTING_NAME))
+    else if (nm_streq(type, NM_SETTING_BRIDGE_SETTING_NAME))
         display_type = _("Bridge");
-    else if (!strcmp(type, NM_SETTING_VLAN_SETTING_NAME))
+    else if (nm_streq(type, NM_SETTING_VLAN_SETTING_NAME))
         display_type = _("VLAN");
-    else if (!strcmp(type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
+    else if (nm_streq(type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
         display_type = _("InfiniBand");
         iface        = nm_setting_infiniband_get_virtual_interface_name(
             nm_connection_get_setting_infiniband(connection));
-    } else if (!strcmp(type, NM_SETTING_IP_TUNNEL_SETTING_NAME))
+    } else if (nm_streq(type, NM_SETTING_IP_TUNNEL_SETTING_NAME))
         display_type = _("IP Tunnel");
-    else if (!strcmp(type, NM_SETTING_WIREGUARD_SETTING_NAME))
+    else if (nm_streq(type, NM_SETTING_WIREGUARD_SETTING_NAME))
         display_type = _("WireGuard");
+    else if (nm_streq(type, NM_SETTING_TUN_SETTING_NAME))
+        display_type = _("TUN/TAP");
 
     if (!iface || !display_type)
         return NULL;
diff --git a/src/libnm-core-impl/nm-keyfile-utils.c b/src/libnm-core-impl/nm-keyfile-utils.c
index c599aefa..95073bcc 100644
--- a/src/libnm-core-impl/nm-keyfile-utils.c
+++ b/src/libnm-core-impl/nm-keyfile-utils.c
@@ -210,7 +210,7 @@ nm_keyfile_plugin_kf_set_integer_list_uint(GKeyFile    *kf,
     g_return_if_fail(group && group[0]);
     g_return_if_fail(key && key[0]);
 
-    nm_str_buf_init(&strbuf, length * 4u + 2u, FALSE);
+    strbuf = NM_STR_BUF_INIT(length * 4u + 2u, FALSE);
     for (i = 0; i < length; i++)
         nm_str_buf_append_printf(&strbuf, "%u;", data[i]);
     nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf));
@@ -231,7 +231,7 @@ nm_keyfile_plugin_kf_set_integer_list_uint8(GKeyFile     *kf,
     g_return_if_fail(group && group[0]);
     g_return_if_fail(key && key[0]);
 
-    nm_str_buf_init(&strbuf, length * 4u + 2u, FALSE);
+    strbuf = NM_STR_BUF_INIT(length * 4u + 2u, FALSE);
     for (i = 0; i < length; i++)
         nm_str_buf_append_printf(&strbuf, "%u;", (guint) data[i]);
     nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf));
@@ -542,7 +542,7 @@ _keyfile_key_encode(const char *name, char **out_to_free)
     len = i + strlen(&name[i]);
     nm_assert(len == strlen(name));
 
-    nm_str_buf_init(&str, len + 15u, FALSE);
+    str = NM_STR_BUF_INIT(len + 15u, FALSE);
 
     if (name[0] == ' ') {
         nm_assert(i == 0);
diff --git a/src/libnm-core-impl/nm-keyfile.c b/src/libnm-core-impl/nm-keyfile.c
index 00fb8a33..6ee68b5c 100644
--- a/src/libnm-core-impl/nm-keyfile.c
+++ b/src/libnm-core-impl/nm-keyfile.c
@@ -21,7 +21,6 @@
 #include "libnm-glib-aux/nm-uuid.h"
 #include "libnm-glib-aux/nm-str-buf.h"
 #include "libnm-glib-aux/nm-secret-utils.h"
-#include "libnm-systemd-shared/nm-sd-utils-shared.h"
 #include "libnm-core-aux-intern/nm-common-macros.h"
 #include "libnm-core-aux-intern/nm-libnm-core-utils.h"
 #include "libnm-core-intern/nm-core-internal.h"
@@ -1160,17 +1159,30 @@ ip6_addr_gen_mode_parser(KeyfileReaderInfo *info, NMSetting *setting, const char
                                     s,
                                     (int *) &addr_gen_mode,
                                     NULL)) {
-            read_handle_warn(info,
-                             key,
-                             key,
-                             NM_KEYFILE_WARN_SEVERITY_WARN,
-                             _("invalid option '%s', use one of [%s]"),
-                             s,
-                             "eui64,stable-privacy");
-            return;
+            if (!read_handle_warn(info,
+                                  key,
+                                  key,
+                                  NM_KEYFILE_WARN_SEVERITY_WARN,
+                                  _("invalid option '%s', use one of [%s]"),
+                                  s,
+                                  "eui64,stable-privacy"))
+                return;
+            addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64;
         }
-    } else
-        addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64;
+    } else {
+        gs_free char *s2 = NULL;
+
+        s2 = nm_keyfile_plugin_kf_get_string(info->keyfile,
+                                             setting_name,
+                                             NM_SETTING_IP6_CONFIG_TOKEN,
+                                             NULL);
+        if (s2) {
+            /* If a token is set, but the addr-gen-mode is not, then the default
+             * is eui64. Otherwise, the result would not verify. */
+            addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64;
+        } else
+            addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64;
+    }
 
     g_object_set(G_OBJECT(setting), key, (int) addr_gen_mode, NULL);
 }
@@ -2190,8 +2202,10 @@ ip6_addr_gen_mode_writer(KeyfileWriterInfo *info,
     gs_free char                 *str = NULL;
 
     addr_gen_mode = (NMSettingIP6ConfigAddrGenMode) g_value_get_int(value);
-    str = nm_utils_enum_to_str(nm_setting_ip6_config_addr_gen_mode_get_type(), addr_gen_mode);
-    nm_keyfile_plugin_kf_set_string(info->keyfile, nm_setting_get_name(setting), key, str);
+    if (addr_gen_mode != NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64) {
+        str = nm_utils_enum_to_str(nm_setting_ip6_config_addr_gen_mode_get_type(), addr_gen_mode);
+        nm_keyfile_plugin_kf_set_string(info->keyfile, nm_setting_get_name(setting), key, str);
+    }
 }
 
 static void
@@ -4062,7 +4076,7 @@ _write_setting_wireguard(NMSetting *setting, KeyfileWriterInfo *info)
 
         public_key = nm_wireguard_peer_get_public_key(peer);
         if (!public_key || !public_key[0]
-            || !NM_STRCHAR_ALL(public_key, ch, nm_sd_utils_unbase64char(ch, TRUE) >= 0)) {
+            || !NM_STRCHAR_ALL(public_key, ch, nm_unbase64char(ch) != -EINVAL)) {
             /* invalid peer. Skip it */
             continue;
         }
@@ -4375,7 +4389,7 @@ nm_keyfile_utils_create_filename(const char *name, gboolean with_extension)
 
     g_return_val_if_fail(name && name[0], NULL);
 
-    nm_str_buf_init(&str, 0, FALSE);
+    str = NM_STR_BUF_INIT(0, FALSE);
 
     len = strlen(name);
 
diff --git a/src/libnm-core-impl/nm-setting-8021x.c b/src/libnm-core-impl/nm-setting-8021x.c
index 41feae57..fd9a0961 100644
--- a/src/libnm-core-impl/nm-setting-8021x.c
+++ b/src/libnm-core-impl/nm-setting-8021x.c
@@ -2980,8 +2980,6 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
                                error))
         return FALSE;
 
-        /* normalizable warnings from here on. */
-
 #define _check_strempty_and_return(priv, prop_name, field, error)                               \
     G_STMT_START                                                                                \
     {                                                                                           \
@@ -2999,6 +2997,8 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
     }                                                                                           \
     G_STMT_END
 
+    /* normalizable warnings from here on. */
+
     _check_strempty_and_return(priv, NM_SETTING_802_1X_IDENTITY, identity, error);
     _check_strempty_and_return(priv,
                                NM_SETTING_802_1X_ANONYMOUS_IDENTITY,
diff --git a/src/libnm-core-impl/nm-setting-bond.c b/src/libnm-core-impl/nm-setting-bond.c
index ae2fe051..cdfc7641 100644
--- a/src/libnm-core-impl/nm-setting-bond.c
+++ b/src/libnm-core-impl/nm-setting-bond.c
@@ -362,15 +362,6 @@ _bond_get_option_normalized(NMSettingBond *self, const char *option, gboolean ge
     return _bond_get_option_or_default(self, option);
 }
 
-const char *
-nm_setting_bond_get_option_or_default(NMSettingBond *self, const char *option)
-{
-    g_return_val_if_fail(NM_IS_SETTING_BOND(self), NULL);
-    g_return_val_if_fail(option, NULL);
-
-    return _bond_get_option_normalized(self, option, FALSE);
-}
-
 static int
 _atoi(const char *value)
 {
@@ -773,6 +764,39 @@ _nm_setting_bond_get_option_type(NMSettingBond *setting, const char *name)
     return option_meta->opt_type;
 }
 
+guint32
+_nm_setting_bond_opt_value_as_u32(NMSettingBond *s_bond, const char *opt)
+{
+    nm_assert(_get_option_meta(opt)->opt_type == NM_BOND_OPTION_TYPE_INT);
+    return _nm_utils_ascii_str_to_uint64(nm_setting_bond_get_option_normalized(s_bond, opt),
+                                         10,
+                                         0,
+                                         G_MAXUINT32,
+                                         0);
+}
+
+guint16
+_nm_setting_bond_opt_value_as_u16(NMSettingBond *s_bond, const char *opt)
+{
+    nm_assert(_get_option_meta(opt)->opt_type == NM_BOND_OPTION_TYPE_INT);
+    return _nm_utils_ascii_str_to_uint64(nm_setting_bond_get_option_normalized(s_bond, opt),
+                                         10,
+                                         0,
+                                         G_MAXUINT16,
+                                         0);
+}
+
+guint8
+_nm_setting_bond_opt_value_as_u8(NMSettingBond *s_bond, const char *opt)
+{
+    nm_assert(_get_option_meta(opt)->opt_type == NM_BOND_OPTION_TYPE_INT);
+    return _nm_utils_ascii_str_to_uint64(nm_setting_bond_get_option_normalized(s_bond, opt),
+                                         10,
+                                         0,
+                                         G_MAXUINT8,
+                                         0);
+}
+
 /*****************************************************************************/
 
 static gboolean
diff --git a/src/libnm-core-impl/nm-setting-bridge.c b/src/libnm-core-impl/nm-setting-bridge.c
index 41cd6632..39a3fb60 100644
--- a/src/libnm-core-impl/nm-setting-bridge.c
+++ b/src/libnm-core-impl/nm-setting-bridge.c
@@ -435,7 +435,7 @@ nm_bridge_vlan_to_str(const NMBridgeVlan *vlan, GError **error)
      * future if more parameters are added to the object that could
      * make it invalid. */
 
-    nm_str_buf_init(&string, NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE);
+    string = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE);
 
     if (vlan->vid_start == vlan->vid_end)
         nm_str_buf_append_printf(&string, "%u", vlan->vid_start);
@@ -1311,6 +1311,15 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
                                            NM_SETTING_BRIDGE_VLANS))
         return NM_SETTING_VERIFY_NORMALIZABLE;
 
+    if (connection && !nm_connection_get_setting_wired(connection)) {
+        g_set_error_literal(error,
+                            NM_CONNECTION_ERROR,
+                            NM_CONNECTION_ERROR_SETTING_NOT_FOUND,
+                            _("bridge connection should have a ethernet setting as well"));
+        g_prefix_error(error, "%s: ", NM_SETTING_BRIDGE_SETTING_NAME);
+        return NM_SETTING_VERIFY_NORMALIZABLE;
+    }
+
     return TRUE;
 }
 
diff --git a/src/libnm-core-impl/nm-setting-connection.c b/src/libnm-core-impl/nm-setting-connection.c
index 0d7d7cd5..cbce1c12 100644
--- a/src/libnm-core-impl/nm-setting-connection.c
+++ b/src/libnm-core-impl/nm-setting-connection.c
@@ -65,10 +65,12 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingConnection,
                              PROP_MDNS,
                              PROP_LLMNR,
                              PROP_DNS_OVER_TLS,
+                             PROP_MPTCP_FLAGS,
                              PROP_STABLE_ID,
                              PROP_AUTH_RETRIES,
                              PROP_WAIT_DEVICE_TIMEOUT,
-                             PROP_MUD_URL, );
+                             PROP_MUD_URL,
+                             PROP_WAIT_ACTIVATION_DELAY, );
 
 typedef struct {
     GArray     *permissions;
@@ -94,6 +96,8 @@ typedef struct {
     gint32      dns_over_tls;
     gint32      wait_device_timeout;
     gint32      lldp;
+    gint32      wait_activation_delay;
+    guint32     mptcp_flags;
     guint32     gateway_ping_timeout;
     bool        autoconnect;
     bool        read_only;
@@ -735,6 +739,23 @@ nm_setting_connection_get_wait_device_timeout(NMSettingConnection *setting)
 }
 
 /**
+ * nm_setting_connection_get_wait_activation_delay:
+ * @setting: the #NMSettingConnection
+ *
+ * Returns: the %NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY property with
+ *   the delay in milliseconds. -1 is the default.
+ *
+ * Since: 1.40
+ */
+gint32
+nm_setting_connection_get_wait_activation_delay(NMSettingConnection *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), -1);
+
+    return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->wait_activation_delay;
+}
+
+/**
  * nm_setting_connection_get_autoconnect_slaves:
  * @setting: the #NMSettingConnection
  *
@@ -996,6 +1017,22 @@ nm_setting_connection_get_dns_over_tls(NMSettingConnection *setting)
     return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->dns_over_tls;
 }
 
+/**
+ * nm_setting_connection_get_mptcp_flags:
+ * @setting: the #NMSettingConnection
+ *
+ * Returns: the #NMSettingConnection:mptcp-flags property of the setting.
+ *
+ * Since: 1.40
+ **/
+NMMptcpFlags
+nm_setting_connection_get_mptcp_flags(NMSettingConnection *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), NM_MPTCP_FLAGS_NONE);
+
+    return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->mptcp_flags;
+}
+
 static void
 _set_error_missing_base_setting(GError **error, const char *type)
 {
@@ -1348,6 +1385,50 @@ after_interface_name:
         return FALSE;
     }
 
+    if (priv->mptcp_flags != 0) {
+        if (NM_FLAGS_HAS(priv->mptcp_flags, NM_MPTCP_FLAGS_DISABLED)) {
+            if (priv->mptcp_flags != NM_MPTCP_FLAGS_DISABLED) {
+                g_set_error_literal(
+                    error,
+                    NM_CONNECTION_ERROR,
+                    NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                    _("\"disabled\" flag cannot be combined with other MPTCP flags"));
+                g_prefix_error(error,
+                               "%s.%s: ",
+                               NM_SETTING_CONNECTION_SETTING_NAME,
+                               NM_SETTING_CONNECTION_MPTCP_FLAGS);
+                return FALSE;
+            }
+        } else {
+            guint32 f;
+
+            if (NM_FLAGS_ALL(priv->mptcp_flags, NM_MPTCP_FLAGS_SIGNAL | NM_MPTCP_FLAGS_FULLMESH)) {
+                g_set_error_literal(error,
+                                    NM_CONNECTION_ERROR,
+                                    NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                                    _("cannot set both \"signal\" and \"fullmesh\" MPTCP flags"));
+                g_prefix_error(error,
+                               "%s.%s: ",
+                               NM_SETTING_CONNECTION_SETTING_NAME,
+                               NM_SETTING_CONNECTION_MPTCP_FLAGS);
+                return FALSE;
+            }
+            f = priv->mptcp_flags | ((guint32) NM_MPTCP_FLAGS_ENABLED);
+            if (f != nm_mptcp_flags_normalize(f)) {
+                g_set_error(error,
+                            NM_CONNECTION_ERROR,
+                            NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                            _("value %u is not a valid combination of MPTCP flags"),
+                            priv->mptcp_flags);
+                g_prefix_error(error,
+                               "%s.%s: ",
+                               NM_SETTING_CONNECTION_SETTING_NAME,
+                               NM_SETTING_CONNECTION_MPTCP_FLAGS);
+                return FALSE;
+            }
+        }
+    }
+
     if (!NM_IN_SET(priv->multi_connect,
                    (int) NM_CONNECTION_MULTI_CONNECT_DEFAULT,
                    (int) NM_CONNECTION_MULTI_CONNECT_SINGLE,
@@ -2464,6 +2545,110 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
                                              NMSettingConnectionPrivate,
                                              dns_over_tls);
 
+    /* Notes about "mptcp-flags":
+     *
+     * It is a bit odd that NMMptcpFlags mixes flags with different purposes:
+     *
+     * - "disabled", "disabled-on-local-iface", "enable": whether MPTCP handling
+     *   is enabled. The flag "disabled-on-local-iface" enables it based on whether
+     *   the interface has a default route.
+     * - "signal", "subflow", "backup", "fullmesh": the endpoint flags
+     *   that are used.
+     *
+     * The reason is, that it is useful to have one "connection.mptcp-flags"
+     * property, that can express various aspects at once. The alternatives
+     * would be multiple properties like "connection.mptcp-enabled",
+     * "connection.mptcp-addr-flags" and "connection.mptcp-notify-flags".
+     * More properties does not necessarily make the API simpler. In particular
+     * for something like MPTCP, which should just work by default and only
+     * in special cases require special configuration.
+     *
+     * The entire idea is to only have one "connection.mptcp-flags" property (for now).
+     * That one can encode multiple aspects about MPTCP, whether it's enabled at all,
+     * which address flags to use when configuring endpoints, and opt-in addresses
+     * that otherwise would not be configured as endpoints.
+     *
+     * "connection.mptcp-flags" applies to all addresses on the interface (minus the ones
+     * that are not included by default). The idea is that in the future we could have
+     * more properties like "ipv4.dhcp-mptcp-flags=subflow", "ipv6.link-local-mptcp-flags=disabled",
+     * "ipv4.addresses='192.168.1.5/24 mptcp-flags=signal,backup'", which can overwrite the
+     * flags on a per-address basis.
+     *
+     * But for that future extension, we now need a global "connection.mptcp-flags" property
+     * in the API that is the basis and applies to all addresses.
+     */
+
+    /**
+     * NMSettingConnection:mptcp-flags:
+     *
+     * Whether to configure MPTCP endpoints and the address flags.
+     * If MPTCP is enabled in NetworkManager, it will configure the
+     * addresses of the interface as MPTCP endpoints. Note that
+     * IPv4 loopback addresses (127.0.0.0/8), IPv4 link local
+     * addresses (169.254.0.0/16), the IPv6 loopback address (::1),
+     * IPv6 link local addresses (fe80::/10), IPv6 unique
+     * local addresses (ULA, fc00::/7) and IPv6 privacy extension addresses
+     * (rfc3041, ipv6.ip6-privacy) will be excluded from being
+     * configured as endpoints.
+     *
+     * If "disabled" (0x1), MPTCP handling for the interface is disabled and
+     * no endpoints are registered.
+     *
+     * The "enabled" (0x2) flag means that MPTCP handling is enabled.
+     * This flag can also be implied from the presence of other flags.
+     *
+     * Even when enabled, MPTCP handling will by default still be disabled
+     * unless "/proc/sys/net/mptcp/enabled" sysctl is on. NetworkManager
+     * does not change the sysctl and this is up to the administrator
+     * or distribution. To configure endpoints even if the sysctl is
+     * disabled, "also-without-sysctl" (0x4) flag can be used. In that case,
+     * NetworkManager doesn't look at the sysctl and configures endpoints
+     * regardless.
+     *
+     * Even when enabled, NetworkManager will only configure MPTCP endpoints
+     * for a certain address family, if there is a unicast default route (0.0.0.0/0
+     * or ::/0) in the main routing table. The flag "also-without-default-route"
+     * (0x8) can override that.
+     *
+     * When MPTCP handling is enabled then endpoints are configured with
+     * the specified address flags "signal" (0x10), "subflow" (0x20), "backup" (0x40),
+     * "fullmesh" (0x80). See ip-mptcp(8) manual for additional information about the flags.
+     *
+     * If the flags are zero (0x0), the global connection default from NetworkManager.conf is
+     * honored. If still unspecified, the fallback is "enabled,subflow".
+     * Note that this means that MPTCP is by default done depending on the
+     * "/proc/sys/net/mptcp/enabled" sysctl.
+     *
+     * NetworkManager does not change the MPTCP limits nor enable MPTCP via
+     * "/proc/sys/net/mptcp/enabled". That is a host configuration which the
+     * admin can change via sysctl and ip-mptcp.
+     *
+     * Strict reverse path filtering (rp_filter) breaks many MPTCP use cases, so when
+     * MPTCP handling for IPv4 addresses on the interface is enabled, NetworkManager would
+     * loosen the strict reverse path filtering (1) to the loose setting (2).
+     *
+     * Since: 1.40
+     **/
+    /* ---ifcfg-rh---
+     * property: mptcp-flags
+     * variable: MPTCP_FLAGS(+)
+     * default: missing variable means global default
+     * description: The MPTCP flags that indicate whether MPTCP is enabled
+     *   and which flags to use for the address endpoints.
+     * example: MPTCP_FLAGS="signal,subflow"
+     * ---end---
+     */
+    _nm_setting_property_define_direct_uint32(properties_override,
+                                              obj_properties,
+                                              NM_SETTING_CONNECTION_MPTCP_FLAGS,
+                                              PROP_MPTCP_FLAGS,
+                                              0,
+                                              G_MAXUINT32,
+                                              NM_MPTCP_FLAGS_NONE,
+                                              NM_SETTING_PARAM_NONE,
+                                              NMSettingConnectionPrivate,
+                                              mptcp_flags);
+
     /**
      * NMSettingConnection:wait-device-timeout:
      *
@@ -2530,6 +2715,37 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
                                               NMSettingConnectionPrivate,
                                               mud_url);
 
+    /**
+     * NMSettingConnection:wait-activation-delay:
+     *
+     * Time in milliseconds to wait for connection to be considered activated.
+     * The wait will start after the pre-up dispatcher event.
+     *
+     * The value 0 means no wait time. The default value is -1, which
+     * currently has the same meaning as no wait time.
+     *
+     * Since: 1.40
+     **/
+    /* ---ifcfg-rh---
+     * property: wait-activation-delay
+     * variable: WAIT_ACTIVATION_DELAY(+)
+     * values: delay in milliseconds.
+     * description: Time in milliseconds to wait for connection to be considered activated.
+     * The wait will start after the pre-up dispatcher event.
+     * example: WAIT_ACTIVATION_DELAY=5000
+     * ---end---
+     */
+    _nm_setting_property_define_direct_int32(properties_override,
+                                             obj_properties,
+                                             NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY,
+                                             PROP_WAIT_ACTIVATION_DELAY,
+                                             -1,
+                                             G_MAXINT32,
+                                             -1,
+                                             NM_SETTING_PARAM_NONE,
+                                             NMSettingConnectionPrivate,
+                                             wait_activation_delay);
+
     g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
     _nm_setting_class_commit(setting_class,
diff --git a/src/libnm-core-impl/nm-setting-ethtool.c b/src/libnm-core-impl/nm-setting-ethtool.c
index 49c0d780..71179efd 100644
--- a/src/libnm-core-impl/nm-setting-ethtool.c
+++ b/src/libnm-core-impl/nm-setting-ethtool.c
@@ -45,11 +45,11 @@ get_variant_type_from_ethtool_id(NMEthtoolID ethtool_id)
  *
  * %Returns: %TRUE, if @optname is valid
  *
- * Since: 1.20
- *
  * Note that nm_ethtool_optname_is_feature() was first added to the libnm header files
  * in 1.14.0 but forgot to actually add to the library. This happened belatedly in 1.20.0 and
  * the stable versions 1.18.2, 1.16.4 and 1.14.8 (with linker version "libnm_1_14_8").
+ *
+ * Since: 1.20
  */
 gboolean
 nm_ethtool_optname_is_feature(const char *optname)
diff --git a/src/libnm-core-impl/nm-setting-ip-config.c b/src/libnm-core-impl/nm-setting-ip-config.c
index cffd5b19..916a8038 100644
--- a/src/libnm-core-impl/nm-setting-ip-config.c
+++ b/src/libnm-core-impl/nm-setting-ip-config.c
@@ -1197,6 +1197,10 @@ nm_ip_route_set_attribute(NMIPRoute *route, const char *name, GVariant *value)
 }
 
 static const NMVariantAttributeSpec *const ip_route_attribute_spec[] = {
+    NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_ADVMSS,
+                                     G_VARIANT_TYPE_UINT32,
+                                     .v4 = TRUE,
+                                     .v6 = TRUE, ),
     NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_CWND,
                                      G_VARIANT_TYPE_UINT32,
                                      .v4 = TRUE,
@@ -1213,6 +1217,10 @@ static const NMVariantAttributeSpec *const ip_route_attribute_spec[] = {
                                      G_VARIANT_TYPE_UINT32,
                                      .v4 = TRUE,
                                      .v6 = TRUE, ),
+    NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_LOCK_ADVMSS,
+                                     G_VARIANT_TYPE_BOOLEAN,
+                                     .v4 = TRUE,
+                                     .v6 = TRUE, ),
     NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND,
                                      G_VARIANT_TYPE_BOOLEAN,
                                      .v4 = TRUE,
@@ -1241,6 +1249,14 @@ static const NMVariantAttributeSpec *const ip_route_attribute_spec[] = {
                                      G_VARIANT_TYPE_BOOLEAN,
                                      .v4 = TRUE,
                                      .v6 = TRUE, ),
+    NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_QUICKACK,
+                                     G_VARIANT_TYPE_BOOLEAN,
+                                     .v4 = TRUE,
+                                     .v6 = TRUE, ),
+    NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_RTO_MIN,
+                                     G_VARIANT_TYPE_UINT32,
+                                     .v4 = TRUE,
+                                     .v6 = TRUE, ),
     NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_SCOPE,
                                      G_VARIANT_TYPE_BYTE,
                                      .v4          = TRUE,
@@ -2481,10 +2497,10 @@ nm_ip_routing_rule_set_suppress_prefixlength(NMIPRoutingRule *self, gint32 suppr
  *
  * Returns: %TRUE if a uid range is set.
  *
- * Since: 1.34
- *
  * This API was wrongly introduced in the header files for 1.32, but the
  * symbols were not exported. The API only works since 1.34 and newer.
+ *
+ * Since: 1.34
  */
 gboolean
 nm_ip_routing_rule_get_uid_range(const NMIPRoutingRule *self,
@@ -2509,10 +2525,10 @@ nm_ip_routing_rule_get_uid_range(const NMIPRoutingRule *self,
  * For a valid range, start must be less or equal to end.
  * If set to an invalid range, the range gets unset.
  *
- * Since: 1.34
- *
  * This API was wrongly introduced in the header files for 1.32, but the
  * symbols were not exported. The API only works since 1.34 and newer.
+ *
+ * Since: 1.34
  */
 void
 nm_ip_routing_rule_set_uid_range(NMIPRoutingRule *self,
@@ -3814,7 +3830,7 @@ nm_ip_routing_rule_to_string(const NMIPRoutingRule       *self,
         }
     }
 
-    nm_str_buf_init(&str, NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE);
+    str = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE);
 
     if (self->priority_has) {
         nm_str_buf_append_printf(nm_str_buf_append_required_delimiter(&str, ' '),
@@ -6149,7 +6165,7 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass)
     /**
      * NMSettingIPConfig:dns-search:
      *
-     * Array of DNS search domains. Domains starting with a tilde ('~')
+     * List of DNS search domains. Domains starting with a tilde ('~')
      * are considered 'routing' domains and are used only to decide the
      * interface over which a query must be forwarded; they are not used
      * to complete unqualified host names.
@@ -6158,6 +6174,12 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass)
      * Split DNS, then the search domains specify which name servers to
      * query. This makes the behavior different from running with plain
      * /etc/resolv.conf. For more information see also the dns-priority setting.
+     *
+     * When set on a profile that also enabled DHCP, the DNS search list
+     * received automatically (option 119 for DHCPv4 and option 24 for DHCPv6)
+     * gets merged with the manual list. This can be prevented by setting
+     * "ignore-auto-dns". Note that if no DNS searches are configured, the
+     * fallback will be derived from the domain from DHCP (option 15).
      **/
     obj_properties[PROP_DNS_SEARCH] =
         g_param_spec_boxed(NM_SETTING_IP_CONFIG_DNS_SEARCH,
@@ -6282,12 +6304,14 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass)
      * The gateway associated with this configuration. This is only meaningful
      * if #NMSettingIPConfig:addresses is also set.
      *
-     * The gateway's main purpose is to control the next hop of the standard default route on the device.
-     * Hence, the gateway property conflicts with #NMSettingIPConfig:never-default and will be
-     * automatically dropped if the IP configuration is set to never-default.
+     * Setting the gateway causes NetworkManager to configure a standard default route
+     * with the gateway as next hop. This is ignored if #NMSettingIPConfig:never-default
+     * is set. An alternative is to configure the default route explicitly with a manual
+     * route and /0 as prefix length.
      *
-     * As an alternative to set the gateway, configure a static default route with /0 as prefix
-     * length.
+     * Note that the gateway usually conflicts with routing that NetworkManager configures
+     * for WireGuard interfaces, so usually it should not be set in that case. See
+     * #NMSettingWireGuard:ip4-auto-default-route.
      **/
     obj_properties[PROP_GATEWAY] = g_param_spec_string(
         NM_SETTING_IP_CONFIG_GATEWAY,
diff --git a/src/libnm-core-impl/nm-setting-ip4-config.c b/src/libnm-core-impl/nm-setting-ip4-config.c
index bf555168..ff56834e 100644
--- a/src/libnm-core-impl/nm-setting-ip4-config.c
+++ b/src/libnm-core-impl/nm-setting-ip4-config.c
@@ -38,14 +38,16 @@
 
 NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_DHCP_CLIENT_ID,
                                   PROP_DHCP_FQDN,
-                                  PROP_DHCP_VENDOR_CLASS_IDENTIFIER, );
+                                  PROP_DHCP_VENDOR_CLASS_IDENTIFIER,
+                                  PROP_LINK_LOCAL, );
 
 typedef struct {
     NMSettingIPConfigPrivate parent;
 
-    char *dhcp_client_id;
-    char *dhcp_fqdn;
-    char *dhcp_vendor_class_identifier;
+    char  *dhcp_client_id;
+    char  *dhcp_fqdn;
+    char  *dhcp_vendor_class_identifier;
+    gint32 link_local;
 } NMSettingIP4ConfigPrivate;
 
 /**
@@ -127,6 +129,25 @@ nm_setting_ip4_config_get_dhcp_vendor_class_identifier(NMSettingIP4Config *setti
     return NM_SETTING_IP4_CONFIG_GET_PRIVATE(setting)->dhcp_vendor_class_identifier;
 }
 
+/**
+ * nm_setting_ip4_config_get_link_local:
+ * @setting: the #NMSettingIP4Config
+ *
+ * Returns the value contained in the #NMSettingIP4Config:link_local
+ * property.
+ *
+ * Returns: the link-local configuration
+ *
+ * Since: 1.40
+ **/
+NMSettingIP4LinkLocal
+nm_setting_ip4_config_get_link_local(NMSettingIP4Config *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_IP4_CONFIG(setting), NM_SETTING_IP4_LL_DEFAULT);
+
+    return NM_SETTING_IP4_CONFIG_GET_PRIVATE(setting)->link_local;
+}
+
 static gboolean
 verify(NMSetting *setting, NMConnection *connection, GError **error)
 {
@@ -218,6 +239,46 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
         return FALSE;
     }
 
+    if (!NM_IN_SET(priv->link_local,
+                   NM_SETTING_IP4_LL_AUTO,
+                   NM_SETTING_IP4_LL_DEFAULT,
+                   NM_SETTING_IP4_LL_DISABLED,
+                   NM_SETTING_IP4_LL_ENABLED)) {
+        g_set_error(error,
+                    NM_CONNECTION_ERROR,
+                    NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                    _("property is invalid"));
+        g_prefix_error(error,
+                       "%s.%s: ",
+                       NM_SETTING_IP4_CONFIG_SETTING_NAME,
+                       NM_SETTING_IP4_CONFIG_LINK_LOCAL);
+        return FALSE;
+    }
+    if (priv->link_local == NM_SETTING_IP4_LL_ENABLED
+        && nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) {
+        g_set_error_literal(error,
+                            NM_CONNECTION_ERROR,
+                            NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                            _("cannot enable ipv4.link-local with ipv4.method=disabled"));
+        g_prefix_error(error,
+                       "%s.%s: ",
+                       NM_SETTING_IP4_CONFIG_SETTING_NAME,
+                       NM_SETTING_IP4_CONFIG_LINK_LOCAL);
+        return FALSE;
+    }
+    if (priv->link_local == NM_SETTING_IP4_LL_DISABLED
+        && nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) {
+        g_set_error_literal(error,
+                            NM_CONNECTION_ERROR,
+                            NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                            _("cannot disable ipv4.link-local with ipv4.method=link-local"));
+        g_prefix_error(error,
+                       "%s.%s: ",
+                       NM_SETTING_IP4_CONFIG_SETTING_NAME,
+                       NM_SETTING_IP4_CONFIG_LINK_LOCAL);
+        return FALSE;
+    }
+
     if (priv->dhcp_client_id && !priv->dhcp_client_id[0]) {
         g_set_error_literal(error,
                             NM_CONNECTION_ERROR,
@@ -854,6 +915,39 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass)
                                               NMSettingIP4ConfigPrivate,
                                               dhcp_vendor_class_identifier);
 
+    /**
+     * NMSettingIP4Config:link-local:
+     *
+     * Enable and disable the IPv4 link-local configuration independently of the
+     * ipv4.method configuration. This allows a link-local address (169.254.x.y/16)
+     * to be obtained in addition to other addresses, such as those manually
+     * configured or obtained from a DHCP server.
+     *
+     * When set to "auto", the value is dependent on "ipv4.method".
+     * When set to "default", it honors the global connection default, before
+     * falling back to "auto". Note that if "ipv4.method" is "disabled", then
+     * link local addressing is always disabled too. The default is "default".
+     *
+     * Since 1.40
+     */
+    /* ---ifcfg-rh---
+     * property: link-local
+     * variable: IPV4_LINK_LOCAL(+)
+     * description: Configure link-local IP address in interaction with method
+     * example: IPV4_LINK_LOCAL=auto
+     * ---end---
+     */
+    _nm_setting_property_define_direct_int32(properties_override,
+                                             obj_properties,
+                                             NM_SETTING_IP4_CONFIG_LINK_LOCAL,
+                                             PROP_LINK_LOCAL,
+                                             G_MININT32,
+                                             G_MAXINT32,
+                                             NM_SETTING_IP4_LL_DEFAULT,
+                                             NM_SETTING_PARAM_NONE,
+                                             NMSettingIP4ConfigPrivate,
+                                             link_local);
+
     /* IP4-specific property overrides */
 
     /* ---dbus---
@@ -963,6 +1057,9 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass)
      *     Various attributes are supported:
      *     <itemizedlist>
      *      <listitem>
+     *        <para><literal>"advmss"</literal> - an unsigned 32 bit integer.</para>
+     *      </listitem>
+     *      <listitem>
      *        <para><literal>"cwnd"</literal> - an unsigned 32 bit integer.</para>
      *      </listitem>
      *      <listitem>
@@ -972,6 +1069,9 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass)
      *        <para><literal>"initrwnd"</literal> - an unsigned 32 bit integer.</para>
      *      </listitem>
      *      <listitem>
+     *        <para><literal>"lock-advmss"</literal> - a boolean value.</para>
+     *      </listitem>
+     *      <listitem>
      *        <para><literal>"lock-cwnd"</literal> - a boolean value.</para>
      *      </listitem>
      *      <listitem>
@@ -993,6 +1093,13 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass)
      *        <para><literal>"onlink"</literal> - a boolean value.</para>
      *      </listitem>
      *      <listitem>
+     *        <para><literal>"quickack"</literal> - a boolean value.</para>
+     *      </listitem>
+     *      <listitem>
+     *        <para><literal>"rto_min"</literal> - an unsigned 32 bit integer.
+     *        The value is in milliseconds.</para>
+     *      </listitem>
+     *      <listitem>
      *        <para><literal>"scope"</literal> - an unsigned 8 bit integer. IPv4 only.</para>
      *      </listitem>
      *      <listitem>
diff --git a/src/libnm-core-impl/nm-setting-ip6-config.c b/src/libnm-core-impl/nm-setting-ip6-config.c
index f75c14ce..8b593b97 100644
--- a/src/libnm-core-impl/nm-setting-ip6-config.c
+++ b/src/libnm-core-impl/nm-setting-ip6-config.c
@@ -43,16 +43,18 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_IP6_PRIVACY,
                                   PROP_ADDR_GEN_MODE,
                                   PROP_TOKEN,
                                   PROP_DHCP_DUID,
-                                  PROP_RA_TIMEOUT, );
+                                  PROP_RA_TIMEOUT,
+                                  PROP_MTU, );
 
 typedef struct {
     NMSettingIPConfigPrivate parent;
 
-    char  *token;
-    char  *dhcp_duid;
-    int    ip6_privacy;
-    gint32 addr_gen_mode;
-    gint32 ra_timeout;
+    char   *token;
+    char   *dhcp_duid;
+    int     ip6_privacy;
+    gint32  addr_gen_mode;
+    gint32  ra_timeout;
+    guint32 mtu;
 } NMSettingIP6ConfigPrivate;
 
 /**
@@ -110,7 +112,7 @@ NMSettingIP6ConfigAddrGenMode
 nm_setting_ip6_config_get_addr_gen_mode(NMSettingIP6Config *setting)
 {
     g_return_val_if_fail(NM_IS_SETTING_IP6_CONFIG(setting),
-                         NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY);
+                         NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT);
 
     return NM_SETTING_IP6_CONFIG_GET_PRIVATE(setting)->addr_gen_mode;
 }
@@ -171,6 +173,23 @@ nm_setting_ip6_config_get_ra_timeout(NMSettingIP6Config *setting)
     return NM_SETTING_IP6_CONFIG_GET_PRIVATE(setting)->ra_timeout;
 }
 
+/**
+ * nm_setting_ip6_config_get_mtu:
+ * @setting: the #NMSettingIP6Config
+ *
+ * Returns: The configured %NM_SETTING_IP6_CONFIG_MTU value for the maximum
+ * transmission unit.
+ *
+ * Since: 1.40
+ **/
+guint32
+nm_setting_ip6_config_get_mtu(NMSettingIP6Config *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_IP6_CONFIG(setting), 0);
+
+    return NM_SETTING_IP6_CONFIG_GET_PRIVATE(setting)->mtu;
+}
+
 static gboolean
 verify(NMSetting *setting, NMConnection *connection, GError **error)
 {
@@ -269,7 +288,9 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
 
     if (!NM_IN_SET(priv->addr_gen_mode,
                    NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
-                   NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY)) {
+                   NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY,
+                   NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64,
+                   NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT)) {
         g_set_error_literal(error,
                             NM_CONNECTION_ERROR,
                             NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -757,8 +778,10 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
      *
      * Configure method for creating the address for use with RFC4862 IPv6
      * Stateless Address Autoconfiguration. The permitted values are:
-     * %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 or
+     * %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
      * %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY.
+     * %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64
+     * or %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT.
      *
      * If the property is set to EUI64, the addresses will be generated
      * using the interface tokens derived from hardware address. This makes
@@ -773,9 +796,16 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
      * and makes the address stable when the network interface hardware is
      * replaced.
      *
-     * On D-Bus, the absence of an addr-gen-mode setting equals enabling
-     * stable-privacy. For keyfile plugin, the absence of the setting
-     * on disk means EUI64 so that the property doesn't change on upgrade
+     * The special values "default" and "default-or-eui64" will fallback to the global
+     * connection default in as documented in NetworkManager.conf(5) manual. If the
+     * global default is not specified, the fallback value is "stable-privacy"
+     * or "eui64", respectively.
+     *
+     * For libnm, the property defaults to "default" since 1.40.
+     * Previously it defaulted to "stable-privacy".
+     * On D-Bus, the absence of an addr-gen-mode setting equals
+     * "default". For keyfile plugin, the absence of the setting
+     * on disk means "default-or-eui64" so that the property doesn't change on upgrade
      * from older versions.
      *
      * Note that this setting is distinct from the Privacy Extensions as
@@ -787,8 +817,8 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
     /* ---ifcfg-rh---
      * property: addr-gen-mode
      * variable: IPV6_ADDR_GEN_MODE
-     * values: IPV6_ADDR_GEN_MODE: eui64, stable-privacy
-     * default: eui64
+     * values: IPV6_ADDR_GEN_MODE: default, default-or-eui64, eui64, stable-privacy
+     * default: "default-or-eui64"
      * description: Configure IPv6 Stable Privacy addressing for SLAAC (RFC7217).
      * example: IPV6_ADDR_GEN_MODE=stable-privacy
      * ---end---
@@ -799,10 +829,11 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
                                              PROP_ADDR_GEN_MODE,
                                              G_MININT32,
                                              G_MAXINT32,
-                                             NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY,
+                                             NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT,
                                              NM_SETTING_PARAM_NONE,
                                              NMSettingIP6ConfigPrivate,
-                                             addr_gen_mode);
+                                             addr_gen_mode,
+                                             .to_dbus_including_default = TRUE);
 
     /**
      * NMSettingIP6Config:token:
@@ -857,6 +888,27 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
                                              ra_timeout);
 
     /**
+     * NMSettingIP6Config:mtu:
+     *
+     * Maximum transmission unit size, in bytes. If zero (the default), the MTU
+     * is set automatically from router advertisements or is left equal to the
+     * link-layer MTU. If greater than the link-layer MTU, or greater than zero
+     * but less than the minimum IPv6 MTU of 1280, this value has no effect.
+     *
+     * Since: 1.40
+     **/
+    _nm_setting_property_define_direct_uint32(properties_override,
+                                              obj_properties,
+                                              NM_SETTING_IP6_CONFIG_MTU,
+                                              PROP_MTU,
+                                              0,
+                                              G_MAXUINT32,
+                                              0,
+                                              NM_SETTING_PARAM_FUZZY_IGNORE,
+                                              NMSettingIP6ConfigPrivate,
+                                              mtu);
+
+    /**
      * NMSettingIP6Config:dhcp-duid:
      *
      * A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp
@@ -936,7 +988,7 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
      *   'address-data' and 'gateway'.
      *
      *   Array of IPv6 address structures.  Each IPv6 address structure is
-     *   composed of an IPv6 address, a prefix length (1 - 128), and an IPv6
+     *   composed of an IPv6 address, a prefix length (0 - 128), and an IPv6
      *   gateway address. The gateway may be zeroed out if no gateway exists for
      *   that subnet.
      * ---end---
@@ -984,7 +1036,7 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
      *   you send this property the daemon will ignore 'route-data'.
      *
      *   Array of IPv6 route structures.  Each IPv6 route structure is
-     *   composed of an IPv6 address, a prefix length (1 - 128), an IPv6
+     *   composed of an IPv6 address, a prefix length (0 - 128), an IPv6
      *   next hop address (which may be zeroed out if there is no next hop),
      *   and a metric. If the metric is 0, NM will choose an appropriate
      *   default metric for the device.
@@ -1003,6 +1055,9 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
      *     Various attributes are supported:
      *     <itemizedlist>
      *      <listitem>
+     *        <para><literal>"advmss"</literal> - an unsigned 32 bit integer.</para>
+     *      </listitem>
+     *      <listitem>
      *        <para><literal>"cwnd"</literal> - an unsigned 32 bit integer.</para>
      *      </listitem>
      *      <listitem>
@@ -1015,6 +1070,9 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
      *        <para><literal>"initrwnd"</literal> - an unsigned 32 bit integer.</para>
      *      </listitem>
      *      <listitem>
+     *        <para><literal>"lock-advmss"</literal> - a boolean value.</para>
+     *      </listitem>
+     *      <listitem>
      *        <para><literal>"lock-cwnd"</literal> - a boolean value.</para>
      *      </listitem>
      *      <listitem>
@@ -1036,6 +1094,13 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
      *        <para><literal>"onlink"</literal> - a boolean value.</para>
      *      </listitem>
      *      <listitem>
+     *        <para><literal>"quickack"</literal> - a boolean value.</para>
+     *      </listitem>
+     *      <listitem>
+     *        <para><literal>"rto_min"</literal> - an unsigned 32 bit integer.
+     *        The value is in milliseconds.</para>
+     *      </listitem>
+     *      <listitem>
      *        <para><literal>"src"</literal> - an IPv6 address.</para>
      *      </listitem>
      *      <listitem>
diff --git a/src/libnm-core-impl/nm-setting-wireguard.c b/src/libnm-core-impl/nm-setting-wireguard.c
index d713b6a5..ad0f01d5 100644
--- a/src/libnm-core-impl/nm-setting-wireguard.c
+++ b/src/libnm-core-impl/nm-setting-wireguard.c
@@ -2488,7 +2488,10 @@ nm_setting_wireguard_class_init(NMSettingWireGuardClass *klass)
      *
      * Leaving this at the default will enable this option automatically
      * if ipv4.never-default is not set and there are any peers that use
-     * a default-route as allowed-ips.
+     * a default-route as allowed-ips. Since this automatism only makes
+     * sense if you also have a peer with an /0 allowed-ips, it is usually
+     * not necessary to enable this explicitly. However, you can disable
+     * it if you want to configure your own routing and rules.
      *
      * Since: 1.20
      **/
diff --git a/src/libnm-core-impl/nm-setting-wireless.c b/src/libnm-core-impl/nm-setting-wireless.c
index 68cc0e13..cf391598 100644
--- a/src/libnm-core-impl/nm-setting-wireless.c
+++ b/src/libnm-core-impl/nm-setting-wireless.c
@@ -825,10 +825,10 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
 {
     NMSettingWirelessPrivate *priv          = NM_SETTING_WIRELESS_GET_PRIVATE(setting);
     const char               *valid_modes[] = {NM_SETTING_WIRELESS_MODE_INFRA,
-                                 NM_SETTING_WIRELESS_MODE_ADHOC,
-                                 NM_SETTING_WIRELESS_MODE_AP,
-                                 NM_SETTING_WIRELESS_MODE_MESH,
-                                 NULL};
+                                               NM_SETTING_WIRELESS_MODE_ADHOC,
+                                               NM_SETTING_WIRELESS_MODE_AP,
+                                               NM_SETTING_WIRELESS_MODE_MESH,
+                                               NULL};
     const char               *valid_bands[] = {"a", "bg", NULL};
     guint                     i;
     gsize                     length;
@@ -1409,6 +1409,10 @@ nm_setting_wireless_class_init(NMSettingWirelessClass *klass)
      * point.  This capability is highly driver dependent and not supported by
      * all devices.  Note: this property does not control the BSSID used when
      * creating an Ad-Hoc network and is unlikely to in the future.
+     *
+     * Locking a client profile to a certain BSSID will prevent roaming and also
+     * disable background scanning. That can be useful, if there is only one access
+     * point for the SSID.
      **/
     /* ---ifcfg-rh---
      * property: bssid
diff --git a/src/libnm-core-impl/nm-team-utils.c b/src/libnm-core-impl/nm-team-utils.c
index 2f62f6c6..6d87f50b 100644
--- a/src/libnm-core-impl/nm-team-utils.c
+++ b/src/libnm-core-impl/nm-team-utils.c
@@ -2148,11 +2148,11 @@ nm_team_setting_config_set(NMTeamSetting *self, const char *js_str)
         else {
             gboolean unrecognized_content            = FALSE;
             bool     has_lst[_NM_TEAM_ATTRIBUTE_NUM] = {
-                FALSE,
+                    FALSE,
             };
             NMValueTypUnion val_lst[_NM_TEAM_ATTRIBUTE_NUM];
             nm_json_t      *found_keys[_NM_TEAM_ATTRIBUTE_NUM] = {
-                NULL,
+                     NULL,
             };
             gs_unref_ptrarray GPtrArray *ptr_array_master_runner_tx_hash_free = NULL;
             gs_unref_ptrarray GPtrArray *ptr_array_link_watchers_free         = NULL;
diff --git a/src/libnm-core-impl/nm-utils.c b/src/libnm-core-impl/nm-utils.c
index d5d884f2..3c4cbc65 100644
--- a/src/libnm-core-impl/nm-utils.c
+++ b/src/libnm-core-impl/nm-utils.c
@@ -23,7 +23,6 @@
 #include "libnm-glib-aux/nm-enum-utils.h"
 #include "libnm-glib-aux/nm-time-utils.h"
 #include "libnm-glib-aux/nm-secret-utils.h"
-#include "libnm-systemd-shared/nm-sd-utils-shared.h"
 #include "libnm-core-aux-intern/nm-common-macros.h"
 #include "nm-utils-private.h"
 #include "nm-setting-private.h"
@@ -1559,29 +1558,33 @@ nm_utils_ip4_routes_from_variant(GVariant *value)
 
 /**
  * nm_utils_ip4_netmask_to_prefix:
- * @netmask: an IPv4 netmask in network byte order
+ * @netmask: an IPv4 netmask in network byte order.
+ *   Usually the netmask has all leading bits up to the prefix
+ *   set so that the netmask is identical to having the first
+ *   prefix bits of the address set.
+ *   If that is not the case and there are "holes" in the
+ *   mask, the prefix is determined based on the lowest bit
+ *   set.
  *
  * Returns: the CIDR prefix represented by the netmask
  **/
 guint32
 nm_utils_ip4_netmask_to_prefix(guint32 netmask)
 {
-    G_STATIC_ASSERT_EXPR(__SIZEOF_INT__ == 4);
-    G_STATIC_ASSERT_EXPR(sizeof(int) == 4);
-    G_STATIC_ASSERT_EXPR(sizeof(netmask) == 4);
-
-    return ((netmask != 0u) ? (guint32) (32 - __builtin_ctz(ntohl(netmask))) : 0u);
+    return _nm_utils_ip4_netmask_to_prefix(netmask);
 }
 
 /**
  * nm_utils_ip4_prefix_to_netmask:
- * @prefix: a CIDR prefix
+ * @prefix: a CIDR prefix, must be not larger than 32.
  *
  * Returns: the netmask represented by the prefix, in network byte order
  **/
 guint32
 nm_utils_ip4_prefix_to_netmask(guint32 prefix)
 {
+    g_return_val_if_fail(prefix <= 32, 0xffffffffu);
+
     return _nm_utils_ip4_prefix_to_netmask(prefix);
 }
 
@@ -5356,7 +5359,7 @@ nm_utils_base64secret_decode(const char *base64_key, gsize required_key_len, gui
 
     base64_key_len = strlen(base64_key);
 
-    r = nm_sd_utils_unbase64mem(base64_key, base64_key_len, TRUE, &bin_arr, &bin_len);
+    r = nm_unbase64mem_full(base64_key, base64_key_len, TRUE, &bin_arr, &bin_len);
     if (r < 0)
         return FALSE;
     if (bin_len != required_key_len) {
diff --git a/src/libnm-core-impl/tests/test-general.c b/src/libnm-core-impl/tests/test-general.c
index 1856f6ad..64b3dca7 100644
--- a/src/libnm-core-impl/tests/test-general.c
+++ b/src/libnm-core-impl/tests/test-general.c
@@ -1338,6 +1338,7 @@ typedef struct {
 static int
 _c_list_sort_cmp(const CList *lst_a, const CList *lst_b, const void *user_data)
 {
+    const int        MODFIER = user_data ? GPOINTER_TO_INT(user_data) : 0;
     const CListSort *a, *b;
 
     g_assert(lst_a);
@@ -1351,9 +1352,36 @@ _c_list_sort_cmp(const CList *lst_a, const CList *lst_b, const void *user_data)
         return -1;
     if (a->val > b->val)
         return 1;
+
+    switch (MODFIER) {
+    case 0:
+        break;
+    case 1:
+        NM_CMP_DIRECT_PTR(a, b);
+        g_assert_not_reached();
+        break;
+    case 2:
+        NM_CMP_DIRECT_PTR(b, a);
+        g_assert_not_reached();
+        break;
+    default:
+        g_assert_not_reached();
+        break;
+    }
+
     return 0;
 }
 
+static int
+_c_list_sort_cmp_inverse(const CList *lst_a, const CList *lst_b, const void *user_data)
+{
+    int c;
+
+    c = _c_list_sort_cmp(lst_b, lst_a, user_data);
+    g_assert(NM_IN_SET(c, -1, 0, 1));
+    return c;
+}
+
 static void
 _do_test_c_list_sort(CListSort *elements, guint n_list, gboolean headless)
 {
@@ -1411,8 +1439,9 @@ static void
 test_c_list_sort(void)
 {
     const guint        N_ELEMENTS = 10000;
-    guint              n_list, repeat;
-    gs_free CListSort *elements = NULL;
+    gs_free CListSort *elements   = NULL;
+    guint              n_list;
+    guint              repeat;
 
     {
         CList head;
@@ -1441,6 +1470,97 @@ test_c_list_sort(void)
 
 /*****************************************************************************/
 
+static void
+_do_test_c_list_insert_sorted(CListSort *elements, guint n_list, bool append_equal)
+{
+    CList            head;
+    guint            i;
+    const CListSort *el_prev;
+    CListSort       *el;
+
+    c_list_init(&head);
+    for (i = 0; i < n_list; i++) {
+        el      = &elements[i];
+        el->val = nmtst_get_rand_uint32() % (2 * n_list);
+
+        if (nmtst_get_rand_bool()) {
+            c_list_insert_sorted(&head, &el->lst, TRUE, append_equal, _c_list_sort_cmp, NULL);
+        } else {
+            c_list_insert_sorted(&head,
+                                 &el->lst,
+                                 FALSE,
+                                 append_equal,
+                                 _c_list_sort_cmp_inverse,
+                                 NULL);
+        }
+
+        if (nmtst_get_rand_one_case_in(20)) {
+            nm_assert(c_list_is_sorted(&head, TRUE, _c_list_sort_cmp, NULL));
+            if (append_equal) {
+                nm_assert(c_list_is_sorted(&head, TRUE, _c_list_sort_cmp, GINT_TO_POINTER(1)));
+            } else {
+                nm_assert(c_list_is_sorted(&head, TRUE, _c_list_sort_cmp, GINT_TO_POINTER(2)));
+            }
+            nm_assert(c_list_is_sorted(&head, FALSE, _c_list_sort_cmp_inverse, NULL));
+            if (append_equal) {
+                nm_assert(
+                    c_list_is_sorted(&head, FALSE, _c_list_sort_cmp_inverse, GINT_TO_POINTER(1)));
+            } else {
+                nm_assert(
+                    c_list_is_sorted(&head, FALSE, _c_list_sort_cmp_inverse, GINT_TO_POINTER(2)));
+            }
+        }
+    }
+
+    g_assert_cmpint(c_list_length(&head), ==, n_list);
+    g_assert(!c_list_length_is(&head, n_list - 1));
+    g_assert(c_list_length_is(&head, n_list));
+    g_assert(!c_list_length_is(&head, n_list + 1));
+
+    el_prev = NULL;
+    c_list_for_each_entry (el, &head, lst) {
+        if (el_prev) {
+            int c;
+
+            c = _c_list_sort_cmp(&el_prev->lst, &el->lst, NULL);
+            g_assert_cmpint(c, <=, 0);
+            if (c == 0) {
+                if (append_equal)
+                    g_assert(&el_prev->lst < &el->lst);
+                else
+                    g_assert(&el_prev->lst > &el->lst);
+            }
+        }
+        el_prev = el;
+    }
+}
+
+static void
+test_c_list_insert_sorted(void)
+{
+    const guint        N_ELEMENTS = 1000;
+    gs_free CListSort *elements   = NULL;
+    guint              n_list;
+    guint              repeat;
+
+    elements = g_new0(CListSort, N_ELEMENTS);
+    for (n_list = 1; n_list < N_ELEMENTS; n_list++) {
+        if (n_list > 150) {
+            n_list += nmtst_get_rand_uint32() % n_list;
+            if (n_list >= N_ELEMENTS)
+                break;
+        }
+        {
+            const guint N_REPEAT = n_list > 50 ? 1 : 5;
+
+            for (repeat = 0; repeat < N_REPEAT; repeat++)
+                _do_test_c_list_insert_sorted(elements, n_list, nmtst_get_rand_bool());
+        }
+    }
+}
+
+/*****************************************************************************/
+
 typedef struct {
     NMDedupMultiObj parent;
     guint           val;
@@ -2381,12 +2501,18 @@ test_setting_ip_route_attributes(void)
     TEST_ATTR("tos", byte, 127, AF_INET, TRUE, TRUE);
     TEST_ATTR("tos", string, "0x28", AF_INET, FALSE, TRUE);
 
+    TEST_ATTR("advmss", uint32, 1400, AF_INET, TRUE, TRUE);
+    TEST_ATTR("advmss", string, "1400", AF_INET, FALSE, TRUE);
+
     TEST_ATTR("cwnd", uint32, 10, AF_INET, TRUE, TRUE);
     TEST_ATTR("cwnd", string, "11", AF_INET, FALSE, TRUE);
 
     TEST_ATTR("lock-mtu", boolean, TRUE, AF_INET, TRUE, TRUE);
     TEST_ATTR("lock-mtu", uint32, 1, AF_INET, FALSE, TRUE);
 
+    TEST_ATTR("lock-advmss", boolean, TRUE, AF_INET, TRUE, TRUE);
+    TEST_ATTR("lock-advmss", boolean, TRUE, AF_INET6, TRUE, TRUE);
+
     TEST_ATTR("from", string, "fd01::1", AF_INET6, TRUE, TRUE);
     TEST_ATTR("from", string, "fd01::1/64", AF_INET6, TRUE, TRUE);
     TEST_ATTR("from", string, "fd01::1/128", AF_INET6, TRUE, TRUE);
@@ -2396,6 +2522,12 @@ test_setting_ip_route_attributes(void)
     TEST_ATTR("from", string, "1.2.3.4", AF_INET, FALSE, TRUE);
     TEST_ATTR("from", string, "1.2.3.4", AF_INET6, FALSE, TRUE);
 
+    TEST_ATTR("quickack", boolean, TRUE, AF_INET, TRUE, TRUE);
+    TEST_ATTR("quickack", boolean, TRUE, AF_INET6, TRUE, TRUE);
+
+    TEST_ATTR("rto_min", uint32, 1000, AF_INET, TRUE, TRUE);
+    TEST_ATTR("rto_min", uint32, 1000, AF_INET6, TRUE, TRUE);
+
     TEST_ATTR("src", string, "1.2.3.4", AF_INET, TRUE, TRUE);
     TEST_ATTR("src", string, "1.2.3.4", AF_INET6, FALSE, TRUE);
     TEST_ATTR("src", string, "1.2.3.0/24", AF_INET, FALSE, TRUE);
@@ -3822,8 +3954,10 @@ test_connection_diff_a_only(void)
           {NM_SETTING_CONNECTION_MDNS, NM_SETTING_DIFF_RESULT_IN_A},
           {NM_SETTING_CONNECTION_LLMNR, NM_SETTING_DIFF_RESULT_IN_A},
           {NM_SETTING_CONNECTION_DNS_OVER_TLS, NM_SETTING_DIFF_RESULT_IN_A},
+          {NM_SETTING_CONNECTION_MPTCP_FLAGS, NM_SETTING_DIFF_RESULT_IN_A},
           {NM_SETTING_CONNECTION_MUD_URL, NM_SETTING_DIFF_RESULT_IN_A},
           {NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A},
+          {NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY, NM_SETTING_DIFF_RESULT_IN_A},
           {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN}}},
         {NM_SETTING_WIRED_SETTING_NAME,
          {
@@ -3872,6 +4006,7 @@ test_connection_diff_a_only(void)
              {NM_SETTING_IP_CONFIG_DHCP_IAID, NM_SETTING_DIFF_RESULT_IN_A},
              {NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER, NM_SETTING_DIFF_RESULT_IN_A},
              {NM_SETTING_IP_CONFIG_DHCP_REJECT_SERVERS, NM_SETTING_DIFF_RESULT_IN_A},
+             {NM_SETTING_IP4_CONFIG_LINK_LOCAL, NM_SETTING_DIFF_RESULT_IN_A},
              {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN},
          }},
     };
@@ -3914,11 +4049,11 @@ test_connection_diff_different(void)
     NMSettingIPConfig *s_ip4;
     gboolean           same;
     const DiffSetting  settings[] = {
-        {NM_SETTING_IP4_CONFIG_SETTING_NAME,
-         {
-             {NM_SETTING_IP_CONFIG_METHOD,
-              NM_SETTING_DIFF_RESULT_IN_A | NM_SETTING_DIFF_RESULT_IN_B},
-             {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN},
+         {NM_SETTING_IP4_CONFIG_SETTING_NAME,
+          {
+              {NM_SETTING_IP_CONFIG_METHOD,
+               NM_SETTING_DIFF_RESULT_IN_A | NM_SETTING_DIFF_RESULT_IN_B},
+              {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN},
          }},
     };
 
@@ -3999,10 +4134,10 @@ test_connection_diff_inferrable(void)
     NMSettingIPConfig   *s_ip4;
     char                *uuid;
     const DiffSetting    settings[] = {
-        {NM_SETTING_CONNECTION_SETTING_NAME,
-         {
-             {NM_SETTING_CONNECTION_INTERFACE_NAME, NM_SETTING_DIFF_RESULT_IN_A},
-             {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN},
+           {NM_SETTING_CONNECTION_SETTING_NAME,
+            {
+                {NM_SETTING_CONNECTION_INTERFACE_NAME, NM_SETTING_DIFF_RESULT_IN_A},
+                {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN},
          }},
     };
 
@@ -4923,7 +5058,7 @@ _netmask_to_prefix(guint32 netmask)
 
     /* we re-implemented the netmask-to-prefix code differently. Check
      * that they agree. */
-    g_assert_cmpint(prefix, ==, nm_utils_ip4_netmask_to_prefix(netmask));
+    g_assert_cmpint(prefix, ==, _nm_utils_ip4_netmask_to_prefix(netmask));
 
     return prefix;
 }
@@ -6722,53 +6857,53 @@ test_setting_ip6_gateway(void)
     GVariant          *gateway_var;
     GVariantBuilder    addrs_builder;
     guint8             addr_bytes_0[]    = {0xab,
-                             0xcd,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x0a};
+                                            0xcd,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x0a};
     guint8             addr_bytes_1[]    = {0xab,
-                             0xcd,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x00,
-                             0x0b};
+                                            0xcd,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x0b};
     guint8             gateway_bytes_1[] = {0xab,
-                                0xcd,
-                                0x00,
-                                0x00,
-                                0x00,
-                                0x00,
-                                0x00,
-                                0x00,
-                                0x00,
-                                0x00,
-                                0x00,
-                                0x00,
-                                0x00,
-                                0x00,
-                                0x00,
-                                0x01};
+                                            0xcd,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x00,
+                                            0x01};
     GError            *error             = NULL;
 
     /* When serializing on the daemon side, ipv6.gateway is copied to the first
@@ -8989,6 +9124,10 @@ test_nm_utils_enum(void)
             .value = 5,
         },
         {
+            .nick  = "nick-0",
+            .value = 0,
+        },
+        {
             .nick  = "nick-red",
             .value = NM_TEST_GENERAL_COLOR_FLAGS_RED,
         },
@@ -9035,6 +9174,8 @@ test_nm_utils_enum(void)
                                        "nick-5, green",
                                        color_value_infos);
 
+    _test_nm_utils_enum_to_str_do_full(color_flags, 0, "nick-0", color_value_infos);
+
     _test_nm_utils_enum_from_str_do(bool_enum, "", FALSE, 0, NULL);
     _test_nm_utils_enum_from_str_do(bool_enum, " ", FALSE, 0, NULL);
     _test_nm_utils_enum_from_str_do(bool_enum, "invalid", FALSE, 0, "invalid");
@@ -10824,6 +10965,7 @@ main(int argc, char **argv)
     g_test_add_func("/core/general/test_nm_hash", test_nm_hash);
     g_test_add_func("/core/general/test_nm_g_slice_free_fcn", test_nm_g_slice_free_fcn);
     g_test_add_func("/core/general/test_c_list_sort", test_c_list_sort);
+    g_test_add_func("/core/general/test_c_list_insert_sorted", test_c_list_insert_sorted);
     g_test_add_func("/core/general/test_dedup_multi", test_dedup_multi);
     g_test_add_func("/core/general/test_utils_str_utf8safe", test_utils_str_utf8safe);
     g_test_add_func("/core/general/test_nm_strsplit_set", test_nm_strsplit_set);
diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c
index 788f218d..5bdae716 100644
--- a/src/libnm-core-impl/tests/test-setting.c
+++ b/src/libnm-core-impl/tests/test-setting.c
@@ -3596,7 +3596,7 @@ test_roundtrip_conversion(gconstpointer test_data)
                             "method=auto\n"
                             "\n"
                             "[ipv6]\n"
-                            "addr-gen-mode=stable-privacy\n"
+                            "addr-gen-mode=default\n"
                             "method=auto\n"
                             "\n"
                             "[proxy]\n"
@@ -3623,7 +3623,7 @@ test_roundtrip_conversion(gconstpointer test_data)
                             "method=auto\n"
                             "\n"
                             "[ipv6]\n"
-                            "addr-gen-mode=stable-privacy\n"
+                            "addr-gen-mode=default\n"
                             "method=auto\n"
                             "",
                             ID,
@@ -3660,7 +3660,7 @@ test_roundtrip_conversion(gconstpointer test_data)
                                         "method=disabled\n"
                                         "\n"
                                         "[ipv6]\n"
-                                        "addr-gen-mode=stable-privacy\n"
+                                        "addr-gen-mode=default\n"
                                         "method=disabled\n"
                                         "\n"
                                         "[proxy]\n"
@@ -3714,7 +3714,7 @@ test_roundtrip_conversion(gconstpointer test_data)
                 "method=disabled\n"
                 "\n"
                 "[ipv6]\n"
-                "addr-gen-mode=stable-privacy\n"
+                "addr-gen-mode=default\n"
                 "method=disabled\n"
                 "\n"
                 "[proxy]\n"
@@ -3795,7 +3795,7 @@ test_roundtrip_conversion(gconstpointer test_data)
                             "routing-rule3=priority 3 from 192.168.2.0/26 table 1002\n"
                             "\n"
                             "[ipv6]\n"
-                            "addr-gen-mode=stable-privacy\n"
+                            "addr-gen-mode=default\n"
                             "method=auto\n"
                             "routing-rule1=priority 1 from ::/0 table 1000\n"
                             "routing-rule2=priority 2 from 1:2:3:b::/65 table 1001\n"