summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/NetworkManagerUtils.c1
-rw-r--r--src/core/devices/nm-device-ethernet.c10
-rw-r--r--src/core/devices/nm-device.c9
-rw-r--r--src/core/devices/wwan/nm-modem-ofono.c11
-rw-r--r--src/core/nm-connectivity.c5
-rw-r--r--src/core/nm-l3cfg.c2
-rw-r--r--src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c9
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-6.cexpected15
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-7.cexpected15
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-8.cexpected15
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-9.cexpected15
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c154
-rw-r--r--src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c13
-rw-r--r--src/libnm-base/nm-ethtool-base.c12
-rw-r--r--src/libnm-base/nm-ethtool-base.h2
-rw-r--r--src/libnm-client-impl/libnm.ver34
-rw-r--r--src/libnm-client-impl/meson.build1
-rw-r--r--src/libnm-client-impl/nm-client.c6
-rw-r--r--src/libnm-client-impl/nm-device-6lowpan.c23
-rw-r--r--src/libnm-client-impl/nm-device-macsec.c2
-rw-r--r--src/libnm-client-impl/nm-device-tun.c2
-rw-r--r--src/libnm-client-impl/nm-device-veth.c2
-rw-r--r--src/libnm-client-impl/nm-device-vxlan.c4
-rw-r--r--src/libnm-client-impl/nm-device-wifi-p2p.c2
-rw-r--r--src/libnm-client-impl/nm-device-wpan.c19
-rw-r--r--src/libnm-client-impl/nm-remote-connection.c2
-rw-r--r--src/libnm-client-impl/nm-settings-docs-gir.xml8
-rw-r--r--src/libnm-client-impl/nm-vpn-plugin-old.c22
-rw-r--r--src/libnm-client-impl/nm-vpn-service-plugin.c30
-rw-r--r--src/libnm-client-impl/tests/meson.build12
-rwxr-xr-xsrc/libnm-client-impl/tests/test-gir.py153
-rw-r--r--src/libnm-client-public/nm-checkpoint.h2
-rw-r--r--src/libnm-client-public/nm-client.h5
-rw-r--r--src/libnm-client-public/nm-device-6lowpan.h8
-rw-r--r--src/libnm-client-public/nm-device-dummy.h2
-rw-r--r--src/libnm-client-public/nm-device-ip-tunnel.h2
-rw-r--r--src/libnm-client-public/nm-device-macsec.h4
-rw-r--r--src/libnm-client-public/nm-device-macvlan.h2
-rw-r--r--src/libnm-client-public/nm-device-ovs-bridge.h2
-rw-r--r--src/libnm-client-public/nm-device-ovs-interface.h2
-rw-r--r--src/libnm-client-public/nm-device-ovs-port.h2
-rw-r--r--src/libnm-client-public/nm-device-ppp.h3
-rw-r--r--src/libnm-client-public/nm-device-tun.h2
-rw-r--r--src/libnm-client-public/nm-device-veth.h4
-rw-r--r--src/libnm-client-public/nm-device-vrf.h2
-rw-r--r--src/libnm-client-public/nm-device-vxlan.h6
-rw-r--r--src/libnm-client-public/nm-device-wifi-p2p.h2
-rw-r--r--src/libnm-client-public/nm-device-wireguard.h2
-rw-r--r--src/libnm-client-public/nm-device-wpan.h6
-rw-r--r--src/libnm-client-public/nm-vpn-plugin-old.h6
-rw-r--r--src/libnm-client-public/nm-vpn-service-plugin.h2
-rw-r--r--src/libnm-client-public/nm-wifi-p2p-peer.h2
-rw-r--r--src/libnm-core-impl/nm-connection.c14
-rw-r--r--src/libnm-core-impl/nm-setting-6lowpan.c6
-rw-r--r--src/libnm-core-impl/nm-setting-bridge.c30
-rw-r--r--src/libnm-core-impl/nm-setting-connection.c2
-rw-r--r--src/libnm-core-impl/nm-setting-ethtool.c18
-rw-r--r--src/libnm-core-impl/nm-setting-hostname.c2
-rw-r--r--src/libnm-core-impl/nm-setting-ip-config.c6
-rw-r--r--src/libnm-core-impl/nm-setting-ip-tunnel.c6
-rw-r--r--src/libnm-core-impl/nm-setting-ip4-config.c6
-rw-r--r--src/libnm-core-impl/nm-setting-ovs-bridge.c2
-rw-r--r--src/libnm-core-impl/nm-setting-ovs-external-ids.c2
-rw-r--r--src/libnm-core-impl/nm-setting-sriov.c4
-rw-r--r--src/libnm-core-impl/nm-setting-tc-config.c4
-rw-r--r--src/libnm-core-impl/nm-setting-user.c6
-rw-r--r--src/libnm-core-impl/nm-setting-vpn.c2
-rw-r--r--src/libnm-core-impl/nm-setting-wireguard.c2
-rw-r--r--src/libnm-core-impl/nm-setting-wireless-security.c4
-rw-r--r--src/libnm-core-impl/nm-setting-wpan.c14
-rw-r--r--src/libnm-core-impl/nm-setting.c16
-rw-r--r--src/libnm-core-impl/nm-utils.c18
-rw-r--r--src/libnm-core-impl/nm-vpn-editor-plugin.c12
-rw-r--r--src/libnm-core-impl/nm-vpn-plugin-info.c2
-rw-r--r--src/libnm-core-impl/tests/test-general.c3
-rw-r--r--src/libnm-core-public/nm-connection.h11
-rw-r--r--src/libnm-core-public/nm-dbus-interface.h4
-rw-r--r--src/libnm-core-public/nm-dbus-types.xml4
-rw-r--r--src/libnm-core-public/nm-setting-6lowpan.h4
-rw-r--r--src/libnm-core-public/nm-setting-connection.h6
-rw-r--r--src/libnm-core-public/nm-setting-hostname.h2
-rw-r--r--src/libnm-core-public/nm-setting-ip-config.h2
-rw-r--r--src/libnm-core-public/nm-setting-ip-tunnel.h6
-rw-r--r--src/libnm-core-public/nm-setting-ip4-config.h2
-rw-r--r--src/libnm-core-public/nm-setting-macvlan.h2
-rw-r--r--src/libnm-core-public/nm-setting-ovs-bridge.h2
-rw-r--r--src/libnm-core-public/nm-setting-sriov.h2
-rw-r--r--src/libnm-core-public/nm-setting-tc-config.h4
-rw-r--r--src/libnm-core-public/nm-setting-team.h2
-rw-r--r--src/libnm-core-public/nm-setting-tun.h2
-rw-r--r--src/libnm-core-public/nm-setting-vpn.h4
-rw-r--r--src/libnm-core-public/nm-setting-wireless-security.h2
-rw-r--r--src/libnm-core-public/nm-setting-wireless.h2
-rw-r--r--src/libnm-core-public/nm-setting-wpan.h12
-rw-r--r--src/libnm-core-public/nm-setting.h8
-rw-r--r--src/libnm-core-public/nm-utils.h8
-rw-r--r--src/libnm-core-public/nm-version-macros.h3
-rw-r--r--src/libnm-core-public/nm-version-macros.h.in1
-rw-r--r--src/libnm-core-public/nm-version.h6
-rw-r--r--src/libnm-core-public/nm-vpn-plugin-info.h2
-rw-r--r--src/libnm-platform/nmp-object.c7
-rw-r--r--src/libnm-std-aux/nm-std-aux.h4
-rw-r--r--src/libnmc-setting/settings-docs-input.xml10
-rw-r--r--src/libnmc-setting/settings-docs.h4
-rw-r--r--src/libnmc-setting/settings-docs.h.in4
-rw-r--r--src/nm-initrd-generator/tests/test-cmdline-reader.c30
-rw-r--r--src/nm-initrd-generator/tests/test-ibft-reader.c6
-rw-r--r--src/nmcli/devices.c2
-rw-r--r--src/nmcli/generate-docs-nm-settings-nmcli.xml4
-rw-r--r--src/nmcli/generate-docs-nm-settings-nmcli.xml.in4
-rw-r--r--src/nmcli/meson.build2
111 files changed, 800 insertions, 239 deletions
diff --git a/src/core/NetworkManagerUtils.c b/src/core/NetworkManagerUtils.c
index 8b0b4845..f5b7666b 100644
--- a/src/core/NetworkManagerUtils.c
+++ b/src/core/NetworkManagerUtils.c
@@ -978,6 +978,7 @@ nm_ip_routing_rule_to_platform(const NMIPRoutingRule *rule, NMPlatformRoutingRul
                 .start = uid_range_start,
                 .end   = uid_range_end,
             },
+        .protocol = RTPROT_STATIC,
     };
 
     nm_ip_routing_rule_get_xifname_bin(rule, TRUE, out_pl->iifname);
diff --git a/src/core/devices/nm-device-ethernet.c b/src/core/devices/nm-device-ethernet.c
index 40c6d208..4788cdc6 100644
--- a/src/core/devices/nm-device-ethernet.c
+++ b/src/core/devices/nm-device-ethernet.c
@@ -1354,6 +1354,11 @@ wake_on_lan_enable(NMDevice *device)
     if (s_wired) {
         wol      = nm_setting_wired_get_wake_on_lan(s_wired);
         password = nm_setting_wired_get_wake_on_lan_password(s_wired);
+
+        /* NMSettingWired does not reject invalid flags. Filter them out here. */
+        wol = (wol
+               & (NM_SETTING_WIRED_WAKE_ON_LAN_ALL | NM_SETTING_WIRED_WAKE_ON_LAN_EXCLUSIVE_FLAGS));
+
         if (wol != NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT)
             goto found;
     }
@@ -1370,9 +1375,14 @@ wake_on_lan_enable(NMDevice *device)
         nm_log_dbg(LOGD_ETHER, "invalid default value %u for wake-on-lan", (guint) wol);
         wol = NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT;
     }
+
+    wol = wol & (NM_SETTING_WIRED_WAKE_ON_LAN_ALL | NM_SETTING_WIRED_WAKE_ON_LAN_EXCLUSIVE_FLAGS);
+
     if (wol != NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT)
         goto found;
+
     wol = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE;
+
 found:
     return nm_platform_ethtool_set_wake_on_lan(nm_device_get_platform(device),
                                                nm_device_get_ifindex(device),
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 6be9bc7c..2cda9b0d 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -6657,7 +6657,6 @@ device_link_changed(gpointer user_data)
     NMDeviceClass                  *klass             = NM_DEVICE_GET_CLASS(self);
     NMDevicePrivate                *priv              = NM_DEVICE_GET_PRIVATE(self);
     gboolean                        ip_ifname_changed = FALSE;
-    gboolean                        hw_addr_changed;
     nm_auto_nmpobj const NMPObject *pllink_keep_alive = NULL;
     const NMPlatformLink           *pllink;
     const char                     *str;
@@ -6704,9 +6703,9 @@ device_link_changed(gpointer user_data)
     if (ifindex == nm_device_get_ip_ifindex(self))
         _stats_update_counters_from_pllink(self, pllink);
 
-    had_hw_addr     = (priv->hw_addr != NULL);
-    hw_addr_changed = nm_device_update_hw_address(self);
-    got_hw_addr     = (!had_hw_addr && priv->hw_addr);
+    had_hw_addr = (priv->hw_addr != NULL);
+    nm_device_update_hw_address(self);
+    got_hw_addr = (!had_hw_addr && priv->hw_addr);
     nm_device_update_permanent_hw_address(self, FALSE);
 
     if (pllink->name[0] && !nm_streq(priv->iface, pllink->name)) {
@@ -6757,8 +6756,6 @@ device_link_changed(gpointer user_data)
     /* Update DHCP, etc, if needed */
     if (ip_ifname_changed)
         nm_device_update_dynamic_ip_setup(self, "IP interface changed");
-    else if (hw_addr_changed)
-        nm_device_update_dynamic_ip_setup(self, "hw-address changed");
 
     was_up   = priv->up;
     priv->up = NM_FLAGS_HAS(pllink->n_ifi_flags, IFF_UP);
diff --git a/src/core/devices/wwan/nm-modem-ofono.c b/src/core/devices/wwan/nm-modem-ofono.c
index c003880e..fc27c3fd 100644
--- a/src/core/devices/wwan/nm-modem-ofono.c
+++ b/src/core/devices/wwan/nm-modem-ofono.c
@@ -739,7 +739,7 @@ handle_settings(GVariant *v_dict, gpointer user_data)
     gboolean             ret = FALSE;
     const char          *interface;
     const char          *s;
-    const char         **array;
+    gs_free const char **array = NULL;
     guint32              address_network, gateway_network;
     int                  ifindex;
     GError              *error = NULL;
@@ -838,15 +838,16 @@ handle_settings(GVariant *v_dict, gpointer user_data)
     }
     if (array) {
         gboolean any_good = FALSE;
+        gsize    i;
 
-        for (; array[0]; array++) {
-            if (!nm_utils_parse_inaddr_bin(AF_INET, *array, NULL, &address_network)
+        for (i = 0; array[i]; i++) {
+            if (!nm_utils_parse_inaddr_bin(AF_INET, array[i], NULL, &address_network)
                 || !address_network) {
-                _LOGW("invalid NameServer: %s", *array);
+                _LOGW("invalid NameServer: %s", array[i]);
                 continue;
             }
             any_good = TRUE;
-            _LOGI("DNS: %s", *array);
+            _LOGI("DNS: %s", array[i]);
             nm_l3_config_data_add_nameserver(priv->l3cd_4, AF_INET, &address_network);
         }
         if (!any_good) {
diff --git a/src/core/nm-connectivity.c b/src/core/nm-connectivity.c
index 25ac3c7f..cd30853d 100644
--- a/src/core/nm-connectivity.c
+++ b/src/core/nm-connectivity.c
@@ -82,7 +82,6 @@ struct _NMConnectivityCheckHandle {
         gsize response_good_cnt;
 
         guint curl_timer;
-        int   ch_ifindex;
     } concheck;
 #endif
 
@@ -1049,8 +1048,6 @@ nm_connectivity_check_start(NMConnectivity             *self,
         NMConnectivityState state;
         const char         *reason;
 
-        cb_data->concheck.ch_ifindex = ifindex;
-
         if (platform) {
             state = check_platform_config(self, platform, ifindex, addr_family, &reason);
             nm_assert((state == NM_CONNECTIVITY_UNKNOWN) == !reason);
@@ -1106,7 +1103,7 @@ nm_connectivity_check_start(NMConnectivity             *self,
                                    "org.freedesktop.resolve1.Manager",
                                    "ResolveHostname",
                                    g_variant_new("(isit)",
-                                                 (gint32) cb_data->concheck.ch_ifindex,
+                                                 0,
                                                  cb_data->concheck.con_config->host,
                                                  (gint32) cb_data->addr_family,
                                                  SD_RESOLVED_DNS),
diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c
index 69ea0d26..8fa1e07d 100644
--- a/src/core/nm-l3cfg.c
+++ b/src/core/nm-l3cfg.c
@@ -4010,7 +4010,7 @@ _l3_commit_ndisc_params(NML3Cfg *self, NML3CfgCommitType commit_type)
 
     if (retrans_set
         && (!self->priv.p->ndisc_retrans_timer_msec_set
-            || self->priv.p->ndisc_reachable_time_msec != retrans)) {
+            || self->priv.p->ndisc_retrans_timer_msec != retrans)) {
         self->priv.p->ndisc_retrans_timer_msec     = retrans;
         self->priv.p->ndisc_retrans_timer_msec_set = TRUE;
         if (ifname) {
diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
index 96efc9e5..e8948c3d 100644
--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
+++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
@@ -1312,6 +1312,7 @@ write_ethtool_setting(NMConnection *connection, shvarFile *ifcfg, GError **error
         gboolean             is_first;
         guint32              u32;
         gboolean             b;
+        gboolean             any_option = FALSE;
 
         s_con = nm_connection_get_setting_connection(connection);
         if (s_con) {
@@ -1341,6 +1342,7 @@ write_ethtool_setting(NMConnection *connection, shvarFile *ifcfg, GError **error
             g_string_append_c(str, ' ');
             g_string_append(str, nms_ifcfg_rh_utils_get_ethtool_name(ethtool_id));
             g_string_append(str, b ? " on" : " off");
+            any_option = TRUE;
         }
 
         is_first = TRUE;
@@ -1356,6 +1358,7 @@ write_ethtool_setting(NMConnection *connection, shvarFile *ifcfg, GError **error
             g_string_append_c(str, ' ');
             g_string_append(str, nms_ifcfg_rh_utils_get_ethtool_name(ethtool_id));
             g_string_append_printf(str, " %" G_GUINT32_FORMAT, u32);
+            any_option = TRUE;
         }
 
         is_first = TRUE;
@@ -1371,7 +1374,10 @@ write_ethtool_setting(NMConnection *connection, shvarFile *ifcfg, GError **error
             g_string_append_c(str, ' ');
             g_string_append(str, nms_ifcfg_rh_utils_get_ethtool_name(ethtool_id));
             g_string_append_printf(str, " %" G_GUINT32_FORMAT, u32);
+            any_option = TRUE;
         }
+
+        is_first = TRUE;
         for (ethtool_id = _NM_ETHTOOL_ID_PAUSE_FIRST; ethtool_id <= _NM_ETHTOOL_ID_PAUSE_LAST;
              ethtool_id++) {
             nm_assert(nms_ifcfg_rh_utils_get_ethtool_name(ethtool_id));
@@ -1384,9 +1390,10 @@ write_ethtool_setting(NMConnection *connection, shvarFile *ifcfg, GError **error
             g_string_append_c(str, ' ');
             g_string_append(str, nms_ifcfg_rh_utils_get_ethtool_name(ethtool_id));
             g_string_append(str, b ? " on" : " off");
+            any_option = TRUE;
         }
 
-        if (!str) {
+        if (!any_option) {
             /* Write an empty dummy "-A" option without arguments. This is to
              * ensure that the reader will create an (all default) NMSettingEthtool.
              * Also, it seems that `ethtool -A "$IFACE"` is silently accepted. */
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-6.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-6.cexpected
new file mode 100644
index 00000000..784ad224
--- /dev/null
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-6.cexpected
@@ -0,0 +1,15 @@
+TYPE=Ethernet
+PROXY_METHOD=none
+BROWSER_ONLY=no
+ETHTOOL_OPTS="autoneg on ; -A net0 pause-autoneg off"
+BOOTPROTO=dhcp
+DEFROUTE=yes
+IPV4_FAILURE_FATAL=no
+IPV6INIT=yes
+IPV6_AUTOCONF=yes
+IPV6_DEFROUTE=yes
+IPV6_FAILURE_FATAL=no
+IPV6_ADDR_GEN_MODE=default
+NAME=test_roundtrip_ethtool
+UUID=${UUID}
+ONBOOT=yes
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-7.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-7.cexpected
new file mode 100644
index 00000000..02ab14fe
--- /dev/null
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-7.cexpected
@@ -0,0 +1,15 @@
+TYPE=Ethernet
+PROXY_METHOD=none
+BROWSER_ONLY=no
+ETHTOOL_OPTS="autoneg on ; -G net0 rx 512"
+BOOTPROTO=dhcp
+DEFROUTE=yes
+IPV4_FAILURE_FATAL=no
+IPV6INIT=yes
+IPV6_AUTOCONF=yes
+IPV6_DEFROUTE=yes
+IPV6_FAILURE_FATAL=no
+IPV6_ADDR_GEN_MODE=default
+NAME=test_roundtrip_ethtool
+UUID=${UUID}
+ONBOOT=yes
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-8.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-8.cexpected
new file mode 100644
index 00000000..fd760839
--- /dev/null
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-8.cexpected
@@ -0,0 +1,15 @@
+TYPE=Ethernet
+PROXY_METHOD=none
+BROWSER_ONLY=no
+ETHTOOL_OPTS="autoneg on ; -A net0"
+BOOTPROTO=dhcp
+DEFROUTE=yes
+IPV4_FAILURE_FATAL=no
+IPV6INIT=yes
+IPV6_AUTOCONF=yes
+IPV6_DEFROUTE=yes
+IPV6_FAILURE_FATAL=no
+IPV6_ADDR_GEN_MODE=default
+NAME=test_roundtrip_ethtool
+UUID=${UUID}
+ONBOOT=yes
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-9.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-9.cexpected
new file mode 100644
index 00000000..1703b0dc
--- /dev/null
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-9.cexpected
@@ -0,0 +1,15 @@
+TYPE=Ethernet
+PROXY_METHOD=none
+BROWSER_ONLY=no
+ETHTOOL_OPTS="autoneg on ; -G net0 rx 512 ; -A net0 pause-autoneg off"
+BOOTPROTO=dhcp
+DEFROUTE=yes
+IPV4_FAILURE_FATAL=no
+IPV6INIT=yes
+IPV6_AUTOCONF=yes
+IPV6_DEFROUTE=yes
+IPV6_FAILURE_FATAL=no
+IPV6_ADDR_GEN_MODE=default
+NAME=test_roundtrip_ethtool
+UUID=${UUID}
+ONBOOT=yes
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index f9fd7fd5..886a605f 100644
--- a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -3425,6 +3425,7 @@ test_roundtrip_ethtool(void)
     gs_unref_object NMConnection *connection = NULL;
     NMSetting                    *s_ethtool;
     NMSetting                    *s_wired;
+    int                           i_run;
 
     connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
                                                  NULL,
@@ -3487,6 +3488,159 @@ test_roundtrip_ethtool(void)
                            TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-5.cexpected",
                            NULL);
     g_clear_object(&connection);
+
+    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
+                                                 NULL,
+                                                 NM_SETTING_WIRED_SETTING_NAME,
+                                                 NULL);
+    s_wired    = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
+    g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL);
+
+    s_ethtool = _nm_connection_new_setting(connection, NM_TYPE_SETTING_ETHTOOL);
+    nm_setting_option_set_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_PAUSE_AUTONEG, FALSE);
+    _writer_new_connec_exp(connection,
+                           TEST_SCRATCH_DIR,
+                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-6.cexpected",
+                           NULL);
+    g_clear_object(&connection);
+
+    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
+                                                 NULL,
+                                                 NM_SETTING_WIRED_SETTING_NAME,
+                                                 NULL);
+    s_wired    = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
+    g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL);
+
+    s_ethtool = _nm_connection_new_setting(connection, NM_TYPE_SETTING_ETHTOOL);
+    nm_setting_option_set_uint32(s_ethtool, NM_ETHTOOL_OPTNAME_RING_RX, 512);
+    _writer_new_connec_exp(connection,
+                           TEST_SCRATCH_DIR,
+                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-7.cexpected",
+                           NULL);
+    g_clear_object(&connection);
+
+    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
+                                                 NULL,
+                                                 NM_SETTING_WIRED_SETTING_NAME,
+                                                 NULL);
+    s_wired    = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
+    g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL);
+
+    s_ethtool = _nm_connection_new_setting(connection, NM_TYPE_SETTING_ETHTOOL);
+    _writer_new_connec_exp(connection,
+                           TEST_SCRATCH_DIR,
+                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-8.cexpected",
+                           NULL);
+    g_clear_object(&connection);
+
+    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
+                                                 NULL,
+                                                 NM_SETTING_WIRED_SETTING_NAME,
+                                                 NULL);
+    s_wired    = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRED);
+    g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL);
+
+    s_ethtool = _nm_connection_new_setting(connection, NM_TYPE_SETTING_ETHTOOL);
+    nm_setting_option_set_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_PAUSE_AUTONEG, FALSE);
+    nm_setting_option_set_uint32(s_ethtool, NM_ETHTOOL_OPTNAME_RING_RX, 512);
+    _writer_new_connec_exp(connection,
+                           TEST_SCRATCH_DIR,
+                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-9.cexpected",
+                           NULL);
+    g_clear_object(&connection);
+
+    for (i_run = 0; i_run < 20; i_run++) {
+        gs_unref_object NMConnection *con2     = NULL;
+        gs_unref_object NMConnection *reread   = NULL;
+        nmtst_auto_unlinkfile char   *testfile = NULL;
+        gboolean                      reread_same;
+        gboolean                      v_bool;
+        NMEthtoolID                   ethtool_ids[_NM_ETHTOOL_ID_NUM];
+        guint                         i;
+        guint                         l;
+        NMSettingWiredWakeOnLan       wake_on_lan;
+
+        con2    = nmtst_create_minimal_connection("test_roundtrip_ethtool",
+                                               NULL,
+                                               NM_SETTING_WIRED_SETTING_NAME,
+                                               NULL);
+        s_wired = nmtst_connection_assert_setting(con2, NM_TYPE_SETTING_WIRED);
+        g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, nmtst_get_rand_bool(), NULL);
+
+        if (nmtst_get_rand_bool()) {
+            g_object_set(s_wired,
+                         NM_SETTING_WIRED_SPEED,
+                         1000u,
+                         NM_SETTING_WIRED_DUPLEX,
+                         nmtst_get_rand_bool() ? "full" : "half",
+                         NULL);
+        }
+
+        wake_on_lan = nmtst_get_rand_uint32();
+        wake_on_lan = wake_on_lan & NM_SETTING_WIRED_WAKE_ON_LAN_ALL;
+        wake_on_lan = nmtst_rand_select(wake_on_lan,
+                                        NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT,
+                                        NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE);
+        g_object_set(s_wired, NM_SETTING_WIRED_WAKE_ON_LAN, (guint) wake_on_lan, NULL);
+
+        if (NM_FLAGS_HAS(wake_on_lan, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)
+            && nmtst_get_rand_bool()) {
+            g_object_set(s_wired, NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, "aa:bb:cc:dd:ee:ff", NULL);
+        }
+
+        l = nmtst_get_rand_uint32() % (G_N_ELEMENTS(ethtool_ids) + 2);
+        if (l == 0) {
+            /* pass. No ethtool setting. */
+            goto check_roundtrip;
+        }
+        l--;
+
+        s_ethtool = _nm_connection_new_setting(con2, NM_TYPE_SETTING_ETHTOOL);
+
+        for (i = 0; i < (int) G_N_ELEMENTS(ethtool_ids); i++)
+            ethtool_ids[i] = i;
+        nmtst_rand_perm(NULL, ethtool_ids, NULL, sizeof(ethtool_ids[0]), G_N_ELEMENTS(ethtool_ids));
+
+        for (i = 0; i < l; i++) {
+            NMEthtoolID         ethtool_id = ethtool_ids[i];
+            const GVariantType *vtype;
+            const char         *optname;
+
+            optname = nm_ethtool_data[ethtool_id]->optname;
+            vtype   = nm_ethtool_id_get_variant_type(ethtool_id);
+
+            if (NM_IN_SET(ethtool_id,
+                          NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX,
+                          NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX)) {
+                nm_setting_option_set_uint32(s_ethtool, optname, nmtst_get_rand_uint32() % 2);
+            } else if (g_variant_type_equal(vtype, G_VARIANT_TYPE_BOOLEAN))
+                nm_setting_option_set_boolean(s_ethtool, optname, nmtst_get_rand_bool());
+            else if (g_variant_type_equal(vtype, G_VARIANT_TYPE_UINT32))
+                nm_setting_option_set_uint32(s_ethtool, optname, nmtst_get_rand_uint32());
+            else
+                g_assert_not_reached();
+        }
+
+        if ((nm_setting_option_get_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_PAUSE_RX, NULL)
+             || nm_setting_option_get_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_PAUSE_TX, NULL))
+            && nm_setting_option_get_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_PAUSE_AUTONEG, &v_bool)
+            && v_bool) {
+            /* don't accidentally create an invalid profile. */
+            nm_setting_option_set(s_ethtool,
+                                  NM_ETHTOOL_OPTNAME_PAUSE_AUTONEG,
+                                  nmtst_get_rand_bool() ? g_variant_new_boolean(FALSE) : NULL);
+        }
+
+check_roundtrip:
+        _writer_new_connection_reread(con2,
+                                      TEST_SCRATCH_DIR,
+                                      &testfile,
+                                      NO_EXPECTED,
+                                      &reread,
+                                      &reread_same);
+        g_assert(NM_IS_CONNECTION(reread));
+        g_assert(reread_same);
+    }
 }
 
 static void
diff --git a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c
index 1307d4b2..47be3a5e 100644
--- a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c
+++ b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c
@@ -2292,14 +2292,19 @@ test_read_missing_vlan_flags(void)
 static void
 test_read_missing_id_uuid(void)
 {
-    gs_unref_object NMConnection *connection    = NULL;
-    gs_free char                 *expected_uuid = NULL;
-    const char                   *FILENAME      = TEST_KEYFILES_DIR "/Test_Missing_ID_UUID";
+    gs_unref_object NMConnection *connection     = NULL;
+    gs_free char                 *expected_uuid  = NULL;
+    gs_free char                 *expected_uuid2 = NULL;
+    const char                   *FILENAME       = TEST_KEYFILES_DIR "/Test_Missing_ID_UUID";
+    const char                    F[] = "keyfile\0" TEST_KEYFILES_DIR "/Test_Missing_ID_UUID";
 
     expected_uuid = nm_uuid_generate_from_strings("keyfile", FILENAME, NULL);
 
-    connection = keyfile_read_connection_from_file(FILENAME);
+    expected_uuid2 =
+        nm_uuid_generate_from_string_str(F, sizeof(F), NM_UUID_TYPE_VERSION3, &nm_uuid_ns_1);
+    g_assert_cmpstr(expected_uuid, ==, expected_uuid2);
 
+    connection = keyfile_read_connection_from_file(FILENAME);
     g_assert_cmpstr(nm_connection_get_id(connection), ==, "Test_Missing_ID_UUID");
     g_assert_cmpstr(nm_connection_get_uuid(connection), ==, expected_uuid);
 }
diff --git a/src/libnm-base/nm-ethtool-base.c b/src/libnm-base/nm-ethtool-base.c
index 99bbe68e..78e9fbc1 100644
--- a/src/libnm-base/nm-ethtool-base.c
+++ b/src/libnm-base/nm-ethtool-base.c
@@ -294,3 +294,15 @@ nm_ethtool_id_to_type(NMEthtoolID id)
 
     return NM_ETHTOOL_TYPE_UNKNOWN;
 }
+
+const GVariantType *
+nm_ethtool_id_get_variant_type(NMEthtoolID ethtool_id)
+{
+    if (nm_ethtool_id_is_feature(ethtool_id) || nm_ethtool_id_is_pause(ethtool_id))
+        return G_VARIANT_TYPE_BOOLEAN;
+
+    if (nm_ethtool_id_is_coalesce(ethtool_id) || nm_ethtool_id_is_ring(ethtool_id))
+        return G_VARIANT_TYPE_UINT32;
+
+    return NULL;
+}
diff --git a/src/libnm-base/nm-ethtool-base.h b/src/libnm-base/nm-ethtool-base.h
index abedcafe..22bb88fb 100644
--- a/src/libnm-base/nm-ethtool-base.h
+++ b/src/libnm-base/nm-ethtool-base.h
@@ -21,6 +21,8 @@ const NMEthtoolData *nm_ethtool_data_get_by_optname(const char *optname);
 
 NMEthtoolType nm_ethtool_id_to_type(NMEthtoolID id);
 
+const GVariantType *nm_ethtool_id_get_variant_type(NMEthtoolID ethtool_id);
+
 /****************************************************************************/
 
 static inline NMEthtoolID
diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver
index e414b7e6..2478defa 100644
--- a/src/libnm-client-impl/libnm.ver
+++ b/src/libnm-client-impl/libnm.ver
@@ -1844,3 +1844,37 @@ global:
 	nm_setting_ip4_link_local_get_type;
 	nm_setting_ip6_config_get_mtu;
 } libnm_1_38_0;
+
+libnm_1_40_4 {
+global:
+	nm_device_6lowpan_get_parent;
+	nm_device_macsec_get_parent;
+	nm_device_veth_get_peer;
+	nm_device_vxlan_get_carrier;
+	nm_device_vxlan_get_rsc;
+	nm_device_wifi_p2p_get_peer_by_path;
+	nm_setting_6lowpan_get_parent;
+	nm_setting_6lowpan_new;
+	nm_setting_connection_get_mptcp_flags;
+	nm_setting_hostname_new;
+	nm_setting_ip4_config_get_link_local;
+	nm_setting_ip_config_get_dhcp_iaid;
+	nm_setting_ip_tunnel_get_encapsulation_limit;
+	nm_setting_ip_tunnel_get_flow_label;
+	nm_setting_ovs_bridge_get_datapath_type;
+	nm_setting_vpn_get_persistent;
+	nm_setting_wpan_get_channel;
+	nm_setting_wpan_get_mac_address;
+	nm_setting_wpan_get_page;
+	nm_setting_wpan_get_pan_id;
+	nm_setting_wpan_get_short_address;
+	nm_setting_wpan_new;
+	nm_sriov_vf_attribute_validate;
+	nm_tc_tfilter_get_action;
+	nm_tc_tfilter_set_action;
+	nm_utils_ip_addresses_from_variant;
+	nm_utils_ip_addresses_to_variant;
+	nm_utils_ip_routes_from_variant;
+	nm_utils_ip_routes_to_variant;
+	nm_vpn_plugin_info_supports_multiple;
+} libnm_1_40_0;
diff --git a/src/libnm-client-impl/meson.build b/src/libnm-client-impl/meson.build
index 46464a63..d72ed545 100644
--- a/src/libnm-client-impl/meson.build
+++ b/src/libnm-client-impl/meson.build
@@ -236,5 +236,4 @@ if enable_introspection
     ],
     depends: libnm_gir,
   )
-
 endif
diff --git a/src/libnm-client-impl/nm-client.c b/src/libnm-client-impl/nm-client.c
index a2ca8333..871c5466 100644
--- a/src/libnm-client-impl/nm-client.c
+++ b/src/libnm-client-impl/nm-client.c
@@ -5248,7 +5248,7 @@ _add_and_activate_connection(NMClient           *self,
  * @partial: (allow-none): an #NMConnection to add; the connection may be
  *   partially filled (or even %NULL) and will be completed by NetworkManager
  *   using the given @device and @specific_object before being added
- * @device: the #NMDevice
+ * @device: (allow-none): the #NMDevice
  * @specific_object: (allow-none): the object path of a connection-type-specific
  *   object this activation should use. This parameter is currently ignored for
  *   wired and mobile broadband connections, and the value of %NULL should be used
@@ -5322,7 +5322,7 @@ nm_client_add_and_activate_connection_finish(NMClient *client, GAsyncResult *res
  * @partial: (allow-none): an #NMConnection to add; the connection may be
  *   partially filled (or even %NULL) and will be completed by NetworkManager
  *   using the given @device and @specific_object before being added
- * @device: the #NMDevice
+ * @device: (allow-none): the #NMDevice
  * @specific_object: (allow-none): the object path of a connection-type-specific
  *   object this activation should use. This parameter is currently ignored for
  *   wired and mobile broadband connections, and the value of %NULL should be used
@@ -5396,6 +5396,8 @@ nm_client_add_and_activate_connection2(NMClient           *client,
  *
  * Returns: (transfer full): the new #NMActiveConnection on success, %NULL on
  *   failure, in which case @error will be set.
+ *
+ * Since: 1.16
  **/
 NMActiveConnection *
 nm_client_add_and_activate_connection2_finish(NMClient     *client,
diff --git a/src/libnm-client-impl/nm-device-6lowpan.c b/src/libnm-client-impl/nm-device-6lowpan.c
index 39558f25..fc1f59ba 100644
--- a/src/libnm-client-impl/nm-device-6lowpan.c
+++ b/src/libnm-client-impl/nm-device-6lowpan.c
@@ -39,7 +39,7 @@ G_DEFINE_TYPE(NMDevice6Lowpan, nm_device_6lowpan, NM_TYPE_DEVICE)
  *
  * Returns: (transfer none): the device's parent device
  *
- * Since: 1.14
+ * Since: 1.42, 1.40.4
  **/
 NMDevice *
 nm_device_6lowpan_get_parent(NMDevice6Lowpan *device)
@@ -49,27 +49,6 @@ nm_device_6lowpan_get_parent(NMDevice6Lowpan *device)
     return nml_dbus_property_o_get_obj(&NM_DEVICE_6LOWPAN_GET_PRIVATE(device)->parent);
 }
 
-/**
- * nm_device_6lowpan_get_hw_address: (skip)
- * @device: a #NMDevice6Lowpan
- *
- * Gets the hardware (MAC) address of the #NMDevice6Lowpan
- *
- * Returns: the hardware address. This is the internal string used by the
- * device, and must not be modified.
- *
- * Since: 1.14
- *
- * Deprecated: 1.24: Use nm_device_get_hw_address() instead.
- **/
-const char *
-nm_device_6lowpan_get_hw_address(NMDevice6Lowpan *device)
-{
-    g_return_val_if_fail(NM_IS_DEVICE_6LOWPAN(device), NULL);
-
-    return nm_device_get_hw_address(NM_DEVICE(device));
-}
-
 /*****************************************************************************/
 
 static void
diff --git a/src/libnm-client-impl/nm-device-macsec.c b/src/libnm-client-impl/nm-device-macsec.c
index 525d32d0..763faa6c 100644
--- a/src/libnm-client-impl/nm-device-macsec.c
+++ b/src/libnm-client-impl/nm-device-macsec.c
@@ -65,7 +65,7 @@ G_DEFINE_TYPE(NMDeviceMacsec, nm_device_macsec, NM_TYPE_DEVICE)
  *
  * Returns: (transfer none): the device's parent device
  *
- * Since: 1.6
+ * Since: 1.42, 1.40.4
  **/
 NMDevice *
 nm_device_macsec_get_parent(NMDeviceMacsec *device)
diff --git a/src/libnm-client-impl/nm-device-tun.c b/src/libnm-client-impl/nm-device-tun.c
index 353b4bdc..2e75c860 100644
--- a/src/libnm-client-impl/nm-device-tun.c
+++ b/src/libnm-client-impl/nm-device-tun.c
@@ -124,7 +124,7 @@ nm_device_tun_get_group(NMDeviceTun *device)
 }
 
 /**
- * nm_device_tun_get_pi:
+ * nm_device_tun_get_no_pi:
  * @device: a #NMDeviceTun
  *
  * Returns whether the #NMDeviceTun has the IFF_NO_PI flag.
diff --git a/src/libnm-client-impl/nm-device-veth.c b/src/libnm-client-impl/nm-device-veth.c
index d9fc325b..0d4537ed 100644
--- a/src/libnm-client-impl/nm-device-veth.c
+++ b/src/libnm-client-impl/nm-device-veth.c
@@ -44,7 +44,7 @@ G_DEFINE_TYPE(NMDeviceVeth, nm_device_veth, NM_TYPE_DEVICE_ETHERNET)
  *
  * Returns: (transfer none): the device's peer device
  *
- * Since: 1.30
+ * Since: 1.42, 1.40.4
  **/
 NMDevice *
 nm_device_veth_get_peer(NMDeviceVeth *device)
diff --git a/src/libnm-client-impl/nm-device-vxlan.c b/src/libnm-client-impl/nm-device-vxlan.c
index d81b5516..13c20536 100644
--- a/src/libnm-client-impl/nm-device-vxlan.c
+++ b/src/libnm-client-impl/nm-device-vxlan.c
@@ -99,7 +99,7 @@ nm_device_vxlan_get_hw_address(NMDeviceVxlan *device)
  * This property is not implemented yet, and the function always returns
  * FALSE.
  *
- * Since: 1.2
+ * Since: 1.42, 1.40.4
  **/
 gboolean
 nm_device_vxlan_get_carrier(NMDeviceVxlan *device)
@@ -325,7 +325,7 @@ nm_device_vxlan_get_proxy(NMDeviceVxlan *device)
  *
  * Returns: whether route short circuit is turned on
  *
- * Since: 1.2
+ * Since: 1.42, 1.40.4
  **/
 gboolean
 nm_device_vxlan_get_rsc(NMDeviceVxlan *device)
diff --git a/src/libnm-client-impl/nm-device-wifi-p2p.c b/src/libnm-client-impl/nm-device-wifi-p2p.c
index 6e667ac6..3d539111 100644
--- a/src/libnm-client-impl/nm-device-wifi-p2p.c
+++ b/src/libnm-client-impl/nm-device-wifi-p2p.c
@@ -100,7 +100,7 @@ nm_device_wifi_p2p_get_peers(NMDeviceWifiP2P *device)
  *
  * Returns: (transfer none): the peer or %NULL if none is found.
  *
- * Since: 1.16
+ * Since: 1.42, 1.40.4
  **/
 NMWifiP2PPeer *
 nm_device_wifi_p2p_get_peer_by_path(NMDeviceWifiP2P *device, const char *path)
diff --git a/src/libnm-client-impl/nm-device-wpan.c b/src/libnm-client-impl/nm-device-wpan.c
index 30c1ea16..337e3de0 100644
--- a/src/libnm-client-impl/nm-device-wpan.c
+++ b/src/libnm-client-impl/nm-device-wpan.c
@@ -24,25 +24,6 @@ struct _NMDeviceWpanClass {
 G_DEFINE_TYPE(NMDeviceWpan, nm_device_wpan, NM_TYPE_DEVICE)
 /*****************************************************************************/
 
-/**
- * nm_device_wpan_get_hw_address: (skip)
- * @device: a #NMDeviceWpan
- *
- * Gets the active hardware (MAC) address of the #NMDeviceWpan
- *
- * Returns: the active hardware address. This is the internal string used by the
- * device, and must not be modified.
- *
- * Deprecated: 1.24: Use nm_device_get_hw_address() instead.
- **/
-const char *
-nm_device_wpan_get_hw_address(NMDeviceWpan *device)
-{
-    g_return_val_if_fail(NM_IS_DEVICE_WPAN(device), NULL);
-
-    return nm_device_get_hw_address(NM_DEVICE(device));
-}
-
 static gboolean
 connection_compatible(NMDevice *device, NMConnection *connection, GError **error)
 {
diff --git a/src/libnm-client-impl/nm-remote-connection.c b/src/libnm-client-impl/nm-remote-connection.c
index 23dfc1da..b10d3d55 100644
--- a/src/libnm-client-impl/nm-remote-connection.c
+++ b/src/libnm-client-impl/nm-remote-connection.c
@@ -125,6 +125,8 @@ nm_remote_connection_update2(NMRemoteConnection    *connection,
  *
  * Returns: (transfer full): on success, a #GVariant of type "a{sv}" with the result. On failure,
  *   %NULL.
+ *
+ * Since: 1.12
  **/
 GVariant *
 nm_remote_connection_update2_finish(NMRemoteConnection *connection,
diff --git a/src/libnm-client-impl/nm-settings-docs-gir.xml b/src/libnm-client-impl/nm-settings-docs-gir.xml
index 3ce853e4..eef7de67 100644
--- a/src/libnm-client-impl/nm-settings-docs-gir.xml
+++ b/src/libnm-client-impl/nm-settings-docs-gir.xml
@@ -145,9 +145,7 @@
 
  This property is currently not implemented for DHCPv6.</description><description-docbook><para> Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers.</para><para> For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. "192.168.122.0/24").</para><para> This property is currently not implemented for DHCPv6.</para></description-docbook></property><property name="dhcp-send-hostname" name_upper="DHCP_SEND_HOSTNAME" type="boolean" default="TRUE"><description> If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the "dhcp-hostname" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.</description><description-docbook><para> If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the "dhcp-hostname" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.</para></description-docbook></property><property name="dhcp-timeout" name_upper="DHCP_TIMEOUT" type="int32" default="0"><description> A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds).
 
- Set to 2147483647 (MAXINT32) for infinity.</description><description-docbook><para> A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds).</para><para> Set to 2147483647 (MAXINT32) for infinity.</para></description-docbook></property><property name="dhcp-vendor-class-identifier" name_upper="DHCP_VENDOR_CLASS_IDENTIFIER" type="string"><description> The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server.
-
- Since 1.28</description><description-docbook><para> The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server.</para><para> Since 1.28</para></description-docbook></property><property name="dns" name_upper="DNS" type="array of uint32"><description> Array of IP addresses of DNS servers.</description><description-docbook><para> Array of IP addresses of DNS servers.</para></description-docbook></property><property name="dns-options" name_upper="DNS_OPTIONS" type="array of string"><description> Array of DNS options as described in man 5 resolv.conf.
+ Set to 2147483647 (MAXINT32) for infinity.</description><description-docbook><para> A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds).</para><para> Set to 2147483647 (MAXINT32) for infinity.</para></description-docbook></property><property name="dhcp-vendor-class-identifier" name_upper="DHCP_VENDOR_CLASS_IDENTIFIER" type="string"><description> The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server.</description><description-docbook><para> The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server.</para></description-docbook></property><property name="dns" name_upper="DNS" type="array of uint32"><description> Array of IP addresses of DNS servers.</description><description-docbook><para> Array of IP addresses of DNS servers.</para></description-docbook></property><property name="dns-options" name_upper="DNS_OPTIONS" type="array of string"><description> Array of DNS options as described in man 5 resolv.conf.
 
  NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.
 
@@ -179,9 +177,7 @@
 
  Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See "ip4-auto-default-route".</description><description-docbook><para> The gateway associated with this configuration. This is only meaningful if "addresses" is also set.</para><para> Setting the gateway causes NetworkManager to configure a standard default route with the gateway as next hop. This is ignored if "never-default" is set. An alternative is to configure the default route explicitly with a manual route and /0 as prefix length.</para><para> Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See "ip4-auto-default-route".</para></description-docbook></property><property name="ignore-auto-dns" name_upper="IGNORE_AUTO_DNS" type="boolean" default="FALSE"><description> When "method" is set to "auto" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the "dns" and "dns-search" properties, if any, are used.</description><description-docbook><para> When "method" is set to "auto" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the "dns" and "dns-search" properties, if any, are used.</para></description-docbook></property><property name="ignore-auto-routes" name_upper="IGNORE_AUTO_ROUTES" type="boolean" default="FALSE"><description> When "method" is set to "auto" and this property to TRUE, automatically configured routes are ignored and only routes specified in the "routes" property, if any, are used.</description><description-docbook><para> When "method" is set to "auto" and this property to TRUE, automatically configured routes are ignored and only routes specified in the "routes" property, if any, are used.</para></description-docbook></property><property name="link-local" name_upper="LINK_LOCAL" type="int32" default="0"><description> Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server.
 
- When set to "auto", the value is dependent on "ipv4.method". When set to "default", it honors the global connection default, before falling back to "auto". Note that if "ipv4.method" is "disabled", then link local addressing is always disabled too. The default is "default".
-
- Since 1.40</description><description-docbook><para> Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server.</para><para> When set to "auto", the value is dependent on "ipv4.method". When set to "default", it honors the global connection default, before falling back to "auto". Note that if "ipv4.method" is "disabled", then link local addressing is always disabled too. The default is "default".</para><para> Since 1.40</para></description-docbook></property><property name="may-fail" name_upper="MAY_FAIL" type="boolean" default="TRUE"><description> If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out.  Note that at least one IP configuration must succeed or overall network configuration will still fail.  For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.</description><description-docbook><para> If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out.  Note that at least one IP configuration must succeed or overall network configuration will still fail.  For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.</para></description-docbook></property><property name="method" name_upper="METHOD" type="string"><description> IP configuration method.
+ When set to "auto", the value is dependent on "ipv4.method". When set to "default", it honors the global connection default, before falling back to "auto". Note that if "ipv4.method" is "disabled", then link local addressing is always disabled too. The default is "default".</description><description-docbook><para> Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server.</para><para> When set to "auto", the value is dependent on "ipv4.method". When set to "default", it honors the global connection default, before falling back to "auto". Note that if "ipv4.method" is "disabled", then link local addressing is always disabled too. The default is "default".</para></description-docbook></property><property name="may-fail" name_upper="MAY_FAIL" type="boolean" default="TRUE"><description> If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out.  Note that at least one IP configuration must succeed or overall network configuration will still fail.  For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.</description><description-docbook><para> If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out.  Note that at least one IP configuration must succeed or overall network configuration will still fail.  For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.</para></description-docbook></property><property name="method" name_upper="METHOD" type="string"><description> IP configuration method.
 
  NMSettingIP4Config and NMSettingIP6Config both support "disabled", "auto", "manual", and "link-local". See the subclass-specific documentation for other values.
 
diff --git a/src/libnm-client-impl/nm-vpn-plugin-old.c b/src/libnm-client-impl/nm-vpn-plugin-old.c
index 19ba2bb0..8898f09a 100644
--- a/src/libnm-client-impl/nm-vpn-plugin-old.c
+++ b/src/libnm-client-impl/nm-vpn-plugin-old.c
@@ -281,13 +281,8 @@ schedule_fail_stop(NMVpnPluginOld *plugin, guint timeout_secs)
         priv->fail_stop_id = g_idle_add(fail_stop, plugin);
 }
 
-/**
- * nm_vpn_plugin_old_set_config:
- *
- * Deprecated: 1.2: Replaced by NMVpnServicePlugin.
- */
-void
-nm_vpn_plugin_old_set_config(NMVpnPluginOld *plugin, GVariant *config)
+static void
+set_config(NMVpnPluginOld *plugin, GVariant *config)
 {
     NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE(plugin);
 
@@ -382,13 +377,8 @@ nm_vpn_plugin_old_set_ip4_config(NMVpnPluginOld *plugin, GVariant *ip4_config)
         nm_vpn_plugin_old_set_state(plugin, NM_VPN_SERVICE_STATE_STARTED);
 }
 
-/**
- * nm_vpn_plugin_old_set_ip6_config:
- *
- * Deprecated: 1.2: Replaced by NMVpnServicePlugin.
- */
-void
-nm_vpn_plugin_old_set_ip6_config(NMVpnPluginOld *plugin, GVariant *ip6_config)
+static void
+set_ip6_config(NMVpnPluginOld *plugin, GVariant *ip6_config)
 {
     NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE(plugin);
 
@@ -721,7 +711,7 @@ impl_vpn_plugin_old_set_config(NMVpnPluginOld        *plugin,
                                GVariant              *config,
                                gpointer               user_data)
 {
-    nm_vpn_plugin_old_set_config(plugin, config);
+    set_config(plugin, config);
     g_dbus_method_invocation_return_value(context, NULL);
 }
 
@@ -741,7 +731,7 @@ impl_vpn_plugin_old_set_ip6_config(NMVpnPluginOld        *plugin,
                                    GVariant              *config,
                                    gpointer               user_data)
 {
-    nm_vpn_plugin_old_set_ip6_config(plugin, config);
+    set_ip6_config(plugin, config);
     g_dbus_method_invocation_return_value(context, NULL);
 }
 
diff --git a/src/libnm-client-impl/nm-vpn-service-plugin.c b/src/libnm-client-impl/nm-vpn-service-plugin.c
index 3493d1db..d26a4ff5 100644
--- a/src/libnm-client-impl/nm-vpn-service-plugin.c
+++ b/src/libnm-client-impl/nm-vpn-service-plugin.c
@@ -136,6 +136,11 @@ nm_vpn_service_plugin_set_state(NMVpnServicePlugin *plugin, NMVpnServiceState st
     }
 }
 
+/**
+ * nm_vpn_service_plugin_set_login_banner:
+ *
+ * Since: 1.2
+ */
 void
 nm_vpn_service_plugin_set_login_banner(NMVpnServicePlugin *plugin, const char *banner)
 {
@@ -160,6 +165,11 @@ _emit_failure(NMVpnServicePlugin *plugin, NMVpnPluginFailure reason)
         nmdbus_vpn_plugin_emit_failure(priv->dbus_vpn_service_plugin, reason);
 }
 
+/**
+ * nm_vpn_service_plugin_failure:
+ *
+ * Since: 1.2
+ */
 void
 nm_vpn_service_plugin_failure(NMVpnServicePlugin *plugin, NMVpnPluginFailure reason)
 {
@@ -169,6 +179,11 @@ nm_vpn_service_plugin_failure(NMVpnServicePlugin *plugin, NMVpnPluginFailure rea
     nm_vpn_service_plugin_disconnect(plugin, NULL);
 }
 
+/**
+ * nm_vpn_service_plugin_disconnect:
+ *
+ * Since: 1.2
+ */
 gboolean
 nm_vpn_service_plugin_disconnect(NMVpnServicePlugin *plugin, GError **err)
 {
@@ -326,6 +341,11 @@ schedule_fail_stop(NMVpnServicePlugin *plugin, guint timeout_secs)
         priv->fail_stop_id = g_idle_add(fail_stop, plugin);
 }
 
+/**
+ * nm_vpn_service_plugin_set_config:
+ *
+ * Since: 1.2
+ */
 void
 nm_vpn_service_plugin_set_config(NMVpnServicePlugin *plugin, GVariant *config)
 {
@@ -364,6 +384,11 @@ nm_vpn_service_plugin_set_config(NMVpnServicePlugin *plugin, GVariant *config)
         nm_vpn_service_plugin_set_state(plugin, NM_VPN_SERVICE_STATE_STARTED);
 }
 
+/**
+ * nm_vpn_service_plugin_set_ip4_config:
+ *
+ * Since: 1.2
+ */
 void
 nm_vpn_service_plugin_set_ip4_config(NMVpnServicePlugin *plugin, GVariant *ip4_config)
 {
@@ -422,6 +447,11 @@ nm_vpn_service_plugin_set_ip4_config(NMVpnServicePlugin *plugin, GVariant *ip4_c
         nm_vpn_service_plugin_set_state(plugin, NM_VPN_SERVICE_STATE_STARTED);
 }
 
+/**
+ * nm_vpn_service_plugin_set_ip6_config:
+ *
+ * Since: 1.2
+ */
 void
 nm_vpn_service_plugin_set_ip6_config(NMVpnServicePlugin *plugin, GVariant *ip6_config)
 {
diff --git a/src/libnm-client-impl/tests/meson.build b/src/libnm-client-impl/tests/meson.build
index 3f2e78a7..0c0e188b 100644
--- a/src/libnm-client-impl/tests/meson.build
+++ b/src/libnm-client-impl/tests/meson.build
@@ -44,3 +44,15 @@ foreach test_unit: test_units
     args: test_args + [exe.full_path()],
   )
 endforeach
+
+if enable_introspection
+  test(
+    'check-local-libnm-gir',
+    python,
+    args: [
+      join_paths(meson.source_root(), 'src', 'libnm-client-impl', 'tests', 'test-gir.py'),
+      '--gir', libnm_gir[0],
+      '--ver', join_paths(meson.source_root(), 'src', 'libnm-client-impl', 'libnm.ver'),
+    ],
+  )
+endif
diff --git a/src/libnm-client-impl/tests/test-gir.py b/src/libnm-client-impl/tests/test-gir.py
new file mode 100755
index 00000000..d91849b8
--- /dev/null
+++ b/src/libnm-client-impl/tests/test-gir.py
@@ -0,0 +1,153 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# Copyright (C) 2022 Red Hat, Inc.
+#
+
+from __future__ import print_function
+import xml.etree.ElementTree as ET
+import argparse
+import sys
+
+C_NS = "http://www.gtk.org/introspection/c/1.0"
+CORE_NS = "http://www.gtk.org/introspection/core/1.0"
+GLIB_NS = "http://www.gtk.org/introspection/glib/1.0"
+
+
+def syms_from_gir(girfile):
+    def xml_symbols(xml, types):
+        ret = []
+        for t in types:
+            ret += xml.findall("./{%s}namespace/{%s}%s" % (CORE_NS, CORE_NS, t))
+            ret += xml.findall("./{%s}namespace/*/{%s}%s" % (CORE_NS, CORE_NS, t))
+        return ret
+
+    girxml = ET.parse(girfile)
+    c_syms = {}
+    for sym in xml_symbols(girxml, ("constructor", "function", "method")):
+        c_syms[sym.get("{%s}identifier" % C_NS)] = sym.get("version")
+
+    for sym in xml_symbols(
+        girxml, ("bitfield", "class", "enumeration", "interface", "record")
+    ):
+        get_type = sym.get("{%s}get-type" % GLIB_NS)
+        if get_type is None:
+            continue
+        version = sym.get("version")
+
+        if version is None:
+            # FIXME: The get_type() functions should be exported in the same
+            # version the type itself appeared. However, a large number of
+            # classes lack Since: tags in their doc blocks. Fall back to using
+            # the tag on _new() method for the test to be able to proceed
+            # reasonably. This should be fixed eventually.
+            constructor = sym.find("./{%s}constructor" % CORE_NS)
+            if constructor is not None:
+                version = constructor.get("version")
+
+        c_syms[get_type] = version
+    return c_syms
+
+
+# Older Python doesn't have str.removesuffix()
+def str_removesuffix(string, suffix):
+    try:
+        return string.removesuffix(suffix)
+    except AttributeError:
+        if string.endswith(suffix):
+            return string[: -len(suffix)]
+        else:
+            return string
+
+
+# Older Python doesn't have str.removeprefix()
+def str_removeprefix(string, prefix):
+    try:
+        return string.removeprefix(prefix)
+    except AttributeError:
+        if string.startswith(prefix):
+            return string[len(prefix) :]
+        else:
+            return string
+
+
+def syms_from_ver(verfile):
+    c_syms = {}
+    for line in open(verfile).readlines():
+        line = line.strip()
+
+        if line.endswith("{"):
+            line = str_removesuffix(line, " {")
+            line = str_removeprefix(line, "libnm_")
+            (major, minor, micro) = line.split("_")
+            if int(major) > 1 or int(minor) > 0:
+                if int(micro) > 0:
+                    # Snap to next major version. Perhaps not
+                    # exactly correct, but good for all symbols
+                    # we export but nm_ethtool_optname_is_feature().
+                    minor = str(int(minor) + 2)
+                version = major + "." + minor
+            else:
+                version = None
+        elif (
+            line.endswith(";")
+            and not line.startswith("}")
+            and not line.startswith("#")
+            and not line == "*;"
+        ):
+            c_syms[str_removesuffix(line, ";")] = version
+
+    # This one is... messy.
+    c_syms["nm_ethtool_optname_is_feature"] = "1.20"
+
+    return c_syms
+
+
+parser = argparse.ArgumentParser()
+parser.add_argument(
+    "--gir",
+    metavar="FILE",
+    help="NM-1.0.gir file",
+    required=True,
+)
+parser.add_argument(
+    "--ver",
+    metavar="FILE",
+    help="libnm.ver file",
+    required=True,
+)
+
+args = parser.parse_args()
+
+gir_syms = syms_from_gir(args.gir)
+ver_syms = syms_from_ver(args.ver)
+
+exit_code = 0
+
+for (gir_sym, gir_ver) in gir_syms.items():
+    if gir_sym not in ver_syms:
+        exit_code = 1
+        print(
+            'FAIL: "%s" found in "%s", but is not exported. Needs adding to "%s"?'
+            % (gir_sym, args.gir, args.ver),
+            file=sys.stderr,
+        )
+        continue
+    if gir_ver != ver_syms[gir_sym]:
+        exit_code = 1
+        print(
+            'FAIL: "%s" exported in version "%s" but documented as available since "%s"'
+            % (gir_sym, ver_syms[gir_sym], gir_ver),
+            file=sys.stderr,
+        )
+
+# In python2, dict.keys() returns lists, not sets. Cast them.
+for sym in set(ver_syms.keys()) - set(gir_syms.keys()):
+    exit_code = 1
+    print(
+        'FAIL: "%s" found in "%s", but not in "%s". Maybe the doc comment is wrong or g-ir-scanner messed up?'
+        % (sym, args.ver, args.gir),
+        file=sys.stderr,
+    )
+
+sys.exit(exit_code)
diff --git a/src/libnm-client-public/nm-checkpoint.h b/src/libnm-client-public/nm-checkpoint.h
index 456d7f6b..c47ff39c 100644
--- a/src/libnm-client-public/nm-checkpoint.h
+++ b/src/libnm-client-public/nm-checkpoint.h
@@ -29,6 +29,8 @@ G_BEGIN_DECLS
 
 /**
  * NMCheckpoint:
+ *
+ * Since: 1.12
  */
 typedef struct _NMCheckpoint      NMCheckpoint;
 typedef struct _NMCheckpointClass NMCheckpointClass;
diff --git a/src/libnm-client-public/nm-client.h b/src/libnm-client-public/nm-client.h
index 6307f112..da5e509e 100644
--- a/src/libnm-client-public/nm-client.h
+++ b/src/libnm-client-public/nm-client.h
@@ -120,6 +120,11 @@ GQuark nm_client_error_quark(void);
 
 /* DNS stuff */
 
+/**
+ * NMDnsEntry:
+ *
+ * Since: 1.6
+ */
 typedef struct NMDnsEntry NMDnsEntry;
 
 NM_AVAILABLE_IN_1_6
diff --git a/src/libnm-client-public/nm-device-6lowpan.h b/src/libnm-client-public/nm-device-6lowpan.h
index d5f8a7a5..7feba237 100644
--- a/src/libnm-client-public/nm-device-6lowpan.h
+++ b/src/libnm-client-public/nm-device-6lowpan.h
@@ -29,6 +29,8 @@ G_BEGIN_DECLS
 
 /**
  * NMDevice6Lowpan:
+ *
+ * Since: 1.14
  */
 typedef struct _NMDevice6Lowpan      NMDevice6Lowpan;
 typedef struct _NMDevice6LowpanClass NMDevice6LowpanClass;
@@ -36,13 +38,9 @@ typedef struct _NMDevice6LowpanClass NMDevice6LowpanClass;
 NM_AVAILABLE_IN_1_14
 GType nm_device_6lowpan_get_type(void);
 
-NM_AVAILABLE_IN_1_14
+NM_AVAILABLE_IN_1_40_4
 NMDevice *nm_device_6lowpan_get_parent(NMDevice6Lowpan *device);
 
-NM_AVAILABLE_IN_1_14
-NM_DEPRECATED_IN_1_24_FOR(nm_device_get_hw_address)
-const char *nm_device_6lowpan_get_hw_address(NMDevice6Lowpan *device);
-
 G_END_DECLS
 
 #endif /* __NM_DEVICE_6LOWPAN_H__ */
diff --git a/src/libnm-client-public/nm-device-dummy.h b/src/libnm-client-public/nm-device-dummy.h
index 8b2f7485..0e6c6fe6 100644
--- a/src/libnm-client-public/nm-device-dummy.h
+++ b/src/libnm-client-public/nm-device-dummy.h
@@ -28,6 +28,8 @@ G_BEGIN_DECLS
 
 /**
  * NMDeviceDummy:
+ *
+ * Since: 1.8
  */
 typedef struct _NMDeviceDummy      NMDeviceDummy;
 typedef struct _NMDeviceDummyClass NMDeviceDummyClass;
diff --git a/src/libnm-client-public/nm-device-ip-tunnel.h b/src/libnm-client-public/nm-device-ip-tunnel.h
index 4f55dc0b..4b9b9f5b 100644
--- a/src/libnm-client-public/nm-device-ip-tunnel.h
+++ b/src/libnm-client-public/nm-device-ip-tunnel.h
@@ -41,6 +41,8 @@ G_BEGIN_DECLS
 
 /**
  * NMDeviceIPTunnel:
+ *
+ * Since: 1.2
  */
 typedef struct _NMDeviceIPTunnel      NMDeviceIPTunnel;
 typedef struct _NMDeviceIPTunnelClass NMDeviceIPTunnelClass;
diff --git a/src/libnm-client-public/nm-device-macsec.h b/src/libnm-client-public/nm-device-macsec.h
index b1ec3637..f4f6f03d 100644
--- a/src/libnm-client-public/nm-device-macsec.h
+++ b/src/libnm-client-public/nm-device-macsec.h
@@ -41,6 +41,8 @@ G_BEGIN_DECLS
 
 /**
  * NMDeviceMacsec:
+ *
+ * Since: 1.6
  */
 typedef struct _NMDeviceMacsec      NMDeviceMacsec;
 typedef struct _NMDeviceMacsecClass NMDeviceMacsecClass;
@@ -48,7 +50,7 @@ typedef struct _NMDeviceMacsecClass NMDeviceMacsecClass;
 NM_AVAILABLE_IN_1_6
 GType nm_device_macsec_get_type(void);
 
-NM_AVAILABLE_IN_1_6
+NM_AVAILABLE_IN_1_40_4
 NMDevice *nm_device_macsec_get_parent(NMDeviceMacsec *device);
 
 NM_AVAILABLE_IN_1_6
diff --git a/src/libnm-client-public/nm-device-macvlan.h b/src/libnm-client-public/nm-device-macvlan.h
index 95699334..85292069 100644
--- a/src/libnm-client-public/nm-device-macvlan.h
+++ b/src/libnm-client-public/nm-device-macvlan.h
@@ -32,6 +32,8 @@ G_BEGIN_DECLS
 
 /**
  * NMDeviceMacvlan:
+ *
+ * Since: 1.2
  */
 typedef struct _NMDeviceMacvlan      NMDeviceMacvlan;
 typedef struct _NMDeviceMacvlanClass NMDeviceMacvlanClass;
diff --git a/src/libnm-client-public/nm-device-ovs-bridge.h b/src/libnm-client-public/nm-device-ovs-bridge.h
index 8c454057..a6c9ff0b 100644
--- a/src/libnm-client-public/nm-device-ovs-bridge.h
+++ b/src/libnm-client-public/nm-device-ovs-bridge.h
@@ -29,6 +29,8 @@ G_BEGIN_DECLS
 
 /**
  * NMDeviceOvsBridge:
+ *
+ * Since: 1.10
  */
 typedef struct _NMDeviceOvsBridge      NMDeviceOvsBridge;
 typedef struct _NMDeviceOvsBridgeClass NMDeviceOvsBridgeClass;
diff --git a/src/libnm-client-public/nm-device-ovs-interface.h b/src/libnm-client-public/nm-device-ovs-interface.h
index 1ba7ac3a..eb74ee48 100644
--- a/src/libnm-client-public/nm-device-ovs-interface.h
+++ b/src/libnm-client-public/nm-device-ovs-interface.h
@@ -28,6 +28,8 @@ G_BEGIN_DECLS
 
 /**
  * NMDeviceOvsInterface:
+ *
+ * Since: 1.10
  */
 typedef struct _NMDeviceOvsInterface      NMDeviceOvsInterface;
 typedef struct _NMDeviceOvsInterfaceClass NMDeviceOvsInterfaceClass;
diff --git a/src/libnm-client-public/nm-device-ovs-port.h b/src/libnm-client-public/nm-device-ovs-port.h
index 7524cacb..8014ed91 100644
--- a/src/libnm-client-public/nm-device-ovs-port.h
+++ b/src/libnm-client-public/nm-device-ovs-port.h
@@ -29,6 +29,8 @@ G_BEGIN_DECLS
 
 /**
  * NMDeviceOvsPort:
+ *
+ * Since: 1.10
  */
 typedef struct _NMDeviceOvsPort      NMDeviceOvsPort;
 typedef struct _NMDeviceOvsPortClass NMDeviceOvsPortClass;
diff --git a/src/libnm-client-public/nm-device-ppp.h b/src/libnm-client-public/nm-device-ppp.h
index 4003f901..4d56cd89 100644
--- a/src/libnm-client-public/nm-device-ppp.h
+++ b/src/libnm-client-public/nm-device-ppp.h
@@ -23,10 +23,13 @@ G_BEGIN_DECLS
 
 /**
  * NMDevicePpp:
+ *
+ * Since: 1.10
  */
 typedef struct _NMDevicePpp      NMDevicePpp;
 typedef struct _NMDevicePppClass NMDevicePppClass;
 
+NM_AVAILABLE_IN_1_10
 GType nm_device_ppp_get_type(void);
 
 G_END_DECLS
diff --git a/src/libnm-client-public/nm-device-tun.h b/src/libnm-client-public/nm-device-tun.h
index e1e7310d..42690358 100644
--- a/src/libnm-client-public/nm-device-tun.h
+++ b/src/libnm-client-public/nm-device-tun.h
@@ -33,6 +33,8 @@ G_BEGIN_DECLS
 
 /**
  * NMDeviceTun:
+ *
+ * Since: 1.2
  */
 typedef struct _NMDeviceTun      NMDeviceTun;
 typedef struct _NMDeviceTunClass NMDeviceTunClass;
diff --git a/src/libnm-client-public/nm-device-veth.h b/src/libnm-client-public/nm-device-veth.h
index 8f61ae20..9de27595 100644
--- a/src/libnm-client-public/nm-device-veth.h
+++ b/src/libnm-client-public/nm-device-veth.h
@@ -27,6 +27,8 @@ G_BEGIN_DECLS
 
 /**
  * NMDeviceVeth:
+ *
+ * Since: 1.30
  */
 typedef struct _NMDeviceVeth      NMDeviceVeth;
 typedef struct _NMDeviceVethClass NMDeviceVethClass;
@@ -34,7 +36,7 @@ typedef struct _NMDeviceVethClass NMDeviceVethClass;
 NM_AVAILABLE_IN_1_30
 GType nm_device_veth_get_type(void);
 
-NM_AVAILABLE_IN_1_30
+NM_AVAILABLE_IN_1_40_4
 NMDevice *nm_device_veth_get_peer(NMDeviceVeth *device);
 
 G_END_DECLS
diff --git a/src/libnm-client-public/nm-device-vrf.h b/src/libnm-client-public/nm-device-vrf.h
index fbc8b202..82e0657d 100644
--- a/src/libnm-client-public/nm-device-vrf.h
+++ b/src/libnm-client-public/nm-device-vrf.h
@@ -24,6 +24,8 @@ G_BEGIN_DECLS
 
 /**
  * NMDeviceVrf:
+ *
+ * Since: 1.24
  */
 typedef struct _NMDeviceVrf      NMDeviceVrf;
 typedef struct _NMDeviceVrfClass NMDeviceVrfClass;
diff --git a/src/libnm-client-public/nm-device-vxlan.h b/src/libnm-client-public/nm-device-vxlan.h
index 7939539d..fa7511e1 100644
--- a/src/libnm-client-public/nm-device-vxlan.h
+++ b/src/libnm-client-public/nm-device-vxlan.h
@@ -45,6 +45,8 @@ G_BEGIN_DECLS
 
 /**
  * NMDeviceVxlan:
+ *
+ * Since: 1.2
  */
 typedef struct _NMDeviceVxlan      NMDeviceVxlan;
 typedef struct _NMDeviceVxlanClass NMDeviceVxlanClass;
@@ -56,7 +58,7 @@ NM_AVAILABLE_IN_1_2
 NM_DEPRECATED_IN_1_24_FOR(nm_device_get_hw_address)
 const char *nm_device_vxlan_get_hw_address(NMDeviceVxlan *device);
 
-NM_AVAILABLE_IN_1_2
+NM_AVAILABLE_IN_1_40_4
 gboolean nm_device_vxlan_get_carrier(NMDeviceVxlan *device);
 NM_AVAILABLE_IN_1_2
 NMDevice *nm_device_vxlan_get_parent(NMDeviceVxlan *device);
@@ -84,7 +86,7 @@ NM_AVAILABLE_IN_1_2
 guint nm_device_vxlan_get_limit(NMDeviceVxlan *device);
 NM_AVAILABLE_IN_1_2
 gboolean nm_device_vxlan_get_proxy(NMDeviceVxlan *device);
-NM_AVAILABLE_IN_1_2
+NM_AVAILABLE_IN_1_40_4
 gboolean nm_device_vxlan_get_rsc(NMDeviceVxlan *device);
 NM_AVAILABLE_IN_1_2
 gboolean nm_device_vxlan_get_l2miss(NMDeviceVxlan *device);
diff --git a/src/libnm-client-public/nm-device-wifi-p2p.h b/src/libnm-client-public/nm-device-wifi-p2p.h
index ad0ca436..31add1e3 100644
--- a/src/libnm-client-public/nm-device-wifi-p2p.h
+++ b/src/libnm-client-public/nm-device-wifi-p2p.h
@@ -44,7 +44,7 @@ NM_AVAILABLE_IN_1_16
 NM_DEPRECATED_IN_1_24_FOR(nm_device_get_hw_address)
 const char *nm_device_wifi_p2p_get_hw_address(NMDeviceWifiP2P *device);
 
-NM_AVAILABLE_IN_1_16
+NM_AVAILABLE_IN_1_40_4
 NMWifiP2PPeer *nm_device_wifi_p2p_get_peer_by_path(NMDeviceWifiP2P *device, const char *path);
 
 NM_AVAILABLE_IN_1_16
diff --git a/src/libnm-client-public/nm-device-wireguard.h b/src/libnm-client-public/nm-device-wireguard.h
index 756dfb4e..fa167878 100644
--- a/src/libnm-client-public/nm-device-wireguard.h
+++ b/src/libnm-client-public/nm-device-wireguard.h
@@ -27,6 +27,8 @@ G_BEGIN_DECLS
 
 /**
  * NMDeviceWireGuard:
+ *
+ * Since: 1.14
  */
 typedef struct _NMDeviceWireGuard      NMDeviceWireGuard;
 typedef struct _NMDeviceWireGuardClass NMDeviceWireGuardClass;
diff --git a/src/libnm-client-public/nm-device-wpan.h b/src/libnm-client-public/nm-device-wpan.h
index 8b011851..d6805040 100644
--- a/src/libnm-client-public/nm-device-wpan.h
+++ b/src/libnm-client-public/nm-device-wpan.h
@@ -27,6 +27,8 @@ G_BEGIN_DECLS
 
 /**
  * NMDeviceWpan:
+ *
+ * Since: 1.14
  */
 typedef struct _NMDeviceWpan      NMDeviceWpan;
 typedef struct _NMDeviceWpanClass NMDeviceWpanClass;
@@ -34,10 +36,6 @@ typedef struct _NMDeviceWpanClass NMDeviceWpanClass;
 NM_AVAILABLE_IN_1_14
 GType nm_device_wpan_get_type(void);
 
-NM_AVAILABLE_IN_1_14
-NM_DEPRECATED_IN_1_24_FOR(nm_device_get_hw_address)
-const char *nm_device_wpan_get_hw_address(NMDeviceWpan *device);
-
 G_END_DECLS
 
 #endif /* __NM_DEVICE_WPAN_H__ */
diff --git a/src/libnm-client-public/nm-vpn-plugin-old.h b/src/libnm-client-public/nm-vpn-plugin-old.h
index fe0d4bc2..cc6f6178 100644
--- a/src/libnm-client-public/nm-vpn-plugin-old.h
+++ b/src/libnm-client-public/nm-vpn-plugin-old.h
@@ -108,15 +108,9 @@ NM_DEPRECATED_IN_1_2
 void nm_vpn_plugin_old_failure(NMVpnPluginOld *plugin, NMVpnPluginFailure reason);
 
 NM_DEPRECATED_IN_1_2
-void nm_vpn_plugin_old_set_config(NMVpnPluginOld *plugin, GVariant *config);
-
-NM_DEPRECATED_IN_1_2
 void nm_vpn_plugin_old_set_ip4_config(NMVpnPluginOld *plugin, GVariant *ip4_config);
 
 NM_DEPRECATED_IN_1_2
-void nm_vpn_plugin_old_set_ip6_config(NMVpnPluginOld *plugin, GVariant *ip6_config);
-
-NM_DEPRECATED_IN_1_2
 gboolean nm_vpn_plugin_old_disconnect(NMVpnPluginOld *plugin, GError **err);
 
 /* Utility functions */
diff --git a/src/libnm-client-public/nm-vpn-service-plugin.h b/src/libnm-client-public/nm-vpn-service-plugin.h
index 5187d93d..baf5b3a6 100644
--- a/src/libnm-client-public/nm-vpn-service-plugin.h
+++ b/src/libnm-client-public/nm-vpn-service-plugin.h
@@ -35,6 +35,8 @@ G_BEGIN_DECLS
 
 /**
  * NMVpnServicePlugin:
+ *
+ * Since: 1.2
  */
 typedef struct {
     NM_AVAILABLE_IN_1_2
diff --git a/src/libnm-client-public/nm-wifi-p2p-peer.h b/src/libnm-client-public/nm-wifi-p2p-peer.h
index eff27bcb..dd8a109f 100644
--- a/src/libnm-client-public/nm-wifi-p2p-peer.h
+++ b/src/libnm-client-public/nm-wifi-p2p-peer.h
@@ -37,6 +37,8 @@ G_BEGIN_DECLS
 
 /**
  * NMWifiP2PPeer:
+ *
+ * Since: 1.16
  */
 typedef struct _NMWifiP2PPeer      NMWifiP2PPeer;
 typedef struct _NMWifiP2PPeerClass NMWifiP2PPeerClass;
diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c
index aed4be21..2f5bf357 100644
--- a/src/libnm-core-impl/nm-connection.c
+++ b/src/libnm-core-impl/nm-connection.c
@@ -228,8 +228,10 @@ _nm_connection_add_setting(NMConnection *connection, NMSetting *setting)
     priv = NM_CONNECTION_GET_PRIVATE(connection);
 
     s_old = priv->settings[setting_info->meta_type];
-    if (s_old == setting)
+    if (s_old == setting) {
+        g_object_unref(s_old);
         return;
+    }
 
     priv->settings[setting_info->meta_type] = setting;
 
@@ -3487,7 +3489,7 @@ nm_connection_get_setting_olpc_mesh(NMConnection *connection)
  *
  * Returns: (transfer none): an #NMSettingOvsBridge if the connection contains one, otherwise %NULL
  *
- * Since: 1.10
+ * Since: 1.14
  **/
 NMSettingOvsBridge *
 nm_connection_get_setting_ovs_bridge(NMConnection *connection)
@@ -3503,7 +3505,7 @@ nm_connection_get_setting_ovs_bridge(NMConnection *connection)
  *
  * Returns: (transfer none): an #NMSettingOvsInterface if the connection contains one, otherwise %NULL
  *
- * Since: 1.10
+ * Since: 1.14
  **/
 NMSettingOvsInterface *
 nm_connection_get_setting_ovs_interface(NMConnection *connection)
@@ -3520,7 +3522,7 @@ nm_connection_get_setting_ovs_interface(NMConnection *connection)
  *
  * Returns: (transfer none): an #NMSettingOvsPatch if the connection contains one, otherwise %NULL
  *
- * Since: 1.10
+ * Since: 1.14
  **/
 NMSettingOvsPatch *
 nm_connection_get_setting_ovs_patch(NMConnection *connection)
@@ -3536,7 +3538,7 @@ nm_connection_get_setting_ovs_patch(NMConnection *connection)
  *
  * Returns: (transfer none): an #NMSettingOvsPort if the connection contains one, otherwise %NULL
  *
- * Since: 1.10
+ * Since: 1.14
  **/
 NMSettingOvsPort *
 nm_connection_get_setting_ovs_port(NMConnection *connection)
@@ -3626,7 +3628,7 @@ nm_connection_get_setting_tc_config(NMConnection *connection)
  *
  * Returns: (transfer none): an #NMSettingTun if the connection contains one, otherwise %NULL
  *
- * Since: 1.2
+ * Since: 1.14
  **/
 NMSettingTun *
 nm_connection_get_setting_tun(NMConnection *connection)
diff --git a/src/libnm-core-impl/nm-setting-6lowpan.c b/src/libnm-core-impl/nm-setting-6lowpan.c
index 765af69b..21b3dbb9 100644
--- a/src/libnm-core-impl/nm-setting-6lowpan.c
+++ b/src/libnm-core-impl/nm-setting-6lowpan.c
@@ -29,6 +29,8 @@ typedef struct {
  * NMSetting6Lowpan:
  *
  * 6LoWPAN Settings
+ *
+ * Since: 1.14
  */
 struct _NMSetting6Lowpan {
     NMSetting parent;
@@ -51,7 +53,7 @@ G_DEFINE_TYPE(NMSetting6Lowpan, nm_setting_6lowpan, NM_TYPE_SETTING)
  *
  * Returns: the #NMSetting6Lowpan:parent property of the setting
  *
- * Since: 1.14
+ * Since: 1.42, 1.40.4
  **/
 const char *
 nm_setting_6lowpan_get_parent(NMSetting6Lowpan *setting)
@@ -139,7 +141,7 @@ nm_setting_6lowpan_init(NMSetting6Lowpan *setting)
  *
  * Returns: (transfer full): the new empty #NMSetting6Lowpan object
  *
- * Since: 1.14
+ * Since: 1.42, 1.40.4
  **/
 NMSetting *
 nm_setting_6lowpan_new(void)
diff --git a/src/libnm-core-impl/nm-setting-bridge.c b/src/libnm-core-impl/nm-setting-bridge.c
index 39a3fb60..89611147 100644
--- a/src/libnm-core-impl/nm-setting-bridge.c
+++ b/src/libnm-core-impl/nm-setting-bridge.c
@@ -926,7 +926,7 @@ _nm_setting_bridge_get_vlans(NMSettingBridge *setting)
  *
  * Returns: the #NMSettingBridge:group-address property of the setting
  *
- * Since 1.24
+ * Since: 1.24
  **/
 const char *
 nm_setting_bridge_get_group_address(const NMSettingBridge *setting)
@@ -942,7 +942,7 @@ nm_setting_bridge_get_group_address(const NMSettingBridge *setting)
  *
  * Returns: the #NMSettingBridge:vlan-protocol property of the setting
  *
- * Since 1.24
+ * Since: 1.24
  **/
 const char *
 nm_setting_bridge_get_vlan_protocol(const NMSettingBridge *setting)
@@ -958,7 +958,7 @@ nm_setting_bridge_get_vlan_protocol(const NMSettingBridge *setting)
  *
  * Returns: the #NMSettingBridge:vlan-stats-enabled property of the setting
  *
- * Since 1.24
+ * Since: 1.24
  **/
 gboolean
 nm_setting_bridge_get_vlan_stats_enabled(const NMSettingBridge *setting)
@@ -974,7 +974,7 @@ nm_setting_bridge_get_vlan_stats_enabled(const NMSettingBridge *setting)
  *
  * Returns: the #NMSettingBridge:multicast-router property of the setting
  *
- * Since 1.24
+ * Since: 1.24
  **/
 const char *
 nm_setting_bridge_get_multicast_router(const NMSettingBridge *setting)
@@ -990,7 +990,7 @@ nm_setting_bridge_get_multicast_router(const NMSettingBridge *setting)
  *
  * Returns: the #NMSettingBridge:multicast-query-use-ifaddr property of the setting
  *
- * Since 1.24
+ * Since: 1.24
  **/
 gboolean
 nm_setting_bridge_get_multicast_query_use_ifaddr(const NMSettingBridge *setting)
@@ -1006,7 +1006,7 @@ nm_setting_bridge_get_multicast_query_use_ifaddr(const NMSettingBridge *setting)
  *
  * Returns: the #NMSettingBridge:multicast-querier property of the setting
  *
- * Since 1.24
+ * Since: 1.24
  **/
 gboolean
 nm_setting_bridge_get_multicast_querier(const NMSettingBridge *setting)
@@ -1022,7 +1022,7 @@ nm_setting_bridge_get_multicast_querier(const NMSettingBridge *setting)
  *
  * Returns: the #NMSettingBridge:multicast-hash-max property of the setting
  *
- * Since 1.26
+ * Since: 1.26
  **/
 guint32
 nm_setting_bridge_get_multicast_hash_max(const NMSettingBridge *setting)
@@ -1038,7 +1038,7 @@ nm_setting_bridge_get_multicast_hash_max(const NMSettingBridge *setting)
  *
  * Returns: the #NMSettingBridge:multicast-last-member-count property of the setting
  *
- * Since 1.26
+ * Since: 1.26
  **/
 guint32
 nm_setting_bridge_get_multicast_last_member_count(const NMSettingBridge *setting)
@@ -1054,7 +1054,7 @@ nm_setting_bridge_get_multicast_last_member_count(const NMSettingBridge *setting
  *
  * Returns: the #NMSettingBridge:multicast-last-member-interval property of the setting
  *
- * Since 1.26
+ * Since: 1.26
  **/
 guint64
 nm_setting_bridge_get_multicast_last_member_interval(const NMSettingBridge *setting)
@@ -1070,7 +1070,7 @@ nm_setting_bridge_get_multicast_last_member_interval(const NMSettingBridge *sett
  *
  * Returns: the #NMSettingBridge:multicast-membership-interval property of the setting
  *
- * Since 1.26
+ * Since: 1.26
  **/
 guint64
 nm_setting_bridge_get_multicast_membership_interval(const NMSettingBridge *setting)
@@ -1086,7 +1086,7 @@ nm_setting_bridge_get_multicast_membership_interval(const NMSettingBridge *setti
  *
  * Returns: the #NMSettingBridge:multicast-querier-interval property of the setting
  *
- * Since 1.26
+ * Since: 1.26
  **/
 guint64
 nm_setting_bridge_get_multicast_querier_interval(const NMSettingBridge *setting)
@@ -1102,7 +1102,7 @@ nm_setting_bridge_get_multicast_querier_interval(const NMSettingBridge *setting)
  *
  * Returns: the #NMSettingBridge:multicast-query-interval property of the setting
  *
- * Since 1.26
+ * Since: 1.26
  **/
 guint64
 nm_setting_bridge_get_multicast_query_interval(const NMSettingBridge *setting)
@@ -1118,7 +1118,7 @@ nm_setting_bridge_get_multicast_query_interval(const NMSettingBridge *setting)
  *
  * Returns: the #NMSettingBridge:multicast-query-response-interval property of the setting
  *
- * Since 1.26
+ * Since: 1.26
  **/
 guint64
 nm_setting_bridge_get_multicast_query_response_interval(const NMSettingBridge *setting)
@@ -1134,7 +1134,7 @@ nm_setting_bridge_get_multicast_query_response_interval(const NMSettingBridge *s
  *
  * Returns: the #NMSettingBridge:multicast-query-response-interval property of the setting
  *
- * Since 1.26
+ * Since: 1.26
  **/
 guint32
 nm_setting_bridge_get_multicast_startup_query_count(const NMSettingBridge *setting)
@@ -1150,7 +1150,7 @@ nm_setting_bridge_get_multicast_startup_query_count(const NMSettingBridge *setti
  *
  * Returns: the #NMSettingBridge:multicast-startup-query-interval property of the setting
  *
- * Since 1.26
+ * Since: 1.26
  **/
 guint64
 nm_setting_bridge_get_multicast_startup_query_interval(const NMSettingBridge *setting)
diff --git a/src/libnm-core-impl/nm-setting-connection.c b/src/libnm-core-impl/nm-setting-connection.c
index cbce1c12..bc14c767 100644
--- a/src/libnm-core-impl/nm-setting-connection.c
+++ b/src/libnm-core-impl/nm-setting-connection.c
@@ -1023,7 +1023,7 @@ nm_setting_connection_get_dns_over_tls(NMSettingConnection *setting)
  *
  * Returns: the #NMSettingConnection:mptcp-flags property of the setting.
  *
- * Since: 1.40
+ * Since: 1.42, 1.40.4
  **/
 NMMptcpFlags
 nm_setting_connection_get_mptcp_flags(NMSettingConnection *setting)
diff --git a/src/libnm-core-impl/nm-setting-ethtool.c b/src/libnm-core-impl/nm-setting-ethtool.c
index 71179efd..1db6c335 100644
--- a/src/libnm-core-impl/nm-setting-ethtool.c
+++ b/src/libnm-core-impl/nm-setting-ethtool.c
@@ -23,20 +23,6 @@
 
 /*****************************************************************************/
 
-static const GVariantType *
-get_variant_type_from_ethtool_id(NMEthtoolID ethtool_id)
-{
-    if (nm_ethtool_id_is_feature(ethtool_id) || nm_ethtool_id_is_pause(ethtool_id))
-        return G_VARIANT_TYPE_BOOLEAN;
-
-    if (nm_ethtool_id_is_coalesce(ethtool_id) || nm_ethtool_id_is_ring(ethtool_id))
-        return G_VARIANT_TYPE_UINT32;
-
-    return NULL;
-}
-
-/*****************************************************************************/
-
 /**
  * nm_ethtool_optname_is_feature:
  * @optname: (allow-none): the option name to check
@@ -302,7 +288,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
         NMEthtoolID         ethtool_id;
 
         ethtool_id   = nm_ethtool_id_get_by_name(optname);
-        variant_type = get_variant_type_from_ethtool_id(ethtool_id);
+        variant_type = nm_ethtool_id_get_variant_type(ethtool_id);
 
         if (!variant_type) {
             g_set_error_literal(error,
@@ -365,7 +351,7 @@ get_variant_type(const NMSettInfoSetting *sett_info, const char *name, GError **
 {
     const GVariantType *variant_type;
 
-    variant_type = get_variant_type_from_ethtool_id(nm_ethtool_id_get_by_name(name));
+    variant_type = nm_ethtool_id_get_variant_type(nm_ethtool_id_get_by_name(name));
 
     if (!variant_type) {
         g_set_error(error,
diff --git a/src/libnm-core-impl/nm-setting-hostname.c b/src/libnm-core-impl/nm-setting-hostname.c
index 276a75a8..8a5e50be 100644
--- a/src/libnm-core-impl/nm-setting-hostname.c
+++ b/src/libnm-core-impl/nm-setting-hostname.c
@@ -134,7 +134,7 @@ nm_setting_hostname_init(NMSettingHostname *setting)
  *
  * Returns: (transfer full): the new empty #NMSettingHostname object
  *
- * Since: 1.30
+ * Since: 1.42, 1.40.4
  **/
 NMSetting *
 nm_setting_hostname_new(void)
diff --git a/src/libnm-core-impl/nm-setting-ip-config.c b/src/libnm-core-impl/nm-setting-ip-config.c
index 916a8038..73f98ab1 100644
--- a/src/libnm-core-impl/nm-setting-ip-config.c
+++ b/src/libnm-core-impl/nm-setting-ip-config.c
@@ -266,6 +266,8 @@ nm_ip_address_unref(NMIPAddress *address)
  *
  * Returns: 0 if the two objects have the same values (according to their flags)
  *   or a integer indicating the compare order.
+ *
+ * Since: 1.22
  **/
 int
 nm_ip_address_cmp_full(const NMIPAddress *a, const NMIPAddress *b, NMIPAddressCmpFlags cmp_flags)
@@ -4343,6 +4345,8 @@ nm_setting_ip_config_get_num_dns_options(NMSettingIPConfig *setting)
  * a default configuration, while the former explicitly means "no-options".
  *
  * Returns: whether DNS options are initialized or left unset (the default).
+ *
+ * Since: 1.2
  **/
 gboolean
 nm_setting_ip_config_has_dns_options(NMSettingIPConfig *setting)
@@ -5291,7 +5295,7 @@ nm_setting_ip_config_get_required_timeout(NMSettingIPConfig *setting)
  *
  * Returns: the configured DHCP IAID (Identity Association Identifier)
  *
- * Since: 1.22
+ * Since: 1.42, 1.40.4
  **/
 const char *
 nm_setting_ip_config_get_dhcp_iaid(NMSettingIPConfig *setting)
diff --git a/src/libnm-core-impl/nm-setting-ip-tunnel.c b/src/libnm-core-impl/nm-setting-ip-tunnel.c
index d42e97b9..73416813 100644
--- a/src/libnm-core-impl/nm-setting-ip-tunnel.c
+++ b/src/libnm-core-impl/nm-setting-ip-tunnel.c
@@ -240,7 +240,7 @@ nm_setting_ip_tunnel_get_output_key(NMSettingIPTunnel *setting)
  *
  * Returns: the encapsulation limit value
  *
- * Since: 1.2
+ * Since: 1.42, 1.40.4
  **/
 guint
 nm_setting_ip_tunnel_get_encapsulation_limit(NMSettingIPTunnel *setting)
@@ -258,7 +258,7 @@ nm_setting_ip_tunnel_get_encapsulation_limit(NMSettingIPTunnel *setting)
  *
  * Returns: the flow label value
  *
- * Since: 1.2
+ * Since: 1.42, 1.40.4
  **/
 guint
 nm_setting_ip_tunnel_get_flow_label(NMSettingIPTunnel *setting)
@@ -286,7 +286,7 @@ nm_setting_ip_tunnel_get_mtu(NMSettingIPTunnel *setting)
     return NM_SETTING_IP_TUNNEL_GET_PRIVATE(setting)->mtu;
 }
 
-/*
+/**
  * nm_setting_ip_tunnel_get_flags:
  * @setting: the #NMSettingIPTunnel
  *
diff --git a/src/libnm-core-impl/nm-setting-ip4-config.c b/src/libnm-core-impl/nm-setting-ip4-config.c
index ff56834e..d991152c 100644
--- a/src/libnm-core-impl/nm-setting-ip4-config.c
+++ b/src/libnm-core-impl/nm-setting-ip4-config.c
@@ -138,7 +138,7 @@ nm_setting_ip4_config_get_dhcp_vendor_class_identifier(NMSettingIP4Config *setti
  *
  * Returns: the link-local configuration
  *
- * Since: 1.40
+ * Since: 1.42, 1.40.4
  **/
 NMSettingIP4LinkLocal
 nm_setting_ip4_config_get_link_local(NMSettingIP4Config *setting)
@@ -898,7 +898,7 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass)
      * a global connection default gets consulted.
      * If still unspecified, the DHCP option is not sent to the server.
      *
-     * Since 1.28
+     * Since: 1.28
      */
     /* ---ifcfg-rh---
      * property: dhcp-vendor-class-identifier
@@ -928,7 +928,7 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass)
      * falling back to "auto". Note that if "ipv4.method" is "disabled", then
      * link local addressing is always disabled too. The default is "default".
      *
-     * Since 1.40
+     * Since: 1.40
      */
     /* ---ifcfg-rh---
      * property: link-local
diff --git a/src/libnm-core-impl/nm-setting-ovs-bridge.c b/src/libnm-core-impl/nm-setting-ovs-bridge.c
index b15aab19..7dc9fda4 100644
--- a/src/libnm-core-impl/nm-setting-ovs-bridge.c
+++ b/src/libnm-core-impl/nm-setting-ovs-bridge.c
@@ -120,7 +120,7 @@ nm_setting_ovs_bridge_get_stp_enable(NMSettingOvsBridge *self)
  *
  * Returns: the #NMSettingOvsBridge:datapath_type property of the setting
  *
- * Since: 1.20
+ * Since: 1.42, 1.40.4
  **/
 const char *
 nm_setting_ovs_bridge_get_datapath_type(NMSettingOvsBridge *self)
diff --git a/src/libnm-core-impl/nm-setting-ovs-external-ids.c b/src/libnm-core-impl/nm-setting-ovs-external-ids.c
index 6b8d5d37..f4e31f81 100644
--- a/src/libnm-core-impl/nm-setting-ovs-external-ids.c
+++ b/src/libnm-core-impl/nm-setting-ovs-external-ids.c
@@ -195,6 +195,8 @@ _nm_setting_ovs_external_ids_get_data(NMSettingOvsExternalIDs *self)
  *
  * Returns: (array length=out_len) (transfer none): a
  *   %NULL-terminated array containing each key from the table.
+ *
+ * Since: 1.30
   **/
 const char *const *
 nm_setting_ovs_external_ids_get_data_keys(NMSettingOvsExternalIDs *setting, guint *out_len)
diff --git a/src/libnm-core-impl/nm-setting-sriov.c b/src/libnm-core-impl/nm-setting-sriov.c
index 30dd8f54..f9bee21e 100644
--- a/src/libnm-core-impl/nm-setting-sriov.c
+++ b/src/libnm-core-impl/nm-setting-sriov.c
@@ -372,7 +372,7 @@ const NMVariantAttributeSpec *const _nm_sriov_vf_attribute_spec[] = {
  *
  * Returns: %TRUE if the attribute is valid, %FALSE otherwise
  *
- * Since: 1.14
+ * Since: 1.42, 1.40.4
  */
 gboolean
 nm_sriov_vf_attribute_validate(const char *name, GVariant *value, gboolean *known, GError **error)
@@ -649,7 +649,7 @@ nm_sriov_vf_get_vlan_qos(const NMSriovVF *vf, guint vlan_id)
     return vlan->qos;
 }
 
-/*
+/**
  * nm_sriov_vf_get_vlan_protocol:
  * @vf: the #NMSriovVF
  * @vlan_id: the VLAN id
diff --git a/src/libnm-core-impl/nm-setting-tc-config.c b/src/libnm-core-impl/nm-setting-tc-config.c
index 08a7f94d..529bbca1 100644
--- a/src/libnm-core-impl/nm-setting-tc-config.c
+++ b/src/libnm-core-impl/nm-setting-tc-config.c
@@ -935,7 +935,7 @@ nm_tc_tfilter_get_parent(NMTCTfilter *tfilter)
  *
  * Returns: the action associated with a traffic filter.
  *
- * Since: 1.12
+ * Since: 1.42, 1.40.4
  **/
 NMTCAction *
 nm_tc_tfilter_get_action(NMTCTfilter *tfilter)
@@ -956,7 +956,7 @@ nm_tc_tfilter_get_action(NMTCTfilter *tfilter)
  *
  * Sets the action associated with a traffic filter.
  *
- * Since: 1.12
+ * Since: 1.42, 1.40.4
  **/
 void
 nm_tc_tfilter_set_action(NMTCTfilter *tfilter, NMTCAction *action)
diff --git a/src/libnm-core-impl/nm-setting-user.c b/src/libnm-core-impl/nm-setting-user.c
index 0e95d38b..70bdc62a 100644
--- a/src/libnm-core-impl/nm-setting-user.c
+++ b/src/libnm-core-impl/nm-setting-user.c
@@ -35,6 +35,8 @@ typedef struct {
  * NMSettingUser:
  *
  * General User Profile Settings
+ *
+ * Since: 1.8
  */
 struct _NMSettingUser {
     NMSetting            parent;
@@ -216,6 +218,8 @@ _create_data_hash(void)
  *
  * Returns: (array length=out_len) (transfer none): a
  *   %NULL-terminated array containing each key from the table.
+ *
+ * Since: 1.8
   **/
 const char *const *
 nm_setting_user_get_keys(NMSettingUser *setting, guint *out_len)
@@ -498,6 +502,8 @@ nm_setting_user_init(NMSettingUser *self)
  * Creates a new #NMSettingUser object with default values.
  *
  * Returns: the new empty #NMSettingUser object
+ *
+ * Since: 1.8
  **/
 NMSetting *
 nm_setting_user_new(void)
diff --git a/src/libnm-core-impl/nm-setting-vpn.c b/src/libnm-core-impl/nm-setting-vpn.c
index 42f75fa2..7e6f18dd 100644
--- a/src/libnm-core-impl/nm-setting-vpn.c
+++ b/src/libnm-core-impl/nm-setting-vpn.c
@@ -147,6 +147,8 @@ nm_setting_vpn_get_user_name(NMSettingVpn *setting)
  * @setting: the #NMSettingVpn
  *
  * Returns: the #NMSettingVpn:persistent property of the setting
+ *
+ * Since: 1.42, 1.40.4
  **/
 gboolean
 nm_setting_vpn_get_persistent(NMSettingVpn *setting)
diff --git a/src/libnm-core-impl/nm-setting-wireguard.c b/src/libnm-core-impl/nm-setting-wireguard.c
index ad0f01d5..599ded3c 100644
--- a/src/libnm-core-impl/nm-setting-wireguard.c
+++ b/src/libnm-core-impl/nm-setting-wireguard.c
@@ -1437,7 +1437,7 @@ _peers_clear(NMSettingWireGuardPrivate *priv)
 }
 
 /**
- * nm_setting_wireguard_:
+ * nm_setting_wireguard_clear_peers:
  * @self: the #NMSettingWireGuard instance
  *
  * Returns: the number of cleared peers.
diff --git a/src/libnm-core-impl/nm-setting-wireless-security.c b/src/libnm-core-impl/nm-setting-wireless-security.c
index d9c5afb8..ebefd504 100644
--- a/src/libnm-core-impl/nm-setting-wireless-security.c
+++ b/src/libnm-core-impl/nm-setting-wireless-security.c
@@ -561,7 +561,7 @@ nm_setting_wireless_security_clear_groups(NMSettingWirelessSecurity *setting)
     _notify(setting, PROP_GROUP);
 }
 
-/*
+/**
  * nm_setting_wireless_security_get_pmf:
  * @setting: the #NMSettingWirelessSecurity
  *
@@ -798,7 +798,7 @@ nm_setting_wireless_security_get_wps_method(NMSettingWirelessSecurity *setting)
     return NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE(setting)->wps_method;
 }
 
-/*
+/**
  * nm_setting_wireless_security_get_fils:
  * @setting: the #NMSettingWirelessSecurity
  *
diff --git a/src/libnm-core-impl/nm-setting-wpan.c b/src/libnm-core-impl/nm-setting-wpan.c
index 9e25dd16..a3e56ded 100644
--- a/src/libnm-core-impl/nm-setting-wpan.c
+++ b/src/libnm-core-impl/nm-setting-wpan.c
@@ -53,6 +53,8 @@ typedef struct {
  * NMSettingWpan:
  *
  * IEEE 802.15.4 (WPAN) MAC Settings
+ *
+ * Since: 1.14
  */
 struct _NMSettingWpan {
     NMSetting parent;
@@ -75,7 +77,7 @@ G_DEFINE_TYPE(NMSettingWpan, nm_setting_wpan, NM_TYPE_SETTING)
  *
  * Returns: the #NMSettingWpan:mac-address property of the setting
  *
- * Since: 1.14
+ * Since: 1.42, 1.40.4
  **/
 const char *
 nm_setting_wpan_get_mac_address(NMSettingWpan *setting)
@@ -91,7 +93,7 @@ nm_setting_wpan_get_mac_address(NMSettingWpan *setting)
  *
  * Returns: the #NMSettingWpan:pan-id property of the setting
  *
- * Since: 1.14
+ * Since: 1.42, 1.40.4
  **/
 guint16
 nm_setting_wpan_get_pan_id(NMSettingWpan *setting)
@@ -107,7 +109,7 @@ nm_setting_wpan_get_pan_id(NMSettingWpan *setting)
  *
  * Returns: the #NMSettingWpan:short-address property of the setting
  *
- * Since: 1.14
+ * Since: 1.42, 1.40.4
  **/
 guint16
 nm_setting_wpan_get_short_address(NMSettingWpan *setting)
@@ -123,7 +125,7 @@ nm_setting_wpan_get_short_address(NMSettingWpan *setting)
  *
  * Returns: the #NMSettingWpan:page property of the setting
  *
- * Since: 1.16
+ * Since: 1.42, 1.40.4
  **/
 gint16
 nm_setting_wpan_get_page(NMSettingWpan *setting)
@@ -139,7 +141,7 @@ nm_setting_wpan_get_page(NMSettingWpan *setting)
  *
  * Returns: the #NMSettingWpan:channel property of the setting
  *
- * Since: 1.16
+ * Since: 1.42, 1.40.4
  **/
 gint16
 nm_setting_wpan_get_channel(NMSettingWpan *setting)
@@ -211,7 +213,7 @@ nm_setting_wpan_init(NMSettingWpan *setting)
  *
  * Returns: (transfer full): the new empty #NMSettingWpan object
  *
- * Since: 1.14
+ * Since: 1.42, 1.40.4
  **/
 NMSetting *
 nm_setting_wpan_new(void)
diff --git a/src/libnm-core-impl/nm-setting.c b/src/libnm-core-impl/nm-setting.c
index 35070bae..b6f72137 100644
--- a/src/libnm-core-impl/nm-setting.c
+++ b/src/libnm-core-impl/nm-setting.c
@@ -30,6 +30,20 @@
 
 /*****************************************************************************/
 
+/*
+ * We use literal numbers in the header (as opposed to e.g.
+ * (1 << (1 + G_PARAM_USER_SHIFT))), because g-ir-scanner sometimes gets
+ * confused by unknown tokens and silently treats them as zero:
+ * https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/366
+ */
+
+G_STATIC_ASSERT(G_PARAM_USER_SHIFT == 8);
+G_STATIC_ASSERT(NM_SETTING_PARAM_REQUIRED == (1 << (1 + G_PARAM_USER_SHIFT)));
+G_STATIC_ASSERT(NM_SETTING_PARAM_SECRET == (1 << (2 + G_PARAM_USER_SHIFT)));
+G_STATIC_ASSERT(NM_SETTING_PARAM_FUZZY_IGNORE == (1 << (3 + G_PARAM_USER_SHIFT)));
+
+/*****************************************************************************/
+
 typedef struct {
     GHashTable  *hash;
     const char **names;
@@ -3847,7 +3861,7 @@ nm_setting_option_clear_by_name(NMSetting *setting, NMUtilsPredicateStr predicat
  * Returns: (transfer none): the #GVariant or %NULL if the option
  *   is not set.
  *
- * Since: 1.26.
+ * Since: 1.26
  */
 GVariant *
 nm_setting_option_get(NMSetting *setting, const char *opt_name)
diff --git a/src/libnm-core-impl/nm-utils.c b/src/libnm-core-impl/nm-utils.c
index 3c4cbc65..be6ad4de 100644
--- a/src/libnm-core-impl/nm-utils.c
+++ b/src/libnm-core-impl/nm-utils.c
@@ -1942,6 +1942,8 @@ next:
  * include additional attributes.
  *
  * Returns: (transfer none): a new floating #GVariant representing @addresses.
+ *
+ * Since: 1.42, 1.40.4
  **/
 GVariant *
 nm_utils_ip_addresses_to_variant(GPtrArray *addresses)
@@ -1995,6 +1997,8 @@ nm_utils_ip_addresses_to_variant(GPtrArray *addresses)
  *
  * Returns: (transfer full) (element-type NMIPAddress): a newly allocated
  *   #GPtrArray of #NMIPAddress objects
+ *
+ * Since: 1.42, 1.40.4
  **/
 GPtrArray *
 nm_utils_ip_addresses_from_variant(GVariant *value, int family)
@@ -2054,6 +2058,8 @@ nm_utils_ip_addresses_from_variant(GVariant *value, int family)
  * prefix, next hop, metric, and additional attributes).
  *
  * Returns: (transfer none): a new floating #GVariant representing @routes.
+ *
+ * Since: 1.42, 1.40.4
  **/
 GVariant *
 nm_utils_ip_routes_to_variant(GPtrArray *routes)
@@ -2120,6 +2126,8 @@ nm_utils_ip_routes_to_variant(GPtrArray *routes)
  *
  * Returns: (transfer full) (element-type NMIPRoute): a newly allocated
  *   #GPtrArray of #NMIPRoute objects
+ *
+ * Since: 1.42, 1.40.4
  **/
 GPtrArray *
 nm_utils_ip_routes_from_variant(GVariant *value, int family)
@@ -4314,6 +4322,8 @@ nm_utils_is_valid_iface_name_utf8safe(const char *utf8safe_name)
  *
  * Before 1.20, this function did not accept %NULL as @name argument. If you
  *   want to run against older versions of libnm, don't pass %NULL.
+ *
+ * Since: 1.6
  */
 gboolean
 nm_utils_is_valid_iface_name(const char *name, GError **error)
@@ -5249,7 +5259,7 @@ next:
     return g_steal_pointer(&ht);
 }
 
-/*
+/**
  * nm_utils_format_variant_attributes:
  * @attributes: (element-type utf8 GVariant): a #GHashTable mapping attribute names to #GVariant values
  * @attr_separator: the attribute separator character
@@ -5275,8 +5285,8 @@ nm_utils_format_variant_attributes(GHashTable *attributes,
 
 /*****************************************************************************/
 
-/*
- * nm_utils_get_timestamp_msec():
+/**
+ * nm_utils_get_timestamp_msec:
  *
  * Gets current time in milliseconds of CLOCK_BOOTTIME.
  *
@@ -5314,7 +5324,7 @@ nm_utils_get_timestamp_msec(void)
  * Returns: the version ID of the libnm version. That is, the %NM_VERSION
  *   at runtime.
  *
- * Since: 1.6.0
+ * Since: 1.6
  */
 guint
 nm_utils_version(void)
diff --git a/src/libnm-core-impl/nm-vpn-editor-plugin.c b/src/libnm-core-impl/nm-vpn-editor-plugin.c
index 225f25ef..3a6abbc2 100644
--- a/src/libnm-core-impl/nm-vpn-editor-plugin.c
+++ b/src/libnm-core-impl/nm-vpn-editor-plugin.c
@@ -470,8 +470,20 @@ nm_vpn_editor_plugin_import(NMVpnEditorPlugin *plugin, const char *path, GError
     g_return_val_if_fail(NM_IS_VPN_EDITOR_PLUGIN(plugin), NULL);
 
     if (nm_vpn_editor_plugin_get_capabilities(plugin) & NM_VPN_EDITOR_PLUGIN_CAPABILITY_IMPORT) {
+        gs_free_error GError *error2 = NULL;
+
         g_return_val_if_fail(NM_VPN_EDITOR_PLUGIN_GET_INTERFACE(plugin)->import_from_file != NULL,
                              NULL);
+
+        if (!error) {
+            /* Some VPN plugins crash if error argument is omitted. Work around that
+             * in libnm by always requesting an error.
+             *
+             * https://gitlab.gnome.org/GNOME/NetworkManager-vpnc/-/blob/c7d197477c94c5bae0396f0ef826db4d835e487d/properties/nm-vpnc-editor-plugin.c#L281
+             **/
+            error = &error2;
+        }
+
         return NM_VPN_EDITOR_PLUGIN_GET_INTERFACE(plugin)->import_from_file(plugin, path, error);
     }
 
diff --git a/src/libnm-core-impl/nm-vpn-plugin-info.c b/src/libnm-core-impl/nm-vpn-plugin-info.c
index 473063fb..baa19347 100644
--- a/src/libnm-core-impl/nm-vpn-plugin-info.c
+++ b/src/libnm-core-impl/nm-vpn-plugin-info.c
@@ -898,7 +898,7 @@ nm_vpn_plugin_info_get_program(NMVpnPluginInfo *self)
  *
  * Returns: %TRUE if the service supports multiple instances with different bus names, otherwise %FALSE
  *
- * Since: 1.2
+ * Since: 1.42, 1.40.4
  */
 gboolean
 nm_vpn_plugin_info_supports_multiple(NMVpnPluginInfo *self)
diff --git a/src/libnm-core-impl/tests/test-general.c b/src/libnm-core-impl/tests/test-general.c
index 64b3dca7..a21f50db 100644
--- a/src/libnm-core-impl/tests/test-general.c
+++ b/src/libnm-core-impl/tests/test-general.c
@@ -3139,6 +3139,9 @@ test_setting_new_from_dbus_bad(void)
                  NULL);
     nm_connection_add_setting(conn, setting);
 
+    /* Test assignment of same setting again. */
+    nm_connection_add_setting(conn, g_object_ref(setting));
+
     setting = nm_setting_wireless_new();
     ssid    = g_bytes_new("my-ssid", 7);
     g_object_set(setting,
diff --git a/src/libnm-core-public/nm-connection.h b/src/libnm-core-public/nm-connection.h
index 93061f25..47004ce8 100644
--- a/src/libnm-core-public/nm-connection.h
+++ b/src/libnm-core-public/nm-connection.h
@@ -220,12 +220,13 @@ NMSettingMacsec *nm_connection_get_setting_macsec(NMConnection *connection);
 NM_AVAILABLE_IN_1_2
 NMSettingMacvlan  *nm_connection_get_setting_macvlan(NMConnection *connection);
 NMSettingOlpcMesh *nm_connection_get_setting_olpc_mesh(NMConnection *connection);
-NM_AVAILABLE_IN_1_10
+NM_AVAILABLE_IN_1_14
 NMSettingOvsBridge *nm_connection_get_setting_ovs_bridge(NMConnection *connection);
-NM_AVAILABLE_IN_1_10
+NM_AVAILABLE_IN_1_14
 NMSettingOvsInterface *nm_connection_get_setting_ovs_interface(NMConnection *connection);
-NMSettingOvsPatch     *nm_connection_get_setting_ovs_patch(NMConnection *connection);
-NM_AVAILABLE_IN_1_10
+NM_AVAILABLE_IN_1_14
+NMSettingOvsPatch *nm_connection_get_setting_ovs_patch(NMConnection *connection);
+NM_AVAILABLE_IN_1_14
 NMSettingOvsPort *nm_connection_get_setting_ovs_port(NMConnection *connection);
 NMSettingPpp     *nm_connection_get_setting_ppp(NMConnection *connection);
 NMSettingPppoe   *nm_connection_get_setting_pppoe(NMConnection *connection);
@@ -234,7 +235,7 @@ NMSettingProxy  *nm_connection_get_setting_proxy(NMConnection *connection);
 NMSettingSerial *nm_connection_get_setting_serial(NMConnection *connection);
 NM_AVAILABLE_IN_1_12
 NMSettingTCConfig *nm_connection_get_setting_tc_config(NMConnection *connection);
-NM_AVAILABLE_IN_1_2
+NM_AVAILABLE_IN_1_14
 NMSettingTun              *nm_connection_get_setting_tun(NMConnection *connection);
 NMSettingVpn              *nm_connection_get_setting_vpn(NMConnection *connection);
 NMSettingWimax            *nm_connection_get_setting_wimax(NMConnection *connection);
diff --git a/src/libnm-core-public/nm-dbus-interface.h b/src/libnm-core-public/nm-dbus-interface.h
index 4557dde0..6e1a84a1 100644
--- a/src/libnm-core-public/nm-dbus-interface.h
+++ b/src/libnm-core-public/nm-dbus-interface.h
@@ -103,6 +103,8 @@
  * The range 0x7000 - 0x7FFF of capabilities is guaranteed not to be
  * used by upstream NetworkManager. It could thus be used for downstream
  * extensions.
+ *
+ * Since: 1.6
  */
 typedef enum {
     NM_CAPABILITY_TEAM = 1,
@@ -967,7 +969,7 @@ typedef enum {
  *
  * The flags for CheckpointCreate call
  *
- * Since: 1.4 (gi flags generated since 1.12)
+ * Since: 1.12 (public since 1.4, g-ir since 1.12)
  */
 typedef enum /*< flags >*/ {
     NM_CHECKPOINT_CREATE_FLAG_NONE                       = 0,
diff --git a/src/libnm-core-public/nm-dbus-types.xml b/src/libnm-core-public/nm-dbus-types.xml
index cb72820d..52ac4981 100644
--- a/src/libnm-core-public/nm-dbus-types.xml
+++ b/src/libnm-core-public/nm-dbus-types.xml
@@ -18,7 +18,7 @@
     <indexterm zone="NMCapability">
       <primary>NMCapability</primary>
     </indexterm>
-    <para><para><link linkend="NMCapability">NMCapability</link> names the numbers in the Capabilities property. Capabilities are positive numbers. They are part of stable API and a certain capability number is guaranteed not to change.</para><para>The range 0x7000 - 0x7FFF of capabilities is guaranteed not to be used by upstream NetworkManager. It could thus be used for downstream extensions.</para><para></para></para>
+    <para><para><link linkend="NMCapability">NMCapability</link> names the numbers in the Capabilities property. Capabilities are positive numbers. They are part of stable API and a certain capability number is guaranteed not to change.</para><para>The range 0x7000 - 0x7FFF of capabilities is guaranteed not to be used by upstream NetworkManager. It could thus be used for downstream extensions.</para><para>Since: 1.6</para><para></para></para>
     <refsect3 role="enum_members">
       <title>Values</title>
       <informaltable role="enum_members_table" pgwide="1" frame="none">
@@ -1613,7 +1613,7 @@
     <indexterm zone="NMCheckpointCreateFlags">
       <primary>NMCheckpointCreateFlags</primary>
     </indexterm>
-    <para><para>The flags for CheckpointCreate call</para><para>Since: 1.4 (gi flags generated since 1.12)</para><para></para></para>
+    <para><para>The flags for CheckpointCreate call</para><para>Since: 1.12 (public since 1.4, g-ir since 1.12)</para><para></para></para>
     <refsect3 role="enum_members">
       <title>Values</title>
       <informaltable role="enum_members_table" pgwide="1" frame="none">
diff --git a/src/libnm-core-public/nm-setting-6lowpan.h b/src/libnm-core-public/nm-setting-6lowpan.h
index 358ccff6..ab2f7b44 100644
--- a/src/libnm-core-public/nm-setting-6lowpan.h
+++ b/src/libnm-core-public/nm-setting-6lowpan.h
@@ -33,10 +33,10 @@ typedef struct _NMSetting6LowpanClass NMSetting6LowpanClass;
 
 NM_AVAILABLE_IN_1_14
 GType nm_setting_6lowpan_get_type(void);
-NM_AVAILABLE_IN_1_14
+NM_AVAILABLE_IN_1_40_4
 NMSetting *nm_setting_6lowpan_new(void);
 
-NM_AVAILABLE_IN_1_14
+NM_AVAILABLE_IN_1_40_4
 const char *nm_setting_6lowpan_get_parent(NMSetting6Lowpan *setting);
 
 G_END_DECLS
diff --git a/src/libnm-core-public/nm-setting-connection.h b/src/libnm-core-public/nm-setting-connection.h
index 4b6ce17c..4f6653bf 100644
--- a/src/libnm-core-public/nm-setting-connection.h
+++ b/src/libnm-core-public/nm-setting-connection.h
@@ -73,6 +73,8 @@ G_BEGIN_DECLS
  *
  * #NMSettingConnectionAutoconnectSlaves values indicate whether slave connections
  * should be activated when master is activated.
+ *
+ * Since: 1.2
  */
 typedef enum {
     NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT = -1,
@@ -87,6 +89,8 @@ typedef enum {
  * @NM_SETTING_CONNECTION_LLDP_ENABLE_RX: enable reception of LLDP frames
  *
  * #NMSettingConnectionLldp values indicate whether LLDP should be enabled.
+ *
+ * Since: 1.2
  */
 typedef enum {
     NM_SETTING_CONNECTION_LLDP_DEFAULT   = -1,
@@ -217,7 +221,7 @@ NMSettingConnectionLlmnr nm_setting_connection_get_llmnr(NMSettingConnection *se
 NM_AVAILABLE_IN_1_34
 NMSettingConnectionDnsOverTls nm_setting_connection_get_dns_over_tls(NMSettingConnection *setting);
 
-NM_AVAILABLE_IN_1_40
+NM_AVAILABLE_IN_1_40_4
 NMMptcpFlags nm_setting_connection_get_mptcp_flags(NMSettingConnection *setting);
 
 NM_AVAILABLE_IN_1_20
diff --git a/src/libnm-core-public/nm-setting-hostname.h b/src/libnm-core-public/nm-setting-hostname.h
index f93e0efe..3fb71197 100644
--- a/src/libnm-core-public/nm-setting-hostname.h
+++ b/src/libnm-core-public/nm-setting-hostname.h
@@ -36,7 +36,7 @@ typedef struct _NMSettingHostnameClass NMSettingHostnameClass;
 
 NM_AVAILABLE_IN_1_30
 GType nm_setting_hostname_get_type(void);
-NM_AVAILABLE_IN_1_30
+NM_AVAILABLE_IN_1_40_4
 NMSetting *nm_setting_hostname_new(void);
 
 NM_AVAILABLE_IN_1_30
diff --git a/src/libnm-core-public/nm-setting-ip-config.h b/src/libnm-core-public/nm-setting-ip-config.h
index 6283ecc9..acbdec0f 100644
--- a/src/libnm-core-public/nm-setting-ip-config.h
+++ b/src/libnm-core-public/nm-setting-ip-config.h
@@ -480,7 +480,7 @@ NM_AVAILABLE_IN_1_2
 int nm_setting_ip_config_get_dhcp_timeout(NMSettingIPConfig *setting);
 NM_AVAILABLE_IN_1_34
 int nm_setting_ip_config_get_required_timeout(NMSettingIPConfig *setting);
-NM_AVAILABLE_IN_1_22
+NM_AVAILABLE_IN_1_40_4
 const char *nm_setting_ip_config_get_dhcp_iaid(NMSettingIPConfig *setting);
 
 NM_AVAILABLE_IN_1_22
diff --git a/src/libnm-core-public/nm-setting-ip-tunnel.h b/src/libnm-core-public/nm-setting-ip-tunnel.h
index 34920099..62472f11 100644
--- a/src/libnm-core-public/nm-setting-ip-tunnel.h
+++ b/src/libnm-core-public/nm-setting-ip-tunnel.h
@@ -43,7 +43,7 @@ G_BEGIN_DECLS
 
 typedef struct _NMSettingIPTunnelClass NMSettingIPTunnelClass;
 
-/*
+/**
  * NMIPTunnelFlags:
  * @NM_IP_TUNNEL_FLAG_NONE: no flag
  * @NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT: don't add encapsulation limit
@@ -94,9 +94,9 @@ NM_AVAILABLE_IN_1_2
 const char *nm_setting_ip_tunnel_get_input_key(NMSettingIPTunnel *setting);
 NM_AVAILABLE_IN_1_2
 const char *nm_setting_ip_tunnel_get_output_key(NMSettingIPTunnel *setting);
-NM_AVAILABLE_IN_1_2
+NM_AVAILABLE_IN_1_40_4
 guint nm_setting_ip_tunnel_get_encapsulation_limit(NMSettingIPTunnel *setting);
-NM_AVAILABLE_IN_1_2
+NM_AVAILABLE_IN_1_40_4
 guint nm_setting_ip_tunnel_get_flow_label(NMSettingIPTunnel *setting);
 NM_AVAILABLE_IN_1_2
 guint nm_setting_ip_tunnel_get_mtu(NMSettingIPTunnel *setting);
diff --git a/src/libnm-core-public/nm-setting-ip4-config.h b/src/libnm-core-public/nm-setting-ip4-config.h
index 7991d682..66c457b9 100644
--- a/src/libnm-core-public/nm-setting-ip4-config.h
+++ b/src/libnm-core-public/nm-setting-ip4-config.h
@@ -113,7 +113,7 @@ const char *nm_setting_ip4_config_get_dhcp_fqdn(NMSettingIP4Config *setting);
 NM_AVAILABLE_IN_1_28
 const char *nm_setting_ip4_config_get_dhcp_vendor_class_identifier(NMSettingIP4Config *setting);
 
-NM_AVAILABLE_IN_1_40
+NM_AVAILABLE_IN_1_40_4
 NMSettingIP4LinkLocal nm_setting_ip4_config_get_link_local(NMSettingIP4Config *setting);
 
 G_END_DECLS
diff --git a/src/libnm-core-public/nm-setting-macvlan.h b/src/libnm-core-public/nm-setting-macvlan.h
index 88ee81e7..25c41346 100644
--- a/src/libnm-core-public/nm-setting-macvlan.h
+++ b/src/libnm-core-public/nm-setting-macvlan.h
@@ -42,6 +42,8 @@ typedef struct _NMSettingMacvlanClass NMSettingMacvlanClass;
  * @NM_SETTING_MACVLAN_MODE_PRIVATE: private mode
  * @NM_SETTING_MACVLAN_MODE_PASSTHRU: passthru mode
  * @NM_SETTING_MACVLAN_MODE_SOURCE: source mode
+ *
+ * Since: 1.2
  **/
 typedef enum {
     NM_SETTING_MACVLAN_MODE_UNKNOWN  = 0,
diff --git a/src/libnm-core-public/nm-setting-ovs-bridge.h b/src/libnm-core-public/nm-setting-ovs-bridge.h
index 33e8dffb..bc7d7e9b 100644
--- a/src/libnm-core-public/nm-setting-ovs-bridge.h
+++ b/src/libnm-core-public/nm-setting-ovs-bridge.h
@@ -49,7 +49,7 @@ NM_AVAILABLE_IN_1_10
 gboolean nm_setting_ovs_bridge_get_rstp_enable(NMSettingOvsBridge *self);
 NM_AVAILABLE_IN_1_10
 gboolean nm_setting_ovs_bridge_get_stp_enable(NMSettingOvsBridge *self);
-NM_AVAILABLE_IN_1_20
+NM_AVAILABLE_IN_1_40_4
 const char *nm_setting_ovs_bridge_get_datapath_type(NMSettingOvsBridge *self);
 
 G_END_DECLS
diff --git a/src/libnm-core-public/nm-setting-sriov.h b/src/libnm-core-public/nm-setting-sriov.h
index 93afde98..0438e800 100644
--- a/src/libnm-core-public/nm-setting-sriov.h
+++ b/src/libnm-core-public/nm-setting-sriov.h
@@ -109,7 +109,7 @@ NM_AVAILABLE_IN_1_14
 const char **nm_sriov_vf_get_attribute_names(const NMSriovVF *vf);
 NM_AVAILABLE_IN_1_14
 GVariant *nm_sriov_vf_get_attribute(const NMSriovVF *vf, const char *name);
-NM_AVAILABLE_IN_1_14
+NM_AVAILABLE_IN_1_40_4
 gboolean
 nm_sriov_vf_attribute_validate(const char *name, GVariant *value, gboolean *known, GError **error);
 
diff --git a/src/libnm-core-public/nm-setting-tc-config.h b/src/libnm-core-public/nm-setting-tc-config.h
index abd61683..ab1a9909 100644
--- a/src/libnm-core-public/nm-setting-tc-config.h
+++ b/src/libnm-core-public/nm-setting-tc-config.h
@@ -102,9 +102,9 @@ NM_AVAILABLE_IN_1_12
 void nm_tc_tfilter_set_handle(NMTCTfilter *tfilter, guint32 handle);
 NM_AVAILABLE_IN_1_12
 guint32 nm_tc_tfilter_get_parent(NMTCTfilter *tfilter);
-NM_AVAILABLE_IN_1_12
+NM_AVAILABLE_IN_1_40_4
 NMTCAction *nm_tc_tfilter_get_action(NMTCTfilter *tfilter);
-NM_AVAILABLE_IN_1_12
+NM_AVAILABLE_IN_1_40_4
 void nm_tc_tfilter_set_action(NMTCTfilter *tfilter, NMTCAction *action);
 
 #define NM_TYPE_SETTING_TC_CONFIG (nm_setting_tc_config_get_type())
diff --git a/src/libnm-core-public/nm-setting-team.h b/src/libnm-core-public/nm-setting-team.h
index 63df4080..2e16ee20 100644
--- a/src/libnm-core-public/nm-setting-team.h
+++ b/src/libnm-core-public/nm-setting-team.h
@@ -25,6 +25,8 @@ G_BEGIN_DECLS
  *    option 'validate_inactive' is enabled (set to true).
  * @NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS: the arp_ping link watcher option
  *    'send_always' is enabled (set to true).
+ *
+ * Since: 1.12
  */
 typedef enum /*< flags >*/ {
     NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE              = 0, /*< skip >*/
diff --git a/src/libnm-core-public/nm-setting-tun.h b/src/libnm-core-public/nm-setting-tun.h
index 8f808410..3575c644 100644
--- a/src/libnm-core-public/nm-setting-tun.h
+++ b/src/libnm-core-public/nm-setting-tun.h
@@ -39,6 +39,8 @@ G_BEGIN_DECLS
  * @NM_SETTING_TUN_MODE_TAP: a TAP device
  *
  * #NMSettingTunMode values indicate the device type (TUN/TAP)
+ *
+ * Since: 1.2
  */
 typedef enum {
     NM_SETTING_TUN_MODE_UNKNOWN = 0,
diff --git a/src/libnm-core-public/nm-setting-vpn.h b/src/libnm-core-public/nm-setting-vpn.h
index 151a293a..a00fa975 100644
--- a/src/libnm-core-public/nm-setting-vpn.h
+++ b/src/libnm-core-public/nm-setting-vpn.h
@@ -49,7 +49,9 @@ GType nm_setting_vpn_get_type(void);
 NMSetting  *nm_setting_vpn_new(void);
 const char *nm_setting_vpn_get_service_type(NMSettingVpn *setting);
 const char *nm_setting_vpn_get_user_name(NMSettingVpn *setting);
-gboolean    nm_setting_vpn_get_persistent(NMSettingVpn *setting);
+
+NM_AVAILABLE_IN_1_40_4
+gboolean nm_setting_vpn_get_persistent(NMSettingVpn *setting);
 
 guint32     nm_setting_vpn_get_num_data_items(NMSettingVpn *setting);
 void        nm_setting_vpn_add_data_item(NMSettingVpn *setting, const char *key, const char *item);
diff --git a/src/libnm-core-public/nm-setting-wireless-security.h b/src/libnm-core-public/nm-setting-wireless-security.h
index e564204b..b9fea123 100644
--- a/src/libnm-core-public/nm-setting-wireless-security.h
+++ b/src/libnm-core-public/nm-setting-wireless-security.h
@@ -74,6 +74,8 @@ typedef enum {
  * @NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED: require PMF and fail if not available
  *
  * These flags indicate whether PMF must be enabled.
+ *
+ * Since: 1.10
  **/
 typedef enum {
     NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT  = 0,
diff --git a/src/libnm-core-public/nm-setting-wireless.h b/src/libnm-core-public/nm-setting-wireless.h
index 1f94060c..bb158112 100644
--- a/src/libnm-core-public/nm-setting-wireless.h
+++ b/src/libnm-core-public/nm-setting-wireless.h
@@ -132,6 +132,8 @@ typedef enum /*< flags >*/ {
  * @NM_SETTING_WIRELESS_POWERSAVE_ENABLE: enable powersave
  *
  * These flags indicate whether wireless powersave must be enabled.
+ *
+ * Since: 1.2
  **/
 typedef enum {
     NM_SETTING_WIRELESS_POWERSAVE_DEFAULT = 0,
diff --git a/src/libnm-core-public/nm-setting-wpan.h b/src/libnm-core-public/nm-setting-wpan.h
index 883b77e1..934ab196 100644
--- a/src/libnm-core-public/nm-setting-wpan.h
+++ b/src/libnm-core-public/nm-setting-wpan.h
@@ -38,18 +38,18 @@ typedef struct _NMSettingWpanClass NMSettingWpanClass;
 
 NM_AVAILABLE_IN_1_14
 GType nm_setting_wpan_get_type(void);
-NM_AVAILABLE_IN_1_14
+NM_AVAILABLE_IN_1_40_4
 NMSetting *nm_setting_wpan_new(void);
 
-NM_AVAILABLE_IN_1_14
+NM_AVAILABLE_IN_1_40_4
 const char *nm_setting_wpan_get_mac_address(NMSettingWpan *setting);
-NM_AVAILABLE_IN_1_14
+NM_AVAILABLE_IN_1_40_4
 guint16 nm_setting_wpan_get_pan_id(NMSettingWpan *setting);
-NM_AVAILABLE_IN_1_14
+NM_AVAILABLE_IN_1_40_4
 guint16 nm_setting_wpan_get_short_address(NMSettingWpan *setting);
-NM_AVAILABLE_IN_1_16
+NM_AVAILABLE_IN_1_40_4
 gint16 nm_setting_wpan_get_page(NMSettingWpan *setting);
-NM_AVAILABLE_IN_1_16
+NM_AVAILABLE_IN_1_40_4
 gint16 nm_setting_wpan_get_channel(NMSettingWpan *setting);
 
 G_END_DECLS
diff --git a/src/libnm-core-public/nm-setting.h b/src/libnm-core-public/nm-setting.h
index ee2076c3..ae898458 100644
--- a/src/libnm-core-public/nm-setting.h
+++ b/src/libnm-core-public/nm-setting.h
@@ -24,15 +24,15 @@ G_BEGIN_DECLS
     (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_SETTING, NMSettingClass))
 
 /* The property of the #NMSetting is required for the setting to be valid */
-#define NM_SETTING_PARAM_REQUIRED (1 << (1 + G_PARAM_USER_SHIFT))
+#define NM_SETTING_PARAM_REQUIRED 0x200
 
 /* The property of the #NMSetting is a secret */
-#define NM_SETTING_PARAM_SECRET (1 << (2 + G_PARAM_USER_SHIFT))
+#define NM_SETTING_PARAM_SECRET 0x400
 
 /* The property of the #NMSetting should be ignored during comparisons that
  * use the %NM_SETTING_COMPARE_FLAG_FUZZY flag.
  */
-#define NM_SETTING_PARAM_FUZZY_IGNORE (1 << (3 + G_PARAM_USER_SHIFT))
+#define NM_SETTING_PARAM_FUZZY_IGNORE 0x800
 
 /* Note: all non-glib GParamFlags bits are reserved by NetworkManager */
 
@@ -122,6 +122,8 @@ typedef enum {
  * @NM_SETTING_MAC_RANDOMIZATION_ALWAYS: a random MAC address is used.
  *
  * Controls if and how the MAC address of a device is randomzied.
+ *
+ * Since: 1.2
  **/
 typedef enum {
     NM_SETTING_MAC_RANDOMIZATION_DEFAULT = 0,
diff --git a/src/libnm-core-public/nm-utils.h b/src/libnm-core-public/nm-utils.h
index 5faed75a..dc89f234 100644
--- a/src/libnm-core-public/nm-utils.h
+++ b/src/libnm-core-public/nm-utils.h
@@ -104,9 +104,13 @@ GPtrArray *nm_utils_ip6_addresses_from_variant(GVariant *value, char **out_gatew
 GVariant  *nm_utils_ip6_routes_to_variant(GPtrArray *routes);
 GPtrArray *nm_utils_ip6_routes_from_variant(GVariant *value);
 
-GVariant  *nm_utils_ip_addresses_to_variant(GPtrArray *addresses);
+NM_AVAILABLE_IN_1_40_4
+GVariant *nm_utils_ip_addresses_to_variant(GPtrArray *addresses);
+NM_AVAILABLE_IN_1_40_4
 GPtrArray *nm_utils_ip_addresses_from_variant(GVariant *value, int family);
-GVariant  *nm_utils_ip_routes_to_variant(GPtrArray *routes);
+NM_AVAILABLE_IN_1_40_4
+GVariant *nm_utils_ip_routes_to_variant(GPtrArray *routes);
+NM_AVAILABLE_IN_1_40_4
 GPtrArray *nm_utils_ip_routes_from_variant(GVariant *value, int family);
 
 char *nm_utils_uuid_generate(void);
diff --git a/src/libnm-core-public/nm-version-macros.h b/src/libnm-core-public/nm-version-macros.h
index edd872e8..4dce57f6 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 (2)
+#define NM_MICRO_VERSION (4)
 
 /**
  * NM_CHECK_VERSION:
@@ -72,6 +72,7 @@
 #define NM_VERSION_1_36   (NM_ENCODE_VERSION (1, 36, 0))
 #define NM_VERSION_1_38   (NM_ENCODE_VERSION (1, 38, 0))
 #define NM_VERSION_1_40   (NM_ENCODE_VERSION (1, 40, 0))
+#define NM_VERSION_1_40_4 (NM_ENCODE_VERSION (1, 40, 4))
 
 /* For releases, NM_API_VERSION is equal to NM_VERSION.
  *
diff --git a/src/libnm-core-public/nm-version-macros.h.in b/src/libnm-core-public/nm-version-macros.h.in
index 07e79899..fc854aef 100644
--- a/src/libnm-core-public/nm-version-macros.h.in
+++ b/src/libnm-core-public/nm-version-macros.h.in
@@ -72,6 +72,7 @@
 #define NM_VERSION_1_36   (NM_ENCODE_VERSION (1, 36, 0))
 #define NM_VERSION_1_38   (NM_ENCODE_VERSION (1, 38, 0))
 #define NM_VERSION_1_40   (NM_ENCODE_VERSION (1, 40, 0))
+#define NM_VERSION_1_40_4 (NM_ENCODE_VERSION (1, 40, 4))
 
 /* For releases, NM_API_VERSION is equal to NM_VERSION.
  *
diff --git a/src/libnm-core-public/nm-version.h b/src/libnm-core-public/nm-version.h
index 9f6e3e78..d9f9a121 100644
--- a/src/libnm-core-public/nm-version.h
+++ b/src/libnm-core-public/nm-version.h
@@ -341,6 +341,12 @@
 #define NM_AVAILABLE_IN_1_40
 #endif
 
+#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_40_4
+#define NM_AVAILABLE_IN_1_40_4 G_UNAVAILABLE(1, 40.4)
+#else
+#define NM_AVAILABLE_IN_1_40_4
+#endif
+
 /*
  * Synchronous API for calling D-Bus in libnm is deprecated. See
  * https://networkmanager.dev/docs/libnm/latest/usage.html#sync-api
diff --git a/src/libnm-core-public/nm-vpn-plugin-info.h b/src/libnm-core-public/nm-vpn-plugin-info.h
index aa319a57..167af52c 100644
--- a/src/libnm-core-public/nm-vpn-plugin-info.h
+++ b/src/libnm-core-public/nm-vpn-plugin-info.h
@@ -62,7 +62,7 @@ NM_AVAILABLE_IN_1_4
 const char *nm_vpn_plugin_info_get_auth_dialog(NMVpnPluginInfo *self);
 NM_AVAILABLE_IN_1_4
 gboolean nm_vpn_plugin_info_supports_hints(NMVpnPluginInfo *self);
-NM_AVAILABLE_IN_1_2
+NM_AVAILABLE_IN_1_40_4
 gboolean nm_vpn_plugin_info_supports_multiple(NMVpnPluginInfo *self);
 NM_AVAILABLE_IN_1_4
 const char *const *nm_vpn_plugin_info_get_aliases(NMVpnPluginInfo *self);
diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c
index d06aa9cd..6609a7d5 100644
--- a/src/libnm-platform/nmp-object.c
+++ b/src/libnm-platform/nmp-object.c
@@ -1318,10 +1318,9 @@ nmp_object_copy(NMPObject *dst, const NMPObject *src, gboolean id_only)
 
         g_return_if_fail(klass == NMP_OBJECT_GET_CLASS(src));
 
-        if (id_only) {
-            if (klass->cmd_plobj_id_copy)
-                klass->cmd_plobj_id_copy(&dst->object, &src->object);
-        } else if (klass->cmd_obj_copy)
+        if (id_only && klass->cmd_plobj_id_copy)
+            klass->cmd_plobj_id_copy(&dst->object, &src->object);
+        else if (klass->cmd_obj_copy)
             klass->cmd_obj_copy(dst, src);
         else
             memcpy(&dst->object, &src->object, klass->sizeof_data);
diff --git a/src/libnm-std-aux/nm-std-aux.h b/src/libnm-std-aux/nm-std-aux.h
index 77243ab1..d49f7c43 100644
--- a/src/libnm-std-aux/nm-std-aux.h
+++ b/src/libnm-std-aux/nm-std-aux.h
@@ -170,8 +170,8 @@ typedef uint64_t _nm_bitwise nm_be64_t;
 #define NM_LIKELY(expr)   (__builtin_expect(NM_BOOLEAN_EXPR(expr), 1))
 #define NM_UNLIKELY(expr) (__builtin_expect(NM_BOOLEAN_EXPR(expr), 0))
 #else
-#define NM_LIKELY(expr)   NM_BOOLEAN_EXPR(expr)
-#define NM_UNLIKELY(expr) NM_BOOLEAN_EXPR(expr)
+#define NM_LIKELY(expr)   (NM_BOOLEAN_EXPR(expr))
+#define NM_UNLIKELY(expr) (NM_BOOLEAN_EXPR(expr))
 #endif
 
 /*****************************************************************************/
diff --git a/src/libnmc-setting/settings-docs-input.xml b/src/libnmc-setting/settings-docs-input.xml
index d9ce0e2d..77643955 100644
--- a/src/libnmc-setting/settings-docs-input.xml
+++ b/src/libnmc-setting/settings-docs-input.xml
@@ -132,9 +132,7 @@
 
  This property is currently not implemented for DHCPv6.</description></property><property name="dhcp-send-hostname" name_upper="DHCP_SEND_HOSTNAME" type="boolean" default="TRUE"><description-docbook><para> If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the "dhcp-hostname" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.</para></description-docbook><description> If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the "dhcp-hostname" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.</description></property><property name="dhcp-timeout" name_upper="DHCP_TIMEOUT" type="int32" default="0"><description-docbook><para> A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds).</para><para> Set to 2147483647 (MAXINT32) for infinity.</para></description-docbook><description> A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds).
 
- Set to 2147483647 (MAXINT32) for infinity.</description></property><property name="dhcp-vendor-class-identifier" name_upper="DHCP_VENDOR_CLASS_IDENTIFIER" type="string"><description-docbook><para> The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server.</para><para> Since 1.28</para></description-docbook><description> The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server.
-
- Since 1.28</description></property><property name="dns" name_upper="DNS" type="array of uint32"><description-docbook><para> Array of IP addresses of DNS servers.</para></description-docbook><description> Array of IP addresses of DNS servers.</description></property><property name="dns-options" name_upper="DNS_OPTIONS" type="array of string"><description-docbook><para> Array of DNS options as described in man 5 resolv.conf.</para><para> NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.</para><para> The currently supported options are "attempts", "debug", "edns0", "inet6", "ip6-bytestring", "ip6-dotint", "ndots", "no-check-names", "no-ip6-dotint", "no-reload", "no-tld-query", "rotate", "single-request", "single-request-reopen", "timeout", "trust-ad", "use-vc".</para><para> The "trust-ad" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have "trust-ad" enabled.</para><para> When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then "edns0" and "trust-ad" are automatically added.</para></description-docbook><description> Array of DNS options as described in man 5 resolv.conf.
+ Set to 2147483647 (MAXINT32) for infinity.</description></property><property name="dhcp-vendor-class-identifier" name_upper="DHCP_VENDOR_CLASS_IDENTIFIER" type="string"><description-docbook><para> The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server.</para></description-docbook><description> The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server.</description></property><property name="dns" name_upper="DNS" type="array of uint32"><description-docbook><para> Array of IP addresses of DNS servers.</para></description-docbook><description> Array of IP addresses of DNS servers.</description></property><property name="dns-options" name_upper="DNS_OPTIONS" type="array of string"><description-docbook><para> Array of DNS options as described in man 5 resolv.conf.</para><para> NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.</para><para> The currently supported options are "attempts", "debug", "edns0", "inet6", "ip6-bytestring", "ip6-dotint", "ndots", "no-check-names", "no-ip6-dotint", "no-reload", "no-tld-query", "rotate", "single-request", "single-request-reopen", "timeout", "trust-ad", "use-vc".</para><para> The "trust-ad" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have "trust-ad" enabled.</para><para> When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then "edns0" and "trust-ad" are automatically added.</para></description-docbook><description> Array of DNS options as described in man 5 resolv.conf.
 
  NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.
 
@@ -164,11 +162,9 @@
 
  Setting the gateway causes NetworkManager to configure a standard default route with the gateway as next hop. This is ignored if "never-default" is set. An alternative is to configure the default route explicitly with a manual route and /0 as prefix length.
 
- Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See "ip4-auto-default-route".</description></property><property name="ignore-auto-dns" name_upper="IGNORE_AUTO_DNS" type="boolean" default="FALSE"><description-docbook><para> When "method" is set to "auto" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the "dns" and "dns-search" properties, if any, are used.</para></description-docbook><description> When "method" is set to "auto" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the "dns" and "dns-search" properties, if any, are used.</description></property><property name="ignore-auto-routes" name_upper="IGNORE_AUTO_ROUTES" type="boolean" default="FALSE"><description-docbook><para> When "method" is set to "auto" and this property to TRUE, automatically configured routes are ignored and only routes specified in the "routes" property, if any, are used.</para></description-docbook><description> When "method" is set to "auto" and this property to TRUE, automatically configured routes are ignored and only routes specified in the "routes" property, if any, are used.</description></property><property name="link-local" name_upper="LINK_LOCAL" type="int32" default="0"><description-docbook><para> Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server.</para><para> When set to "auto", the value is dependent on "ipv4.method". When set to "default", it honors the global connection default, before falling back to "auto". Note that if "ipv4.method" is "disabled", then link local addressing is always disabled too. The default is "default".</para><para> Since 1.40</para></description-docbook><description> Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server.
-
- When set to "auto", the value is dependent on "ipv4.method". When set to "default", it honors the global connection default, before falling back to "auto". Note that if "ipv4.method" is "disabled", then link local addressing is always disabled too. The default is "default".
+ Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See "ip4-auto-default-route".</description></property><property name="ignore-auto-dns" name_upper="IGNORE_AUTO_DNS" type="boolean" default="FALSE"><description-docbook><para> When "method" is set to "auto" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the "dns" and "dns-search" properties, if any, are used.</para></description-docbook><description> When "method" is set to "auto" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the "dns" and "dns-search" properties, if any, are used.</description></property><property name="ignore-auto-routes" name_upper="IGNORE_AUTO_ROUTES" type="boolean" default="FALSE"><description-docbook><para> When "method" is set to "auto" and this property to TRUE, automatically configured routes are ignored and only routes specified in the "routes" property, if any, are used.</para></description-docbook><description> When "method" is set to "auto" and this property to TRUE, automatically configured routes are ignored and only routes specified in the "routes" property, if any, are used.</description></property><property name="link-local" name_upper="LINK_LOCAL" type="int32" default="0"><description-docbook><para> Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server.</para><para> When set to "auto", the value is dependent on "ipv4.method". When set to "default", it honors the global connection default, before falling back to "auto". Note that if "ipv4.method" is "disabled", then link local addressing is always disabled too. The default is "default".</para></description-docbook><description> Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server.
 
- Since 1.40</description></property><property name="may-fail" name_upper="MAY_FAIL" type="boolean" default="TRUE"><description-docbook><para> If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out.  Note that at least one IP configuration must succeed or overall network configuration will still fail.  For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.</para></description-docbook><description> If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out.  Note that at least one IP configuration must succeed or overall network configuration will still fail.  For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.</description></property><property name="method" name_upper="METHOD" type="string"><description-docbook><para> IP configuration method.</para><para> NMSettingIP4Config and NMSettingIP6Config both support "disabled", "auto", "manual", and "link-local". See the subclass-specific documentation for other values.</para><para> In general, for the "auto" method, properties such as "dns" and "routes" specify information that is added on to the information returned from automatic configuration.  The "ignore-auto-routes" and "ignore-auto-dns" properties modify this behavior.</para><para> For methods that imply no upstream network, such as "shared" or "link-local", these properties must be empty.</para><para> For IPv4 method "shared", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.</para></description-docbook><description> IP configuration method.
+ When set to "auto", the value is dependent on "ipv4.method". When set to "default", it honors the global connection default, before falling back to "auto". Note that if "ipv4.method" is "disabled", then link local addressing is always disabled too. The default is "default".</description></property><property name="may-fail" name_upper="MAY_FAIL" type="boolean" default="TRUE"><description-docbook><para> If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out.  Note that at least one IP configuration must succeed or overall network configuration will still fail.  For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.</para></description-docbook><description> If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out.  Note that at least one IP configuration must succeed or overall network configuration will still fail.  For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.</description></property><property name="method" name_upper="METHOD" type="string"><description-docbook><para> IP configuration method.</para><para> NMSettingIP4Config and NMSettingIP6Config both support "disabled", "auto", "manual", and "link-local". See the subclass-specific documentation for other values.</para><para> In general, for the "auto" method, properties such as "dns" and "routes" specify information that is added on to the information returned from automatic configuration.  The "ignore-auto-routes" and "ignore-auto-dns" properties modify this behavior.</para><para> For methods that imply no upstream network, such as "shared" or "link-local", these properties must be empty.</para><para> For IPv4 method "shared", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.</para></description-docbook><description> IP configuration method.
 
  NMSettingIP4Config and NMSettingIP6Config both support "disabled", "auto", "manual", and "link-local". See the subclass-specific documentation for other values.
 
diff --git a/src/libnmc-setting/settings-docs.h b/src/libnmc-setting/settings-docs.h
index 1ed2f134..934ddff9 100644
--- a/src/libnmc-setting/settings-docs.h
+++ b/src/libnmc-setting/settings-docs.h
@@ -166,7 +166,7 @@
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_REJECT_SERVERS N_("Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers. For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. \"192.168.122.0/24\"). This property is currently not implemented for DHCPv6.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). Set to 2147483647 (MAXINT32) for infinity.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER N_("The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server. Since 1.28")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER N_("The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are \"attempts\", \"debug\", \"edns0\", \"inet6\", \"ip6-bytestring\", \"ip6-dotint\", \"ndots\", \"no-check-names\", \"no-ip6-dotint\", \"no-reload\", \"no-tld-query\", \"rotate\", \"single-request\", \"single-request-reopen\", \"timeout\", \"trust-ad\", \"use-vc\". The \"trust-ad\" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have \"trust-ad\" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then \"edns0\" and \"trust-ad\" are automatically added.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the \"rotate\" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins.  If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured.")
@@ -174,7 +174,7 @@
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set. Setting the gateway causes NetworkManager to configure a standard default route with the gateway as next hop. This is ignored if \"never-default\" is set. An alternative is to configure the default route explicitly with a manual route and /0 as prefix length. Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See \"ip4-auto-default-route\".")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_LINK_LOCAL N_("Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. When set to \"auto\", the value is dependent on \"ipv4.method\". When set to \"default\", it honors the global connection default, before falling back to \"auto\". Note that if \"ipv4.method\" is \"disabled\", then link local addressing is always disabled too. The default is \"default\". Since 1.40")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_LINK_LOCAL N_("Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. When set to \"auto\", the value is dependent on \"ipv4.method\". When set to \"default\", it honors the global connection default, before falling back to \"auto\". Note that if \"ipv4.method\" is \"disabled\", then link local addressing is always disabled too. The default is \"default\".")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_MAY_FAIL N_("If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out.  Note that at least one IP configuration must succeed or overall network configuration will still fail.  For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_METHOD N_("IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support \"disabled\", \"auto\", \"manual\", and \"link-local\". See the subclass-specific documentation for other values. In general, for the \"auto\" method, properties such as \"dns\" and \"routes\" specify information that is added on to the information returned from automatic configuration.  The \"ignore-auto-routes\" and \"ignore-auto-dns\" properties modify this behavior. For methods that imply no upstream network, such as \"shared\" or \"link-local\", these properties must be empty. For IPv4 method \"shared\", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_NEVER_DEFAULT N_("If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager.")
diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in
index 1ed2f134..934ddff9 100644
--- a/src/libnmc-setting/settings-docs.h.in
+++ b/src/libnmc-setting/settings-docs.h.in
@@ -166,7 +166,7 @@
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_REJECT_SERVERS N_("Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers. For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. \"192.168.122.0/24\"). This property is currently not implemented for DHCPv6.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). Set to 2147483647 (MAXINT32) for infinity.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER N_("The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server. Since 1.28")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER N_("The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are \"attempts\", \"debug\", \"edns0\", \"inet6\", \"ip6-bytestring\", \"ip6-dotint\", \"ndots\", \"no-check-names\", \"no-ip6-dotint\", \"no-reload\", \"no-tld-query\", \"rotate\", \"single-request\", \"single-request-reopen\", \"timeout\", \"trust-ad\", \"use-vc\". The \"trust-ad\" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have \"trust-ad\" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then \"edns0\" and \"trust-ad\" are automatically added.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the \"rotate\" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins.  If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured.")
@@ -174,7 +174,7 @@
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set. Setting the gateway causes NetworkManager to configure a standard default route with the gateway as next hop. This is ignored if \"never-default\" is set. An alternative is to configure the default route explicitly with a manual route and /0 as prefix length. Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See \"ip4-auto-default-route\".")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_LINK_LOCAL N_("Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. When set to \"auto\", the value is dependent on \"ipv4.method\". When set to \"default\", it honors the global connection default, before falling back to \"auto\". Note that if \"ipv4.method\" is \"disabled\", then link local addressing is always disabled too. The default is \"default\". Since 1.40")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_LINK_LOCAL N_("Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. When set to \"auto\", the value is dependent on \"ipv4.method\". When set to \"default\", it honors the global connection default, before falling back to \"auto\". Note that if \"ipv4.method\" is \"disabled\", then link local addressing is always disabled too. The default is \"default\".")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_MAY_FAIL N_("If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out.  Note that at least one IP configuration must succeed or overall network configuration will still fail.  For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_METHOD N_("IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support \"disabled\", \"auto\", \"manual\", and \"link-local\". See the subclass-specific documentation for other values. In general, for the \"auto\" method, properties such as \"dns\" and \"routes\" specify information that is added on to the information returned from automatic configuration.  The \"ignore-auto-routes\" and \"ignore-auto-dns\" properties modify this behavior. For methods that imply no upstream network, such as \"shared\" or \"link-local\", these properties must be empty. For IPv4 method \"shared\", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_NEVER_DEFAULT N_("If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager.")
diff --git a/src/nm-initrd-generator/tests/test-cmdline-reader.c b/src/nm-initrd-generator/tests/test-cmdline-reader.c
index d7b7b3cb..977e58b9 100644
--- a/src/nm-initrd-generator/tests/test-cmdline-reader.c
+++ b/src/nm-initrd-generator/tests/test-cmdline-reader.c
@@ -13,6 +13,7 @@
 #include <sys/socket.h>
 
 #include "libnm-core-intern/nm-core-internal.h"
+#include "libnm-glib-aux/nm-uuid.h"
 
 #include "nm-initrd-generator/nm-initrd-generator.h"
 
@@ -114,6 +115,9 @@ test_auto(void)
     g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1);
 
     g_assert(nm_setting_connection_get_autoconnect(s_con));
+    g_assert_cmpint(nm_setting_connection_get_autoconnect_priority(s_con),
+                    ==,
+                    NMI_AUTOCONNECT_PRIORITY_CMDLINE);
 
     s_wired = nm_connection_get_setting_wired(connection);
     g_assert(s_wired);
@@ -174,6 +178,9 @@ test_dhcp_with_hostname(void)
     g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1);
 
     g_assert(nm_setting_connection_get_autoconnect(s_con));
+    g_assert_cmpint(nm_setting_connection_get_autoconnect_priority(s_con),
+                    ==,
+                    NMI_AUTOCONNECT_PRIORITY_CMDLINE);
 
     s_wired = nm_connection_get_setting_wired(connection);
     g_assert(s_wired);
@@ -219,6 +226,9 @@ test_dhcp_with_mtu(void)
         g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1);
 
         g_assert(nm_setting_connection_get_autoconnect(s_con));
+        g_assert_cmpint(nm_setting_connection_get_autoconnect_priority(s_con),
+                        ==,
+                        NMI_AUTOCONNECT_PRIORITY_CMDLINE);
 
         s_wired = nm_connection_get_setting_wired(connection);
         g_assert(s_wired);
@@ -279,6 +289,9 @@ test_dhcp_timeout(void)
         g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1);
         g_assert_cmpint(nm_setting_connection_get_autoconnect_retries(s_con), ==, 1);
         g_assert(nm_setting_connection_get_autoconnect(s_con));
+        g_assert_cmpint(nm_setting_connection_get_autoconnect_priority(s_con),
+                        ==,
+                        NMI_AUTOCONNECT_PRIORITY_CMDLINE);
 
         s_ip4 = nm_connection_get_setting_ip4_config(connection);
         g_assert(s_ip4);
@@ -1652,7 +1665,11 @@ test_ibft_ip_dev(void)
 {
     const char *const            *ARGV = NM_MAKE_STRV("ip=eth0:ibft");
     NMSettingConnection          *s_con;
-    gs_unref_object NMConnection *connection = NULL;
+    gs_unref_object NMConnection *connection    = NULL;
+    const char                   *s_hwaddr      = "00:53:00:ab:00:01";
+    const char                   *s_vlanid      = "666";
+    const char                   *s_ipaddr      = "2001:0db8:0000:0000:0000:0000:0000:0002";
+    gs_free char                 *expected_uuid = NULL;
 
     connection = _parse_con(ARGV, "eth0");
 
@@ -1662,6 +1679,17 @@ test_ibft_ip_dev(void)
                     ==,
                     NM_SETTING_VLAN_SETTING_NAME);
     g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL);
+
+    expected_uuid = nm_uuid_generate_from_strings("ibft",
+                                                  s_hwaddr,
+                                                  s_vlanid ? "V" : "v",
+                                                  s_vlanid ? s_vlanid : "",
+                                                  s_ipaddr ? "A" : "DHCP",
+                                                  s_ipaddr ? s_ipaddr : "",
+                                                  NULL);
+
+    g_assert_cmpstr(expected_uuid, ==, "16d9bd1c-e2ab-31ef-9196-860078e81a23");
+    g_assert_cmpstr(nm_connection_get_uuid(connection), ==, expected_uuid);
 }
 
 static void
diff --git a/src/nm-initrd-generator/tests/test-ibft-reader.c b/src/nm-initrd-generator/tests/test-ibft-reader.c
index 55925a9a..4aa4d7f3 100644
--- a/src/nm-initrd-generator/tests/test-ibft-reader.c
+++ b/src/nm-initrd-generator/tests/test-ibft-reader.c
@@ -72,6 +72,9 @@ test_read_ibft_dhcp(void)
     g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL);
     g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
     g_assert(nm_setting_connection_get_autoconnect(s_con));
+    g_assert_cmpint(nm_setting_connection_get_autoconnect_priority(s_con),
+                    ==,
+                    NMI_AUTOCONNECT_PRIORITY_FIRMWARE);
 
     s_wired = nm_connection_get_setting_wired(connection);
     g_assert(s_wired);
@@ -121,6 +124,9 @@ test_read_ibft_static(void)
     g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL);
     g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
     g_assert(nm_setting_connection_get_autoconnect(s_con));
+    g_assert_cmpint(nm_setting_connection_get_autoconnect_priority(s_con),
+                    ==,
+                    NMI_AUTOCONNECT_PRIORITY_FIRMWARE);
 
     s_wired = nm_connection_get_setting_wired(connection);
     g_assert(s_wired);
diff --git a/src/nmcli/devices.c b/src/nmcli/devices.c
index 43bd3724..9b7ebce3 100644
--- a/src/nmcli/devices.c
+++ b/src/nmcli/devices.c
@@ -2919,6 +2919,8 @@ do_devices_monitor(const NMCCommand *cmd, NmCli *nmc, int argc, const char *cons
             nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
             return;
         }
+        if (!devices)
+            return;
     } else {
         /* No devices specified. Monitor all. */
         devices = nm_client_get_devices(nmc->client);
diff --git a/src/nmcli/generate-docs-nm-settings-nmcli.xml b/src/nmcli/generate-docs-nm-settings-nmcli.xml
index 371081b0..5da5c979 100644
--- a/src/nmcli/generate-docs-nm-settings-nmcli.xml
+++ b/src/nmcli/generate-docs-nm-settings-nmcli.xml
@@ -699,9 +699,9 @@
         <property name="dad-timeout"
                   description="Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero).  A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4." />
         <property name="dhcp-vendor-class-identifier"
-                  description="The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server. Since 1.28" />
+                  description="The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server." />
         <property name="link-local"
-                  description="Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. When set to &quot;auto&quot;, the value is dependent on &quot;ipv4.method&quot;. When set to &quot;default&quot;, it honors the global connection default, before falling back to &quot;auto&quot;. Note that if &quot;ipv4.method&quot; is &quot;disabled&quot;, then link local addressing is always disabled too. The default is &quot;default&quot;. Since 1.40" />
+                  description="Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. When set to &quot;auto&quot;, the value is dependent on &quot;ipv4.method&quot;. When set to &quot;default&quot;, it honors the global connection default, before falling back to &quot;auto&quot;. Note that if &quot;ipv4.method&quot; is &quot;disabled&quot;, then link local addressing is always disabled too. The default is &quot;default&quot;." />
         <property name="dhcp-reject-servers"
                   description="Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers. For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. &quot;192.168.122.0/24&quot;). This property is currently not implemented for DHCPv6." />
     </setting>
diff --git a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in
index 371081b0..5da5c979 100644
--- a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in
+++ b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in
@@ -699,9 +699,9 @@
         <property name="dad-timeout"
                   description="Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero).  A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4." />
         <property name="dhcp-vendor-class-identifier"
-                  description="The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server. Since 1.28" />
+                  description="The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server." />
         <property name="link-local"
-                  description="Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. When set to &quot;auto&quot;, the value is dependent on &quot;ipv4.method&quot;. When set to &quot;default&quot;, it honors the global connection default, before falling back to &quot;auto&quot;. Note that if &quot;ipv4.method&quot; is &quot;disabled&quot;, then link local addressing is always disabled too. The default is &quot;default&quot;. Since 1.40" />
+                  description="Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. When set to &quot;auto&quot;, the value is dependent on &quot;ipv4.method&quot;. When set to &quot;default&quot;, it honors the global connection default, before falling back to &quot;auto&quot;. Note that if &quot;ipv4.method&quot; is &quot;disabled&quot;, then link local addressing is always disabled too. The default is &quot;default&quot;." />
         <property name="dhcp-reject-servers"
                   description="Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers. For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. &quot;192.168.122.0/24&quot;). This property is currently not implemented for DHCPv6." />
     </setting>
diff --git a/src/nmcli/meson.build b/src/nmcli/meson.build
index a122e2af..be625fe0 100644
--- a/src/nmcli/meson.build
+++ b/src/nmcli/meson.build
@@ -87,7 +87,7 @@ if enable_docs
     ],
   )
 else
-  settings_docs_source = configure_file(
+  gen_metadata_nm_settings_nmcli_xml = configure_file(
     input: 'generate-docs-nm-settings-nmcli.xml.in',
     output: '@BASENAME@',
     configuration: configuration_data(),