summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2023-01-11 13:39:59 +0100
committerMichael Biebl <biebl@debian.org>2023-01-11 13:39:59 +0100
commit5d9e3721ad196595acd064e0d3ce66edc2613e51 (patch)
tree6480cd1117dca38cc1e38915cfc34e81d0f899d5
parent2965dc70bb3cbfa8de2f279761812b84b87600cb (diff)
New upstream version 1.40.10 upstream/1.40.10
-rw-r--r--Makefile.examples1
-rw-r--r--Makefile.in1
-rw-r--r--NEWS12
-rwxr-xr-xconfigure26
-rw-r--r--configure.ac2
-rw-r--r--docs/api/dbus-org.freedesktop.NetworkManager.Device.xml5
-rw-r--r--docs/api/html/NetworkManager.devhelp299
-rw-r--r--docs/api/html/gdbus-org.freedesktop.NetworkManager.Device.html6
-rw-r--r--docs/api/html/index.html2
-rw-r--r--docs/api/html/ix01.html16
-rw-r--r--docs/api/html/nm-dbus-types.html67
-rw-r--r--docs/api/version.xml2
-rw-r--r--docs/libnm/html/NMDevice.html4
-rw-r--r--docs/libnm/html/NMVpnConnection.html8
-rw-r--r--docs/libnm/html/NMVpnPluginOld.html12
-rw-r--r--docs/libnm/html/NMVpnServicePlugin.html6
-rw-r--r--docs/libnm/html/api-index-full.html12
-rw-r--r--docs/libnm/html/index.html2
-rw-r--r--docs/libnm/html/libnm-nm-dbus-interface.html38
-rw-r--r--docs/libnm/html/libnm.devhelp23
-rw-r--r--docs/libnm/html/object-tree.html8
-rw-r--r--docs/libnm/html/usage.html2
-rw-r--r--docs/libnm/libnm-sections.txt1
-rw-r--r--docs/libnm/version.xml2
-rwxr-xr-xexamples/python/gi/device-reapply.py147
-rw-r--r--introspection/org.freedesktop.NetworkManager.Device.xml5
-rw-r--r--man/NetworkManager-dispatcher.84
-rw-r--r--man/NetworkManager-wait-online.service.84
-rw-r--r--man/NetworkManager.86
-rw-r--r--man/NetworkManager.conf.56
-rw-r--r--man/nm-cloud-setup.86
-rw-r--r--man/nm-initrd-generator.86
-rw-r--r--man/nm-online.16
-rw-r--r--man/nm-openvswitch.76
-rw-r--r--man/nm-settings-dbus.56
-rw-r--r--man/nm-settings-dbus.xml2
-rw-r--r--man/nm-settings-ifcfg-rh.56
-rw-r--r--man/nm-settings-ifcfg-rh.xml2
-rw-r--r--man/nm-settings-keyfile.56
-rw-r--r--man/nm-settings-keyfile.xml2
-rw-r--r--man/nm-settings-nmcli.56
-rw-r--r--man/nm-settings-nmcli.xml2
-rw-r--r--man/nmcli-examples.76
-rw-r--r--man/nmcli.16
-rw-r--r--man/nmtui.16
-rw-r--r--meson.build2
-rw-r--r--po/NetworkManager.pot252
-rw-r--r--src/core/devices/nm-device-veth.c32
-rw-r--r--src/core/devices/nm-device.c128
-rw-r--r--src/core/devices/nm-device.h5
-rw-r--r--src/core/dhcp/nm-dhcp-client.c117
-rw-r--r--src/core/dhcp/nm-dhcp-client.h17
-rw-r--r--src/core/dhcp/nm-dhcp-dhclient-utils.c91
-rw-r--r--src/core/dhcp/nm-dhcp-dhclient-utils.h5
-rw-r--r--src/core/dhcp/nm-dhcp-dhclient.c39
-rw-r--r--src/core/dhcp/nm-dhcp-nettools.c17
-rw-r--r--src/core/dhcp/nm-dhcp-options.c8
-rw-r--r--src/core/dhcp/nm-dhcp-options.h9
-rw-r--r--src/core/dhcp/nm-dhcp-systemd.c6
-rw-r--r--src/core/dhcp/tests/test-dhcp-dhclient.c248
-rw-r--r--src/core/dns/nm-dns-dnsmasq.c11
-rw-r--r--src/core/dns/nm-dns-dnsmasq.h2
-rw-r--r--src/core/dns/nm-dns-manager.c3
-rw-r--r--src/core/ndisc/nm-fake-ndisc.c2
-rw-r--r--src/core/nm-policy.c112
-rw-r--r--src/libnm-client-impl/nm-device-modem.c10
-rw-r--r--src/libnm-client-impl/nm-device.c4
-rw-r--r--src/libnm-core-public/nm-dbus-interface.h18
-rw-r--r--src/libnm-core-public/nm-dbus-types.xml30
-rw-r--r--src/libnm-core-public/nm-version-macros.h2
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.c47
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.h21
-rw-r--r--src/nm-cloud-setup/main.c64
-rw-r--r--src/nm-cloud-setup/nm-cloud-setup-utils.c16
-rw-r--r--src/nm-cloud-setup/nm-cloud-setup-utils.h1
-rw-r--r--src/nmcli/devices.c5
-rw-r--r--src/nmtui/nmt-device-entry.c2
77 files changed, 1167 insertions, 742 deletions
diff --git a/Makefile.examples b/Makefile.examples
index 076af724..3b262209 100644
--- a/Makefile.examples
+++ b/Makefile.examples
@@ -182,6 +182,7 @@ EXTRA_DIST += \
 	examples/python/gi/add_connection.py \
 	examples/python/gi/checkpoint.py \
 	examples/python/gi/deactivate-all.py \
+	examples/python/gi/device-reapply.py \
 	examples/python/gi/device-state-ip4config.py \
 	examples/python/gi/dns.py \
 	examples/python/gi/firewall-zone.py \
diff --git a/Makefile.in b/Makefile.in
index 51c5b09b..9128eb17 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -4993,6 +4993,7 @@ EXTRA_DIST = src/c-stdaux/src/c-stdaux.h $(NULL) \
 	examples/python/gi/add_connection.py \
 	examples/python/gi/checkpoint.py \
 	examples/python/gi/deactivate-all.py \
+	examples/python/gi/device-reapply.py \
 	examples/python/gi/device-state-ip4config.py \
 	examples/python/gi/dns.py examples/python/gi/firewall-zone.py \
 	examples/python/gi/get-active-connections.py \
diff --git a/NEWS b/NEWS
index 6ec9b358..237ef590 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,16 @@
 ===============================================
+NetworkManager-1.40.10
+Overview of changes since NetworkManager-1.40.8
+===============================================
+
+* Fix the evaluation of the autoconnect retries.
+* nm-cloud-setup now preserves addresses added externally.
+* Ensure that dnsmasq is stopped after changing the dns backend and
+  restarting the service.
+* Fix honoring an explicit DHCPv6 DUID with dhclient.
+* Other various fixes.
+
+===============================================
 NetworkManager-1.40.8
 Overview of changes since NetworkManager-1.40.6
 ===============================================
diff --git a/configure b/configure
index 5f7abe4e..d387a2f4 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for NetworkManager 1.40.8.
+# Generated by GNU Autoconf 2.71 for NetworkManager 1.40.10.
 #
 # Report bugs to <http://bugzilla.gnome.org/enter_bug.cgi?product=NetworkManager>.
 #
@@ -622,8 +622,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='NetworkManager'
 PACKAGE_TARNAME='NetworkManager'
-PACKAGE_VERSION='1.40.8'
-PACKAGE_STRING='NetworkManager 1.40.8'
+PACKAGE_VERSION='1.40.10'
+PACKAGE_STRING='NetworkManager 1.40.10'
 PACKAGE_BUGREPORT='http://bugzilla.gnome.org/enter_bug.cgi?product=NetworkManager'
 PACKAGE_URL=''
 
@@ -1744,7 +1744,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures NetworkManager 1.40.8 to adapt to many kinds of systems.
+\`configure' configures NetworkManager 1.40.10 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1816,7 +1816,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of NetworkManager 1.40.8:";;
+     short | recursive ) echo "Configuration of NetworkManager 1.40.10:";;
    esac
   cat <<\_ACEOF
 
@@ -2171,7 +2171,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-NetworkManager configure 1.40.8
+NetworkManager configure 1.40.10
 generated by GNU Autoconf 2.71
 
 Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2892,7 +2892,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by NetworkManager $as_me 1.40.8, which was
+It was created by NetworkManager $as_me 1.40.10, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -4388,7 +4388,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='NetworkManager'
- VERSION='1.40.8'
+ VERSION='1.40.10'
 
 
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -19328,8 +19328,8 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 NM_MAJOR_VERSION=1
 NM_MINOR_VERSION=40
-NM_MICRO_VERSION=8
-NM_VERSION=1.40.8
+NM_MICRO_VERSION=10
+NM_VERSION=1.40.10
 
 
 
@@ -19337,7 +19337,7 @@ NM_VERSION=1.40.8
 
 
 
-NM_GIT_SHA=56e29666629b4de98121acd50f0dc364f2066384
+NM_GIT_SHA=5a82c141562dc3a23c73514f7981d76c8b55ea19
 
 if test """" != "no-config-h" ; then
 
@@ -32786,7 +32786,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by NetworkManager $as_me 1.40.8, which was
+This file was extended by NetworkManager $as_me 1.40.10, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -32854,7 +32854,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-NetworkManager config.status 1.40.8
+NetworkManager config.status 1.40.10
 configured by $0, generated by GNU Autoconf 2.71,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index 27da3dcc..d5353e6e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,7 +8,7 @@ dnl    "shared/nm-version-macros.h.in"
 dnl  - update number in meson.build
 m4_define([nm_major_version], [1])
 m4_define([nm_minor_version], [40])
-m4_define([nm_micro_version], [8])
+m4_define([nm_micro_version], [10])
 m4_define([nm_version],
           [nm_major_version.nm_minor_version.nm_micro_version])
 
diff --git a/docs/api/dbus-org.freedesktop.NetworkManager.Device.xml b/docs/api/dbus-org.freedesktop.NetworkManager.Device.xml
index 0d73ca72..c8ccbd52 100644
--- a/docs/api/dbus-org.freedesktop.NetworkManager.Device.xml
+++ b/docs/api/dbus-org.freedesktop.NetworkManager.Device.xml
@@ -100,6 +100,9 @@ that the user made these changes intentionally outside of NetworkManager).
 Reapply can make the applied-connection different from the
 settings-connection, just like updating the settings-connection can make
 them different.
+</para><para>
+Since 1.42, 1.40.10, "preserve-external-ip" flag (0x1) is supported to not
+remove externally added IP addresses and routes on the device during reapply.
 </para>
 <variablelist role="params">
 <varlistentry>
@@ -117,7 +120,7 @@ If non-zero, the current version id of the applied-connection must match. The cu
 <varlistentry>
   <term><literal>IN u <parameter>flags</parameter></literal>:</term>
   <listitem><para>
-Flags which would modify the behavior of the Reapply call. There are no flags defined currently and the users should use the value of 0.
+Flags which would modify the behavior of the Reapply call. Invalid flags are rejected.
 </para></listitem>
 </varlistentry>
 </variablelist>
diff --git a/docs/api/html/NetworkManager.devhelp2 b/docs/api/html/NetworkManager.devhelp2
index 257f6bde..52186b6b 100644
--- a/docs/api/html/NetworkManager.devhelp2
+++ b/docs/api/html/NetworkManager.devhelp2
@@ -508,6 +508,7 @@
     <keyword type="enum" name="enum NMActivationStateFlags" link="nm-dbus-types.html#NMActivationStateFlags"/>
     <keyword type="enum" name="enum NMSettingsAddConnection2Flags" link="nm-dbus-types.html#NMSettingsAddConnection2Flags"/>
     <keyword type="enum" name="enum NMSettingsUpdate2Flags" link="nm-dbus-types.html#NMSettingsUpdate2Flags"/>
+    <keyword type="enum" name="enum NMDeviceReapplyFlags" link="nm-dbus-types.html#NMDeviceReapplyFlags"/>
     <keyword type="enum" name="enum NMTernary" link="nm-dbus-types.html#NMTernary"/>
     <keyword type="enum" name="enum NMManagerReloadFlags" link="nm-dbus-types.html#NMManagerReloadFlags"/>
     <keyword type="enum" name="enum NMDeviceInterfaceFlags" link="nm-dbus-types.html#NMDeviceInterfaceFlags"/>
@@ -811,54 +812,56 @@
     <keyword type="constant" name="NM_SETTINGS_UPDATE2_FLAG_VOLATILE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.29.4.2.1.4.6.1.1id-1.4.17.2.29.4.2.1.4.6.1.2"/>
     <keyword type="constant" name="NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.29.4.2.1.4.7.1.1id-1.4.17.2.29.4.2.1.4.7.1.2"/>
     <keyword type="constant" name="NM_SETTINGS_UPDATE2_FLAG_NO_REAPPLY" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.29.4.2.1.4.8.1.1id-1.4.17.2.29.4.2.1.4.8.1.2"/>
-    <keyword type="constant" name="NM_TERNARY_DEFAULT" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.30.4.2.1.4.1.1.1id-1.4.17.2.30.4.2.1.4.1.1.2"/>
-    <keyword type="constant" name="NM_TERNARY_FALSE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.30.4.2.1.4.2.1.1id-1.4.17.2.30.4.2.1.4.2.1.2"/>
-    <keyword type="constant" name="NM_TERNARY_TRUE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.30.4.2.1.4.3.1.1id-1.4.17.2.30.4.2.1.4.3.1.2"/>
-    <keyword type="constant" name="NM_MANAGER_RELOAD_FLAG_NONE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.31.4.2.1.4.1.1.1id-1.4.17.2.31.4.2.1.4.1.1.2"/>
-    <keyword type="constant" name="NM_MANAGER_RELOAD_FLAG_CONF" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.31.4.2.1.4.2.1.1id-1.4.17.2.31.4.2.1.4.2.1.2"/>
-    <keyword type="constant" name="NM_MANAGER_RELOAD_FLAG_DNS_RC" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.31.4.2.1.4.3.1.1id-1.4.17.2.31.4.2.1.4.3.1.2"/>
-    <keyword type="constant" name="NM_MANAGER_RELOAD_FLAG_DNS_FULL" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.31.4.2.1.4.4.1.1id-1.4.17.2.31.4.2.1.4.4.1.2"/>
-    <keyword type="constant" name="NM_MANAGER_RELOAD_FLAG_ALL" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.31.4.2.1.4.5.1.1id-1.4.17.2.31.4.2.1.4.5.1.2"/>
-    <keyword type="constant" name="NM_DEVICE_INTERFACE_FLAG_NONE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.32.4.2.1.4.1.1.1id-1.4.17.2.32.4.2.1.4.1.1.2"/>
-    <keyword type="constant" name="NM_DEVICE_INTERFACE_FLAG_UP" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.32.4.2.1.4.2.1.1id-1.4.17.2.32.4.2.1.4.2.1.2"/>
-    <keyword type="constant" name="NM_DEVICE_INTERFACE_FLAG_LOWER_UP" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.32.4.2.1.4.3.1.1id-1.4.17.2.32.4.2.1.4.3.1.2"/>
-    <keyword type="constant" name="NM_DEVICE_INTERFACE_FLAG_PROMISC" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.32.4.2.1.4.4.1.1id-1.4.17.2.32.4.2.1.4.4.1.2"/>
-    <keyword type="constant" name="NM_DEVICE_INTERFACE_FLAG_CARRIER" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.32.4.2.1.4.5.1.1id-1.4.17.2.32.4.2.1.4.5.1.2"/>
-    <keyword type="constant" name="NM_DEVICE_INTERFACE_FLAG_LLDP_CLIENT_ENABLED" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.32.4.2.1.4.6.1.1id-1.4.17.2.32.4.2.1.4.6.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_NONE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.1.1.1id-1.4.17.2.33.4.2.1.4.1.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_ENABLE_DISABLE_NETWORK" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.2.1.1id-1.4.17.2.33.4.2.1.4.2.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.3.1.1id-1.4.17.2.33.4.2.1.4.3.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.4.1.1id-1.4.17.2.33.4.2.1.4.4.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIMAX" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.5.1.1id-1.4.17.2.33.4.2.1.4.5.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_SLEEP_WAKE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.6.1.1id-1.4.17.2.33.4.2.1.4.6.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_NETWORK_CONTROL" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.7.1.1id-1.4.17.2.33.4.2.1.4.7.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_WIFI_SHARE_PROTECTED" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.8.1.1id-1.4.17.2.33.4.2.1.4.8.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.9.1.1id-1.4.17.2.33.4.2.1.4.9.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.10.1.1id-1.4.17.2.33.4.2.1.4.10.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_SETTINGS_MODIFY_OWN" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.11.1.1id-1.4.17.2.33.4.2.1.4.11.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_SETTINGS_MODIFY_HOSTNAME" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.12.1.1id-1.4.17.2.33.4.2.1.4.12.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.13.1.1id-1.4.17.2.33.4.2.1.4.13.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_RELOAD" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.14.1.1id-1.4.17.2.33.4.2.1.4.14.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.15.1.1id-1.4.17.2.33.4.2.1.4.15.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.16.1.1id-1.4.17.2.33.4.2.1.4.16.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.17.1.1id-1.4.17.2.33.4.2.1.4.17.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_WIFI_SCAN" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.18.1.1id-1.4.17.2.33.4.2.1.4.18.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_RESULT_UNKNOWN" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.1.1.1id-1.4.17.2.34.4.2.1.4.1.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_RESULT_YES" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.2.1.1id-1.4.17.2.34.4.2.1.4.2.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_RESULT_AUTH" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.3.1.1id-1.4.17.2.34.4.2.1.4.3.1.2"/>
-    <keyword type="constant" name="NM_CLIENT_PERMISSION_RESULT_NO" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.4.1.1id-1.4.17.2.34.4.2.1.4.4.1.2"/>
-    <keyword type="constant" name="NM_RADIO_FLAG_NONE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.35.4.2.1.4.1.1.1id-1.4.17.2.35.4.2.1.4.1.1.2"/>
-    <keyword type="constant" name="NM_RADIO_FLAG_WLAN_AVAILABLE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.35.4.2.1.4.2.1.1id-1.4.17.2.35.4.2.1.4.2.1.2"/>
-    <keyword type="constant" name="NM_RADIO_FLAG_WWAN_AVAILABLE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.35.4.2.1.4.3.1.1id-1.4.17.2.35.4.2.1.4.3.1.2"/>
-    <keyword type="constant" name="NM_MPTCP_FLAGS_NONE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.36.4.2.1.4.1.1.1id-1.4.17.2.36.4.2.1.4.1.1.2"/>
-    <keyword type="constant" name="NM_MPTCP_FLAGS_DISABLED" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.36.4.2.1.4.2.1.1id-1.4.17.2.36.4.2.1.4.2.1.2"/>
-    <keyword type="constant" name="NM_MPTCP_FLAGS_ENABLED" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.36.4.2.1.4.3.1.1id-1.4.17.2.36.4.2.1.4.3.1.2"/>
-    <keyword type="constant" name="NM_MPTCP_FLAGS_ALSO_WITHOUT_SYSCTL" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.36.4.2.1.4.4.1.1id-1.4.17.2.36.4.2.1.4.4.1.2"/>
-    <keyword type="constant" name="NM_MPTCP_FLAGS_ALSO_WITHOUT_DEFAULT_ROUTE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.36.4.2.1.4.5.1.1id-1.4.17.2.36.4.2.1.4.5.1.2"/>
-    <keyword type="constant" name="NM_MPTCP_FLAGS_SIGNAL" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.36.4.2.1.4.6.1.1id-1.4.17.2.36.4.2.1.4.6.1.2"/>
-    <keyword type="constant" name="NM_MPTCP_FLAGS_SUBFLOW" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.36.4.2.1.4.7.1.1id-1.4.17.2.36.4.2.1.4.7.1.2"/>
-    <keyword type="constant" name="NM_MPTCP_FLAGS_BACKUP" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.36.4.2.1.4.8.1.1id-1.4.17.2.36.4.2.1.4.8.1.2"/>
-    <keyword type="constant" name="NM_MPTCP_FLAGS_FULLMESH" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.36.4.2.1.4.9.1.1id-1.4.17.2.36.4.2.1.4.9.1.2"/>
+    <keyword type="constant" name="NM_DEVICE_REAPPLY_FLAGS_NONE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.30.4.2.1.4.1.1.1id-1.4.17.2.30.4.2.1.4.1.1.2"/>
+    <keyword type="constant" name="NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.30.4.2.1.4.2.1.1id-1.4.17.2.30.4.2.1.4.2.1.2"/>
+    <keyword type="constant" name="NM_TERNARY_DEFAULT" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.31.4.2.1.4.1.1.1id-1.4.17.2.31.4.2.1.4.1.1.2"/>
+    <keyword type="constant" name="NM_TERNARY_FALSE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.31.4.2.1.4.2.1.1id-1.4.17.2.31.4.2.1.4.2.1.2"/>
+    <keyword type="constant" name="NM_TERNARY_TRUE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.31.4.2.1.4.3.1.1id-1.4.17.2.31.4.2.1.4.3.1.2"/>
+    <keyword type="constant" name="NM_MANAGER_RELOAD_FLAG_NONE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.32.4.2.1.4.1.1.1id-1.4.17.2.32.4.2.1.4.1.1.2"/>
+    <keyword type="constant" name="NM_MANAGER_RELOAD_FLAG_CONF" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.32.4.2.1.4.2.1.1id-1.4.17.2.32.4.2.1.4.2.1.2"/>
+    <keyword type="constant" name="NM_MANAGER_RELOAD_FLAG_DNS_RC" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.32.4.2.1.4.3.1.1id-1.4.17.2.32.4.2.1.4.3.1.2"/>
+    <keyword type="constant" name="NM_MANAGER_RELOAD_FLAG_DNS_FULL" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.32.4.2.1.4.4.1.1id-1.4.17.2.32.4.2.1.4.4.1.2"/>
+    <keyword type="constant" name="NM_MANAGER_RELOAD_FLAG_ALL" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.32.4.2.1.4.5.1.1id-1.4.17.2.32.4.2.1.4.5.1.2"/>
+    <keyword type="constant" name="NM_DEVICE_INTERFACE_FLAG_NONE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.1.1.1id-1.4.17.2.33.4.2.1.4.1.1.2"/>
+    <keyword type="constant" name="NM_DEVICE_INTERFACE_FLAG_UP" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.2.1.1id-1.4.17.2.33.4.2.1.4.2.1.2"/>
+    <keyword type="constant" name="NM_DEVICE_INTERFACE_FLAG_LOWER_UP" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.3.1.1id-1.4.17.2.33.4.2.1.4.3.1.2"/>
+    <keyword type="constant" name="NM_DEVICE_INTERFACE_FLAG_PROMISC" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.4.1.1id-1.4.17.2.33.4.2.1.4.4.1.2"/>
+    <keyword type="constant" name="NM_DEVICE_INTERFACE_FLAG_CARRIER" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.5.1.1id-1.4.17.2.33.4.2.1.4.5.1.2"/>
+    <keyword type="constant" name="NM_DEVICE_INTERFACE_FLAG_LLDP_CLIENT_ENABLED" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.33.4.2.1.4.6.1.1id-1.4.17.2.33.4.2.1.4.6.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_NONE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.1.1.1id-1.4.17.2.34.4.2.1.4.1.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_ENABLE_DISABLE_NETWORK" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.2.1.1id-1.4.17.2.34.4.2.1.4.2.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.3.1.1id-1.4.17.2.34.4.2.1.4.3.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.4.1.1id-1.4.17.2.34.4.2.1.4.4.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIMAX" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.5.1.1id-1.4.17.2.34.4.2.1.4.5.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_SLEEP_WAKE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.6.1.1id-1.4.17.2.34.4.2.1.4.6.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_NETWORK_CONTROL" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.7.1.1id-1.4.17.2.34.4.2.1.4.7.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_WIFI_SHARE_PROTECTED" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.8.1.1id-1.4.17.2.34.4.2.1.4.8.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.9.1.1id-1.4.17.2.34.4.2.1.4.9.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.10.1.1id-1.4.17.2.34.4.2.1.4.10.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_SETTINGS_MODIFY_OWN" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.11.1.1id-1.4.17.2.34.4.2.1.4.11.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_SETTINGS_MODIFY_HOSTNAME" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.12.1.1id-1.4.17.2.34.4.2.1.4.12.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.13.1.1id-1.4.17.2.34.4.2.1.4.13.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_RELOAD" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.14.1.1id-1.4.17.2.34.4.2.1.4.14.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.15.1.1id-1.4.17.2.34.4.2.1.4.15.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.16.1.1id-1.4.17.2.34.4.2.1.4.16.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.17.1.1id-1.4.17.2.34.4.2.1.4.17.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_WIFI_SCAN" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.34.4.2.1.4.18.1.1id-1.4.17.2.34.4.2.1.4.18.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_RESULT_UNKNOWN" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.35.4.2.1.4.1.1.1id-1.4.17.2.35.4.2.1.4.1.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_RESULT_YES" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.35.4.2.1.4.2.1.1id-1.4.17.2.35.4.2.1.4.2.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_RESULT_AUTH" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.35.4.2.1.4.3.1.1id-1.4.17.2.35.4.2.1.4.3.1.2"/>
+    <keyword type="constant" name="NM_CLIENT_PERMISSION_RESULT_NO" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.35.4.2.1.4.4.1.1id-1.4.17.2.35.4.2.1.4.4.1.2"/>
+    <keyword type="constant" name="NM_RADIO_FLAG_NONE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.36.4.2.1.4.1.1.1id-1.4.17.2.36.4.2.1.4.1.1.2"/>
+    <keyword type="constant" name="NM_RADIO_FLAG_WLAN_AVAILABLE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.36.4.2.1.4.2.1.1id-1.4.17.2.36.4.2.1.4.2.1.2"/>
+    <keyword type="constant" name="NM_RADIO_FLAG_WWAN_AVAILABLE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.36.4.2.1.4.3.1.1id-1.4.17.2.36.4.2.1.4.3.1.2"/>
+    <keyword type="constant" name="NM_MPTCP_FLAGS_NONE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.37.4.2.1.4.1.1.1id-1.4.17.2.37.4.2.1.4.1.1.2"/>
+    <keyword type="constant" name="NM_MPTCP_FLAGS_DISABLED" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.37.4.2.1.4.2.1.1id-1.4.17.2.37.4.2.1.4.2.1.2"/>
+    <keyword type="constant" name="NM_MPTCP_FLAGS_ENABLED" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.37.4.2.1.4.3.1.1id-1.4.17.2.37.4.2.1.4.3.1.2"/>
+    <keyword type="constant" name="NM_MPTCP_FLAGS_ALSO_WITHOUT_SYSCTL" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.37.4.2.1.4.4.1.1id-1.4.17.2.37.4.2.1.4.4.1.2"/>
+    <keyword type="constant" name="NM_MPTCP_FLAGS_ALSO_WITHOUT_DEFAULT_ROUTE" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.37.4.2.1.4.5.1.1id-1.4.17.2.37.4.2.1.4.5.1.2"/>
+    <keyword type="constant" name="NM_MPTCP_FLAGS_SIGNAL" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.37.4.2.1.4.6.1.1id-1.4.17.2.37.4.2.1.4.6.1.2"/>
+    <keyword type="constant" name="NM_MPTCP_FLAGS_SUBFLOW" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.37.4.2.1.4.7.1.1id-1.4.17.2.37.4.2.1.4.7.1.2"/>
+    <keyword type="constant" name="NM_MPTCP_FLAGS_BACKUP" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.37.4.2.1.4.8.1.1id-1.4.17.2.37.4.2.1.4.8.1.2"/>
+    <keyword type="constant" name="NM_MPTCP_FLAGS_FULLMESH" link="nm-dbus-types.htmlnm-dbus-types.html#id-1.4.17.2.37.4.2.1.4.9.1.1id-1.4.17.2.37.4.2.1.4.9.1.2"/>
     <keyword type="constant" name="NM_VPN_SERVICE_STATE_UNKNOWN" link="nm-vpn-dbus-types.htmlnm-vpn-dbus-types.html#id-1.6.3.2.3.4.2.1.4.1.1.1id-1.6.3.2.3.4.2.1.4.1.1.2"/>
     <keyword type="constant" name="NM_VPN_SERVICE_STATE_INIT" link="nm-vpn-dbus-types.htmlnm-vpn-dbus-types.html#id-1.6.3.2.3.4.2.1.4.2.1.1id-1.6.3.2.3.4.2.1.4.2.1.2"/>
     <keyword type="constant" name="NM_VPN_SERVICE_STATE_SHUTDOWN" link="nm-vpn-dbus-types.htmlnm-vpn-dbus-types.html#id-1.6.3.2.3.4.2.1.4.3.1.1id-1.6.3.2.3.4.2.1.4.3.1.2"/>
diff --git a/docs/api/html/gdbus-org.freedesktop.NetworkManager.Device.html b/docs/api/html/gdbus-org.freedesktop.NetworkManager.Device.html
index b1e492cb..f5026a1f 100644
--- a/docs/api/html/gdbus-org.freedesktop.NetworkManager.Device.html
+++ b/docs/api/html/gdbus-org.freedesktop.NetworkManager.Device.html
@@ -129,6 +129,10 @@ Reapply can make the applied-connection different from the
 settings-connection, just like updating the settings-connection can make
 them different.
 </p>
+<p>
+Since 1.42, 1.40.10, "preserve-external-ip" flag (0x1) is supported to not
+remove externally added IP addresses and routes on the device during reapply.
+</p>
 <div class="variablelist"><table border="0" class="variablelist">
 <colgroup>
 <col align="left" valign="top">
@@ -150,7 +154,7 @@ If non-zero, the current version id of the applied-connection must match. The cu
 <tr>
 <td><p><span class="term"><code class="literal">IN u <em class="parameter"><code>flags</code></em></code>:</span></p></td>
 <td><p>
-Flags which would modify the behavior of the Reapply call. There are no flags defined currently and the users should use the value of 0.
+Flags which would modify the behavior of the Reapply call. Invalid flags are rejected.
 </p></td>
 </tr>
 </tbody>
diff --git a/docs/api/html/index.html b/docs/api/html/index.html
index 6c1324c1..240e61e6 100644
--- a/docs/api/html/index.html
+++ b/docs/api/html/index.html
@@ -16,7 +16,7 @@
 <div>
 <div><table class="navigation" id="top" width="100%" cellpadding="2" cellspacing="0"><tr><th valign="middle"><p class="title">NetworkManager Reference Manual</p></th></tr></table></div>
 <div><p class="releaseinfo">
-      for NetworkManager 1.40.8
+      for NetworkManager 1.40.10
 
       The latest version of this documentation can be found on-line at
       <a class="ulink" href="https://networkmanager.dev/docs/api/latest/" target="_top">https://networkmanager.dev/docs/api/latest/</a>.
diff --git a/docs/api/html/ix01.html b/docs/api/html/ix01.html
index 15c9933b..d1897057 100644
--- a/docs/api/html/ix01.html
+++ b/docs/api/html/ix01.html
@@ -1123,9 +1123,9 @@
 </dt>
 <dt id="ientry-id-1.4.17.2.24.2">NMCheckpointCreateFlags, <a class="indexterm" href="nm-dbus-types.html#NMCheckpointCreateFlags">enum NMCheckpointCreateFlags</a>
 </dt>
-<dt id="ientry-id-1.4.17.2.33.2">NMClientPermission, <a class="indexterm" href="nm-dbus-types.html#NMClientPermission">enum NMClientPermission</a>
+<dt id="ientry-id-1.4.17.2.34.2">NMClientPermission, <a class="indexterm" href="nm-dbus-types.html#NMClientPermission">enum NMClientPermission</a>
 </dt>
-<dt id="ientry-id-1.4.17.2.34.2">NMClientPermissionResult, <a class="indexterm" href="nm-dbus-types.html#NMClientPermissionResult">enum NMClientPermissionResult</a>
+<dt id="ientry-id-1.4.17.2.35.2">NMClientPermissionResult, <a class="indexterm" href="nm-dbus-types.html#NMClientPermissionResult">enum NMClientPermissionResult</a>
 </dt>
 <dt id="ientry-id-1.4.17.2.18.2">NMConnectionMultiConnect, <a class="indexterm" href="nm-dbus-types.html#NMConnectionMultiConnect">enum NMConnectionMultiConnect</a>
 </dt>
@@ -1133,10 +1133,12 @@
 </dt>
 <dt id="ientry-id-1.4.17.2.7.2">NMDeviceCapabilities, <a class="indexterm" href="nm-dbus-types.html#NMDeviceCapabilities">enum NMDeviceCapabilities</a>
 </dt>
-<dt id="ientry-id-1.4.17.2.32.2">NMDeviceInterfaceFlags, <a class="indexterm" href="nm-dbus-types.html#NMDeviceInterfaceFlags">enum NMDeviceInterfaceFlags</a>
+<dt id="ientry-id-1.4.17.2.33.2">NMDeviceInterfaceFlags, <a class="indexterm" href="nm-dbus-types.html#NMDeviceInterfaceFlags">enum NMDeviceInterfaceFlags</a>
 </dt>
 <dt id="ientry-id-1.4.17.2.13.2">NMDeviceModemCapabilities, <a class="indexterm" href="nm-dbus-types.html#NMDeviceModemCapabilities">enum NMDeviceModemCapabilities</a>
 </dt>
+<dt id="ientry-id-1.4.17.2.30.2">NMDeviceReapplyFlags, <a class="indexterm" href="nm-dbus-types.html#NMDeviceReapplyFlags">enum NMDeviceReapplyFlags</a>
+</dt>
 <dt id="ientry-id-1.4.17.2.15.2">NMDeviceState, <a class="indexterm" href="nm-dbus-types.html#NMDeviceState">enum NMDeviceState</a>
 </dt>
 <dt id="ientry-id-1.4.17.2.16.2">NMDeviceStateReason, <a class="indexterm" href="nm-dbus-types.html#NMDeviceStateReason">enum NMDeviceStateReason</a>
@@ -1147,13 +1149,13 @@
 </dt>
 <dt id="ientry-id-1.4.17.2.23.2">NMIPTunnelMode, <a class="indexterm" href="nm-dbus-types.html#NMIPTunnelMode">enum NMIPTunnelMode</a>
 </dt>
-<dt id="ientry-id-1.4.17.2.31.2">NMManagerReloadFlags, <a class="indexterm" href="nm-dbus-types.html#NMManagerReloadFlags">enum NMManagerReloadFlags</a>
+<dt id="ientry-id-1.4.17.2.32.2">NMManagerReloadFlags, <a class="indexterm" href="nm-dbus-types.html#NMManagerReloadFlags">enum NMManagerReloadFlags</a>
 </dt>
 <dt id="ientry-id-1.4.17.2.17.2">NMMetered, <a class="indexterm" href="nm-dbus-types.html#NMMetered">enum NMMetered</a>
 </dt>
-<dt id="ientry-id-1.4.17.2.36.2">NMMptcpFlags, <a class="indexterm" href="nm-dbus-types.html#NMMptcpFlags">enum NMMptcpFlags</a>
+<dt id="ientry-id-1.4.17.2.37.2">NMMptcpFlags, <a class="indexterm" href="nm-dbus-types.html#NMMptcpFlags">enum NMMptcpFlags</a>
 </dt>
-<dt id="ientry-id-1.4.17.2.35.2">NMRadioFlags, <a class="indexterm" href="nm-dbus-types.html#NMRadioFlags">enum NMRadioFlags</a>
+<dt id="ientry-id-1.4.17.2.36.2">NMRadioFlags, <a class="indexterm" href="nm-dbus-types.html#NMRadioFlags">enum NMRadioFlags</a>
 </dt>
 <dt id="ientry-id-1.4.17.2.25.2">NMRollbackResult, <a class="indexterm" href="nm-dbus-types.html#NMRollbackResult">enum NMRollbackResult</a>
 </dt>
@@ -1169,7 +1171,7 @@
 </dt>
 <dt id="ientry-id-1.4.17.2.4.2">NMState, <a class="indexterm" href="nm-dbus-types.html#NMState">enum NMState</a>
 </dt>
-<dt id="ientry-id-1.4.17.2.30.2">NMTernary, <a class="indexterm" href="nm-dbus-types.html#NMTernary">enum NMTernary</a>
+<dt id="ientry-id-1.4.17.2.31.2">NMTernary, <a class="indexterm" href="nm-dbus-types.html#NMTernary">enum NMTernary</a>
 </dt>
 <dt id="ientry-id-1.6.3.2.4.2">NMVpnConnectionState, <a class="indexterm" href="nm-vpn-dbus-types.html#NMVpnConnectionState">enum NMVpnConnectionState</a>
 </dt>
diff --git a/docs/api/html/nm-dbus-types.html b/docs/api/html/nm-dbus-types.html
index 0580b439..892a1924 100644
--- a/docs/api/html/nm-dbus-types.html
+++ b/docs/api/html/nm-dbus-types.html
@@ -3071,7 +3071,7 @@
 <hr>
 <div class="refsect2">
 <a name="NMMetered"></a><h3>enum NMMetered</h3>
-<p>The NMMetered enum has two different purposes: one is to configure "connection.metered" setting of a connection profile in NMSettingConnection, and the other is to express the actual metered state of the NMDevice at a given moment.</p>
+<p>The NMMetered enum has two different purposes: one is to configure "connection.metered" setting of a connection profile in NMSettingConnection, and the other is to express the actual metered state of the <a href="/usr/share/gtk-doc/html/libnm/NMDevice.html#NMDevice-struct">NMDevice</a> at a given moment.</p>
 <p>For the connection profile only NM_METERED_UNKNOWN, NM_METERED_NO and NM_METERED_YES are allowed.</p>
 <p>The device's metered state at runtime is determined by the profile which is currently active. If the profile explicitly specifies NM_METERED_NO or NM_METERED_YES, then the device's metered state is as such. If the connection profile leaves it undecided at NM_METERED_UNKNOWN (the default), then NetworkManager tries to guess the metered state, for example based on the device type or on DHCP options (like Android devices exposing a "ANDROID_METERED" DHCP vendor option). This then leads to either NM_METERED_GUESS_NO or NM_METERED_GUESS_YES.</p>
 <p>Most applications probably should treat the runtime state NM_METERED_GUESS_YES like NM_METERED_YES, and all other states as not metered.</p>
@@ -4619,12 +4619,63 @@
 </div>
 <hr>
 <div class="refsect2">
+<a name="NMDeviceReapplyFlags"></a><h3>enum NMDeviceReapplyFlags</h3>
+<p>Flags for the Reapply() D-Bus call of a device and nm_device_reapply_async().</p>
+<p>Since: 1.42, 1.40.10</p>
+<p>On 1.40.10+, no GFlags type is created.</p>
+<p></p>
+<div class="refsect3">
+<a name="id-1.4.17.2.30.4"></a><h4>Values</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="300px" class="enum_members_name">
+<col width="100px" class="enum_members_value">
+<col class="enum_members_description">
+<col>
+</colgroup>
+<tbody>
+<tr>
+<td class="enum_member_name">
+<p>NM_DEVICE_REAPPLY_FLAGS_NONE</p>
+<p></p>
+</td>
+<td class="enum_member_value">
+<p>= <code class="literal">0</code></p>
+<p></p>
+</td>
+<td class="enum_member_description">
+<p>no flag set.</p>
+<p></p>
+</td>
+<td class="auto-generated"> </td>
+</tr>
+<tr>
+<td class="enum_member_name">
+<p>NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP</p>
+<p></p>
+</td>
+<td class="enum_member_value">
+<p>= <code class="literal">0x1</code></p>
+<p></p>
+</td>
+<td class="enum_member_description">
+<p>during reapply, preserve external IP addresses and routes.</p>
+<p></p>
+</td>
+<td class="auto-generated"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+</div>
+<hr>
+<div class="refsect2">
 <a name="NMTernary"></a><h3>enum NMTernary</h3>
 <p>An boolean value that can be overridden by a default.</p>
 <p>Since: 1.14</p>
 <p></p>
 <div class="refsect3">
-<a name="id-1.4.17.2.30.4"></a><h4>Values</h4>
+<a name="id-1.4.17.2.31.4"></a><h4>Values</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="300px" class="enum_members_name">
@@ -4689,7 +4740,7 @@
 <p>Since: 1.22</p>
 <p></p>
 <div class="refsect3">
-<a name="id-1.4.17.2.31.4"></a><h4>Values</h4>
+<a name="id-1.4.17.2.32.4"></a><h4>Values</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="300px" class="enum_members_name">
@@ -4784,7 +4835,7 @@
 <p>Since: 1.22</p>
 <p></p>
 <div class="refsect3">
-<a name="id-1.4.17.2.32.4"></a><h4>Values</h4>
+<a name="id-1.4.17.2.33.4"></a><h4>Values</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="300px" class="enum_members_name">
@@ -4893,7 +4944,7 @@
 <p><a class="link" href="nm-dbus-types.html#NMClientPermission" title="enum NMClientPermission">NMClientPermission</a> values indicate various permissions that NetworkManager clients can obtain to perform certain tasks on behalf of the current user.</p>
 <p></p>
 <div class="refsect3">
-<a name="id-1.4.17.2.33.4"></a><h4>Values</h4>
+<a name="id-1.4.17.2.34.4"></a><h4>Values</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="300px" class="enum_members_name">
@@ -5182,7 +5233,7 @@
 <p><a class="link" href="nm-dbus-types.html#NMClientPermissionResult" title="enum NMClientPermissionResult">NMClientPermissionResult</a> values indicate what authorizations and permissions the user requires to obtain a given <a class="link" href="nm-dbus-types.html#NMClientPermission" title="enum NMClientPermission">NMClientPermission</a></p>
 <p></p>
 <div class="refsect3">
-<a name="id-1.4.17.2.34.4"></a><h4>Values</h4>
+<a name="id-1.4.17.2.35.4"></a><h4>Values</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="300px" class="enum_members_name">
@@ -5262,7 +5313,7 @@
 <p>Since: 1.38</p>
 <p></p>
 <div class="refsect3">
-<a name="id-1.4.17.2.35.4"></a><h4>Values</h4>
+<a name="id-1.4.17.2.36.4"></a><h4>Values</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="300px" class="enum_members_name">
@@ -5326,7 +5377,7 @@
 <p>Since: 1.40</p>
 <p></p>
 <div class="refsect3">
-<a name="id-1.4.17.2.36.4"></a><h4>Values</h4>
+<a name="id-1.4.17.2.37.4"></a><h4>Values</h4>
 <div class="informaltable"><table class="informaltable" width="100%" border="0">
 <colgroup>
 <col width="300px" class="enum_members_name">
diff --git a/docs/api/version.xml b/docs/api/version.xml
index 19d25d0a..5faa4fff 100644
--- a/docs/api/version.xml
+++ b/docs/api/version.xml
@@ -1 +1 @@
-1.40.8
+1.40.10
diff --git a/docs/libnm/html/NMDevice.html b/docs/libnm/html/NMDevice.html
index ac125f88..6542dc63 100644
--- a/docs/libnm/html/NMDevice.html
+++ b/docs/libnm/html/NMDevice.html
@@ -2242,7 +2242,7 @@ nm_device_get_applied_connection (<em class="parameter"><code><a class="link" hr
 </tr>
 <tr>
 <td class="parameter_name"><p>flags</p></td>
-<td class="parameter_description"><p>the flags argument. Currently, this value must always be zero.</p></td>
+<td class="parameter_description"><p>the flags argument. See <a class="link" href="libnm-nm-dbus-interface.html#NMDeviceReapplyFlags" title="enum NMDeviceReapplyFlags"><span class="type">NMDeviceReapplyFlags</span></a>.</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
@@ -2301,7 +2301,7 @@ nm_device_get_applied_connection_async
 </tr>
 <tr>
 <td class="parameter_name"><p>flags</p></td>
-<td class="parameter_description"><p>the flags argument. Currently, this value must always be zero.</p></td>
+<td class="parameter_description"><p>the flags argument. See <a class="link" href="libnm-nm-dbus-interface.html#NMDeviceReapplyFlags" title="enum NMDeviceReapplyFlags"><span class="type">NMDeviceReapplyFlags</span></a>.</p></td>
 <td class="parameter_annotations"> </td>
 </tr>
 <tr>
diff --git a/docs/libnm/html/NMVpnConnection.html b/docs/libnm/html/NMVpnConnection.html
index 6dfe6f8b..1aeca777 100644
--- a/docs/libnm/html/NMVpnConnection.html
+++ b/docs/libnm/html/NMVpnConnection.html
@@ -44,7 +44,7 @@
 <tbody>
 <tr>
 <td class="function_type">
-<span class="returnvalue">NMVpnConnectionState</span>
+<a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnConnectionState"><span class="returnvalue">NMVpnConnectionState</span></a>
 </td>
 <td class="function_name">
 <a class="link" href="NMVpnConnection.html#nm-vpn-connection-get-vpn-state" title="nm_vpn_connection_get_vpn_state ()">nm_vpn_connection_get_vpn_state</a> <span class="c_punctuation">()</span>
@@ -76,7 +76,7 @@
 <td class="property_flags">Read</td>
 </tr>
 <tr>
-<td class="property_type"><span class="type">NMVpnConnectionState</span></td>
+<td class="property_type"><a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnConnectionState"><span class="type">NMVpnConnectionState</span></a></td>
 <td class="property_name"><a class="link" href="NMVpnConnection.html#NMVpnConnection--vpn-state" title="The “vpn-state” property">vpn-state</a></td>
 <td class="property_flags">Read</td>
 </tr>
@@ -136,7 +136,7 @@
 <a name="NMVpnConnection.functions_details"></a><h2>Functions</h2>
 <div class="refsect2">
 <a name="nm-vpn-connection-get-vpn-state"></a><h3>nm_vpn_connection_get_vpn_state ()</h3>
-<pre class="programlisting"><span class="returnvalue">NMVpnConnectionState</span>
+<pre class="programlisting"><a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnConnectionState"><span class="returnvalue">NMVpnConnectionState</span></a>
 nm_vpn_connection_get_vpn_state (<em class="parameter"><code><a class="link" href="NMVpnConnection.html" title="NMVpnConnection"><span class="type">NMVpnConnection</span></a> *vpn</code></em>);</pre>
 <p>Gets the current <a class="link" href="NMVpnConnection.html" title="NMVpnConnection"><span class="type">NMVpnConnection</span></a> state.</p>
 <div class="refsect3">
@@ -219,7 +219,7 @@ string used by the connection, and must not be modified.</p>
 <hr>
 <div class="refsect2">
 <a name="NMVpnConnection--vpn-state"></a><h3>The <code class="literal">“vpn-state”</code> property</h3>
-<pre class="programlisting">  “vpn-state”                <span class="type">NMVpnConnectionState</span></pre>
+<pre class="programlisting">  “vpn-state”                <a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnConnectionState"><span class="type">NMVpnConnectionState</span></a></pre>
 <p>The VPN state of the active VPN connection.</p>
 <p>Owner: NMVpnConnection</p>
 <p>Flags: Read</p>
diff --git a/docs/libnm/html/NMVpnPluginOld.html b/docs/libnm/html/NMVpnPluginOld.html
index ed72c07f..276d337b 100644
--- a/docs/libnm/html/NMVpnPluginOld.html
+++ b/docs/libnm/html/NMVpnPluginOld.html
@@ -53,7 +53,7 @@
 </tr>
 <tr>
 <td class="function_type">
-<span class="returnvalue">NMVpnServiceState</span>
+<a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnServiceState"><span class="returnvalue">NMVpnServiceState</span></a>
 </td>
 <td class="function_name">
 <a class="link" href="NMVpnPluginOld.html#nm-vpn-plugin-old-get-state" title="nm_vpn_plugin_old_get_state ()">nm_vpn_plugin_old_get_state</a> <span class="c_punctuation">()</span>
@@ -142,7 +142,7 @@
 <td class="property_flags">Read / Write / Construct Only</td>
 </tr>
 <tr>
-<td class="property_type"><span class="type">NMVpnServiceState</span></td>
+<td class="property_type"><a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnServiceState"><span class="type">NMVpnServiceState</span></a></td>
 <td class="property_name"><a class="link" href="NMVpnPluginOld.html#NMVpnPluginOld--state" title="The “state” property">state</a></td>
 <td class="property_flags">Read / Write</td>
 </tr>
@@ -258,7 +258,7 @@ nm_vpn_plugin_old_get_connection (<em class="parameter"><code><a class="link" hr
 <hr>
 <div class="refsect2">
 <a name="nm-vpn-plugin-old-get-state"></a><h3>nm_vpn_plugin_old_get_state ()</h3>
-<pre class="programlisting"><span class="returnvalue">NMVpnServiceState</span>
+<pre class="programlisting"><a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnServiceState"><span class="returnvalue">NMVpnServiceState</span></a>
 nm_vpn_plugin_old_get_state (<em class="parameter"><code><a class="link" href="NMVpnPluginOld.html" title="NMVpnPluginOld"><span class="type">NMVpnPluginOld</span></a> *plugin</code></em>);</pre>
 <div class="warning">
 <p><code class="literal">nm_vpn_plugin_old_get_state</code> has been deprecated since version 1.2 and should not be used in newly-written code.</p>
@@ -270,7 +270,7 @@ nm_vpn_plugin_old_get_state (<em class="parameter"><code><a class="link" href="N
 <a name="nm-vpn-plugin-old-set-state"></a><h3>nm_vpn_plugin_old_set_state ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 nm_vpn_plugin_old_set_state (<em class="parameter"><code><a class="link" href="NMVpnPluginOld.html" title="NMVpnPluginOld"><span class="type">NMVpnPluginOld</span></a> *plugin</code></em>,
-                             <em class="parameter"><code><span class="type">NMVpnServiceState</span> state</code></em>);</pre>
+                             <em class="parameter"><code><a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnServiceState"><span class="type">NMVpnServiceState</span></a> state</code></em>);</pre>
 <div class="warning">
 <p><code class="literal">nm_vpn_plugin_old_set_state</code> has been deprecated since version 1.2 and should not be used in newly-written code.</p>
 <p>Replaced by NMVpnServicePlugin.</p>
@@ -336,7 +336,7 @@ nm_vpn_plugin_old_set_login_banner (<em class="parameter"><code><a class="link"
 <a name="nm-vpn-plugin-old-failure"></a><h3>nm_vpn_plugin_old_failure ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 nm_vpn_plugin_old_failure (<em class="parameter"><code><a class="link" href="NMVpnPluginOld.html" title="NMVpnPluginOld"><span class="type">NMVpnPluginOld</span></a> *plugin</code></em>,
-                           <em class="parameter"><code><span class="type">NMVpnPluginFailure</span> reason</code></em>);</pre>
+                           <em class="parameter"><code><a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnPluginFailure"><span class="type">NMVpnPluginFailure</span></a> reason</code></em>);</pre>
 <div class="warning">
 <p><code class="literal">nm_vpn_plugin_old_failure</code> has been deprecated since version 1.2 and should not be used in newly-written code.</p>
 <p>Replaced by NMVpnServicePlugin.</p>
@@ -497,7 +497,7 @@ to flags, <a href="https://developer.gnome.org/glib/unstable/glib-Standard-Macro
 <hr>
 <div class="refsect2">
 <a name="NMVpnPluginOld--state"></a><h3>The <code class="literal">“state”</code> property</h3>
-<pre class="programlisting">  “state”                    <span class="type">NMVpnServiceState</span></pre>
+<pre class="programlisting">  “state”                    <a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnServiceState"><span class="type">NMVpnServiceState</span></a></pre>
 <p>The state of the plugin.</p>
 <div class="warning">
 <p><code class="literal">NMVpnPluginOld:state</code> has been deprecated since version 1.2 and should not be used in newly-written code.</p>
diff --git a/docs/libnm/html/NMVpnServicePlugin.html b/docs/libnm/html/NMVpnServicePlugin.html
index e53bfaa2..6349d207 100644
--- a/docs/libnm/html/NMVpnServicePlugin.html
+++ b/docs/libnm/html/NMVpnServicePlugin.html
@@ -150,7 +150,7 @@
 <td class="property_flags">Read / Write / Construct Only</td>
 </tr>
 <tr>
-<td class="property_type"><span class="type">NMVpnServiceState</span></td>
+<td class="property_type"><a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnServiceState"><span class="type">NMVpnServiceState</span></a></td>
 <td class="property_name"><a class="link" href="NMVpnServicePlugin.html#NMVpnServicePlugin--state" title="The “state” property">state</a></td>
 <td class="property_flags">Read / Write</td>
 </tr>
@@ -325,7 +325,7 @@ nm_vpn_service_plugin_set_login_banner
 <a name="nm-vpn-service-plugin-failure"></a><h3>nm_vpn_service_plugin_failure ()</h3>
 <pre class="programlisting"><span class="returnvalue">void</span>
 nm_vpn_service_plugin_failure (<em class="parameter"><code><a class="link" href="NMVpnServicePlugin.html" title="NMVpnServicePlugin"><span class="type">NMVpnServicePlugin</span></a> *plugin</code></em>,
-                               <em class="parameter"><code><span class="type">NMVpnPluginFailure</span> reason</code></em>);</pre>
+                               <em class="parameter"><code><a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnPluginFailure"><span class="type">NMVpnPluginFailure</span></a> reason</code></em>);</pre>
 <p class="since">Since: 1.2</p>
 </div>
 <hr>
@@ -522,7 +522,7 @@ to flags, <a href="https://developer.gnome.org/glib/unstable/glib-Standard-Macro
 <hr>
 <div class="refsect2">
 <a name="NMVpnServicePlugin--state"></a><h3>The <code class="literal">“state”</code> property</h3>
-<pre class="programlisting">  “state”                    <span class="type">NMVpnServiceState</span></pre>
+<pre class="programlisting">  “state”                    <a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnServiceState"><span class="type">NMVpnServiceState</span></a></pre>
 <p>The state of the plugin.</p>
 <p>Owner: NMVpnServicePlugin</p>
 <p>Flags: Read / Write</p>
diff --git a/docs/libnm/html/api-index-full.html b/docs/libnm/html/api-index-full.html
index a07306d0..a56e05db 100644
--- a/docs/libnm/html/api-index-full.html
+++ b/docs/libnm/html/api-index-full.html
@@ -913,6 +913,10 @@ NMDeviceEthernetClass, struct in <a class="link" href="NMIPConfig.html" title="N
 </dt>
 <dd></dd>
 <dt>
+<a class="link" href="libnm-nm-dbus-interface.html#NMDeviceReapplyFlags" title="enum NMDeviceReapplyFlags">NMDeviceReapplyFlags</a>, enum in <a class="link" href="libnm-nm-dbus-interface.html" title="nm-dbus-interface">nm-dbus-interface</a>
+</dt>
+<dd></dd>
+<dt>
 <a class="link" href="libnm-nm-dbus-interface.html#NMDeviceState" title="enum NMDeviceState">NMDeviceState</a>, enum in <a class="link" href="libnm-nm-dbus-interface.html" title="nm-dbus-interface">nm-dbus-interface</a>
 </dt>
 <dd></dd>
@@ -3765,11 +3769,11 @@ NMUtilsPredicateStr, user_function in NMSettingOvs
 </dt>
 <dd></dd>
 <dt>
-NMVpnConnectionState, enum in nm-vpn-dbus-interface
+<a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnConnectionState">NMVpnConnectionState</a>, enum in nm-vpn-dbus-interface
 </dt>
 <dd></dd>
 <dt>
-NMVpnConnectionStateReason, enum in nm-vpn-dbus-interface
+<a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnConnectionStateReason">NMVpnConnectionStateReason</a>, enum in nm-vpn-dbus-interface
 </dt>
 <dd></dd>
 <dt>
@@ -3821,7 +3825,7 @@ NMVpnConnectionStateReason, enum in nm-vpn-dbus-interface
 </dt>
 <dd></dd>
 <dt>
-NMVpnPluginFailure, enum in nm-vpn-dbus-interface
+<a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnPluginFailure">NMVpnPluginFailure</a>, enum in nm-vpn-dbus-interface
 </dt>
 <dd></dd>
 <dt>
@@ -3933,7 +3937,7 @@ NMVpnPluginFailure, enum in nm-vpn-dbus-interface
 </dt>
 <dd></dd>
 <dt>
-NMVpnServiceState, enum in nm-vpn-dbus-interface
+<a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnServiceState">NMVpnServiceState</a>, enum in nm-vpn-dbus-interface
 </dt>
 <dd></dd>
 <dt>
diff --git a/docs/libnm/html/index.html b/docs/libnm/html/index.html
index 9b382b70..6ed937a6 100644
--- a/docs/libnm/html/index.html
+++ b/docs/libnm/html/index.html
@@ -15,7 +15,7 @@
 <div>
 <div><table class="navigation" id="top" width="100%" cellpadding="2" cellspacing="0"><tr><th valign="middle"><p class="title">libnm Reference Manual</p></th></tr></table></div>
 <div><p class="releaseinfo">
-      for libnm 1.40.8
+      for libnm 1.40.10
 
       The latest version of this documentation can be found on-line at
       <a class="ulink" href="https://networkmanager.dev/docs/libnm/latest/" target="_top">https://networkmanager.dev/docs/libnm/latest/</a>.
diff --git a/docs/libnm/html/libnm-nm-dbus-interface.html b/docs/libnm/html/libnm-nm-dbus-interface.html
index 4db42937..a91a828e 100644
--- a/docs/libnm/html/libnm-nm-dbus-interface.html
+++ b/docs/libnm/html/libnm-nm-dbus-interface.html
@@ -490,6 +490,10 @@
 </tr>
 <tr>
 <td class="datatype_keyword">enum</td>
+<td class="function_name"><a class="link" href="libnm-nm-dbus-interface.html#NMDeviceReapplyFlags" title="enum NMDeviceReapplyFlags">NMDeviceReapplyFlags</a></td>
+</tr>
+<tr>
+<td class="datatype_keyword">enum</td>
 <td class="function_name"><a class="link" href="libnm-nm-dbus-interface.html#NMTernary" title="enum NMTernary">NMTernary</a></td>
 </tr>
 <tr>
@@ -3671,6 +3675,40 @@ the profile. Since: 1.20.</p>
 </div>
 <hr>
 <div class="refsect2">
+<a name="NMDeviceReapplyFlags"></a><h3>enum NMDeviceReapplyFlags</h3>
+<p>Flags for the <code class="function">Reapply()</code> D-Bus call of a device and
+<a class="link" href="NMDevice.html#nm-device-reapply-async" title="nm_device_reapply_async ()"><code class="function">nm_device_reapply_async()</code></a>.</p>
+<div class="refsect3">
+<a name="NMDeviceReapplyFlags.members"></a><h4>Members</h4>
+<div class="informaltable"><table class="informaltable" width="100%" border="0">
+<colgroup>
+<col width="300px" class="enum_members_name">
+<col class="enum_members_description">
+<col width="200px" class="enum_members_annotations">
+</colgroup>
+<tbody>
+<tr>
+<td class="enum_member_name"><p><a name="NM-DEVICE-REAPPLY-FLAGS-NONE:CAPS"></a>NM_DEVICE_REAPPLY_FLAGS_NONE</p></td>
+<td class="enum_member_description">
+<p>no flag set.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+<tr>
+<td class="enum_member_name"><p><a name="NM-DEVICE-REAPPLY-FLAGS-PRESERVE-EXTERNAL-IP:CAPS"></a>NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP</p></td>
+<td class="enum_member_description">
+<p>during reapply,
+preserve external IP addresses and routes.</p>
+</td>
+<td class="enum_member_annotations"> </td>
+</tr>
+</tbody>
+</table></div>
+</div>
+<p class="since">Since: 1.42, 1.40.10</p>
+</div>
+<hr>
+<div class="refsect2">
 <a name="NMTernary"></a><h3>enum NMTernary</h3>
 <p>An boolean value that can be overridden by a default.</p>
 <div class="refsect3">
diff --git a/docs/libnm/html/libnm.devhelp2 b/docs/libnm/html/libnm.devhelp2
index c3b8145c..308e60cd 100644
--- a/docs/libnm/html/libnm.devhelp2
+++ b/docs/libnm/html/libnm.devhelp2
@@ -494,6 +494,7 @@
     <keyword type="enum" name="enum NMActivationStateFlags" link="libnm-nm-dbus-interface.html#NMActivationStateFlags" since="1.10"/>
     <keyword type="enum" name="enum NMSettingsAddConnection2Flags" link="libnm-nm-dbus-interface.html#NMSettingsAddConnection2Flags" since="1.20"/>
     <keyword type="enum" name="enum NMSettingsUpdate2Flags" link="libnm-nm-dbus-interface.html#NMSettingsUpdate2Flags" since="1.12"/>
+    <keyword type="enum" name="enum NMDeviceReapplyFlags" link="libnm-nm-dbus-interface.html#NMDeviceReapplyFlags" since="1.42, 1.40.10"/>
     <keyword type="enum" name="enum NMTernary" link="libnm-nm-dbus-interface.html#NMTernary" since="1.14"/>
     <keyword type="enum" name="enum NMManagerReloadFlags" link="libnm-nm-dbus-interface.html#NMManagerReloadFlags" since="1.22"/>
     <keyword type="enum" name="enum NMDeviceInterfaceFlags" link="libnm-nm-dbus-interface.html#NMDeviceInterfaceFlags" since="1.22"/>
@@ -3485,6 +3486,8 @@
     <keyword type="constant" name="NM_SETTINGS_UPDATE2_FLAG_VOLATILE" link="libnm-nm-dbus-interface.html#NM-SETTINGS-UPDATE2-FLAG-VOLATILE:CAPS"/>
     <keyword type="constant" name="NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT" link="libnm-nm-dbus-interface.html#NM-SETTINGS-UPDATE2-FLAG-BLOCK-AUTOCONNECT:CAPS"/>
     <keyword type="constant" name="NM_SETTINGS_UPDATE2_FLAG_NO_REAPPLY" link="libnm-nm-dbus-interface.html#NM-SETTINGS-UPDATE2-FLAG-NO-REAPPLY:CAPS"/>
+    <keyword type="constant" name="NM_DEVICE_REAPPLY_FLAGS_NONE" link="libnm-nm-dbus-interface.html#NM-DEVICE-REAPPLY-FLAGS-NONE:CAPS"/>
+    <keyword type="constant" name="NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP" link="libnm-nm-dbus-interface.html#NM-DEVICE-REAPPLY-FLAGS-PRESERVE-EXTERNAL-IP:CAPS"/>
     <keyword type="constant" name="NM_TERNARY_DEFAULT" link="libnm-nm-dbus-interface.html#NM-TERNARY-DEFAULT:CAPS"/>
     <keyword type="constant" name="NM_TERNARY_FALSE" link="libnm-nm-dbus-interface.html#NM-TERNARY-FALSE:CAPS"/>
     <keyword type="constant" name="NM_TERNARY_TRUE" link="libnm-nm-dbus-interface.html#NM-TERNARY-TRUE:CAPS"/>
diff --git a/docs/libnm/html/object-tree.html b/docs/libnm/html/object-tree.html
index 04306fd0..ebc3205c 100644
--- a/docs/libnm/html/object-tree.html
+++ b/docs/libnm/html/object-tree.html
@@ -214,10 +214,10 @@
     <span class="lineart">├──</span> <a class="link" href="libnm-nm-dbus-interface.html#NMTernary" title="enum NMTernary">NMTernary</a>
     <span class="lineart">├──</span> <a class="link" href="libnm-nm-utils.html#NMUtilsSecurityType" title="enum NMUtilsSecurityType">NMUtilsSecurityType</a>
     <span class="lineart">├──</span> <a class="link" href="NMSettingVlan.html#NMVlanPriorityMap" title="enum NMVlanPriorityMap">NMVlanPriorityMap</a>
-    <span class="lineart">├──</span> NMVpnConnectionState
-    <span class="lineart">├──</span> NMVpnConnectionStateReason
-    <span class="lineart">├──</span> NMVpnPluginFailure
-    <span class="lineart">├──</span> NMVpnServiceState
+    <span class="lineart">├──</span> <a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnConnectionState">NMVpnConnectionState</a>
+    <span class="lineart">├──</span> <a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnConnectionStateReason">NMVpnConnectionStateReason</a>
+    <span class="lineart">├──</span> <a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnPluginFailure">NMVpnPluginFailure</a>
+    <span class="lineart">├──</span> <a href="/usr/share/gtk-doc/html/NetworkManager/nm-vpn-dbus-types.html#NMVpnServiceState">NMVpnServiceState</a>
     <span class="lineart">├──</span> <a class="link" href="NMSettingWirelessSecurity.html#NMWepKeyType" title="enum NMWepKeyType">NMWepKeyType</a>
     <span class="lineart">╰──</span> <a class="link" href="libnm-nm-dbus-interface.html#NMWimaxNspNetworkType" title="enum NMWimaxNspNetworkType">NMWimaxNspNetworkType</a>
     <a href="/usr/share/gtk-doc/html/gobject/gobject-Boxed-Types.html">GBoxed</a>
diff --git a/docs/libnm/html/usage.html b/docs/libnm/html/usage.html
index 3857f15a..e5334abc 100644
--- a/docs/libnm/html/usage.html
+++ b/docs/libnm/html/usage.html
@@ -96,7 +96,7 @@
         </p>
 <pre class="screen"><code class="prompt">$ </code><strong class="userinput"><code>cc $(pkg-config --libs --cflags libnm) -o hello-nm hello-nm.c</code></strong>
   <code class="prompt">$ </code><strong class="userinput"><code>./hello-nm</code></strong>
-  NetworkManager version: 1.40.8
+  NetworkManager version: 1.40.10
 
   <code class="prompt">$ </code></pre>
 <p>
diff --git a/docs/libnm/libnm-sections.txt b/docs/libnm/libnm-sections.txt
index e497c044..8bfa213b 100644
--- a/docs/libnm/libnm-sections.txt
+++ b/docs/libnm/libnm-sections.txt
@@ -722,6 +722,7 @@ NMSettingsConnectionFlags
 NMActivationStateFlags
 NMSettingsAddConnection2Flags
 NMSettingsUpdate2Flags
+NMDeviceReapplyFlags
 NMTernary
 NMManagerReloadFlags
 NMDeviceInterfaceFlags
diff --git a/docs/libnm/version.xml b/docs/libnm/version.xml
index 19d25d0a..5faa4fff 100644
--- a/docs/libnm/version.xml
+++ b/docs/libnm/version.xml
@@ -1 +1 @@
-1.40.8
+1.40.10
diff --git a/examples/python/gi/device-reapply.py b/examples/python/gi/device-reapply.py
new file mode 100755
index 00000000..9f5d3306
--- /dev/null
+++ b/examples/python/gi/device-reapply.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+import os
+import sys
+
+import gi
+
+gi.require_version("NM", "1.0")
+from gi.repository import NM, GLib, Gio, GObject
+
+
+def eprint(*args, **kwargs):
+    print(*args, file=sys.stderr, **kwargs)
+
+
+def kf_from_data(data):
+    kf = GLib.KeyFile.new()
+    kf.load_from_data(data, 18446744073709551615, GLib.KeyFileFlags.NONE)
+    return kf
+
+
+def kf_to_data(kf):
+    data, l = kf.to_data()
+    return data
+
+
+def connection_to_kf(connection):
+    return kf_to_data(NM.keyfile_write(connection, NM.KeyfileHandlerFlags.NONE))
+
+
+def connection_from_kf(data):
+    base_dir = os.getcwd()
+    return NM.keyfile_read(kf_from_data(data), base_dir, NM.KeyfileHandlerFlags.NONE)
+
+
+def connection_from_stdin():
+    return connection_from_kf(sys.stdin.read())
+
+
+def device_get_applied_connection(device):
+    mainloop = GLib.MainLoop()
+    r = []
+
+    def cb(device, result):
+        try:
+            connection, version_id = device.get_applied_connection_finish(result)
+        except Exception as e:
+            r.append(e)
+        else:
+            r.append(connection)
+            r.append(version_id)
+        mainloop.quit()
+
+    device.get_applied_connection_async(0, None, cb)
+    mainloop.run()
+    if len(r) == 1:
+        raise r[0]
+    connection, version_id = r
+    return connection, version_id
+
+
+def device_reapply(device, connection, version_id, reapply_flags):
+    mainloop = GLib.MainLoop()
+    r = []
+
+    def cb(device, result):
+        try:
+            device.reapply_finish(result)
+        except Exception as e:
+            r.append(e)
+        mainloop.quit()
+
+    device.reapply_async(connection, version_id or 0, reapply_flags, None, cb)
+    mainloop.run()
+    if len(r) == 1:
+        raise r[0]
+
+
+def parse_args():
+    import argparse
+
+    parser = argparse.ArgumentParser(
+        prog="device-reapply.py",
+        description="Example program to interact with the applied connection",
+    )
+
+    parser.add_argument("mode", choices=["get", "reapply", "modify"])
+    parser.add_argument("device")
+    parser.add_argument("-V", "--version-id", type=int)
+    parser.add_argument("-s", "--stdin", action="store_true")
+    parser.add_argument("-p", "--preserve-external-ip", action="store_true")
+
+    return parser.parse_args()
+
+
+def main():
+    args = parse_args()
+
+    nmc = NM.Client.new()
+
+    device = [d for d in nmc.get_devices() if d.get_iface() == args.device]
+    if not device:
+        raise Exception(f'Device "{args.device}" not found')
+    if len(device) != 1:
+        raise Exception(f'Not unique device "{args.device}" found')
+    device = device[0]
+
+    assert not args.stdin or args.mode == "modify"
+    assert not args.preserve_external_ip or args.mode in ["modify", "reapply"]
+
+    if args.mode == "get":
+        connection, version_id = device_get_applied_connection(device)
+
+        version_id_matches = args.version_id is None or args.version_id == version_id
+
+        print(
+            f'# Applied connection on "{device.get_iface()}": "{connection.get_id()}" ({connection.get_uuid()}, {connection.get_connection_type()})'
+        )
+        s = "" if version_id_matches else f" (expected {args.version_id})"
+        print(f"# version-id={version_id}{s}")
+        print(f"#")
+        print(f"{connection_to_kf(connection)}")
+
+        if not version_id_matches:
+            eprint(
+                f"Applied version-id does not match (expects {args.version_id} but got {version_id})"
+            )
+            sys.exit(1)
+        sys.exit(0)
+
+    if args.mode == "reapply":
+        new_connection = None
+    elif args.stdin:
+        new_connection = connection_from_stdin()
+    else:
+        new_connection, _ = device_get_applied_connection(device)
+
+    reapply_flags = 0
+    if args.preserve_external_ip:
+        reapply_flags = 1  # NM.DeviceReapplyFlags.PRESERVE_EXTERNAL_IP
+
+    device_reapply(device, new_connection, args.version_id, reapply_flags)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/introspection/org.freedesktop.NetworkManager.Device.xml b/introspection/org.freedesktop.NetworkManager.Device.xml
index e694fcda..ae626a8e 100644
--- a/introspection/org.freedesktop.NetworkManager.Device.xml
+++ b/introspection/org.freedesktop.NetworkManager.Device.xml
@@ -322,7 +322,7 @@
         Reapply:
         @connection: The optional connection settings that will be reapplied on the device. If empty, the currently active settings-connection will be used. The connection cannot arbitrarily differ from the current applied-connection otherwise the call will fail. Only certain changes are supported, like adding or removing IP addresses.
         @version_id: If non-zero, the current version id of the applied-connection must match. The current version id can be retrieved via GetAppliedConnection. This optional argument allows to catch concurrent modifications between the GetAppliedConnection call and Reapply.
-        @flags: Flags which would modify the behavior of the Reapply call. There are no flags defined currently and the users should use the value of 0.
+        @flags: Flags which would modify the behavior of the Reapply call. Invalid flags are rejected.
 
         Attempts to update the configuration of a device without deactivating it.
         NetworkManager has the concept of connections, which are profiles that
@@ -344,6 +344,9 @@
         Reapply can make the applied-connection different from the
         settings-connection, just like updating the settings-connection can make
         them different.
+
+        Since 1.42, 1.40.10, "preserve-external-ip" flag (0x1) is supported to not
+        remove externally added IP addresses and routes on the device during reapply.
     -->
     <method name="Reapply">
       <arg name="connection" type="a{sa{sv}}" direction="in"/>
diff --git a/man/NetworkManager-dispatcher.8 b/man/NetworkManager-dispatcher.8
index ba14b58a..8c6b44b4 100644
--- a/man/NetworkManager-dispatcher.8
+++ b/man/NetworkManager-dispatcher.8
@@ -2,9 +2,9 @@
 .\"     Title: NetworkManager-dispatcher
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: Network management daemons
-.\"    Source: NetworkManager-dispatcher 1.40.8
+.\"    Source: NetworkManager-dispatcher 1.40.10
 .\"  Language: English
 .\"
 .TH "NETWORKMANAGER\-DISPATCHER" "8" "" "NetworkManager\-dispatcher 1\&" "Network management daemons"
diff --git a/man/NetworkManager-wait-online.service.8 b/man/NetworkManager-wait-online.service.8
index bfe4c230..7d5691b8 100644
--- a/man/NetworkManager-wait-online.service.8
+++ b/man/NetworkManager-wait-online.service.8
@@ -2,9 +2,9 @@
 .\"     Title: NetworkManager-wait-online.service
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: Network management daemons
-.\"    Source: NetworkManager-wait-online.service 1.40.8
+.\"    Source: NetworkManager-wait-online.service 1.40.10
 .\"  Language: English
 .\"
 .TH "NETWORKMANAGER\-WAIT\-ONLINE\&" "8" "" "NetworkManager\-wait\-online\&" "Network management daemons"
diff --git a/man/NetworkManager.8 b/man/NetworkManager.8
index b102b9c4..558500f6 100644
--- a/man/NetworkManager.8
+++ b/man/NetworkManager.8
@@ -2,12 +2,12 @@
 .\"     Title: NetworkManager
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: Network management daemons
-.\"    Source: NetworkManager 1.40.8
+.\"    Source: NetworkManager 1.40.10
 .\"  Language: English
 .\"
-.TH "NETWORKMANAGER" "8" "" "NetworkManager 1\&.40\&.8" "Network management daemons"
+.TH "NETWORKMANAGER" "8" "" "NetworkManager 1\&.40\&.10" "Network management daemons"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/man/NetworkManager.conf.5 b/man/NetworkManager.conf.5
index 8d092163..926d5ce6 100644
--- a/man/NetworkManager.conf.5
+++ b/man/NetworkManager.conf.5
@@ -2,12 +2,12 @@
 .\"     Title: NetworkManager.conf
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: Configuration
-.\"    Source: NetworkManager 1.40.8
+.\"    Source: NetworkManager 1.40.10
 .\"  Language: English
 .\"
-.TH "NETWORKMANAGER\&.CONF" "5" "" "NetworkManager 1\&.40\&.8" "Configuration"
+.TH "NETWORKMANAGER\&.CONF" "5" "" "NetworkManager 1\&.40\&.10" "Configuration"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/man/nm-cloud-setup.8 b/man/nm-cloud-setup.8
index 6e034264..2bab0ed6 100644
--- a/man/nm-cloud-setup.8
+++ b/man/nm-cloud-setup.8
@@ -2,12 +2,12 @@
 .\"     Title: nm-cloud-setup
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: Automatic Network Configuration in Cloud with NetworkManager
-.\"    Source: NetworkManager 1.40.8
+.\"    Source: NetworkManager 1.40.10
 .\"  Language: English
 .\"
-.TH "NM\-CLOUD\-SETUP" "8" "" "NetworkManager 1\&.40\&.8" "Automatic Network Configuratio"
+.TH "NM\-CLOUD\-SETUP" "8" "" "NetworkManager 1\&.40\&.10" "Automatic Network Configuratio"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/man/nm-initrd-generator.8 b/man/nm-initrd-generator.8
index f62e4732..902affd9 100644
--- a/man/nm-initrd-generator.8
+++ b/man/nm-initrd-generator.8
@@ -2,12 +2,12 @@
 .\"     Title: nm-initrd-generator
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: System Administration
-.\"    Source: NetworkManager 1.40.8
+.\"    Source: NetworkManager 1.40.10
 .\"  Language: English
 .\"
-.TH "NM\-INITRD\-GENERATOR" "8" "" "NetworkManager 1\&.40\&.8" "System Administration"
+.TH "NM\-INITRD\-GENERATOR" "8" "" "NetworkManager 1\&.40\&.10" "System Administration"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/man/nm-online.1 b/man/nm-online.1
index 6e554414..ea6b855d 100644
--- a/man/nm-online.1
+++ b/man/nm-online.1
@@ -2,12 +2,12 @@
 .\"     Title: nm-online
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: General Commands Manual
-.\"    Source: NetworkManager 1.40.8
+.\"    Source: NetworkManager 1.40.10
 .\"  Language: English
 .\"
-.TH "NM\-ONLINE" "1" "" "NetworkManager 1\&.40\&.8" "General Commands Manual"
+.TH "NM\-ONLINE" "1" "" "NetworkManager 1\&.40\&.10" "General Commands Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/man/nm-openvswitch.7 b/man/nm-openvswitch.7
index b6f9fba8..ced68ccd 100644
--- a/man/nm-openvswitch.7
+++ b/man/nm-openvswitch.7
@@ -2,12 +2,12 @@
 .\"     Title: nm-openvswitch
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: Open vSwitch support overview
-.\"    Source: NetworkManager 1.40.8
+.\"    Source: NetworkManager 1.40.10
 .\"  Language: English
 .\"
-.TH "NM\-OPENVSWITCH" "7" "" "NetworkManager 1\&.40\&.8" "Open vSwitch support overview"
+.TH "NM\-OPENVSWITCH" "7" "" "NetworkManager 1\&.40\&.10" "Open vSwitch support overview"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/man/nm-settings-dbus.5 b/man/nm-settings-dbus.5
index 5f38dc88..5cff29d2 100644
--- a/man/nm-settings-dbus.5
+++ b/man/nm-settings-dbus.5
@@ -2,12 +2,12 @@
 .\"     Title: nm-settings-dbus
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: Configuration
-.\"    Source: NetworkManager 1.40.8
+.\"    Source: NetworkManager 1.40.10
 .\"  Language: English
 .\"
-.TH "NM\-SETTINGS\-DBUS" "5" "" "NetworkManager 1\&.40\&.8" "Configuration"
+.TH "NM\-SETTINGS\-DBUS" "5" "" "NetworkManager 1\&.40\&.10" "Configuration"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/man/nm-settings-dbus.xml b/man/nm-settings-dbus.xml
index bb56ea04..6111a8f1 100644
--- a/man/nm-settings-dbus.xml
+++ b/man/nm-settings-dbus.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
-<refentry id="nm-settings-dbus"><refentryinfo><title>nm-settings-dbus</title><author>NetworkManager developers</author></refentryinfo><refmeta><refentrytitle>nm-settings-dbus</refentrytitle><manvolnum>5</manvolnum><refmiscinfo class="source">NetworkManager</refmiscinfo><refmiscinfo class="manual">Configuration</refmiscinfo><refmiscinfo class="version">1.40.8</refmiscinfo></refmeta><refnamediv><refname>nm-settings-dbus</refname><refpurpose>Description of settings and properties of NetworkManager connection profiles on the D-Bus API</refpurpose></refnamediv><refsect1 id="description"><title>Description</title><para>
+<refentry id="nm-settings-dbus"><refentryinfo><title>nm-settings-dbus</title><author>NetworkManager developers</author></refentryinfo><refmeta><refentrytitle>nm-settings-dbus</refentrytitle><manvolnum>5</manvolnum><refmiscinfo class="source">NetworkManager</refmiscinfo><refmiscinfo class="manual">Configuration</refmiscinfo><refmiscinfo class="version">1.40.10</refmiscinfo></refmeta><refnamediv><refname>nm-settings-dbus</refname><refpurpose>Description of settings and properties of NetworkManager connection profiles on the D-Bus API</refpurpose></refnamediv><refsect1 id="description"><title>Description</title><para>
           NetworkManager is based on a concept of connection profiles, sometimes referred to as
           connections only. These connection profiles contain a network configuration. When
           NetworkManager activates a connection profile on a network device the configuration will
diff --git a/man/nm-settings-ifcfg-rh.5 b/man/nm-settings-ifcfg-rh.5
index cd438540..55af04f4 100644
--- a/man/nm-settings-ifcfg-rh.5
+++ b/man/nm-settings-ifcfg-rh.5
@@ -2,12 +2,12 @@
 .\"     Title: nm-settings-ifcfg-rh
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: Configuration
-.\"    Source: NetworkManager 1.40.8
+.\"    Source: NetworkManager 1.40.10
 .\"  Language: English
 .\"
-.TH "NM\-SETTINGS\-IFCFG\-RH" "5" "" "NetworkManager 1\&.40\&.8" "Configuration"
+.TH "NM\-SETTINGS\-IFCFG\-RH" "5" "" "NetworkManager 1\&.40\&.10" "Configuration"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/man/nm-settings-ifcfg-rh.xml b/man/nm-settings-ifcfg-rh.xml
index 3834ec51..3e74ef76 100644
--- a/man/nm-settings-ifcfg-rh.xml
+++ b/man/nm-settings-ifcfg-rh.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
-<refentry id="nm-settings-ifcfg-rh"><refentryinfo><title>nm-settings-ifcfg-rh</title><author>NetworkManager developers</author></refentryinfo><refmeta><refentrytitle>nm-settings-ifcfg-rh</refentrytitle><manvolnum>5</manvolnum><refmiscinfo class="source">NetworkManager</refmiscinfo><refmiscinfo class="manual">Configuration</refmiscinfo><refmiscinfo class="version">1.40.8</refmiscinfo></refmeta><refnamediv><refname>nm-settings-ifcfg-rh</refname><refpurpose>Description of <emphasis>ifcfg-rh</emphasis> settings plugin</refpurpose></refnamediv><refsect1 id="description"><title>Description</title><para>
+<refentry id="nm-settings-ifcfg-rh"><refentryinfo><title>nm-settings-ifcfg-rh</title><author>NetworkManager developers</author></refentryinfo><refmeta><refentrytitle>nm-settings-ifcfg-rh</refentrytitle><manvolnum>5</manvolnum><refmiscinfo class="source">NetworkManager</refmiscinfo><refmiscinfo class="manual">Configuration</refmiscinfo><refmiscinfo class="version">1.40.10</refmiscinfo></refmeta><refnamediv><refname>nm-settings-ifcfg-rh</refname><refpurpose>Description of <emphasis>ifcfg-rh</emphasis> settings plugin</refpurpose></refnamediv><refsect1 id="description"><title>Description</title><para>
           NetworkManager is based on the concept of connection profiles that contain
           network configuration (see <citerefentry><refentrytitle>nm-settings</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details). The profiles can be
           stored in various formats. NetworkManager uses plugins for reading and writing
diff --git a/man/nm-settings-keyfile.5 b/man/nm-settings-keyfile.5
index c08e2c8f..7e7efd21 100644
--- a/man/nm-settings-keyfile.5
+++ b/man/nm-settings-keyfile.5
@@ -2,12 +2,12 @@
 .\"     Title: nm-settings-keyfile
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: Configuration
-.\"    Source: NetworkManager 1.40.8
+.\"    Source: NetworkManager 1.40.10
 .\"  Language: English
 .\"
-.TH "NM\-SETTINGS\-KEYFILE" "5" "" "NetworkManager 1\&.40\&.8" "Configuration"
+.TH "NM\-SETTINGS\-KEYFILE" "5" "" "NetworkManager 1\&.40\&.10" "Configuration"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/man/nm-settings-keyfile.xml b/man/nm-settings-keyfile.xml
index b3487914..8b85a440 100644
--- a/man/nm-settings-keyfile.xml
+++ b/man/nm-settings-keyfile.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
-<refentry id="nm-settings-keyfile"><refentryinfo><title>nm-settings-keyfile</title><author>NetworkManager developers</author></refentryinfo><refmeta><refentrytitle>nm-settings-keyfile</refentrytitle><manvolnum>5</manvolnum><refmiscinfo class="source">NetworkManager</refmiscinfo><refmiscinfo class="manual">Configuration</refmiscinfo><refmiscinfo class="version">1.40.8</refmiscinfo></refmeta><refnamediv><refname>nm-settings-keyfile</refname><refpurpose>Description of <emphasis>keyfile</emphasis> settings plugin</refpurpose></refnamediv><refsect1 id="description"><title>Description</title><para>
+<refentry id="nm-settings-keyfile"><refentryinfo><title>nm-settings-keyfile</title><author>NetworkManager developers</author></refentryinfo><refmeta><refentrytitle>nm-settings-keyfile</refentrytitle><manvolnum>5</manvolnum><refmiscinfo class="source">NetworkManager</refmiscinfo><refmiscinfo class="manual">Configuration</refmiscinfo><refmiscinfo class="version">1.40.10</refmiscinfo></refmeta><refnamediv><refname>nm-settings-keyfile</refname><refpurpose>Description of <emphasis>keyfile</emphasis> settings plugin</refpurpose></refnamediv><refsect1 id="description"><title>Description</title><para>
           NetworkManager is based on the concept of connection profiles that contain
           network configuration (see <citerefentry><refentrytitle>nm-settings</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details). The profiles can be
           stored in various formats. NetworkManager uses plugins for reading and writing
diff --git a/man/nm-settings-nmcli.5 b/man/nm-settings-nmcli.5
index d9c1bd4f..fc794c68 100644
--- a/man/nm-settings-nmcli.5
+++ b/man/nm-settings-nmcli.5
@@ -2,12 +2,12 @@
 .\"     Title: nm-settings-nmcli
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: Configuration
-.\"    Source: NetworkManager 1.40.8
+.\"    Source: NetworkManager 1.40.10
 .\"  Language: English
 .\"
-.TH "NM\-SETTINGS\-NMCLI" "5" "" "NetworkManager 1\&.40\&.8" "Configuration"
+.TH "NM\-SETTINGS\-NMCLI" "5" "" "NetworkManager 1\&.40\&.10" "Configuration"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/man/nm-settings-nmcli.xml b/man/nm-settings-nmcli.xml
index 2a77ffa8..a5ebbdd5 100644
--- a/man/nm-settings-nmcli.xml
+++ b/man/nm-settings-nmcli.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
-<refentry id="nm-settings-nmcli"><refentryinfo><title>nm-settings-nmcli</title><author>NetworkManager developers</author></refentryinfo><refmeta><refentrytitle>nm-settings-nmcli</refentrytitle><manvolnum>5</manvolnum><refmiscinfo class="source">NetworkManager</refmiscinfo><refmiscinfo class="manual">Configuration</refmiscinfo><refmiscinfo class="version">1.40.8</refmiscinfo></refmeta><refnamediv><refname>nm-settings-nmcli</refname><refpurpose>Description of settings and properties of NetworkManager connection profiles for nmcli</refpurpose></refnamediv><refsect1 id="description"><title>Description</title><para>
+<refentry id="nm-settings-nmcli"><refentryinfo><title>nm-settings-nmcli</title><author>NetworkManager developers</author></refentryinfo><refmeta><refentrytitle>nm-settings-nmcli</refentrytitle><manvolnum>5</manvolnum><refmiscinfo class="source">NetworkManager</refmiscinfo><refmiscinfo class="manual">Configuration</refmiscinfo><refmiscinfo class="version">1.40.10</refmiscinfo></refmeta><refnamediv><refname>nm-settings-nmcli</refname><refpurpose>Description of settings and properties of NetworkManager connection profiles for nmcli</refpurpose></refnamediv><refsect1 id="description"><title>Description</title><para>
           NetworkManager is based on a concept of connection profiles, sometimes referred to as
           connections only. These connection profiles contain a network configuration. When
           NetworkManager activates a connection profile on a network device the configuration will
diff --git a/man/nmcli-examples.7 b/man/nmcli-examples.7
index d7c97a67..12d16a6b 100644
--- a/man/nmcli-examples.7
+++ b/man/nmcli-examples.7
@@ -2,12 +2,12 @@
 .\"     Title: nmcli-examples
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: Examples
-.\"    Source: NetworkManager 1.40.8
+.\"    Source: NetworkManager 1.40.10
 .\"  Language: English
 .\"
-.TH "NMCLI\-EXAMPLES" "7" "" "NetworkManager 1\&.40\&.8" "Examples"
+.TH "NMCLI\-EXAMPLES" "7" "" "NetworkManager 1\&.40\&.10" "Examples"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/man/nmcli.1 b/man/nmcli.1
index 409a59ad..f547f431 100644
--- a/man/nmcli.1
+++ b/man/nmcli.1
@@ -2,12 +2,12 @@
 .\"     Title: nmcli
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: General Commands Manual
-.\"    Source: NetworkManager 1.40.8
+.\"    Source: NetworkManager 1.40.10
 .\"  Language: English
 .\"
-.TH "NMCLI" "1" "" "NetworkManager 1\&.40\&.8" "General Commands Manual"
+.TH "NMCLI" "1" "" "NetworkManager 1\&.40\&.10" "General Commands Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/man/nmtui.1 b/man/nmtui.1
index 5d74d326..ad188170 100644
--- a/man/nmtui.1
+++ b/man/nmtui.1
@@ -2,12 +2,12 @@
 .\"     Title: nmtui
 .\"    Author: 
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/16/2022
+.\"      Date: 01/11/2023
 .\"    Manual: General Commands Manual
-.\"    Source: NetworkManager 1.40.8
+.\"    Source: NetworkManager 1.40.10
 .\"  Language: English
 .\"
-.TH "NMTUI" "1" "" "NetworkManager 1\&.40\&.8" "General Commands Manual"
+.TH "NMTUI" "1" "" "NetworkManager 1\&.40\&.10" "General Commands Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
diff --git a/meson.build b/meson.build
index 465558be..f30573f1 100644
--- a/meson.build
+++ b/meson.build
@@ -6,7 +6,7 @@ project(
 #  - add corresponding NM_VERSION_x_y_z macros in
 #    "src/libnm-core-public/nm-version-macros.h.in"
 #  - update number in configure.ac
-  version: '1.40.8',
+  version: '1.40.10',
   license: 'GPL2+',
   default_options: [
     'buildtype=debugoptimized',
diff --git a/po/NetworkManager.pot b/po/NetworkManager.pot
index 29434902..17e471f4 100644
--- a/po/NetworkManager.pot
+++ b/po/NetworkManager.pot
@@ -6,10 +6,10 @@
 #, fuzzy
 msgid ""
 msgstr ""
-"Project-Id-Version: NetworkManager 1.40.8\n"
+"Project-Id-Version: NetworkManager 1.40.10\n"
 "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/NetworkManager/"
 "NetworkManager/issues\n"
-"POT-Creation-Date: 2022-12-16 15:48+0100\n"
+"POT-Creation-Date: 2023-01-11 12:01+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -301,7 +301,7 @@ msgstr ""
 msgid "Team connection"
 msgstr ""
 
-#: src/core/devices/wifi/nm-device-olpc-mesh.c:112 src/nmcli/devices.c:1397
+#: src/core/devices/wifi/nm-device-olpc-mesh.c:112 src/nmcli/devices.c:1394
 msgid "Mesh"
 msgstr ""
 
@@ -770,15 +770,15 @@ msgstr ""
 msgid "The connection was not a MAC-VLAN connection."
 msgstr ""
 
-#: src/libnm-client-impl/nm-device-modem.c:179
+#: src/libnm-client-impl/nm-device-modem.c:181
 msgid "The connection was not a modem connection."
 msgstr ""
 
-#: src/libnm-client-impl/nm-device-modem.c:189
+#: src/libnm-client-impl/nm-device-modem.c:191
 msgid "The connection was not a valid modem connection."
 msgstr ""
 
-#: src/libnm-client-impl/nm-device-modem.c:198
+#: src/libnm-client-impl/nm-device-modem.c:200
 msgid "The device is lacking capabilities required by the connection."
 msgstr ""
 
@@ -3653,46 +3653,46 @@ msgid ""
 "type '%s'"
 msgstr ""
 
-#: src/libnm-glib-aux/nm-shared-utils.c:5745
+#: src/libnm-glib-aux/nm-shared-utils.c:5756
 msgid "interface name is missing"
 msgstr ""
 
-#: src/libnm-glib-aux/nm-shared-utils.c:5753
+#: src/libnm-glib-aux/nm-shared-utils.c:5764
 msgid "interface name is too short"
 msgstr ""
 
-#: src/libnm-glib-aux/nm-shared-utils.c:5761
+#: src/libnm-glib-aux/nm-shared-utils.c:5772
 msgid "interface name is reserved"
 msgstr ""
 
-#: src/libnm-glib-aux/nm-shared-utils.c:5774
+#: src/libnm-glib-aux/nm-shared-utils.c:5785
 msgid "interface name contains an invalid character"
 msgstr ""
 
-#: src/libnm-glib-aux/nm-shared-utils.c:5782
+#: src/libnm-glib-aux/nm-shared-utils.c:5793
 msgid "interface name is longer than 15 characters"
 msgstr ""
 
-#: src/libnm-glib-aux/nm-shared-utils.c:5807
+#: src/libnm-glib-aux/nm-shared-utils.c:5818
 #, c-format
 msgid "'%%' is not allowed in interface names"
 msgstr ""
 
-#: src/libnm-glib-aux/nm-shared-utils.c:5819
+#: src/libnm-glib-aux/nm-shared-utils.c:5830
 #, c-format
 msgid "'%s' is not allowed as interface name"
 msgstr ""
 
-#: src/libnm-glib-aux/nm-shared-utils.c:5841
+#: src/libnm-glib-aux/nm-shared-utils.c:5852
 msgid ""
 "interface name must be alphanumerical with no forward or backward slashes"
 msgstr ""
 
-#: src/libnm-glib-aux/nm-shared-utils.c:5858
+#: src/libnm-glib-aux/nm-shared-utils.c:5869
 msgid "interface name must not be empty"
 msgstr ""
 
-#: src/libnm-glib-aux/nm-shared-utils.c:5866
+#: src/libnm-glib-aux/nm-shared-utils.c:5877
 msgid "interface name must be UTF-8 encoded"
 msgstr ""
 
@@ -3818,7 +3818,7 @@ msgstr ""
 #: src/libnmc-setting/nm-meta-setting-desc.c:885
 #: src/libnmc-setting/nm-meta-setting-desc.c:2847 src/nmcli/connections.c:5533
 #: src/nmcli/connections.c:7507 src/nmcli/connections.c:7508
-#: src/nmcli/devices.c:590 src/nmcli/devices.c:596 src/nmcli/devices.c:1408
+#: src/nmcli/devices.c:590 src/nmcli/devices.c:596 src/nmcli/devices.c:1405
 #: src/nmcli/general.c:92 src/nmcli/utils.h:313
 msgid "yes"
 msgstr ""
@@ -3827,7 +3827,7 @@ msgstr ""
 #: src/libnmc-setting/nm-meta-setting-desc.c:885
 #: src/libnmc-setting/nm-meta-setting-desc.c:2850 src/nmcli/connections.c:5532
 #: src/nmcli/connections.c:7507 src/nmcli/connections.c:7508
-#: src/nmcli/devices.c:590 src/nmcli/devices.c:596 src/nmcli/devices.c:1408
+#: src/nmcli/devices.c:590 src/nmcli/devices.c:596 src/nmcli/devices.c:1405
 #: src/nmcli/general.c:93 src/nmcli/utils.h:313
 msgid "no"
 msgstr ""
@@ -4234,7 +4234,7 @@ msgstr ""
 #: src/libnmc-base/nm-secret-agent-simple.c:979
 #: src/libnmc-base/nm-vpn-helpers.c:143 src/libnmc-base/nm-vpn-helpers.c:147
 #: src/libnmc-base/nm-vpn-helpers.c:153 src/libnmc-base/nm-vpn-helpers.c:158
-#: src/nmcli/devices.c:4691 src/nmtui/nmt-page-dsl.c:64
+#: src/nmcli/devices.c:4688 src/nmtui/nmt-page-dsl.c:64
 #: src/nmtui/nmt-page-wifi.c:271 src/nmtui/nmt-page-wifi.c:305
 #: src/nmtui/nmt-page-wifi.c:344
 msgid "Password"
@@ -9361,9 +9361,9 @@ msgstr ""
 msgid "Active connection details"
 msgstr ""
 
-#: src/nmcli/connections.c:1795 src/nmcli/devices.c:1663
-#: src/nmcli/devices.c:1680 src/nmcli/devices.c:1698 src/nmcli/devices.c:1717
-#: src/nmcli/devices.c:1781 src/nmcli/devices.c:1910
+#: src/nmcli/connections.c:1795 src/nmcli/devices.c:1660
+#: src/nmcli/devices.c:1677 src/nmcli/devices.c:1695 src/nmcli/devices.c:1714
+#: src/nmcli/devices.c:1778 src/nmcli/devices.c:1907
 msgid "NAME"
 msgstr ""
 
@@ -9416,14 +9416,14 @@ msgstr ""
 #: src/nmcli/connections.c:2432 src/nmcli/connections.c:3153
 #: src/nmcli/connections.c:3165 src/nmcli/connections.c:3177
 #: src/nmcli/connections.c:3413 src/nmcli/connections.c:9640
-#: src/nmcli/connections.c:9662 src/nmcli/devices.c:3346
-#: src/nmcli/devices.c:3359 src/nmcli/devices.c:3371 src/nmcli/devices.c:3675
-#: src/nmcli/devices.c:3686 src/nmcli/devices.c:3705 src/nmcli/devices.c:3714
-#: src/nmcli/devices.c:3736 src/nmcli/devices.c:3747 src/nmcli/devices.c:3768
-#: src/nmcli/devices.c:4332 src/nmcli/devices.c:4343 src/nmcli/devices.c:4352
-#: src/nmcli/devices.c:4366 src/nmcli/devices.c:4384 src/nmcli/devices.c:4393
-#: src/nmcli/devices.c:4549 src/nmcli/devices.c:4560 src/nmcli/devices.c:4779
-#: src/nmcli/devices.c:4958 src/nmcli/devices.c:5179
+#: src/nmcli/connections.c:9662 src/nmcli/devices.c:3343
+#: src/nmcli/devices.c:3356 src/nmcli/devices.c:3368 src/nmcli/devices.c:3672
+#: src/nmcli/devices.c:3683 src/nmcli/devices.c:3702 src/nmcli/devices.c:3711
+#: src/nmcli/devices.c:3733 src/nmcli/devices.c:3744 src/nmcli/devices.c:3765
+#: src/nmcli/devices.c:4329 src/nmcli/devices.c:4340 src/nmcli/devices.c:4349
+#: src/nmcli/devices.c:4363 src/nmcli/devices.c:4381 src/nmcli/devices.c:4390
+#: src/nmcli/devices.c:4546 src/nmcli/devices.c:4557 src/nmcli/devices.c:4776
+#: src/nmcli/devices.c:4955 src/nmcli/devices.c:5176
 #, c-format
 msgid "Error: %s argument is missing."
 msgstr ""
@@ -9436,14 +9436,14 @@ msgstr ""
 #: src/nmcli/connections.c:2559 src/nmcli/connections.c:3139
 #: src/nmcli/connections.c:3213 src/nmcli/connections.c:9146
 #: src/nmcli/connections.c:9230 src/nmcli/connections.c:9769
-#: src/nmcli/devices.c:2010 src/nmcli/devices.c:2286 src/nmcli/devices.c:2453
-#: src/nmcli/devices.c:2579 src/nmcli/devices.c:2763 src/nmcli/devices.c:3546
-#: src/nmcli/devices.c:4513 src/nmcli/devices.c:4965 src/nmcli/general.c:1068
+#: src/nmcli/devices.c:2007 src/nmcli/devices.c:2283 src/nmcli/devices.c:2450
+#: src/nmcli/devices.c:2576 src/nmcli/devices.c:2760 src/nmcli/devices.c:3543
+#: src/nmcli/devices.c:4510 src/nmcli/devices.c:4962 src/nmcli/general.c:1068
 #, c-format
 msgid "Error: %s."
 msgstr ""
 
-#: src/nmcli/connections.c:2651 src/nmcli/devices.c:4732
+#: src/nmcli/connections.c:2651 src/nmcli/devices.c:4729
 #, c-format
 msgid "no active connection on device '%s'"
 msgstr ""
@@ -9518,10 +9518,10 @@ msgid "invalid passwd-file '%s': %s"
 msgstr ""
 
 #: src/nmcli/connections.c:3187 src/nmcli/connections.c:9673
-#: src/nmcli/devices.c:1967 src/nmcli/devices.c:2016 src/nmcli/devices.c:2459
-#: src/nmcli/devices.c:2651 src/nmcli/devices.c:2718 src/nmcli/devices.c:2918
-#: src/nmcli/devices.c:3406 src/nmcli/devices.c:3784 src/nmcli/devices.c:4403
-#: src/nmcli/devices.c:4566 src/nmcli/devices.c:4787 src/nmcli/devices.c:4970
+#: src/nmcli/devices.c:1964 src/nmcli/devices.c:2013 src/nmcli/devices.c:2456
+#: src/nmcli/devices.c:2648 src/nmcli/devices.c:2715 src/nmcli/devices.c:2915
+#: src/nmcli/devices.c:3403 src/nmcli/devices.c:3781 src/nmcli/devices.c:4400
+#: src/nmcli/devices.c:4563 src/nmcli/devices.c:4784 src/nmcli/devices.c:4967
 #, c-format
 msgid "Error: invalid extra argument '%s'."
 msgstr ""
@@ -9645,7 +9645,7 @@ msgstr ""
 msgid "Error: invalid <setting>.<property> '%s'."
 msgstr ""
 
-#: src/nmcli/connections.c:5429 src/nmcli/devices.c:2185
+#: src/nmcli/connections.c:5429 src/nmcli/devices.c:2182
 #, c-format
 msgid "Warning: %s.\n"
 msgstr ""
@@ -10479,7 +10479,7 @@ msgstr ""
 msgid "Interface(s): "
 msgstr ""
 
-#: src/nmcli/devices.c:71 src/nmcli/devices.c:1442
+#: src/nmcli/devices.c:71 src/nmcli/devices.c:1439
 msgid "(none)"
 msgstr ""
 
@@ -10754,399 +10754,399 @@ msgstr ""
 msgid "Error: Device '%s' not found.\n"
 msgstr ""
 
-#: src/nmcli/devices.c:1184 src/nmcli/devices.c:5203
+#: src/nmcli/devices.c:1184 src/nmcli/devices.c:5200
 msgid "Error: not all devices found."
 msgstr ""
 
-#: src/nmcli/devices.c:1216
+#: src/nmcli/devices.c:1213
 msgid "No interface specified"
 msgstr ""
 
-#: src/nmcli/devices.c:1237
+#: src/nmcli/devices.c:1234
 #, c-format
 msgid "Device '%s' not found"
 msgstr ""
 
-#: src/nmcli/devices.c:1349
+#: src/nmcli/devices.c:1346
 #, c-format
 msgid "%u MHz"
 msgstr ""
 
-#: src/nmcli/devices.c:1350
+#: src/nmcli/devices.c:1347
 #, c-format
 msgid "%u Mbit/s"
 msgstr ""
 
-#: src/nmcli/devices.c:1395
+#: src/nmcli/devices.c:1392
 msgid "Ad-Hoc"
 msgstr ""
 
-#: src/nmcli/devices.c:1396
+#: src/nmcli/devices.c:1393
 msgid "Infra"
 msgstr ""
 
-#: src/nmcli/devices.c:1398
+#: src/nmcli/devices.c:1395
 msgid "N/A"
 msgstr ""
 
-#: src/nmcli/devices.c:1590
+#: src/nmcli/devices.c:1587
 msgid "Device details"
 msgstr ""
 
-#: src/nmcli/devices.c:1607
+#: src/nmcli/devices.c:1604
 #, c-format
 msgid "Error: 'device show': %s"
 msgstr ""
 
-#: src/nmcli/devices.c:1984
+#: src/nmcli/devices.c:1981
 msgid "Status of devices"
 msgstr ""
 
-#: src/nmcli/devices.c:1988
+#: src/nmcli/devices.c:1985
 #, c-format
 msgid "Error: 'device status': %s"
 msgstr ""
 
-#: src/nmcli/devices.c:2051 src/nmcli/general.c:527
+#: src/nmcli/devices.c:2048 src/nmcli/general.c:527
 #, c-format
 msgid "Error: Timeout %d sec expired."
 msgstr ""
 
-#: src/nmcli/devices.c:2126
+#: src/nmcli/devices.c:2123
 #, c-format
 msgid "Device '%s' successfully activated with '%s'.\n"
 msgstr ""
 
-#: src/nmcli/devices.c:2132
+#: src/nmcli/devices.c:2129
 msgid ""
 "Hint: \"nmcli dev wifi show-password\" shows the Wi-Fi name and password.\n"
 msgstr ""
 
-#: src/nmcli/devices.c:2135
+#: src/nmcli/devices.c:2132
 #, c-format
 msgid "Error: Connection activation failed: (%d) %s.\n"
 msgstr ""
 
-#: src/nmcli/devices.c:2166
+#: src/nmcli/devices.c:2163
 #, c-format
 msgid "Error: Failed to setup a Wi-Fi hotspot: %s"
 msgstr ""
 
-#: src/nmcli/devices.c:2170
+#: src/nmcli/devices.c:2167
 #, c-format
 msgid "Error: Failed to add/activate new connection: %s"
 msgstr ""
 
-#: src/nmcli/devices.c:2174
+#: src/nmcli/devices.c:2171
 #, c-format
 msgid "Error: Failed to activate connection: %s"
 msgstr ""
 
-#: src/nmcli/devices.c:2242
+#: src/nmcli/devices.c:2239
 #, c-format
 msgid "Error: Device activation failed: %s"
 msgstr ""
 
-#: src/nmcli/devices.c:2292
+#: src/nmcli/devices.c:2289
 #, c-format
 msgid "Error: extra argument not allowed: '%s'."
 msgstr ""
 
-#: src/nmcli/devices.c:2361 src/nmcli/devices.c:2374 src/nmcli/devices.c:2629
+#: src/nmcli/devices.c:2358 src/nmcli/devices.c:2371 src/nmcli/devices.c:2626
 #, c-format
 msgid "Device '%s' successfully disconnected.\n"
 msgstr ""
 
-#: src/nmcli/devices.c:2363 src/nmcli/devices.c:2699
+#: src/nmcli/devices.c:2360 src/nmcli/devices.c:2696
 #, c-format
 msgid "Device '%s' successfully removed.\n"
 msgstr ""
 
-#: src/nmcli/devices.c:2423 src/nmcli/devices.c:2505
+#: src/nmcli/devices.c:2420 src/nmcli/devices.c:2502
 #, c-format
 msgid "Error: Reapplying connection to device '%s' (%s) failed: %s"
 msgstr ""
 
-#: src/nmcli/devices.c:2433 src/nmcli/devices.c:2514
+#: src/nmcli/devices.c:2430 src/nmcli/devices.c:2511
 #, c-format
 msgid "Connection successfully reapplied to device '%s'.\n"
 msgstr ""
 
-#: src/nmcli/devices.c:2536
+#: src/nmcli/devices.c:2533
 #, c-format
 msgid "Error: Reading applied connection from device '%s' (%s) failed: %s"
 msgstr ""
 
-#: src/nmcli/devices.c:2613
+#: src/nmcli/devices.c:2610
 msgid "Error: not all devices disconnected."
 msgstr ""
 
-#: src/nmcli/devices.c:2614
+#: src/nmcli/devices.c:2611
 #, c-format
 msgid "Error: Device '%s' (%s) disconnecting failed: %s\n"
 msgstr ""
 
-#: src/nmcli/devices.c:2690
+#: src/nmcli/devices.c:2687
 msgid "Error: not all devices deleted."
 msgstr ""
 
-#: src/nmcli/devices.c:2691
+#: src/nmcli/devices.c:2688
 #, c-format
 msgid "Error: Device '%s' (%s) deletion failed: %s\n"
 msgstr ""
 
-#: src/nmcli/devices.c:2769
+#: src/nmcli/devices.c:2766
 msgid "Error: No property specified."
 msgstr ""
 
-#: src/nmcli/devices.c:2786 src/nmcli/devices.c:2805 src/nmcli/general.c:797
+#: src/nmcli/devices.c:2783 src/nmcli/devices.c:2802 src/nmcli/general.c:797
 #: src/nmcli/general.c:819
 #, c-format
 msgid "Error: '%s' argument is missing."
 msgstr ""
 
-#: src/nmcli/devices.c:2794
+#: src/nmcli/devices.c:2791
 #, c-format
 msgid "Error: 'managed': %s."
 msgstr ""
 
-#: src/nmcli/devices.c:2813
+#: src/nmcli/devices.c:2810
 #, c-format
 msgid "Error: 'autoconnect': %s."
 msgstr ""
 
-#: src/nmcli/devices.c:2820 src/nmcli/general.c:869
+#: src/nmcli/devices.c:2817 src/nmcli/general.c:869
 #, c-format
 msgid "Error: property '%s' is not known."
 msgstr ""
 
-#: src/nmcli/devices.c:2867
+#: src/nmcli/devices.c:2864
 #, c-format
 msgid "%s: using connection '%s'\n"
 msgstr ""
 
-#: src/nmcli/devices.c:2893
+#: src/nmcli/devices.c:2890
 #, c-format
 msgid "%s: device created\n"
 msgstr ""
 
-#: src/nmcli/devices.c:2900
+#: src/nmcli/devices.c:2897
 #, c-format
 msgid "%s: device removed\n"
 msgstr ""
 
-#: src/nmcli/devices.c:3080
+#: src/nmcli/devices.c:3077
 msgid "Wi-Fi scan list"
 msgstr ""
 
-#: src/nmcli/devices.c:3197 src/nmcli/devices.c:3478
+#: src/nmcli/devices.c:3194 src/nmcli/devices.c:3475
 #, c-format
 msgid "Error: Access point with bssid '%s' not found."
 msgstr ""
 
-#: src/nmcli/devices.c:3399
+#: src/nmcli/devices.c:3396
 #, c-format
 msgid "Error: 'device wifi': %s"
 msgstr ""
 
-#: src/nmcli/devices.c:3419
+#: src/nmcli/devices.c:3416
 #, c-format
 msgid "Error: invalid rescan argument: '%s' not among [auto, no, yes]"
 msgstr ""
 
-#: src/nmcli/devices.c:3458
+#: src/nmcli/devices.c:3455
 #, c-format
 msgid "Error: Device '%s' not found."
 msgstr ""
 
-#: src/nmcli/devices.c:3462
+#: src/nmcli/devices.c:3459
 #, c-format
 msgid ""
 "Error: Device '%s' was not recognized as a Wi-Fi device, check "
 "NetworkManager Wi-Fi plugin."
 msgstr ""
 
-#: src/nmcli/devices.c:3467 src/nmcli/devices.c:3819 src/nmcli/devices.c:4448
-#: src/nmcli/devices.c:4583 src/nmcli/devices.c:4718
+#: src/nmcli/devices.c:3464 src/nmcli/devices.c:3816 src/nmcli/devices.c:4445
+#: src/nmcli/devices.c:4580 src/nmcli/devices.c:4715
 #, c-format
 msgid "Error: Device '%s' is not a Wi-Fi device."
 msgstr ""
 
-#: src/nmcli/devices.c:3647
+#: src/nmcli/devices.c:3644
 msgid "SSID or BSSID: "
 msgstr ""
 
-#: src/nmcli/devices.c:3652
+#: src/nmcli/devices.c:3649
 msgid "Error: SSID or BSSID are missing."
 msgstr ""
 
-#: src/nmcli/devices.c:3696
+#: src/nmcli/devices.c:3693
 #, c-format
 msgid "Error: bssid argument value '%s' is not a valid BSSID."
 msgstr ""
 
-#: src/nmcli/devices.c:3727
+#: src/nmcli/devices.c:3724
 #, c-format
 msgid ""
 "Error: wep-key-type argument value '%s' is invalid, use 'key' or 'phrase'."
 msgstr ""
 
-#: src/nmcli/devices.c:3755 src/nmcli/devices.c:3776
+#: src/nmcli/devices.c:3752 src/nmcli/devices.c:3773
 #, c-format
 msgid "Error: %s: %s."
 msgstr ""
 
-#: src/nmcli/devices.c:3798
+#: src/nmcli/devices.c:3795
 #, c-format
 msgid "Error: BSSID to connect to (%s) differs from bssid argument (%s)."
 msgstr ""
 
-#: src/nmcli/devices.c:3806
+#: src/nmcli/devices.c:3803
 #, c-format
 msgid "Error: Parameter '%s' is neither SSID nor BSSID."
 msgstr ""
 
-#: src/nmcli/devices.c:3822 src/nmcli/devices.c:4451 src/nmcli/devices.c:4586
-#: src/nmcli/devices.c:4818
+#: src/nmcli/devices.c:3819 src/nmcli/devices.c:4448 src/nmcli/devices.c:4583
+#: src/nmcli/devices.c:4815
 msgid "Error: No Wi-Fi device found."
 msgstr ""
 
-#: src/nmcli/devices.c:3844
+#: src/nmcli/devices.c:3841
 #, c-format
 msgid "Error: Failed to scan hidden SSID: %s."
 msgstr ""
 
-#: src/nmcli/devices.c:3876
+#: src/nmcli/devices.c:3873
 #, c-format
 msgid "Error: No network with SSID '%s' found."
 msgstr ""
 
-#: src/nmcli/devices.c:3880
+#: src/nmcli/devices.c:3877
 #, c-format
 msgid "Error: No access point with BSSID '%s' found."
 msgstr ""
 
-#: src/nmcli/devices.c:3909
+#: src/nmcli/devices.c:3906
 #, c-format
 msgid "Error: Connection '%s' exists but properties don't match."
 msgstr ""
 
-#: src/nmcli/devices.c:3958
+#: src/nmcli/devices.c:3955
 #, c-format
 msgid ""
 "Warning: '%s' should be SSID for hidden APs; but it looks like a BSSID.\n"
 msgstr ""
 
-#: src/nmcli/devices.c:4000
+#: src/nmcli/devices.c:3997
 msgid "Password: "
 msgstr ""
 
-#: src/nmcli/devices.c:4138
+#: src/nmcli/devices.c:4135
 #, c-format
 msgid "'%s' is not valid WPA PSK"
 msgstr ""
 
-#: src/nmcli/devices.c:4159
+#: src/nmcli/devices.c:4156
 #, c-format
 msgid "'%s' is not valid WEP key (it should be 5 or 13 ASCII chars)"
 msgstr ""
 
-#: src/nmcli/devices.c:4178
+#: src/nmcli/devices.c:4175
 #, c-format
 msgid "Hotspot password: %s\n"
 msgstr ""
 
-#: src/nmcli/devices.c:4357
+#: src/nmcli/devices.c:4354
 msgid "Error: ssid is too long."
 msgstr ""
 
-#: src/nmcli/devices.c:4375
+#: src/nmcli/devices.c:4372
 #, c-format
 msgid "Error: band argument value '%s' is invalid; use 'a' or 'bg'."
 msgstr ""
 
-#: src/nmcli/devices.c:4426
+#: src/nmcli/devices.c:4423
 msgid "Error: channel requires band too."
 msgstr ""
 
-#: src/nmcli/devices.c:4433
+#: src/nmcli/devices.c:4430
 #, c-format
 msgid "Error: channel '%s' not valid for band '%s'."
 msgstr ""
 
-#: src/nmcli/devices.c:4464
+#: src/nmcli/devices.c:4461
 #, c-format
 msgid "Error: Device '%s' supports neither AP nor Ad-Hoc mode."
 msgstr ""
 
-#: src/nmcli/devices.c:4491
+#: src/nmcli/devices.c:4488
 #, c-format
 msgid "Error: Invalid 'password': %s."
 msgstr ""
 
-#: src/nmcli/devices.c:4542 src/nmcli/devices.c:4772
+#: src/nmcli/devices.c:4539 src/nmcli/devices.c:4769
 #, c-format
 msgid "Error: '%s' cannot repeat."
 msgstr ""
 
-#: src/nmcli/devices.c:4677 src/nmcli/devices.c:4680 src/nmcli/devices.c:4684
-#: src/nmcli/devices.c:4687 src/nmtui/nmt-page-wifi.c:253
+#: src/nmcli/devices.c:4674 src/nmcli/devices.c:4677 src/nmcli/devices.c:4681
+#: src/nmcli/devices.c:4684 src/nmtui/nmt-page-wifi.c:253
 msgid "Security"
 msgstr ""
 
-#: src/nmcli/devices.c:4677
+#: src/nmcli/devices.c:4674
 msgid "None"
 msgstr ""
 
-#: src/nmcli/devices.c:4806
+#: src/nmcli/devices.c:4803
 #, c-format
 msgid "%s"
 msgstr ""
 
 #. Main header name
-#: src/nmcli/devices.c:4859
+#: src/nmcli/devices.c:4856
 msgid "Device LLDP neighbors"
 msgstr ""
 
-#: src/nmcli/devices.c:4992
+#: src/nmcli/devices.c:4989
 #, c-format
 msgid "Error: 'device lldp list': %s"
 msgstr ""
 
-#: src/nmcli/devices.c:5060
+#: src/nmcli/devices.c:5057
 msgid "Checkpoint was removed."
 msgstr ""
 
 #. The command is done, we're in the confirmation prompt.
-#: src/nmcli/devices.c:5067
+#: src/nmcli/devices.c:5064
 msgid "No"
 msgstr ""
 
-#: src/nmcli/devices.c:5080
+#: src/nmcli/devices.c:5077
 #, c-format
 msgid "Error: Destroying a checkpoint failed: %s"
 msgstr ""
 
-#: src/nmcli/devices.c:5102 src/nmcli/devices.c:5103
+#: src/nmcli/devices.c:5099 src/nmcli/devices.c:5100
 msgid "Yes"
 msgstr ""
 
-#: src/nmcli/devices.c:5129
+#: src/nmcli/devices.c:5126
 #, c-format
 msgid "Error: Creating a checkpoint failed: %s"
 msgstr ""
 
-#: src/nmcli/devices.c:5145
+#: src/nmcli/devices.c:5142
 #, c-format
 msgid "Error: %s"
 msgstr ""
 
-#: src/nmcli/devices.c:5184 src/nmcli/nmcli.c:885
+#: src/nmcli/devices.c:5181 src/nmcli/nmcli.c:885
 #, c-format
 msgid "Error: '%s' is not a valid timeout."
 msgstr ""
 
-#: src/nmcli/devices.c:5211
+#: src/nmcli/devices.c:5208
 msgid "Error: Expected a command to run after '--'"
 msgstr ""
 
@@ -11938,7 +11938,7 @@ msgstr ""
 msgid "WireGuard connection %d"
 msgstr ""
 
-#: src/nmtui/nmt-device-entry.c:348
+#: src/nmtui/nmt-device-entry.c:350
 msgid "Select..."
 msgstr ""
 
diff --git a/src/core/devices/nm-device-veth.c b/src/core/devices/nm-device-veth.c
index c3482e78..17115d33 100644
--- a/src/core/devices/nm-device-veth.c
+++ b/src/core/devices/nm-device-veth.c
@@ -81,11 +81,13 @@ create_and_realize(NMDevice              *device,
                    const NMPlatformLink **out_plink,
                    GError               **error)
 {
-    const char    *iface = nm_device_get_iface(device);
-    const char    *peer;
-    NMDevice      *peer_device;
-    NMSettingVeth *s_veth;
-    int            r;
+    NMPlatform           *platform = nm_device_get_platform(device);
+    const char           *iface    = nm_device_get_iface(device);
+    NMSettingVeth        *s_veth;
+    const NMPlatformLink *plink;
+    const NMPlatformLink *peer_plink;
+    int                   peer_ifindex;
+    int                   r;
 
     s_veth = _nm_connection_get_setting(connection, NM_TYPE_SETTING_VETH);
     if (!s_veth) {
@@ -98,15 +100,23 @@ create_and_realize(NMDevice              *device,
         return FALSE;
     }
 
-    peer        = nm_setting_veth_get_peer(s_veth);
-    peer_device = nm_manager_get_device(NM_MANAGER_GET, peer, NM_DEVICE_TYPE_VETH);
-    if (peer_device) {
-        if (nm_device_parent_get_device(peer_device))
-            /* The veth device and its peer already exist. No need to create it again. */
+    /* For veths, users can define two connection profiles referencing each
+     * other as 'veth.peer'. Only the first to be activated will actually
+     * create the veth pair; the other must detect that interfaces already
+     * exist and proceed. */
+    plink = nm_platform_link_get_by_ifname(platform, iface);
+    if (plink && nm_platform_link_veth_get_properties(platform, plink->ifindex, &peer_ifindex)) {
+        peer_plink = nm_platform_link_get(platform, peer_ifindex);
+        if (peer_plink && peer_plink->type == NM_LINK_TYPE_VETH
+            && nm_streq0(peer_plink->name, nm_setting_veth_get_peer(s_veth))) {
             return TRUE;
+        }
     }
 
-    r = nm_platform_link_veth_add(nm_device_get_platform(device), iface, peer, out_plink);
+    r = nm_platform_link_veth_add(nm_device_get_platform(device),
+                                  iface,
+                                  nm_setting_veth_get_peer(s_veth),
+                                  out_plink);
     if (r < 0) {
         g_set_error(error,
                     NM_DEVICE_ERROR,
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 059e31f2..a723bf7f 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -96,8 +96,6 @@
 #define NM_DEVICE_AUTH_RETRIES_INFINITY -2
 #define NM_DEVICE_AUTH_RETRIES_DEFAULT  3
 
-#define AUTOCONNECT_RESET_RETRIES_TIMER 300
-
 /*****************************************************************************/
 
 typedef void (*ActivationHandleFunc)(NMDevice *self);
@@ -763,9 +761,6 @@ typedef struct _NMDevicePrivate {
 
     GVariant *ports_variant; /* Array of port devices D-Bus path */
     char     *prop_ip_iface; /* IP interface D-Bus property */
-
-    int    autoconnect_retries;
-    gint32 autoconnect_retries_blocked_until;
 } NMDevicePrivate;
 
 G_DEFINE_ABSTRACT_TYPE(NMDevice, nm_device, NM_TYPE_DBUS_OBJECT)
@@ -6397,7 +6392,8 @@ carrier_changed(NMDevice *self, gboolean carrier)
         if (carrier) {
             /* If needed, also resume IP configuration that is
              * waiting for carrier. */
-            if (priv->state == NM_DEVICE_STATE_IP_CONFIG)
+            if (priv->state >= NM_DEVICE_STATE_IP_CONFIG
+                && priv->state <= NM_DEVICE_STATE_ACTIVATED)
                 nm_device_activate_schedule_stage3_ip_config(self, FALSE);
             return;
         }
@@ -12791,6 +12787,7 @@ reapply_connection(NMDevice *self, NMConnection *con_old, NMConnection *con_new)
  *   the current settings connection
  * @version_id: either zero, or the current version id for the applied
  *   connection.
+ * @reapply_flags: the #NMDeviceReapplyFlags.
  * @audit_args: on return, a string representing the changes
  * @error: the error if %FALSE is returned
  *
@@ -12800,11 +12797,12 @@ reapply_connection(NMDevice *self, NMConnection *con_old, NMConnection *con_new)
  * Return: %FALSE if the new configuration can not be reapplied.
  */
 static gboolean
-check_and_reapply_connection(NMDevice     *self,
-                             NMConnection *connection,
-                             guint64       version_id,
-                             char        **audit_args,
-                             GError      **error)
+check_and_reapply_connection(NMDevice            *self,
+                             NMConnection        *connection,
+                             guint64              version_id,
+                             NMDeviceReapplyFlags reapply_flags,
+                             char               **audit_args,
+                             GError             **error)
 {
     NMDeviceClass                 *klass         = NM_DEVICE_GET_CLASS(self);
     NMDevicePrivate               *priv          = NM_DEVICE_GET_PRIVATE(self);
@@ -12972,7 +12970,12 @@ check_and_reapply_connection(NMDevice     *self,
 
         reactivate_proxy_config(self);
 
-        nm_device_l3cfg_commit(self, NM_L3_CFG_COMMIT_TYPE_REAPPLY, FALSE);
+        nm_device_l3cfg_commit(
+            self,
+            NM_FLAGS_HAS(reapply_flags, NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP)
+                ? NM_L3_CFG_COMMIT_TYPE_UPDATE
+                : NM_L3_CFG_COMMIT_TYPE_REAPPLY,
+            FALSE);
     }
 
     if (priv->state >= NM_DEVICE_STATE_IP_CHECK)
@@ -12989,12 +12992,18 @@ nm_device_reapply(NMDevice *self, NMConnection *connection, GError **error)
 {
     g_return_val_if_fail(NM_IS_DEVICE(self), FALSE);
 
-    return check_and_reapply_connection(self, connection, 0, NULL, error);
+    return check_and_reapply_connection(self,
+                                        connection,
+                                        0,
+                                        NM_DEVICE_REAPPLY_FLAGS_NONE,
+                                        NULL,
+                                        error);
 }
 
 typedef struct {
-    NMConnection *connection;
-    guint64       version_id;
+    NMConnection        *connection;
+    guint64              version_id;
+    NMDeviceReapplyFlags reapply_flags;
 } ReapplyData;
 
 static void
@@ -13005,16 +13014,16 @@ reapply_cb(NMDevice              *self,
            gpointer               user_data)
 {
     ReapplyData                  *reapply_data = user_data;
-    guint64                       version_id   = 0;
-    gs_unref_object NMConnection *connection   = NULL;
-    GError                       *local        = NULL;
-    gs_free char                 *audit_args   = NULL;
+    guint64                       version_id;
+    gs_unref_object NMConnection *connection = NULL;
+    NMDeviceReapplyFlags          reapply_flags;
+    GError                       *local      = NULL;
+    gs_free char                 *audit_args = NULL;
 
-    if (reapply_data) {
-        connection = reapply_data->connection;
-        version_id = reapply_data->version_id;
-        g_slice_free(ReapplyData, reapply_data);
-    }
+    connection    = reapply_data->connection;
+    version_id    = reapply_data->version_id;
+    reapply_flags = reapply_data->reapply_flags;
+    nm_g_slice_free(reapply_data);
 
     if (error) {
         nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY,
@@ -13034,6 +13043,7 @@ reapply_cb(NMDevice              *self,
                                       connection
                                           ?: nm_device_get_settings_connection_get_connection(self),
                                       version_id,
+                                      reapply_flags,
                                       &audit_args,
                                       &local)) {
         nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY,
@@ -13067,12 +13077,12 @@ impl_device_reapply(NMDBusObject                      *obj,
     ReapplyData               *reapply_data;
     gs_unref_variant GVariant *settings = NULL;
     guint64                    version_id;
-    guint32                    flags;
+    guint32                    reapply_flags_u;
+    NMDeviceReapplyFlags       reapply_flags;
 
-    g_variant_get(parameters, "(@a{sa{sv}}tu)", &settings, &version_id, &flags);
+    g_variant_get(parameters, "(@a{sa{sv}}tu)", &settings, &version_id, &reapply_flags_u);
 
-    /* No flags supported as of now. */
-    if (flags != 0) {
+    if (NM_FLAGS_ANY(reapply_flags_u, ~((guint32) NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP))) {
         error =
             g_error_new_literal(NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "Invalid flags specified");
         nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY,
@@ -13085,6 +13095,9 @@ impl_device_reapply(NMDBusObject                      *obj,
         return;
     }
 
+    reapply_flags = reapply_flags_u;
+    nm_assert(reapply_flags_u == reapply_flags);
+
     if (priv->state < NM_DEVICE_STATE_PREPARE || priv->state > NM_DEVICE_STATE_ACTIVATED) {
         error = g_error_new_literal(NM_DEVICE_ERROR,
                                     NM_DEVICE_ERROR_NOT_ACTIVE,
@@ -13122,12 +13135,12 @@ impl_device_reapply(NMDBusObject                      *obj,
         nm_connection_clear_secrets(connection);
     }
 
-    if (connection || version_id) {
-        reapply_data             = g_slice_new(ReapplyData);
-        reapply_data->connection = connection;
-        reapply_data->version_id = version_id;
-    } else
-        reapply_data = NULL;
+    reapply_data  = g_slice_new(ReapplyData);
+    *reapply_data = (ReapplyData){
+        .connection    = connection,
+        .version_id    = version_id,
+        .reapply_flags = reapply_flags,
+    };
 
     nm_device_auth_request(self,
                            invocation,
@@ -13163,7 +13176,7 @@ impl_device_get_applied_connection(NMDBusObject                      *obj,
     if (flags != 0) {
         g_dbus_method_invocation_return_error_literal(invocation,
                                                       NM_DEVICE_ERROR,
-                                                      NM_DEVICE_ERROR_FAILED,
+                                                      NM_DEVICE_ERROR_INVALID_ARGUMENT,
                                                       "Invalid flags specified");
         return;
     }
@@ -16881,49 +16894,6 @@ nm_device_get_initial_hw_address(NMDevice *self)
     return NM_DEVICE_GET_PRIVATE(self)->hw_addr_initial;
 }
 
-void
-nm_device_set_autoconnect_retries(NMDevice *self, int tries)
-{
-    NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
-
-    if (priv->autoconnect_retries != tries) {
-        _LOGT(LOGD_DEVICE, "autoconnect: retries set %d", tries);
-        priv->autoconnect_retries = tries;
-    }
-
-    if (tries)
-        priv->autoconnect_retries_blocked_until = 0; /* we are not blocked anymore */
-    else
-        priv->autoconnect_retries_blocked_until =
-            nm_utils_get_monotonic_timestamp_sec() + AUTOCONNECT_RESET_RETRIES_TIMER;
-}
-
-int
-nm_device_get_autoconnect_retries(NMDevice *self)
-{
-    NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
-
-    return priv->autoconnect_retries;
-}
-
-gint32
-nm_device_autoconnect_retries_blocked_until(NMDevice *self)
-{
-    NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
-
-    return priv->autoconnect_retries_blocked_until;
-}
-
-void
-nm_device_autoconnect_retries_reset(NMDevice *self)
-{
-    NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
-
-    /* default value, we will sync. with connection value when needed */
-    priv->autoconnect_retries               = -2;
-    priv->autoconnect_retries_blocked_until = 0;
-}
-
 /**
  * nm_device_spec_match_list:
  * @self: an #NMDevice
@@ -17675,8 +17645,6 @@ nm_device_init(NMDevice *self)
     priv->sys_iface_state_      = NM_DEVICE_SYS_IFACE_STATE_EXTERNAL;
 
     priv->promisc_reset = NM_OPTION_BOOL_DEFAULT;
-
-    priv->autoconnect_retries = -2;
 }
 
 static GObject *
diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h
index fea46bb7..de850e68 100644
--- a/src/core/devices/nm-device.h
+++ b/src/core/devices/nm-device.h
@@ -464,11 +464,6 @@ const char *nm_device_get_permanent_hw_address_full(NMDevice *self,
                                                     gboolean *out_is_fake);
 const char *nm_device_get_initial_hw_address(NMDevice *dev);
 
-void   nm_device_set_autoconnect_retries(NMDevice *self, int tries);
-int    nm_device_get_autoconnect_retries(NMDevice *self);
-gint32 nm_device_autoconnect_retries_blocked_until(NMDevice *self);
-void   nm_device_autoconnect_retries_reset(NMDevice *self);
-
 NMDhcpConfig *nm_device_get_dhcp_config(NMDevice *dev, int addr_family);
 
 NML3Cfg *nm_device_get_l3cfg(NMDevice *self);
diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c
index 1329b953..805b42d2 100644
--- a/src/core/dhcp/nm-dhcp-client.c
+++ b/src/core/dhcp/nm-dhcp-client.c
@@ -237,30 +237,65 @@ nm_dhcp_client_create_l3cd(NMDhcpClient *self)
                                  NM_IP_CONFIG_SOURCE_DHCP);
 }
 
+GHashTable *
+nm_dhcp_client_create_options_dict(NMDhcpClient *self, gboolean static_keys)
+{
+    NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
+    GHashTable          *options;
+    GBytes              *effective_client_id;
+
+    options = nm_dhcp_option_create_options_dict(static_keys);
+
+    effective_client_id = nm_dhcp_client_get_effective_client_id(self);
+    if (effective_client_id) {
+        guint         option = NM_IS_IPv4(priv->config.addr_family) ? NM_DHCP_OPTION_DHCP4_CLIENT_ID
+                                                                    : NM_DHCP_OPTION_DHCP6_CLIENT_ID;
+        gs_free char *str    = nm_dhcp_utils_duid_to_string(effective_client_id);
+
+        /* Note that for the nm-dhcp-helper based plugins (dhclient), the plugin
+         * may send the used client-id/DUID via the environment variables and
+         * overwrite them yet again. */
+
+        if (static_keys) {
+            nm_dhcp_option_add_option(options, priv->config.addr_family, option, str);
+        } else {
+            g_hash_table_insert(
+                options,
+                g_strdup(nm_dhcp_option_request_string(priv->config.addr_family, option)),
+                g_steal_pointer(&str));
+        }
+    }
+
+    return options;
+}
+
 /*****************************************************************************/
 
-void
+gboolean
 nm_dhcp_client_set_effective_client_id(NMDhcpClient *self, GBytes *client_id)
 {
-    NMDhcpClientPrivate *priv    = NM_DHCP_CLIENT_GET_PRIVATE(self);
-    gs_free char        *tmp_str = NULL;
+    NMDhcpClientPrivate   *priv              = NM_DHCP_CLIENT_GET_PRIVATE(self);
+    gs_free char          *tmp_str           = NULL;
+    gs_unref_bytes GBytes *client_id_to_free = NULL;
 
-    g_return_if_fail(NM_IS_DHCP_CLIENT(self));
-    g_return_if_fail(!client_id || g_bytes_get_size(client_id) >= 2);
+    g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE);
+    g_return_val_if_fail(!client_id || g_bytes_get_size(client_id) >= 2, FALSE);
 
     priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
 
     if (nm_g_bytes_equal0(priv->effective_client_id, client_id))
-        return;
+        return FALSE;
 
-    g_bytes_unref(priv->effective_client_id);
+    client_id_to_free         = g_steal_pointer(&priv->effective_client_id);
     priv->effective_client_id = nm_g_bytes_ref(client_id);
 
-    _LOGT("%s: set %s",
+    _LOGT("%s: set effective %s",
           priv->config.addr_family == AF_INET6 ? "duid" : "client-id",
           priv->effective_client_id
               ? (tmp_str = nm_dhcp_utils_duid_to_string(priv->effective_client_id))
               : "default");
+
+    return TRUE;
 }
 
 /*****************************************************************************/
@@ -967,12 +1002,6 @@ _dhcp_client_decline(NMDhcpClient         *self,
     return klass->decline(self, l3cd, error_message, error);
 }
 
-static GBytes *
-get_duid(NMDhcpClient *self)
-{
-    return NULL;
-}
-
 static gboolean
 ipv6_lladdr_timeout(gpointer user_data)
 {
@@ -1302,8 +1331,7 @@ gboolean
 nm_dhcp_client_start(NMDhcpClient *self, GError **error)
 {
     NMDhcpClientPrivate        *priv;
-    gs_unref_bytes GBytes      *own_client_id = NULL;
-    const NMPlatformIP6Address *addr          = NULL;
+    const NMPlatformIP6Address *addr = NULL;
     int                         IS_IPv4;
 
     g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE);
@@ -1317,11 +1345,6 @@ nm_dhcp_client_start(NMDhcpClient *self, GError **error)
     IS_IPv4 = NM_IS_IPv4(priv->config.addr_family);
 
     if (!IS_IPv4) {
-        if (!priv->config.v6.enforce_duid)
-            own_client_id = NM_DHCP_CLIENT_GET_CLASS(self)->get_duid(self);
-
-        nm_dhcp_client_set_effective_client_id(self, own_client_id ?: priv->config.client_id);
-
         addr = ipv6_lladdr_find(self);
         if (!addr) {
             _LOGD("waiting for IPv6LL address");
@@ -1449,7 +1472,7 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release)
 /*****************************************************************************/
 
 static char *
-bytearray_variant_to_string(NMDhcpClient *self, GVariant *value, const char *key)
+bytearray_variant_to_string(GVariant *value)
 {
     const guint8 *array;
     char         *str;
@@ -1499,8 +1522,9 @@ label_is_unknown_xyz(const char *label)
 static void
 maybe_add_option(NMDhcpClient *self, GHashTable *hash, const char *key, GVariant *value)
 {
-    char *str_value;
-    int   priv_opt_num;
+    const int IS_IPv4 = NM_IS_IPv4(NM_DHCP_CLIENT_GET_PRIVATE(self)->config.addr_family);
+    char     *str_value;
+    int       priv_opt_num;
 
     if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BYTESTRING))
         return;
@@ -1517,27 +1541,49 @@ maybe_add_option(NMDhcpClient *self, GHashTable *hash, const char *key, GVariant
     if (NM_STR_HAS_PREFIX(key, "private_") || !key[0])
         return;
 
-    str_value = bytearray_variant_to_string(self, value, key);
+    str_value = bytearray_variant_to_string(value);
     if (!str_value)
         return;
 
+    if ((IS_IPv4 && nm_streq(key, "dhcp_client_identifier"))
+        || (!IS_IPv4 && nm_streq(key, "dhcp6_client_id"))) {
+        gs_free char          *str   = g_steal_pointer(&str_value);
+        gs_unref_bytes GBytes *bytes = NULL;
+
+        /* Validate and normalize the client-id/DUID. */
+
+        bytes = nm_utils_hexstr2bin(str);
+        if (!bytes || g_bytes_get_size(bytes) < 2) {
+            /* Seems invalid. Ignore */
+            return;
+        }
+
+        if (!nm_dhcp_client_set_effective_client_id(self, bytes)) {
+            /* the client-id is identical and we already set it. Nothing to do. */
+            return;
+        }
+
+        /* The effective-client-id was (re)set. Update "hash" with the new value... */
+        str_value = nm_dhcp_utils_duid_to_string(bytes);
+    }
+
     g_hash_table_insert(hash, g_strdup(key), str_value);
 
     /* dhclient has no special labels for private dhcp options: it uses "unknown_xyz"
-         * labels for that. We need to identify those to alias them to our "private_xyz"
-         * format unused in the internal dchp plugins.
-         */
+     * labels for that. We need to identify those to alias them to our "private_xyz"
+     * format unused in the internal dchp plugins.
+     */
     if ((priv_opt_num = label_is_unknown_xyz(key)) > 0) {
         gs_free guint8 *check_val = NULL;
         char           *hex_str   = NULL;
         gsize           len;
 
         /* dhclient passes values from dhcp private options in its own "string" format:
-             * if the raw values are printable as ascii strings, it will pass the string
-             * representation; if the values are not printable as an ascii string, it will
-             * pass a string displaying the hex values (hex string). Try to enforce passing
-             * always an hex string, converting string representation if needed.
-             */
+         * if the raw values are printable as ascii strings, it will pass the string
+         * representation; if the values are not printable as an ascii string, it will
+         * pass a string displaying the hex values (hex string). Try to enforce passing
+         * always an hex string, converting string representation if needed.
+         */
         check_val = nm_utils_hexstr2bin_alloc(str_value, FALSE, TRUE, ":", 0, &len);
         hex_str   = nm_utils_bin2hexstr_full(check_val ?: (guint8 *) str_value,
                                            check_val ? len : strlen(str_value),
@@ -1623,7 +1669,7 @@ nm_dhcp_client_handle_event(gpointer               unused,
         GVariant                      *value;
 
         /* Copy options */
-        str_options = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free);
+        str_options = nm_dhcp_client_create_options_dict(self, FALSE);
         g_variant_iter_init(&iter, options);
         while (g_variant_iter_next(&iter, "{&sv}", &name, &value)) {
             maybe_add_option(self, str_options, name, value);
@@ -1914,8 +1960,7 @@ nm_dhcp_client_class_init(NMDhcpClientClass *client_class)
     client_class->accept       = _accept;
     client_class->decline      = decline;
 
-    client_class->stop     = stop;
-    client_class->get_duid = get_duid;
+    client_class->stop = stop;
 
     obj_properties[PROP_CONFIG] =
         g_param_spec_pointer(NM_DHCP_CLIENT_CONFIG,
diff --git a/src/core/dhcp/nm-dhcp-client.h b/src/core/dhcp/nm-dhcp-client.h
index 51c6bc04..6f403b61 100644
--- a/src/core/dhcp/nm-dhcp-client.h
+++ b/src/core/dhcp/nm-dhcp-client.h
@@ -214,17 +214,6 @@ typedef struct {
     gboolean (*ip6_start)(NMDhcpClient *self, const struct in6_addr *ll_addr, GError **error);
 
     void (*stop)(NMDhcpClient *self, gboolean release);
-
-    /**
-     * get_duid:
-     * @self: the #NMDhcpClient
-     *
-     * Attempts to find an existing DHCPv6 DUID for this client in the DHCP
-     * client's persistent configuration.  Returned DUID should be the binary
-     * representation of the DUID.  If no DUID is found, %NULL should be
-     * returned.
-     */
-    GBytes *(*get_duid)(NMDhcpClient *self);
 } NMDhcpClientClass;
 
 GType nm_dhcp_client_get_type(void);
@@ -285,11 +274,13 @@ const char        *nm_dhcp_client_get_iface(NMDhcpClient *self);
 NMDedupMultiIndex *nm_dhcp_client_get_multi_idx(NMDhcpClient *self);
 int                nm_dhcp_client_get_ifindex(NMDhcpClient *self);
 
-void    nm_dhcp_client_set_effective_client_id(NMDhcpClient *self, GBytes *client_id);
-GBytes *nm_dhcp_client_get_effective_client_id(NMDhcpClient *self);
+gboolean nm_dhcp_client_set_effective_client_id(NMDhcpClient *self, GBytes *client_id);
+GBytes  *nm_dhcp_client_get_effective_client_id(NMDhcpClient *self);
 
 NML3ConfigData *nm_dhcp_client_create_l3cd(NMDhcpClient *self);
 
+GHashTable *nm_dhcp_client_create_options_dict(NMDhcpClient *self, gboolean static_keys);
+
 /*****************************************************************************
  * Client data
  *****************************************************************************/
diff --git a/src/core/dhcp/nm-dhcp-dhclient-utils.c b/src/core/dhcp/nm-dhcp-dhclient-utils.c
index 74e6b905..ea8943fa 100644
--- a/src/core/dhcp/nm-dhcp-dhclient-utils.c
+++ b/src/core/dhcp/nm-dhcp-dhclient-utils.c
@@ -399,6 +399,7 @@ nm_dhcp_dhclient_create_config(const char         *interface,
                 if (out_new_client_id)
                     nm_clear_pointer(out_new_client_id, g_bytes_unref);
                 NM_SET_OUT(out_new_client_id, read_client_id(p));
+                /* fall-through. We keep the line... */
             }
 
             /* Override config file hostname and use one from the connection */
@@ -523,6 +524,20 @@ nm_dhcp_dhclient_create_config(const char         *interface,
     return g_string_free(g_steal_pointer(&new_contents), FALSE);
 }
 
+/* In the lease file, dhclient will write "option dhcp6.client-id $HEXSTR". This
+ * function does the same. */
+static char *
+nm_dhcp_dhclient_escape_duid_as_hex(GBytes *duid)
+{
+    const guint8 *s;
+    gsize         len;
+
+    nm_assert(duid);
+
+    s = g_bytes_get_data(duid, &len);
+    return nm_utils_bin2hexstr_fuller(s, len, ':', FALSE, FALSE, NULL);
+}
+
 /* Roughly follow what dhclient's quotify_buf() and pretty_escape() functions do */
 char *
 nm_dhcp_dhclient_escape_duid(GBytes *duid)
@@ -605,7 +620,7 @@ error:
     return NULL;
 }
 
-#define DUID_PREFIX "default-duid \""
+#define DEFAULT_DUID_PREFIX "default-duid \""
 
 /* Beware: @error may be unset even if the function returns %NULL. */
 GBytes *
@@ -626,10 +641,10 @@ nm_dhcp_dhclient_read_duid(const char *leasefile, GError **error)
         const char *p = nm_str_skip_leading_spaces(contents_v[i]);
         GBytes     *duid;
 
-        if (!NM_STR_HAS_PREFIX(p, DUID_PREFIX))
+        if (!NM_STR_HAS_PREFIX(p, DEFAULT_DUID_PREFIX))
             continue;
 
-        p += NM_STRLEN(DUID_PREFIX);
+        p += NM_STRLEN(DEFAULT_DUID_PREFIX);
 
         g_strchomp((char *) p);
 
@@ -647,15 +662,21 @@ nm_dhcp_dhclient_read_duid(const char *leasefile, GError **error)
 }
 
 gboolean
-nm_dhcp_dhclient_save_duid(const char *leasefile, GBytes *duid, GError **error)
+nm_dhcp_dhclient_save_duid(const char *leasefile,
+                           GBytes     *duid,
+                           gboolean    enforce_duid,
+                           GError    **error)
 {
     gs_free char                 *escaped_duid = NULL;
     gs_free const char          **lines        = NULL;
     nm_auto_free_gstring GString *s            = NULL;
     const char *const            *iter;
-    gsize                         len = 0;
+    gs_free char                 *conflicting_duid_line = NULL;
+    gs_free char                 *contents              = NULL;
+    gsize                         contents_len          = 0;
 
     g_return_val_if_fail(leasefile != NULL, FALSE);
+
     if (!duid) {
         nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "missing duid");
         g_return_val_if_reached(FALSE);
@@ -665,48 +686,68 @@ nm_dhcp_dhclient_save_duid(const char *leasefile, GBytes *duid, GError **error)
     nm_assert(escaped_duid);
 
     if (g_file_test(leasefile, G_FILE_TEST_EXISTS)) {
-        gs_free char *contents = NULL;
-
-        if (!g_file_get_contents(leasefile, &contents, &len, error)) {
+        if (!g_file_get_contents(leasefile, &contents, &contents_len, error)) {
             g_prefix_error(error, "failed to read lease file %s: ", leasefile);
             return FALSE;
         }
 
-        lines = nm_strsplit_set_with_empty(contents, "\n\r");
+        lines = nm_strsplit_set_with_empty(contents, "\n");
     }
 
-    s = g_string_sized_new(len + 50);
-    g_string_append_printf(s, DUID_PREFIX "%s\";\n", escaped_duid);
+    s = g_string_sized_new(contents_len + 50);
+    g_string_append_printf(s, DEFAULT_DUID_PREFIX "%s\";\n", escaped_duid);
 
     /* Preserve existing leasefile contents */
     if (lines) {
         for (iter = lines; *iter; iter++) {
             const char *str = *iter;
             const char *l;
+            gboolean    ends_with_r;
+            gsize       l_len;
+            gsize       prefix_len;
 
-            /* If we find an uncommented DUID in the file, check if
-             * equal to the one we are going to write: if so, no need
-             * to update the lease file, otherwise skip the old DUID.
-             */
-            l = nm_str_skip_leading_spaces(str);
-            if (g_str_has_prefix(l, DUID_PREFIX)) {
-                gs_strfreev char **split = NULL;
+            l          = nm_str_skip_leading_spaces(str);
+            l_len      = strlen(l);
+            prefix_len = l - str;
 
-                split = g_strsplit(l, "\"", -1);
-                if (split[0] && nm_streq0(split[1], escaped_duid))
-                    return TRUE;
+            ends_with_r = l_len > 0 && l[l_len - 1u] == '\r';
+            if (ends_with_r) {
+                ((char *) l)[--l_len] = '\0';
+            }
 
+            if (NM_STR_HAS_PREFIX(l, DEFAULT_DUID_PREFIX)) {
+                /* We always add our line on top. This line can be skipped. */
                 continue;
             }
 
-            if (str)
-                g_string_append(s, str);
-            /* avoid to add an extra '\n' at the end of file */
-            if ((iter[1]) != NULL)
+            if (enforce_duid & NM_STR_HAS_PREFIX(l, "option dhcp6.client-id ")) {
+                /* we want to use our duid. Skip the per-lease client-id. */
+                if (!conflicting_duid_line) {
+                    gs_free char *duid_hex = nm_dhcp_dhclient_escape_duid_as_hex(duid);
+
+                    conflicting_duid_line = g_strdup_printf("option dhcp6.client-id %s;", duid_hex);
+                }
+                /* We adjust the duid line and set what we want. */
+                l = conflicting_duid_line;
+            }
+
+            g_string_append_len(s, str, prefix_len);
+            g_string_append(s, l);
+            if (ends_with_r) {
+                g_string_append_c(s, '\r');
                 g_string_append_c(s, '\n');
+            } else if ((iter[1]) != NULL) {
+                /* avoid to add an extra '\n' at the end of file */
+                g_string_append_c(s, '\n');
+            }
         }
     }
 
+    if (contents && strlen(contents) == contents_len && nm_streq(contents, s->str)) {
+        /* The file is already as we want it. We are done. */
+        return TRUE;
+    }
+
     if (!g_file_set_contents(leasefile, s->str, -1, error)) {
         g_prefix_error(error, "failed to set DUID in lease file %s: ", leasefile);
         return FALSE;
diff --git a/src/core/dhcp/nm-dhcp-dhclient-utils.h b/src/core/dhcp/nm-dhcp-dhclient-utils.h
index 0ce7dd90..6187cce0 100644
--- a/src/core/dhcp/nm-dhcp-dhclient-utils.h
+++ b/src/core/dhcp/nm-dhcp-dhclient-utils.h
@@ -29,6 +29,9 @@ GBytes *nm_dhcp_dhclient_unescape_duid(const char *duid);
 
 GBytes *nm_dhcp_dhclient_read_duid(const char *leasefile, GError **error);
 
-gboolean nm_dhcp_dhclient_save_duid(const char *leasefile, GBytes *duid, GError **error);
+gboolean nm_dhcp_dhclient_save_duid(const char *leasefile,
+                                    GBytes     *duid,
+                                    gboolean    enforce_duid,
+                                    GError    **error);
 
 #endif /* __NETWORKMANAGER_DHCP_DHCLIENT_UTILS_H__ */
diff --git a/src/core/dhcp/nm-dhcp-dhclient.c b/src/core/dhcp/nm-dhcp-dhclient.c
index d0cd5ebd..e4f40d7c 100644
--- a/src/core/dhcp/nm-dhcp-dhclient.c
+++ b/src/core/dhcp/nm-dhcp-dhclient.c
@@ -82,6 +82,10 @@ G_DEFINE_TYPE(NMDhcpDhclient, nm_dhcp_dhclient, NM_TYPE_DHCP_CLIENT)
 
 /*****************************************************************************/
 
+static GBytes *read_duid_from_lease(NMDhcpDhclient *self);
+
+/*****************************************************************************/
+
 static const char *
 nm_dhcp_dhclient_get_path(void)
 {
@@ -332,6 +336,7 @@ static gboolean
 dhclient_start(NMDhcpClient *client,
                gboolean      set_mode,
                gboolean      release,
+               gboolean      set_duid,
                pid_t        *out_pid,
                GError      **error)
 {
@@ -410,8 +415,11 @@ dhclient_start(NMDhcpClient *client,
     }
 
     /* Save the DUID to the leasefile dhclient will actually use */
-    if (addr_family == AF_INET6) {
-        if (!nm_dhcp_dhclient_save_duid(priv->lease_file, client_config->client_id, &local)) {
+    if (set_duid && addr_family == AF_INET6) {
+        if (!nm_dhcp_dhclient_save_duid(priv->lease_file,
+                                        nm_dhcp_client_get_effective_client_id(client),
+                                        client_config->v6.enforce_duid,
+                                        &local)) {
             nm_utils_error_set(error,
                                NM_UTILS_ERROR_UNKNOWN,
                                "failed to save DUID to '%s': %s",
@@ -547,11 +555,11 @@ ip4_start(NMDhcpClient *client, GError **error)
         return FALSE;
     }
 
-    if (new_client_id) {
-        nm_assert(!client_config->client_id);
-        nm_dhcp_client_set_effective_client_id(client, new_client_id);
-    }
-    return dhclient_start(client, FALSE, FALSE, NULL, error);
+    /* Note that the effective-client-id for IPv4 here might be unknown/NULL. */
+    nm_assert(!new_client_id || !client_config->client_id);
+    nm_dhcp_client_set_effective_client_id(client, client_config->client_id ?: new_client_id);
+
+    return dhclient_start(client, FALSE, FALSE, FALSE, NULL, error);
 }
 
 static gboolean
@@ -560,6 +568,7 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
     NMDhcpDhclient           *self = NM_DHCP_DHCLIENT(client);
     NMDhcpDhclientPrivate    *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self);
     const NMDhcpClientConfig *config;
+    gs_unref_bytes GBytes    *effective_client_id = NULL;
 
     config = nm_dhcp_client_get_config(client);
 
@@ -586,7 +595,12 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
         return FALSE;
     }
 
-    return dhclient_start(client, TRUE, FALSE, NULL, error);
+    nm_assert(config->client_id);
+    if (!config->v6.enforce_duid)
+        effective_client_id = read_duid_from_lease(self);
+    nm_dhcp_client_set_effective_client_id(client, effective_client_id ?: config->client_id);
+
+    return dhclient_start(client, TRUE, FALSE, TRUE, NULL, error);
 }
 
 static void
@@ -620,7 +634,7 @@ stop(NMDhcpClient *client, gboolean release)
     if (release) {
         pid_t rpid = -1;
 
-        if (dhclient_start(client, FALSE, TRUE, &rpid, NULL)) {
+        if (dhclient_start(client, FALSE, TRUE, FALSE, &rpid, NULL)) {
             /* Wait a few seconds for the release to happen */
             nm_dhcp_client_stop_pid(rpid, nm_dhcp_client_get_iface(client));
         }
@@ -628,10 +642,10 @@ stop(NMDhcpClient *client, gboolean release)
 }
 
 static GBytes *
-get_duid(NMDhcpClient *client)
+read_duid_from_lease(NMDhcpDhclient *self)
 {
-    NMDhcpDhclient           *self = NM_DHCP_DHCLIENT(client);
-    NMDhcpDhclientPrivate    *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self);
+    NMDhcpClient             *client = NM_DHCP_CLIENT(self);
+    NMDhcpDhclientPrivate    *priv   = NM_DHCP_DHCLIENT_GET_PRIVATE(self);
     const NMDhcpClientConfig *client_config;
     GBytes                   *duid      = NULL;
     gs_free char             *leasefile = NULL;
@@ -724,7 +738,6 @@ nm_dhcp_dhclient_class_init(NMDhcpDhclientClass *dhclient_class)
     client_class->ip4_start = ip4_start;
     client_class->ip6_start = ip6_start;
     client_class->stop      = stop;
-    client_class->get_duid  = get_duid;
 }
 
 const NMDhcpClientFactory _nm_dhcp_client_factory_dhclient = {
diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c
index 05b7b52e..df88362e 100644
--- a/src/core/dhcp/nm-dhcp-nettools.c
+++ b/src/core/dhcp/nm-dhcp-nettools.c
@@ -624,7 +624,7 @@ lease_to_ip4_config(NMDhcpNettools *self, NDhcp4ClientLease *lease, GError **err
 
     l3cd = nm_dhcp_client_create_l3cd(NM_DHCP_CLIENT(self));
 
-    options = nm_dhcp_option_create_options_dict();
+    options = nm_dhcp_client_create_options_dict(NM_DHCP_CLIENT(self), TRUE);
 
     if (!lease_parse_address(self, lease, l3cd, iface, options, &lease_address, error))
         return NULL;
@@ -1100,7 +1100,7 @@ dhcp4_event_cb(int fd, GIOCondition condition, gpointer user_data)
 }
 
 static gboolean
-nettools_create(NMDhcpNettools *self, GError **error)
+nettools_create(NMDhcpNettools *self, GBytes **out_effective_client_id, GError **error)
 {
     NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
     nm_auto(n_dhcp4_client_config_freep) NDhcp4ClientConfig *config = NULL;
@@ -1197,6 +1197,9 @@ nettools_create(NMDhcpNettools *self, GError **error)
 
     priv->event_source = nm_g_unix_fd_add_source(fd, G_IO_IN, dhcp4_event_cb, self);
 
+    *out_effective_client_id =
+        (client_id == client_id_new) ? g_steal_pointer(&client_id_new) : g_bytes_ref(client_id);
+
     return TRUE;
 }
 
@@ -1287,8 +1290,9 @@ static gboolean
 ip4_start(NMDhcpClient *client, GError **error)
 {
     nm_auto(n_dhcp4_client_probe_config_freep) NDhcp4ClientProbeConfig *config = NULL;
-    NMDhcpNettools           *self = NM_DHCP_NETTOOLS(client);
-    NMDhcpNettoolsPrivate    *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
+    NMDhcpNettools           *self                = NM_DHCP_NETTOOLS(client);
+    NMDhcpNettoolsPrivate    *priv                = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
+    gs_unref_bytes GBytes    *effective_client_id = NULL;
     const NMDhcpClientConfig *client_config;
     gs_free char             *lease_file = NULL;
     struct in_addr            last_addr  = {0};
@@ -1299,7 +1303,7 @@ ip4_start(NMDhcpClient *client, GError **error)
     g_return_val_if_fail(!priv->probe, FALSE);
     g_return_val_if_fail(client_config, FALSE);
 
-    if (!nettools_create(self, error))
+    if (!nettools_create(self, &effective_client_id, error))
         return FALSE;
 
     r = n_dhcp4_client_probe_config_new(&config);
@@ -1445,6 +1449,9 @@ ip4_start(NMDhcpClient *client, GError **error)
     }
 
     _LOGT("dhcp-client4: start " NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(priv->client));
+
+    nm_dhcp_client_set_effective_client_id(client, effective_client_id);
+
     return TRUE;
 }
 
diff --git a/src/core/dhcp/nm-dhcp-options.c b/src/core/dhcp/nm-dhcp-options.c
index 96fef81a..a5bb06d1 100644
--- a/src/core/dhcp/nm-dhcp-options.c
+++ b/src/core/dhcp/nm-dhcp-options.c
@@ -190,12 +190,12 @@ static const NMDhcpOption *const _sorted_options_4[G_N_ELEMENTS(_nm_dhcp_option_
 };
 
 const NMDhcpOption _nm_dhcp_option_dhcp6_options[] = {
-    REQ(NM_DHCP_OPTION_DHCP6_CLIENTID, "dhcp6_client_id", FALSE),
+    REQ(NM_DHCP_OPTION_DHCP6_CLIENT_ID, "dhcp6_client_id", FALSE),
 
     /* Don't request server ID by default; some servers don't reply to
      * Information Requests that request the Server ID.
      */
-    REQ(NM_DHCP_OPTION_DHCP6_SERVERID, "dhcp6_server_id", FALSE),
+    REQ(NM_DHCP_OPTION_DHCP6_SERVER_ID, "dhcp6_server_id", FALSE),
 
     REQ(NM_DHCP_OPTION_DHCP6_DNS_SERVERS, "dhcp6_name_servers", TRUE),
     REQ(NM_DHCP_OPTION_DHCP6_DOMAIN_LIST, "dhcp6_domain_search", TRUE),
@@ -460,7 +460,7 @@ nm_dhcp_option_add_requests_to_options(GHashTable *options, int addr_family)
 }
 
 GHashTable *
-nm_dhcp_option_create_options_dict(void)
+nm_dhcp_option_create_options_dict(gboolean static_keys)
 {
-    return g_hash_table_new_full(nm_str_hash, g_str_equal, NULL, g_free);
+    return g_hash_table_new_full(nm_str_hash, g_str_equal, static_keys ? NULL : g_free, g_free);
 }
diff --git a/src/core/dhcp/nm-dhcp-options.h b/src/core/dhcp/nm-dhcp-options.h
index 4c978c4f..fcc6f9cd 100644
--- a/src/core/dhcp/nm-dhcp-options.h
+++ b/src/core/dhcp/nm-dhcp-options.h
@@ -157,8 +157,8 @@ typedef enum {
 } NMDhcpOptionDhcp4Options;
 
 typedef enum {
-    NM_DHCP_OPTION_DHCP6_CLIENTID     = 1,
-    NM_DHCP_OPTION_DHCP6_SERVERID     = 2,
+    NM_DHCP_OPTION_DHCP6_CLIENT_ID    = 1,
+    NM_DHCP_OPTION_DHCP6_SERVER_ID    = 2,
     NM_DHCP_OPTION_DHCP6_DNS_SERVERS  = 23,
     NM_DHCP_OPTION_DHCP6_DOMAIN_LIST  = 24,
     NM_DHCP_OPTION_DHCP6_SNTP_SERVERS = 31,
@@ -222,7 +222,8 @@ void nm_dhcp_option_add_option_in_addr(GHashTable *options,
                                        in_addr_t   value);
 void
 nm_dhcp_option_add_option_u64(GHashTable *options, int addr_family, guint option, guint64 value);
-void        nm_dhcp_option_add_requests_to_options(GHashTable *options, int addr_family);
-GHashTable *nm_dhcp_option_create_options_dict(void);
+void nm_dhcp_option_add_requests_to_options(GHashTable *options, int addr_family);
+
+GHashTable *nm_dhcp_option_create_options_dict(gboolean static_keys);
 
 #endif /* __NM_DHCP_OPTIONS_H__ */
diff --git a/src/core/dhcp/nm-dhcp-systemd.c b/src/core/dhcp/nm-dhcp-systemd.c
index 49e21d97..7ce15d30 100644
--- a/src/core/dhcp/nm-dhcp-systemd.c
+++ b/src/core/dhcp/nm-dhcp-systemd.c
@@ -86,7 +86,7 @@ lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GErro
 
     l3cd = nm_dhcp_client_create_l3cd(NM_DHCP_CLIENT(self));
 
-    options = nm_dhcp_option_create_options_dict();
+    options = nm_dhcp_client_create_options_dict(NM_DHCP_CLIENT(self), TRUE);
 
     if (!nm_dhcp_client_get_config(NM_DHCP_CLIENT(self))->v6.info_only) {
         gboolean has_any_addresses = FALSE;
@@ -271,7 +271,7 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
 
     /* TODO: honor nm_dhcp_client_get_anycast_address() */
 
-    duid = nm_dhcp_client_get_effective_client_id(client);
+    duid = client_config->client_id;
     if (!duid || !(duid_arr = g_bytes_get_data(duid, &duid_len)) || duid_len < 2) {
         nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "missing DUID");
         g_return_val_if_reached(FALSE);
@@ -379,6 +379,8 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
         return FALSE;
     }
 
+    nm_dhcp_client_set_effective_client_id(client, duid);
+
     return TRUE;
 }
 
diff --git a/src/core/dhcp/tests/test-dhcp-dhclient.c b/src/core/dhcp/tests/test-dhcp-dhclient.c
index aaa0dbc3..e95f218e 100644
--- a/src/core/dhcp/tests/test-dhcp-dhclient.c
+++ b/src/core/dhcp/tests/test-dhcp-dhclient.c
@@ -895,122 +895,175 @@ test_read_commented_duid_from_leasefile(void)
 /*****************************************************************************/
 
 static void
-_save_duid(const char *path, const guint8 *duid_bin, gsize duid_len)
+_check_duid_impl(const guint8 *duid_bin,
+                 gsize         duid_len,
+                 gboolean      enforce_duid,
+                 const char   *old_content,
+                 const char   *new_content)
 {
-    gs_unref_bytes GBytes *duid  = NULL;
-    GError                *error = NULL;
+    gs_free_error GError  *error    = NULL;
+    gs_free char          *contents = NULL;
     gboolean               success;
+    const char            *path = NM_BUILD_BUILDDIR "/src/core/dhcp/tests/check-duid.lease";
+    gs_unref_bytes GBytes *duid = NULL;
+    gsize                  contents_len;
 
-    g_assert(path);
     g_assert(duid_bin);
     g_assert(duid_len > 0);
 
-    duid    = g_bytes_new(duid_bin, duid_len);
-    success = nm_dhcp_dhclient_save_duid(path, duid, &error);
-    nmtst_assert_success(success, error);
-}
-
-static void
-test_write_duid(void)
-{
-    const guint8 duid[] = {000, 001, 000, 001, 027, 'X', 0350, 'X', 0, '#', 025, 010, '~', 0254};
-    const char  *expected_contents =
-        "default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n";
-    GError       *error    = NULL;
-    gs_free char *contents = NULL;
-    gboolean      success;
-    const char   *path = "test-dhclient-write-duid.leases";
+    if (!nm_str_is_empty(old_content) || nmtst_get_rand_bool()) {
+        success = g_file_set_contents(path, old_content ?: "", -1, &error);
+        nmtst_assert_success(success, error);
+    } else
+        nmtst_file_unlink_if_exists(path);
 
-    _save_duid(path, duid, G_N_ELEMENTS(duid));
+    duid = g_bytes_new(duid_bin, duid_len);
 
-    success = g_file_get_contents(path, &contents, NULL, &error);
+    success = nm_dhcp_dhclient_save_duid(path, duid, enforce_duid, &error);
     nmtst_assert_success(success, error);
 
-    unlink(path);
-
-    g_assert_cmpstr(expected_contents, ==, contents);
-}
-
-static void
-test_write_existing_duid(void)
-{
-    const guint8 duid[] =
-        {000, 001, 000, 001, 023, 'o', 023, 'n', 000, '"', 0372, 0214, 0326, 0302};
-    const char *original_contents =
-        "default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n";
-    const char *expected_contents =
-        "default-duid \"\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302\";\n";
-    GError       *error    = NULL;
-    gs_free char *contents = NULL;
-    gboolean      success;
-    const char   *path = "test-dhclient-write-existing-duid.leases";
-
-    success = g_file_set_contents(path, original_contents, -1, &error);
+    success = g_file_get_contents(path, &contents, &contents_len, &error);
     nmtst_assert_success(success, error);
+    g_assert(contents);
 
-    /* Save other DUID; should be overwritten */
-    _save_duid(path, duid, G_N_ELEMENTS(duid));
+    nmtst_file_unlink(path);
 
-    /* reread original contents */
-    success = g_file_get_contents(path, &contents, NULL, &error);
-    nmtst_assert_success(success, error);
+    if (!nm_streq0(new_content, contents))
+        g_error("FAILING:\n\nEXPECTED:\n%s\nACTUAL:\n%s\n\n", new_content, contents);
 
-    unlink(path);
-    g_assert_cmpstr(expected_contents, ==, contents);
+    g_assert_cmpstr(new_content, ==, contents);
+    g_assert_cmpint(contents_len, ==, strlen(contents));
 }
 
-static const guint8 DUID_BIN[] =
-    {000, 001, 000, 001, 023, 'o', 023, 'n', 000, '"', 0372, 0214, 0326, 0302};
-#define DUID "\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302"
+#define _DUID(...) ((const guint8[]){__VA_ARGS__})
 
-static void
-test_write_existing_commented_duid(void)
-{
-#define ORIG_CONTENTS "#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n"
-    const char   *expected_contents = "default-duid \"" DUID "\";\n" ORIG_CONTENTS;
-    GError       *error             = NULL;
-    gs_free char *contents          = NULL;
-    gboolean      success;
-    const char   *path = "test-dhclient-write-existing-commented-duid.leases";
-
-    success = g_file_set_contents(path, ORIG_CONTENTS, -1, &error);
-    nmtst_assert_success(success, error);
-
-    /* Save other DUID; should be saved on top */
-    _save_duid(path, DUID_BIN, G_N_ELEMENTS(DUID_BIN));
-
-    /* reread original contents */
-    success = g_file_get_contents(path, &contents, NULL, &error);
-    nmtst_assert_success(success, error);
-
-    unlink(path);
-    g_assert_cmpstr(expected_contents, ==, contents);
-#undef ORIG_CONTENTS
-}
+#define _check_duid(duid, enforce_duid, old_content, new_content) \
+    _check_duid_impl((duid), sizeof(duid), (enforce_duid), (old_content), (new_content))
 
 static void
-test_write_existing_multiline_duid(void)
+test_write_duid(void)
 {
-#define ORIG_CONTENTS              \
-    "### Commented old DUID ###\n" \
-    "#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n"
-    const char                 *expected_contents = "default-duid \"" DUID "\";\n" ORIG_CONTENTS;
-    GError                     *error             = NULL;
-    gs_free char               *contents          = NULL;
-    gboolean                    success;
-    nmtst_auto_unlinkfile char *path =
-        g_strdup("test-dhclient-write-existing-multiline-duid.leases");
-
-    success = g_file_set_contents(path, ORIG_CONTENTS, -1, &error);
-    nmtst_assert_success(success, error);
-
-    _save_duid(path, DUID_BIN, G_N_ELEMENTS(DUID_BIN));
+    _check_duid(_DUID(000, 001, 000, 001, 027, 'X', 0350, 'X', 0, '#', 025, 010, '~', 0254),
+                FALSE,
+                NULL,
+                "default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n");
 
-    success = g_file_get_contents(path, &contents, NULL, &error);
-    nmtst_assert_success(success, error);
+    _check_duid(
+        _DUID(000, 001, 000, 001, 023, 'o', 023, 'n', 000, '"', 0372, 0214, 0326, 0302),
+        FALSE,
+        "default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n",
+        "default-duid \"\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302\";\n");
 
-    g_assert_cmpstr(expected_contents, ==, contents);
-#undef ORIG_CONTENTS
+    _check_duid(_DUID(000, 001, 000, 001, 023, 'o', 023, 'n', 000, '"', 0372, 0214, 0326, 0302),
+                FALSE,
+                "#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n",
+                "default-duid "
+                "\"\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302\";\n#default-duid "
+                "\"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n");
+    _check_duid(
+        _DUID(000, 001, 000, 001, 023, 'o', 023, 'n', 000, '"', 0372, 0214, 0326, 0302),
+        FALSE,
+        "### Commented old DUID ###\n#default-duid "
+        "\"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n",
+        "default-duid \"\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302\";\n### "
+        "Commented old DUID ###\n#default-duid "
+        "\"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n");
+
+    _check_duid(
+        _DUID(0xaa, 0xb, 0xcc, 0xd, 0xee, 0xf),
+        FALSE,
+        "default-duid \"\\252\\013\\314\\015\\356\\017\";\nlease6 {\n  interface \"eth1\";\n "
+        " ia-na f1:ce:00:01 {\n    starts 1671015678;\n    renew 60;\n    rebind 105;\n    "
+        "iaaddr 192:168:121::1:112c {\n      starts 1671015678;\n      preferred-life 120;\n "
+        "     max-life 120;\n    }\n  }\n  option fqdn.encoded true;\n  option "
+        "fqdn.server-update true;\n  option fqdn.no-client-update false;\n  option fqdn.fqdn "
+        "\"dff6de4fcb0f\";\n  option fqdn.hostname \"dff6de4fcb0f\";\n  option dhcp6.client-id "
+        "aa:b:cc:d:ee:f;\n  option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n  option "
+        "dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n  option dhcp6.fqdn "
+        "1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n  option dhcp6.status-code success "
+        "\"success\";\n}\n",
+        "default-duid \"\\252\\013\\314\\015\\356\\017\";\nlease6 {\n  interface \"eth1\";\n "
+        " ia-na f1:ce:00:01 {\n    starts 1671015678;\n    renew 60;\n    rebind 105;\n    "
+        "iaaddr 192:168:121::1:112c {\n      starts 1671015678;\n      preferred-life 120;\n "
+        "     max-life 120;\n    }\n  }\n  option fqdn.encoded true;\n  option "
+        "fqdn.server-update true;\n  option fqdn.no-client-update false;\n  option fqdn.fqdn "
+        "\"dff6de4fcb0f\";\n  option fqdn.hostname \"dff6de4fcb0f\";\n  option dhcp6.client-id "
+        "aa:b:cc:d:ee:f;\n  option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n  option "
+        "dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n  option dhcp6.fqdn "
+        "1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n  option dhcp6.status-code success "
+        "\"success\";\n}\n");
+
+    _check_duid(
+        _DUID(0xaa, 0xb, 0xcc, 0xd, 0xee, 0xf),
+        FALSE,
+        "default-duid \"\\252\\013\\314\\015\\356\\017\";\nlease6 {\n  interface \"eth1\";\n "
+        " ia-na f1:ce:00:01 {\n    starts 1671015678;\n    renew 60;\n    rebind 105;\n    "
+        "iaaddr 192:168:121::1:112c {\n      starts 1671015678;\n      preferred-life 120;\n "
+        "     max-life 120;\n    }\n  }\n  option fqdn.encoded true;\n  option "
+        "fqdn.server-update true;\n  option fqdn.no-client-update false;\n  option fqdn.fqdn "
+        "\"dff6de4fcb0f\";\n  option fqdn.hostname \"dff6de4fcb0f\";\n  option dhcp6.client-id "
+        "aa:b:cc:d:ee:f;\n  option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n  option "
+        "dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n  option dhcp6.fqdn "
+        "1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n  option dhcp6.status-code success "
+        "\"success\";\r\n}\n",
+        "default-duid \"\\252\\013\\314\\015\\356\\017\";\nlease6 {\n  interface \"eth1\";\n "
+        " ia-na f1:ce:00:01 {\n    starts 1671015678;\n    renew 60;\n    rebind 105;\n    "
+        "iaaddr 192:168:121::1:112c {\n      starts 1671015678;\n      preferred-life 120;\n "
+        "     max-life 120;\n    }\n  }\n  option fqdn.encoded true;\n  option "
+        "fqdn.server-update true;\n  option fqdn.no-client-update false;\n  option fqdn.fqdn "
+        "\"dff6de4fcb0f\";\n  option fqdn.hostname \"dff6de4fcb0f\";\n  option dhcp6.client-id "
+        "aa:b:cc:d:ee:f;\n  option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n  option "
+        "dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n  option dhcp6.fqdn "
+        "1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n  option dhcp6.status-code success "
+        "\"success\";\r\n}\n");
+
+    _check_duid(
+        _DUID(0xaa, 0xb, 0xcc, 0xd, 0xee, 0xe),
+        FALSE,
+        "default-duid \"\\252\\013\\314\\015\\356\\017\";\nlease6 {\n  interface \"eth1\";\n "
+        " ia-na f1:ce:00:01 {\n    starts 1671015678;\n    renew 60;\n    rebind 105;\n    "
+        "iaaddr 192:168:121::1:112c {\n      starts 1671015678;\n      preferred-life 120;\n "
+        "     max-life 120;\n    }\n  }\n  option fqdn.encoded true;\n  option "
+        "fqdn.server-update true;\n  option fqdn.no-client-update false;\n  option fqdn.fqdn "
+        "\"dff6de4fcb0f\";\n  option fqdn.hostname \"dff6de4fcb0f\";\n  option dhcp6.client-id "
+        "aa:b:cc:d:ee:f;\n  option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n  option "
+        "dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n  option dhcp6.fqdn "
+        "1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n  option dhcp6.status-code success "
+        "\"success\";\r\n}\n",
+        "default-duid \"\\252\\013\\314\\015\\356\\016\";\nlease6 {\n  interface \"eth1\";\n "
+        " ia-na f1:ce:00:01 {\n    starts 1671015678;\n    renew 60;\n    rebind 105;\n    "
+        "iaaddr 192:168:121::1:112c {\n      starts 1671015678;\n      preferred-life 120;\n "
+        "     max-life 120;\n    }\n  }\n  option fqdn.encoded true;\n  option "
+        "fqdn.server-update true;\n  option fqdn.no-client-update false;\n  option fqdn.fqdn "
+        "\"dff6de4fcb0f\";\n  option fqdn.hostname \"dff6de4fcb0f\";\n  option dhcp6.client-id "
+        "aa:b:cc:d:ee:f;\n  option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n  option "
+        "dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n  option dhcp6.fqdn "
+        "1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n  option dhcp6.status-code success "
+        "\"success\";\r\n}\n");
+
+    _check_duid(
+        _DUID(0xaa, 0xb, 0xcc, 0xd, 0xee, 0xe),
+        TRUE,
+        "default-duid \"\\252\\013\\314\\015\\356\\017\";\nlease6 {\n  interface \"eth1\";\n "
+        " ia-na f1:ce:00:01 {\n    starts 1671015678;\n    renew 60;\n    rebind 105;\n    "
+        "iaaddr 192:168:121::1:112c {\n      starts 1671015678;\n      preferred-life 120;\n "
+        "     max-life 120;\n    }\n  }\n  option fqdn.encoded true;\n  option "
+        "fqdn.server-update true;\n  option fqdn.no-client-update false;\n  option fqdn.fqdn "
+        "\"dff6de4fcb0f\";\n  option fqdn.hostname \"dff6de4fcb0f\";\n  option dhcp6.client-id "
+        "aa:b:cc:d:ee:f;\n  option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n  option "
+        "dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n  option dhcp6.fqdn "
+        "1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n  option dhcp6.status-code success "
+        "\"success\";\n}\n",
+        "default-duid \"\\252\\013\\314\\015\\356\\016\";\nlease6 {\n  interface \"eth1\";\n "
+        " ia-na f1:ce:00:01 {\n    starts 1671015678;\n    renew 60;\n    rebind 105;\n    "
+        "iaaddr 192:168:121::1:112c {\n      starts 1671015678;\n      preferred-life 120;\n "
+        "     max-life 120;\n    }\n  }\n  option fqdn.encoded true;\n  option "
+        "fqdn.server-update true;\n  option fqdn.no-client-update false;\n  option fqdn.fqdn "
+        "\"dff6de4fcb0f\";\n  option fqdn.hostname \"dff6de4fcb0f\";\n  option dhcp6.client-id "
+        "aa:b:cc:d:ee:e;\n  option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n  option "
+        "dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n  option dhcp6.fqdn "
+        "1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n  option dhcp6.status-code success "
+        "\"success\";\n}\n");
 }
 
 /*****************************************************************************/
@@ -1329,12 +1382,7 @@ main(int argc, char **argv)
     g_test_add_func("/dhcp/dhclient/read_commented_duid_from_leasefile",
                     test_read_commented_duid_from_leasefile);
 
-    g_test_add_func("/dhcp/dhclient/write_duid", test_write_duid);
-    g_test_add_func("/dhcp/dhclient/write_existing_duid", test_write_existing_duid);
-    g_test_add_func("/dhcp/dhclient/write_existing_commented_duid",
-                    test_write_existing_commented_duid);
-    g_test_add_func("/dhcp/dhclient/write_existing_multiline_duid",
-                    test_write_existing_multiline_duid);
+    g_test_add_func("/dhcp/dhclient/test_write_duid", test_write_duid);
 
     return g_test_run();
 }
diff --git a/src/core/dns/nm-dns-dnsmasq.c b/src/core/dns/nm-dns-dnsmasq.c
index 7d0f0490..cc7c03a2 100644
--- a/src/core/dns/nm-dns-dnsmasq.c
+++ b/src/core/dns/nm-dns-dnsmasq.c
@@ -191,7 +191,8 @@ _gl_pid_kill_external(void)
     if (!g_file_get_contents(PIDFILE, &contents, NULL, &error)) {
         if (g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
             do_unlink = FALSE;
-        _LOGD("spawn: failure to read pidfile %s: %s", PIDFILE, error->message);
+        else
+            _LOGD("spawn: failure to read pidfile %s: %s", PIDFILE, error->message);
         g_clear_error(&error);
         goto handle_kill;
     }
@@ -667,6 +668,14 @@ _gl_pid_spawn(const char           *dm_binary,
 
 /*****************************************************************************/
 
+void
+nm_dnsmasq_kill_external(void)
+{
+    _gl_pid_kill_external();
+}
+
+/*****************************************************************************/
+
 typedef struct {
     GDBusConnection *dbus_connection;
 
diff --git a/src/core/dns/nm-dns-dnsmasq.h b/src/core/dns/nm-dns-dnsmasq.h
index 575b0b26..98761d3d 100644
--- a/src/core/dns/nm-dns-dnsmasq.h
+++ b/src/core/dns/nm-dns-dnsmasq.h
@@ -25,4 +25,6 @@ GType nm_dns_dnsmasq_get_type(void);
 
 NMDnsPlugin *nm_dns_dnsmasq_new(void);
 
+void nm_dnsmasq_kill_external(void);
+
 #endif /* __NETWORKMANAGER_DNS_DNSMASQ_H__ */
diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c
index a2fead3f..edb8ce0f 100644
--- a/src/core/dns/nm-dns-manager.c
+++ b/src/core/dns/nm-dns-manager.c
@@ -2513,6 +2513,9 @@ again:
                                                              self);
     }
 
+    if (!NM_IS_DNS_DNSMASQ(priv->plugin))
+        nm_dnsmasq_kill_external();
+
     _update_pending_maybe_changed(self);
 
     g_object_thaw_notify(G_OBJECT(self));
diff --git a/src/core/ndisc/nm-fake-ndisc.c b/src/core/ndisc/nm-fake-ndisc.c
index 5aea273e..59bf0c1b 100644
--- a/src/core/ndisc/nm-fake-ndisc.c
+++ b/src/core/ndisc/nm-fake-ndisc.c
@@ -358,7 +358,7 @@ NMNDisc *
 nm_fake_ndisc_new(NML3Cfg *l3cfg)
 {
     const NMNDiscConfig config = {
-        .l3cfg                        = g_object_ref(NM_L3CFG(l3cfg)),
+        .l3cfg                        = NM_L3CFG(l3cfg),
         .ifname                       = nm_l3cfg_get_ifname(l3cfg, TRUE),
         .node_type                    = NM_NDISC_NODE_TYPE_HOST,
         .stable_type                  = NM_UTILS_STABLE_TYPE_UUID,
diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c
index 518fc596..0c07c29e 100644
--- a/src/core/nm-policy.c
+++ b/src/core/nm-policy.c
@@ -1579,7 +1579,6 @@ nm_policy_unblock_failed_ovs_interfaces(NMPolicy *self)
     NMPolicyPrivate             *priv        = NM_POLICY_GET_PRIVATE(self);
     NMSettingsConnection *const *connections = NULL;
     guint                        i;
-    gboolean                     multiconnect = FALSE;
 
     _LOGT(LOGD_DEVICE, "unblocking failed OVS interfaces");
 
@@ -1587,13 +1586,6 @@ nm_policy_unblock_failed_ovs_interfaces(NMPolicy *self)
     for (i = 0; connections[i]; i++) {
         NMSettingsConnection *sett_conn  = connections[i];
         NMConnection         *connection = nm_settings_connection_get_connection(sett_conn);
-        NMSettingConnection  *s_con      = nm_connection_get_setting_connection(connection);
-
-        /* Check if any connection is connect multiple */
-        if (s_con
-            && nm_setting_connection_get_multi_connect(s_con)
-                   == NM_CONNECTION_MULTI_CONNECT_MULTIPLE)
-            multiconnect = TRUE;
 
         if (nm_connection_get_setting_ovs_interface(connection)) {
             nm_settings_connection_autoconnect_retries_reset(sett_conn);
@@ -1603,18 +1595,6 @@ nm_policy_unblock_failed_ovs_interfaces(NMPolicy *self)
                 FALSE);
         }
     }
-
-    /* There is, at least, one multiconnect connection with an OVS setting.
-     * Let's check the OVS devices retries */
-    if (multiconnect) {
-        NMDevice      *device;
-        GHashTableIter h_iter;
-        g_hash_table_iter_init(&h_iter, priv->devices);
-        while (g_hash_table_iter_next(&h_iter, (gpointer *) &device, NULL)) {
-            if (nm_device_get_device_type(device) == NM_DEVICE_TYPE_OVS_INTERFACE)
-                nm_device_autoconnect_retries_reset(device);
-        }
-    }
 }
 
 static gboolean
@@ -1626,8 +1606,7 @@ reset_autoconnect_all(
     NMPolicyPrivate             *priv        = NM_POLICY_GET_PRIVATE(self);
     NMSettingsConnection *const *connections = NULL;
     guint                        i;
-    gboolean                     changed      = FALSE;
-    gboolean                     multiconnect = FALSE;
+    gboolean                     changed = FALSE;
 
     _LOGD(LOGD_DEVICE,
           "re-enabling autoconnect for all connections%s%s%s",
@@ -1638,8 +1617,6 @@ reset_autoconnect_all(
     connections = nm_settings_get_connections(priv->settings, NULL);
     for (i = 0; connections[i]; i++) {
         NMSettingsConnection *sett_conn = connections[i];
-        NMSettingConnection  *s_con =
-            nm_connection_get_setting_connection(nm_settings_connection_get_connection(sett_conn));
 
         if (device
             && !nm_device_check_connection_compatible(
@@ -1648,11 +1625,6 @@ reset_autoconnect_all(
                 NULL))
             continue;
 
-        if (s_con
-            && nm_setting_connection_get_multi_connect(s_con)
-                   == NM_CONNECTION_MULTI_CONNECT_MULTIPLE)
-            multiconnect = TRUE;
-
         if (only_no_secrets) {
             /* we only reset the no-secrets blocked flag. */
             if (nm_settings_connection_autoconnect_blocked_reason_set(
@@ -1681,20 +1653,6 @@ reset_autoconnect_all(
             }
         }
     }
-
-    /* There is, at least, one multiconnect connection. Let's check the devices retries */
-    if (multiconnect) {
-        NMDevice      *device_iter;
-        GHashTableIter h_iter;
-        g_hash_table_iter_init(&h_iter, priv->devices);
-        while (g_hash_table_iter_next(&h_iter, (gpointer *) &device_iter, NULL)) {
-            if (nm_device_get_autoconnect_retries(device_iter) != -2) {
-                nm_device_autoconnect_retries_reset(device_iter);
-                changed = TRUE;
-            }
-        }
-    }
-
     return changed;
 }
 
@@ -1752,8 +1710,7 @@ reset_connections_retries(gpointer user_data)
     NMSettingsConnection *const *connections = NULL;
     guint                        i;
     gint32                       con_stamp, min_stamp, now;
-    gboolean                     changed      = FALSE;
-    gboolean                     multiconnect = FALSE;
+    gboolean                     changed = FALSE;
 
     priv->reset_retries_id = 0;
 
@@ -1762,14 +1719,6 @@ reset_connections_retries(gpointer user_data)
     connections = nm_settings_get_connections(priv->settings, NULL);
     for (i = 0; connections[i]; i++) {
         NMSettingsConnection *connection = connections[i];
-        NMSettingConnection  *s_con =
-            nm_connection_get_setting_connection(nm_settings_connection_get_connection(connection));
-
-        /* Check if any connection is connect multiple */
-        if (s_con
-            && nm_setting_connection_get_multi_connect(s_con)
-                   == NM_CONNECTION_MULTI_CONNECT_MULTIPLE)
-            multiconnect = TRUE;
 
         con_stamp = nm_settings_connection_autoconnect_retries_blocked_until(connection);
         if (con_stamp == 0)
@@ -1782,25 +1731,6 @@ reset_connections_retries(gpointer user_data)
             min_stamp = con_stamp;
     }
 
-    /* There is, at least, one multiconnect connection. Let's check the devices retries */
-    if (multiconnect) {
-        NMDevice      *device;
-        GHashTableIter h_iter;
-        g_hash_table_iter_init(&h_iter, priv->devices);
-        while (g_hash_table_iter_next(&h_iter, (gpointer *) &device, NULL)) {
-            con_stamp = nm_device_autoconnect_retries_blocked_until(device);
-
-            /* default value in device is -2, which means, we do not care */
-            if (con_stamp <= 0)
-                continue;
-            if (con_stamp <= now) {
-                nm_device_autoconnect_retries_reset(device);
-                changed = TRUE;
-            } else if (min_stamp == 0 || min_stamp > con_stamp)
-                min_stamp = con_stamp;
-        }
-    }
-
     /* Schedule the handler again if there are some stamps left */
     if (min_stamp != 0)
         priv->reset_retries_id =
@@ -1814,31 +1744,21 @@ reset_connections_retries(gpointer user_data)
 }
 
 static void
-_connection_autoconnect_retries_set(NMPolicy             *self,
-                                    NMSettingsConnection *connection,
-                                    NMDevice             *device,
-                                    int                   tries)
+_connection_autoconnect_retries_set(NMPolicy *self, NMSettingsConnection *connection, int tries)
 {
-    NMPolicyPrivate     *priv = NM_POLICY_GET_PRIVATE(self);
-    NMSettingConnection *s_con;
-    gint32               retry_time;
+    NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self);
 
     nm_assert(NM_IS_SETTINGS_CONNECTION(connection));
     nm_assert(tries >= 0);
 
-    s_con = nm_connection_get_setting_connection(nm_settings_connection_get_connection(connection));
-    if (s_con
-        && nm_setting_connection_get_multi_connect(s_con) == NM_CONNECTION_MULTI_CONNECT_MULTIPLE) {
-        nm_device_set_autoconnect_retries(device, tries);
-        retry_time = nm_device_autoconnect_retries_blocked_until(device);
-    } else {
-        nm_settings_connection_autoconnect_retries_set(connection, tries);
-        retry_time = nm_settings_connection_autoconnect_retries_blocked_until(connection);
-    }
+    nm_settings_connection_autoconnect_retries_set(connection, tries);
 
     if (tries == 0) {
         /* Schedule a handler to reset retries count */
         if (!priv->reset_retries_id) {
+            gint32 retry_time =
+                nm_settings_connection_autoconnect_retries_blocked_until(connection);
+
             g_warn_if_fail(retry_time != 0);
             priv->reset_retries_id =
                 g_timeout_add_seconds(MAX(0, retry_time - nm_utils_get_monotonic_timestamp_sec()),
@@ -2100,25 +2020,13 @@ device_state_changed(NMDevice           *device,
             }
 
             if (!blocked) {
-                s_con = nm_connection_get_setting_connection(
-                    nm_settings_connection_get_connection(sett_conn));
-                if (s_con
-                    && nm_setting_connection_get_multi_connect(s_con)
-                           == NM_CONNECTION_MULTI_CONNECT_MULTIPLE) {
-                    if (nm_device_get_autoconnect_retries(device) == -2)
-                        nm_device_set_autoconnect_retries(
-                            device,
-                            nm_settings_connection_autoconnect_retries_get(sett_conn));
-
-                    tries = nm_device_get_autoconnect_retries(device);
-                } else
-                    tries = nm_settings_connection_autoconnect_retries_get(sett_conn);
+                tries = nm_settings_connection_autoconnect_retries_get(sett_conn);
                 if (tries > 0) {
                     _LOGD(LOGD_DEVICE,
                           "connection '%s' failed to autoconnect; %d tries left",
                           nm_settings_connection_get_id(sett_conn),
                           tries - 1);
-                    _connection_autoconnect_retries_set(self, sett_conn, device, tries - 1);
+                    _connection_autoconnect_retries_set(self, sett_conn, tries - 1);
                 } else if (tries != 0) {
                     _LOGD(LOGD_DEVICE,
                           "connection '%s' failed to autoconnect; infinite tries left",
diff --git a/src/libnm-client-impl/nm-device-modem.c b/src/libnm-client-impl/nm-device-modem.c
index a1edfb04..4cf6a9bd 100644
--- a/src/libnm-client-impl/nm-device-modem.c
+++ b/src/libnm-client-impl/nm-device-modem.c
@@ -145,12 +145,14 @@ get_type_description(NMDevice *device)
     NMDeviceModemCapabilities caps;
 
     caps = nm_device_modem_get_current_capabilities(NM_DEVICE_MODEM(device));
-    if (caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS)
+    if (NM_FLAGS_ANY(caps,
+                     NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS | NM_DEVICE_MODEM_CAPABILITY_LTE
+                         | NM_DEVICE_MODEM_CAPABILITY_5GNR))
         return "gsm";
-    else if (caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO)
+    if (NM_FLAGS_HAS(caps, NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO))
         return "cdma";
-    else
-        return NULL;
+
+    return "modem";
 }
 
 #define MODEM_CAPS_3GPP(caps)                                                          \
diff --git a/src/libnm-client-impl/nm-device.c b/src/libnm-client-impl/nm-device.c
index 238e7c17..0e971d39 100644
--- a/src/libnm-client-impl/nm-device.c
+++ b/src/libnm-client-impl/nm-device.c
@@ -2496,7 +2496,7 @@ nm_device_reapply_finish(NMDevice *device, GAsyncResult *result, GError **error)
 /**
  * nm_device_get_applied_connection:
  * @device: a #NMDevice
- * @flags: the flags argument. Currently, this value must always be zero.
+ * @flags: the flags argument. See #NMDeviceReapplyFlags.
  * @version_id: (out) (allow-none): returns the current version id of
  *   the applied connection
  * @cancellable: a #GCancellable, or %NULL
@@ -2559,7 +2559,7 @@ nm_device_get_applied_connection(NMDevice     *device,
 /**
  * nm_device_get_applied_connection_async:
  * @device: a #NMDevice
- * @flags: the flags argument. Currently, this value must always be zero.
+ * @flags: the flags argument. See #NMDeviceReapplyFlags.
  * @cancellable: a #GCancellable, or %NULL
  * @callback: callback to be called when the reapply operation completes
  * @user_data: caller-specific data passed to @callback
diff --git a/src/libnm-core-public/nm-dbus-interface.h b/src/libnm-core-public/nm-dbus-interface.h
index 6e1a84a1..3e79d4c6 100644
--- a/src/libnm-core-public/nm-dbus-interface.h
+++ b/src/libnm-core-public/nm-dbus-interface.h
@@ -1145,6 +1145,24 @@ typedef enum /*< flags >*/ {
 } NMSettingsUpdate2Flags;
 
 /**
+ * NMDeviceReapplyFlags:
+ * @NM_DEVICE_REAPPLY_FLAGS_NONE: no flag set.
+ * @NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP: during reapply,
+ *   preserve external IP addresses and routes.
+ *
+ * Flags for the Reapply() D-Bus call of a device and
+ * nm_device_reapply_async().
+ *
+ * Since: 1.42, 1.40.10
+ *
+ * On 1.40.10+, no GFlags type is created.
+ */
+typedef enum /*< skip >*/ {
+    NM_DEVICE_REAPPLY_FLAGS_NONE                 = 0,
+    NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP = 0x1,
+} NMDeviceReapplyFlags;
+
+/**
  * NMTernary:
  * @NM_TERNARY_DEFAULT: use the globally-configured default value.
  * @NM_TERNARY_FALSE: the option is disabled.
diff --git a/src/libnm-core-public/nm-dbus-types.xml b/src/libnm-core-public/nm-dbus-types.xml
index 52ac4981..d8de9002 100644
--- a/src/libnm-core-public/nm-dbus-types.xml
+++ b/src/libnm-core-public/nm-dbus-types.xml
@@ -1908,6 +1908,36 @@
     </refsect3>
   </refsect2>
 
+  <refsect2 id="NMDeviceReapplyFlags" role="enum">
+    <title>enum NMDeviceReapplyFlags</title>
+    <indexterm zone="NMDeviceReapplyFlags">
+      <primary>NMDeviceReapplyFlags</primary>
+    </indexterm>
+    <para><para>Flags for the Reapply() D-Bus call of a device and nm_device_reapply_async().</para><para>Since: 1.42, 1.40.10</para><para>On 1.40.10+, no GFlags type is created.</para><para></para></para>
+    <refsect3 role="enum_members">
+      <title>Values</title>
+      <informaltable role="enum_members_table" pgwide="1" frame="none">
+        <tgroup cols="4">
+          <colspec colname="enum_members_name" colwidth="300px" />
+          <colspec colname="enum_members_value" colwidth="100px"/>
+          <colspec colname="enum_members_description" />
+          <tbody>
+            <row role="constant">
+              <entry role="enum_member_name"><para>NM_DEVICE_REAPPLY_FLAGS_NONE</para><para></para></entry>
+              <entry role="enum_member_value"><para>= <literal>0</literal></para><para></para></entry>
+              <entry role="enum_member_description"><para>no flag set.</para><para></para></entry>
+            </row>
+            <row role="constant">
+              <entry role="enum_member_name"><para>NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP</para><para></para></entry>
+              <entry role="enum_member_value"><para>= <literal>0x1</literal></para><para></para></entry>
+              <entry role="enum_member_description"><para>during reapply, preserve external IP addresses and routes.</para><para></para></entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </informaltable>
+    </refsect3>
+  </refsect2>
+
   <refsect2 id="NMTernary" role="enum">
     <title>enum NMTernary</title>
     <indexterm zone="NMTernary">
diff --git a/src/libnm-core-public/nm-version-macros.h b/src/libnm-core-public/nm-version-macros.h
index 2b5bc67e..f95ca8ae 100644
--- a/src/libnm-core-public/nm-version-macros.h
+++ b/src/libnm-core-public/nm-version-macros.h
@@ -30,7 +30,7 @@
  * Evaluates to the micro version number of NetworkManager which this source
  * compiled against.
  */
-#define NM_MICRO_VERSION (8)
+#define NM_MICRO_VERSION (10)
 
 /**
  * NM_CHECK_VERSION:
diff --git a/src/libnm-glib-aux/nm-shared-utils.c b/src/libnm-glib-aux/nm-shared-utils.c
index d0885477..aca7d708 100644
--- a/src/libnm-glib-aux/nm-shared-utils.c
+++ b/src/libnm-glib-aux/nm-shared-utils.c
@@ -4846,7 +4846,7 @@ nm_utils_memeqzero(gconstpointer data, gsize length)
 }
 
 /**
- * nm_utils_bin2hexstr_full:
+ * nm_utils_bin2hexstr_fuller:
  * @addr: pointer of @length bytes. If @length is zero, this may
  *   also be %NULL.
  * @length: number of bytes in @addr. May also be zero, in which
@@ -4854,12 +4854,17 @@ nm_utils_memeqzero(gconstpointer data, gsize length)
  * @delimiter: either '\0', otherwise the output string will have the
  *   given delimiter character between each two hex numbers.
  * @upper_case: if TRUE, use upper case ASCII characters for hex.
+ * @with_leading_zero: if TRUE, then the hex values from 0 to 0xf
+ *   are written as "00" to "0f", respectively. Otherwise, the leading
+ *   zero is dropped. With @with_leading_zero set to FALSE, the resulting
+ *   string may be shorter than expected. @delimiter must be set
+ *   if @with_leading_zero is FALSE.
  * @out: if %NULL, the function will allocate a new buffer of
- *   either (@length*2+1) or (@length*3) bytes, depending on whether
+ *   either (@length*2+1) or MAX(1, (@length*3)) bytes, depending on whether
  *   a @delimiter is specified. In that case, the allocated buffer will
  *   be returned and must be freed by the caller.
  *   If not %NULL, the buffer must already be preallocated and contain
- *   at least (@length*2+1) or (@length*3) bytes, depending on the delimiter.
+ *   at least (@length*2+1) or MAX(1, (@length*3)) bytes, depending on the delimiter.
  *   If @length is zero, then of course at least one byte will be allocated
  *   or @out (if given) must contain at least room for the trailing NUL byte.
  *
@@ -4869,37 +4874,43 @@ nm_utils_memeqzero(gconstpointer data, gsize length)
  *   an empty string is returned.
  */
 char *
-nm_utils_bin2hexstr_full(gconstpointer addr,
-                         gsize         length,
-                         char          delimiter,
-                         gboolean      upper_case,
-                         char         *out)
+nm_utils_bin2hexstr_fuller(gconstpointer addr,
+                           gsize         length,
+                           char          delimiter,
+                           gboolean      upper_case,
+                           gboolean      with_leading_zero,
+                           char         *out)
 {
     const guint8 *in     = addr;
     const char   *LOOKUP = upper_case ? "0123456789ABCDEF" : "0123456789abcdef";
     char         *out0;
 
-    if (out)
-        out0 = out;
-    else {
-        out0 = out =
-            g_new(char, length == 0 ? 1u : (delimiter == '\0' ? length * 2u + 1u : length * 3u));
-    }
+    nm_assert(with_leading_zero || delimiter != '\0');
 
-    /* @out must contain at least @length*3 bytes if @delimiter is set,
+    /* @out must contain at least (MAX(1, @length*3)) bytes if @delimiter is set,
      * otherwise, @length*2+1. */
 
+    if (!out)
+        out = g_new(char, length == 0 ? 1u : (delimiter == '\0' ? length * 2u + 1u : length * 3u));
+
+    out0 = out;
+
     if (length > 0) {
         nm_assert(in);
         for (;;) {
             const guint8 v = *in++;
+            guint8       v_hi;
 
-            *out++ = LOOKUP[v >> 4];
+            v_hi = (v >> 4);
+            if (v_hi != 0 || with_leading_zero) {
+                nm_assert(v_hi < 16);
+                *out++ = LOOKUP[v_hi];
+            }
             *out++ = LOOKUP[v & 0x0F];
             length--;
-            if (!length)
+            if (length == 0)
                 break;
-            if (delimiter)
+            if (delimiter != '\0')
                 *out++ = delimiter;
         }
     }
diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h
index fe7c59f3..53cf7f3e 100644
--- a/src/libnm-glib-aux/nm-shared-utils.h
+++ b/src/libnm-glib-aux/nm-shared-utils.h
@@ -2842,11 +2842,22 @@ nm_ascii_is_regular(char ch)
     return ch >= ' ' && ch < 127;
 }
 
-char *nm_utils_bin2hexstr_full(gconstpointer addr,
-                               gsize         length,
-                               char          delimiter,
-                               gboolean      upper_case,
-                               char         *out);
+char *nm_utils_bin2hexstr_fuller(gconstpointer addr,
+                                 gsize         length,
+                                 char          delimiter,
+                                 gboolean      upper_case,
+                                 gboolean      with_leading_zero,
+                                 char         *out);
+
+static inline char *
+nm_utils_bin2hexstr_full(gconstpointer addr,
+                         gsize         length,
+                         char          delimiter,
+                         gboolean      upper_case,
+                         char         *out)
+{
+    return nm_utils_bin2hexstr_fuller(addr, length, delimiter, upper_case, TRUE, out);
+}
 
 char *_nm_utils_bin2hexstr(gconstpointer src, gsize len, int final_len);
 
diff --git a/src/nm-cloud-setup/main.c b/src/nm-cloud-setup/main.c
index 0c452acf..e1cbd1d4 100644
--- a/src/nm-cloud-setup/main.c
+++ b/src/nm-cloud-setup/main.c
@@ -251,24 +251,38 @@ _get_config(GCancellable *sigterm_cancellable, NMCSProvider *provider, NMClient
 /*****************************************************************************/
 
 static gboolean
-_nmc_skip_connection(NMConnection *connection)
+_nmc_skip_connection_by_user_data(NMConnection *connection)
 {
     NMSettingUser *s_user;
     const char    *v;
 
-    s_user = NM_SETTING_USER(nm_connection_get_setting(connection, NM_TYPE_SETTING_USER));
-    if (!s_user)
-        return FALSE;
-
 #define USER_TAG_SKIP "org.freedesktop.nm-cloud-setup.skip"
 
     nm_assert(nm_setting_user_check_key(USER_TAG_SKIP, NULL));
 
-    v = nm_setting_user_get_data(s_user, USER_TAG_SKIP);
-    return _nm_utils_ascii_str_to_bool(v, FALSE);
+    s_user = NM_SETTING_USER(nm_connection_get_setting(connection, NM_TYPE_SETTING_USER));
+    if (s_user) {
+        v = nm_setting_user_get_data(s_user, USER_TAG_SKIP);
+        if (_nm_utils_ascii_str_to_bool(v, FALSE))
+            return TRUE;
+    }
+
+    return FALSE;
 }
 
 static gboolean
+_nmc_skip_connection_by_type(NMConnection *connection)
+{
+    if (!nm_streq0(nm_connection_get_connection_type(connection), NM_SETTING_WIRED_SETTING_NAME))
+        return TRUE;
+
+    if (!nm_connection_get_setting_ip4_config(connection))
+        return TRUE;
+
+    return FALSE;
+}
+
+static void
 _nmc_mangle_connection(NMDevice                             *device,
                        NMConnection                         *connection,
                        const NMCSProviderGetConfigResult    *result,
@@ -291,12 +305,8 @@ _nmc_mangle_connection(NMDevice                             *device,
     NM_SET_OUT(out_skipped_single_addr, FALSE);
     NM_SET_OUT(out_changed, FALSE);
 
-    if (!nm_streq0(nm_connection_get_connection_type(connection), NM_SETTING_WIRED_SETTING_NAME))
-        return FALSE;
-
     s_ip = nm_connection_get_setting_ip4_config(connection);
-    if (!s_ip)
-        return FALSE;
+    nm_assert(NM_IS_SETTING_IP4_CONFIG(s_ip));
 
     if ((ac = nm_device_get_active_connection(device))
         && (remote_connection = NM_CONNECTION(nm_active_connection_get_connection(ac))))
@@ -429,7 +439,6 @@ _nmc_mangle_connection(NMDevice                             *device,
                                                        rules_new->len);
 
     NM_SET_OUT(out_changed, addrs_changed || routes_changed || rules_changed);
-    return TRUE;
 }
 
 /*****************************************************************************/
@@ -451,6 +460,7 @@ _config_one(GCancellable                      *sigterm_cancellable,
     gboolean                              version_id_changed;
     guint                                 try_count;
     gboolean                              any_changes = FALSE;
+    gboolean                              maybe_no_preserved_external_ip;
 
     g_main_context_iteration(NULL, FALSE);
 
@@ -484,6 +494,8 @@ _config_one(GCancellable                      *sigterm_cancellable,
     try_count = 0;
 
 try_again:
+    g_clear_object(&applied_connection);
+    g_clear_error(&error);
 
     applied_connection = nmcs_device_get_applied_connection(device,
                                                             sigterm_cancellable,
@@ -497,23 +509,25 @@ try_again:
         return any_changes;
     }
 
-    if (_nmc_skip_connection(applied_connection)) {
+    if (_nmc_skip_connection_by_user_data(applied_connection)) {
         _LOGD("config device %s: skip applied connection due to user data %s",
               hwaddr,
               USER_TAG_SKIP);
         return any_changes;
     }
 
-    if (!_nmc_mangle_connection(device,
-                                applied_connection,
-                                result,
-                                config_data,
-                                &skipped_single_addr,
-                                &changed)) {
+    if (_nmc_skip_connection_by_type(applied_connection)) {
         _LOGD("config device %s: device has no suitable applied connection. Skip", hwaddr);
         return any_changes;
     }
 
+    _nmc_mangle_connection(device,
+                           applied_connection,
+                           result,
+                           config_data,
+                           &skipped_single_addr,
+                           &changed);
+
     if (!changed) {
         if (skipped_single_addr) {
             _LOGD("config device %s: device needs no update to applied connection \"%s\" (%s) "
@@ -539,16 +553,22 @@ try_again:
     /* we are about to call Reapply(). Even if that fails, it counts as if we changed something. */
     any_changes = TRUE;
 
+    /* "preserve-external-ip" flag was only introduced in 1.41.6 and 1.40.9.
+     * We have no convenient way to check the daemon version (short of parsing the "Version"
+     * string). Hence, we don't know it. Take into account, that the daemon that we
+     * talk to might not support the flag yet. This is to support backward compatibility
+     * during package upgrade. */
+    maybe_no_preserved_external_ip = TRUE;
+
     if (!nmcs_device_reapply(device,
                              sigterm_cancellable,
                              applied_connection,
                              applied_version_id,
+                             maybe_no_preserved_external_ip,
                              &version_id_changed,
                              &error)) {
         if (version_id_changed && try_count < 5) {
             _LOGD("config device %s: applied connection changed in the meantime. Retry...", hwaddr);
-            g_clear_object(&applied_connection);
-            g_clear_error(&error);
             try_count++;
             goto try_again;
         }
diff --git a/src/nm-cloud-setup/nm-cloud-setup-utils.c b/src/nm-cloud-setup/nm-cloud-setup-utils.c
index e505f8bd..7cf79592 100644
--- a/src/nm-cloud-setup/nm-cloud-setup-utils.c
+++ b/src/nm-cloud-setup/nm-cloud-setup-utils.c
@@ -822,6 +822,7 @@ nmcs_device_reapply(NMDevice     *device,
                     GCancellable *sigterm_cancellable,
                     NMConnection *connection,
                     guint64       version_id,
+                    gboolean      maybe_no_preserved_external_ip,
                     gboolean     *out_version_id_changed,
                     GError      **error)
 {
@@ -829,11 +830,13 @@ nmcs_device_reapply(NMDevice     *device,
     DeviceReapplyData                  data      = {
                               .main_loop = main_loop,
     };
+    NMDeviceReapplyFlags reapply_flags = NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP;
 
+again:
     nm_device_reapply_async(device,
                             connection,
                             version_id,
-                            0,
+                            reapply_flags,
                             sigterm_cancellable,
                             _nmcs_device_reapply_cb,
                             &data);
@@ -841,6 +844,17 @@ nmcs_device_reapply(NMDevice     *device,
     g_main_loop_run(main_loop);
 
     if (data.error) {
+        if (maybe_no_preserved_external_ip
+            && reapply_flags == NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP
+            && nm_g_error_matches(data.error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED)) {
+            /* Hm? Maybe we running against an older version of NetworkManager that
+             * doesn't support "preserve-external-ip" flags? Retry without the flag.
+             *
+             * Note that recent version would reject invalid flags with NM_DEVICE_ERROR_INVALID_ARGUMENT,
+             * but we want to detect old daemon versions here. */
+            reapply_flags = NM_DEVICE_REAPPLY_FLAGS_NONE;
+            goto again;
+        }
         NM_SET_OUT(
             out_version_id_changed,
             g_error_matches(data.error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_VERSION_ID_MISMATCH));
diff --git a/src/nm-cloud-setup/nm-cloud-setup-utils.h b/src/nm-cloud-setup/nm-cloud-setup-utils.h
index 4131abfe..fed0f4b6 100644
--- a/src/nm-cloud-setup/nm-cloud-setup-utils.h
+++ b/src/nm-cloud-setup/nm-cloud-setup-utils.h
@@ -136,6 +136,7 @@ gboolean nmcs_device_reapply(NMDevice     *device,
                              GCancellable *sigterm_cancellable,
                              NMConnection *connection,
                              guint64       version_id,
+                             gboolean      maybe_no_preserved_external_ip,
                              gboolean     *out_version_id_changed,
                              GError      **error);
 
diff --git a/src/nmcli/devices.c b/src/nmcli/devices.c
index 9b7ebce3..db14ec05 100644
--- a/src/nmcli/devices.c
+++ b/src/nmcli/devices.c
@@ -1149,7 +1149,7 @@ get_device_list(NmCli *nmc, int *argc, const char *const **argv)
     if (*argc == 0) {
         g_string_printf(nmc->return_text, _("Error: No interface specified."));
         nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-        goto error;
+        return NULL;
     }
 
     devices = nmc_get_devices_sorted(nmc->client);
@@ -1190,9 +1190,6 @@ get_device_list(NmCli *nmc, int *argc, const char *const **argv)
     }
     g_free(devices);
 
-error:
-    g_strfreev(arg_arr);
-
     return queue;
 }
 
diff --git a/src/nmtui/nmt-device-entry.c b/src/nmtui/nmt-device-entry.c
index 7f312bd1..99cc43ad 100644
--- a/src/nmtui/nmt-device-entry.c
+++ b/src/nmtui/nmt-device-entry.c
@@ -132,12 +132,14 @@ device_entry_parse(NmtDeviceEntry *deventry,
         && (!words[1] || nm_utils_ifname_valid_kernel(words[1], NULL))) {
         *mac_address    = words[0];
         *interface_name = NULL;
+        g_free(words[1]);
         g_free(words);
         return TRUE;
     } else if (nm_utils_ifname_valid_kernel(words[0], NULL)
                && (!words[1] || nm_utils_hwaddr_aton(words[1], buf, len))) {
         *interface_name = words[0];
         *mac_address    = NULL;
+        g_free(words[1]);
         g_free(words);
         return TRUE;
     }