about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2022-05-13 15:11:15 +0200
committerMichael Biebl <biebl@debian.org>2022-05-13 15:11:15 +0200
commit87d61411bb3453587d21487da04fcf770fee7d55 (patch)
treee84f1bcc59ec448f8d6f8754391974f0f9bd6cd9 /src
parent9959fdb2e8ddd06f2161798ca0a39c77d67c652d (diff)
New upstream version 1.38.0 upstream/1.38.0
Diffstat (limited to 'src')
-rw-r--r--src/core/devices/nm-device.c3
-rw-r--r--src/core/dhcp/nm-dhcp-dhclient.c21
-rw-r--r--src/core/dhcp/nm-dhcp-systemd.c74
-rw-r--r--src/core/dhcp/nm-dhcp-utils.c12
-rw-r--r--src/core/ndisc/tests/test-ndisc-fake.c6
-rw-r--r--src/core/nm-audit-manager.c7
-rw-r--r--src/core/nm-l3cfg.c35
-rw-r--r--src/libnm-core-impl/nm-setting-infiniband.c34
-rw-r--r--src/libnm-core-public/nm-version-macros.h4
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.h6
-rw-r--r--src/libnm-platform/nm-platform.c91
-rw-r--r--src/libnm-platform/nm-platform.h42
-rw-r--r--src/n-dhcp4/src/n-dhcp4-c-probe.c3
-rw-r--r--src/nm-cloud-setup/nmcs-provider-aliyun.c109
-rw-r--r--src/nm-cloud-setup/nmcs-provider-azure.c4
-rw-r--r--src/nm-cloud-setup/nmcs-provider-ec2.c33
-rw-r--r--src/nm-cloud-setup/nmcs-provider-gcp.c4
-rw-r--r--src/nm-cloud-setup/nmcs-provider.c32
-rw-r--r--src/nm-cloud-setup/nmcs-provider.h43
-rw-r--r--src/nmcli/connections.c11
-rw-r--r--src/nmcli/connections.h2
-rw-r--r--src/nmcli/devices.c8
22 files changed, 390 insertions, 194 deletions
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 1d9f235a..70b52b1a 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -6585,7 +6585,8 @@ device_link_changed(gpointer user_data)
          * so that it theoretically would also work for NMVpnConnection (although,
          * NMVpnConnection should become like a regular device, akin to NMDevicePpp).
          */
-        if (!nm_device_sys_iface_state_is_external(self))
+        if (priv->state >= NM_DEVICE_STATE_IP_CONFIG && priv->state <= NM_DEVICE_STATE_ACTIVATED
+            && !nm_device_sys_iface_state_is_external(self))
             nm_device_l3cfg_commit(self, NM_L3_CFG_COMMIT_TYPE_REAPPLY, FALSE);
     }
 
diff --git a/src/core/dhcp/nm-dhcp-dhclient.c b/src/core/dhcp/nm-dhcp-dhclient.c
index 28d40c07..d0cd5ebd 100644
--- a/src/core/dhcp/nm-dhcp-dhclient.c
+++ b/src/core/dhcp/nm-dhcp-dhclient.c
@@ -330,7 +330,7 @@ create_dhclient_config(NMDhcpDhclient     *self,
 
 static gboolean
 dhclient_start(NMDhcpClient *client,
-               const char   *mode_opt,
+               gboolean      set_mode,
                gboolean      release,
                pid_t        *out_pid,
                GError      **error)
@@ -439,14 +439,19 @@ dhclient_start(NMDhcpClient *client,
     }
 
     if (addr_family == AF_INET6) {
-        guint prefixes = client_config->v6.needed_prefixes;
+        guint       prefixes = client_config->v6.needed_prefixes;
+        const char *mode_opt;
 
         g_ptr_array_add(argv, (gpointer) "-6");
 
-        if (prefixes > 0 && nm_streq0(mode_opt, "-S")) {
-            /* -S is incompatible with -P, only use the latter */
+        if (!set_mode)
+            mode_opt = NULL;
+        else if (!client_config->v6.info_only)
+            mode_opt = "-N";
+        else if (prefixes == 0)
+            mode_opt = "-S";
+        else
             mode_opt = NULL;
-        }
 
         if (mode_opt)
             g_ptr_array_add(argv, (gpointer) mode_opt);
@@ -546,7 +551,7 @@ ip4_start(NMDhcpClient *client, GError **error)
         nm_assert(!client_config->client_id);
         nm_dhcp_client_set_effective_client_id(client, new_client_id);
     }
-    return dhclient_start(client, NULL, FALSE, NULL, error);
+    return dhclient_start(client, FALSE, FALSE, NULL, error);
 }
 
 static gboolean
@@ -581,7 +586,7 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
         return FALSE;
     }
 
-    return dhclient_start(client, config->v6.needed_prefixes ? "-S" : "-N", FALSE, NULL, error);
+    return dhclient_start(client, TRUE, FALSE, NULL, error);
 }
 
 static void
@@ -615,7 +620,7 @@ stop(NMDhcpClient *client, gboolean release)
     if (release) {
         pid_t rpid = -1;
 
-        if (dhclient_start(client, NULL, TRUE, &rpid, NULL)) {
+        if (dhclient_start(client, FALSE, TRUE, &rpid, NULL)) {
             /* Wait a few seconds for the release to happen */
             nm_dhcp_client_stop_pid(rpid, nm_dhcp_client_get_iface(client));
         }
diff --git a/src/core/dhcp/nm-dhcp-systemd.c b/src/core/dhcp/nm-dhcp-systemd.c
index 14a121e7..4a718de9 100644
--- a/src/core/dhcp/nm-dhcp-systemd.c
+++ b/src/core/dhcp/nm-dhcp-systemd.c
@@ -751,14 +751,12 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx,
     gs_unref_hashtable GHashTable          *options = NULL;
     struct in6_addr                         tmp_addr;
     const struct in6_addr                  *dns;
-    uint32_t                                lft_pref, lft_valid;
     char                                    addr_str[NM_UTILS_INET_ADDRSTRLEN];
     char                                  **domains;
     char                                  **ntp_fqdns;
     const struct in6_addr                  *ntp_addrs;
     const char                             *s;
-    nm_auto_free_gstring GString           *str               = NULL;
-    gboolean                                has_any_addresses = FALSE;
+    nm_auto_free_gstring GString           *str = NULL;
     int                                     num, i;
 
     nm_assert(lease);
@@ -767,36 +765,45 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx,
 
     options = nm_dhcp_option_create_options_dict();
 
-    sd_dhcp6_lease_reset_address_iter(lease);
-    nm_gstring_prepare(&str);
-    while (sd_dhcp6_lease_get_address(lease, &tmp_addr, &lft_pref, &lft_valid) >= 0) {
-        const NMPlatformIP6Address address = {
-            .plen        = 128,
-            .address     = tmp_addr,
-            .timestamp   = ts,
-            .lifetime    = lft_valid,
-            .preferred   = lft_pref,
-            .addr_source = NM_IP_CONFIG_SOURCE_DHCP,
-        };
-
-        nm_l3_config_data_add_address_6(l3cd, &address);
+    if (!info_only) {
+        gboolean has_any_addresses = FALSE;
+        uint32_t lft_pref;
+        uint32_t lft_valid;
 
-        _nm_utils_inet6_ntop(&tmp_addr, addr_str);
-        g_string_append(nm_gstring_add_space_delimiter(str), addr_str);
+        sd_dhcp6_lease_reset_address_iter(lease);
+        nm_gstring_prepare(&str);
+        while (sd_dhcp6_lease_get_address(lease, &tmp_addr, &lft_pref, &lft_valid) >= 0) {
+            const NMPlatformIP6Address address = {
+                .plen        = 128,
+                .address     = tmp_addr,
+                .timestamp   = ts,
+                .lifetime    = lft_valid,
+                .preferred   = lft_pref,
+                .addr_source = NM_IP_CONFIG_SOURCE_DHCP,
+            };
+
+            nm_l3_config_data_add_address_6(l3cd, &address);
+
+            _nm_utils_inet6_ntop(&tmp_addr, addr_str);
+            g_string_append(nm_gstring_add_space_delimiter(str), addr_str);
 
-        has_any_addresses = TRUE;
-    }
+            has_any_addresses = TRUE;
+        }
 
-    if (str->len) {
-        nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS, str->str);
-    }
+        if (str->len) {
+            nm_dhcp_option_add_option(options,
+                                      AF_INET6,
+                                      NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS,
+                                      str->str);
+        }
 
-    if (!info_only && !has_any_addresses) {
-        g_set_error_literal(error,
-                            NM_MANAGER_ERROR,
-                            NM_MANAGER_ERROR_FAILED,
-                            "no address received in managed mode");
-        return NULL;
+        if (!has_any_addresses) {
+            g_set_error_literal(error,
+                                NM_MANAGER_ERROR,
+                                NM_MANAGER_ERROR_FAILED,
+                                "no address received in managed mode");
+            return NULL;
+        }
     }
 
     num = sd_dhcp6_lease_get_dns(lease, &dns);
@@ -966,11 +973,10 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
 
     _LOGT("dhcp-client6: set %p", sd_client);
 
-    if (client_config->v6.info_only) {
-        sd_dhcp6_client_set_address_request(sd_client, 0);
-        if (client_config->v6.needed_prefixes == 0)
-            sd_dhcp6_client_set_information_request(sd_client, 1);
-    }
+    sd_dhcp6_client_set_address_request(sd_client, !client_config->v6.info_only);
+    sd_dhcp6_client_set_information_request(sd_client,
+                                            client_config->v6.info_only
+                                                && client_config->v6.needed_prefixes == 0);
 
     r = sd_dhcp6_client_set_iaid(sd_client, client_config->v6.iaid);
     if (r < 0) {
diff --git a/src/core/dhcp/nm-dhcp-utils.c b/src/core/dhcp/nm-dhcp-utils.c
index a0eec6e0..081e2841 100644
--- a/src/core/dhcp/nm-dhcp-utils.c
+++ b/src/core/dhcp/nm-dhcp-utils.c
@@ -669,8 +669,13 @@ nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx,
         _LOG2I(LOGD_DHCP6, iface, "  preferred_lft %u", address.preferred);
     }
 
-    str = g_hash_table_lookup(options, "ip6_address");
-    if (str) {
+    if (!info_only) {
+        str = g_hash_table_lookup(options, "ip6_address");
+        if (!str) {
+            /* No address in Managed mode is a hard error */
+            return NULL;
+        }
+
         if (!inet_pton(AF_INET6, str, &tmp_addr)) {
             _LOG2W(LOGD_DHCP6, iface, "(%s): DHCP returned invalid address '%s'", iface, str);
             return NULL;
@@ -680,9 +685,6 @@ nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx,
         address.addr_source = NM_IP_CONFIG_SOURCE_DHCP;
         nm_l3_config_data_add_address_6(l3cd, &address);
         _LOG2I(LOGD_DHCP6, iface, "  address %s", str);
-    } else if (info_only == FALSE) {
-        /* No address in Managed mode is a hard error */
-        return NULL;
     }
 
     str = g_hash_table_lookup(options, "host_name");
diff --git a/src/core/ndisc/tests/test-ndisc-fake.c b/src/core/ndisc/tests/test-ndisc-fake.c
index 0763b64e..457dcf19 100644
--- a/src/core/ndisc/tests/test-ndisc-fake.c
+++ b/src/core/ndisc/tests/test-ndisc-fake.c
@@ -646,7 +646,11 @@ test_dns_solicit_loop(void)
     nm_ndisc_start(NM_NDISC(ndisc));
     if (nmtst_main_loop_run(data.loop, 10000))
         g_error("we expect to run the loop until timeout. What is wrong?");
-    g_assert_cmpint(data.counter, ==, 3);
+    if (data.counter == 2) {
+        /* Hm. I saw this too. Odd. But as there are dependencies on the run time,
+         * I guess it can just happen. It's probably fine. */
+    } else
+        g_assert_cmpint(data.counter, ==, 3);
     g_assert_cmpint(data.rs_counter, ==, 1);
 }
 
diff --git a/src/core/nm-audit-manager.c b/src/core/nm-audit-manager.c
index dd96d834..4e134d1a 100644
--- a/src/core/nm-audit-manager.c
+++ b/src/core/nm-audit-manager.c
@@ -135,10 +135,13 @@ build_message(NMStrBuf *strbuf, AuditBackend backend, GPtrArray *fields)
 #if HAVE_LIBAUDIT
             if (backend == BACKEND_AUDITD) {
                 if (field->need_encoding) {
-                    gs_free char *value = NULL;
+                    nm_auto_free char *value = NULL;
 
                     value = audit_encode_nv_string(field->name, str, 0);
-                    nm_str_buf_append(strbuf, value);
+                    if (value)
+                        nm_str_buf_append(strbuf, value);
+                    else
+                        nm_str_buf_append_printf(strbuf, "%s=???", field->name);
                 } else
                     nm_str_buf_append_printf(strbuf, "%s=%s", field->name, str);
                 continue;
diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c
index 6b7e6f4b..38b9d822 100644
--- a/src/core/nm-l3cfg.c
+++ b/src/core/nm-l3cfg.c
@@ -4186,6 +4186,7 @@ _l3_commit_one(NML3Cfg              *self,
     gboolean                     final_failure_for_temporary_not_available = FALSE;
     char                         sbuf_commit_type[50];
     gboolean                     success = TRUE;
+    guint                        i;
 
     nm_assert(NM_IS_L3CFG(self));
     nm_assert(NM_IN_SET(commit_type,
@@ -4218,11 +4219,35 @@ _l3_commit_one(NML3Cfg              *self,
         route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN;
 
     if (commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY) {
-        addresses_prune = nm_platform_ip_address_get_prune_list(self->priv.platform,
-                                                                addr_family,
-                                                                self->priv.ifindex,
-                                                                TRUE);
-        routes_prune    = nm_platform_ip_route_get_prune_list(self->priv.platform,
+        gs_unref_array GArray *ipv6_temp_addrs_keep = NULL;
+
+        nm_platform_process_events(self->priv.platform);
+
+        if (!IS_IPv4 && addresses) {
+            for (i = 0; i < addresses->len; i++) {
+                const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS(addresses->pdata[i]);
+
+                if (!NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_MANAGETEMPADDR))
+                    continue;
+
+                nm_assert(addr->plen == 64);
+
+                /* Construct a list of all IPv6 prefixes for which we (still) set
+                 * IFA_F_MANAGETEMPADDR (that is, for which we will have temporary addresses).
+                 * Those should not be pruned during reapply. */
+                if (!ipv6_temp_addrs_keep)
+                    ipv6_temp_addrs_keep = g_array_new(FALSE, FALSE, sizeof(struct in6_addr));
+                g_array_append_val(ipv6_temp_addrs_keep, addr->address);
+            }
+        }
+        addresses_prune =
+            nm_platform_ip_address_get_prune_list(self->priv.platform,
+                                                  addr_family,
+                                                  self->priv.ifindex,
+                                                  nm_g_array_data(ipv6_temp_addrs_keep),
+                                                  nm_g_array_len(ipv6_temp_addrs_keep));
+
+        routes_prune = nm_platform_ip_route_get_prune_list(self->priv.platform,
                                                            addr_family,
                                                            self->priv.ifindex,
                                                            route_table_sync);
diff --git a/src/libnm-core-impl/nm-setting-infiniband.c b/src/libnm-core-impl/nm-setting-infiniband.c
index eb6c9536..787b838b 100644
--- a/src/libnm-core-impl/nm-setting-infiniband.c
+++ b/src/libnm-core-impl/nm-setting-infiniband.c
@@ -241,6 +241,14 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
             g_prefix_error(error, "%s: ", NM_SETTING_INFINIBAND_PARENT);
             return FALSE;
         }
+        if (NM_IN_SET(priv->p_key, 0, 0x8000)) {
+            g_set_error_literal(error,
+                                NM_CONNECTION_ERROR,
+                                NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                                _("the values 0 and 0x8000 are not allowed"));
+            g_prefix_error(error, "%s: ", NM_SETTING_INFINIBAND_P_KEY);
+            return FALSE;
+        }
     }
 
     if (connection)
@@ -254,17 +262,27 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
             virtual_iface_name =
                 nm_setting_infiniband_get_virtual_interface_name(NM_SETTING_INFINIBAND(setting));
 
-            if (!nm_streq(interface_name, virtual_iface_name)) {
+            if (!nm_streq0(interface_name, virtual_iface_name)) {
                 /* We don't support renaming software infiniband devices. Later we might, but
                  * for now just reject such connections.
                  **/
-                g_set_error(error,
-                            NM_CONNECTION_ERROR,
-                            NM_CONNECTION_ERROR_INVALID_PROPERTY,
-                            _("interface name of software infiniband device must be '%s' or unset "
-                              "(instead it is '%s')"),
-                            virtual_iface_name,
-                            interface_name);
+                if (virtual_iface_name) {
+                    g_set_error(
+                        error,
+                        NM_CONNECTION_ERROR,
+                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                        _("interface name of software infiniband device must be '%s' or unset "
+                          "(instead it is '%s')"),
+                        virtual_iface_name,
+                        interface_name);
+                } else {
+                    g_set_error(error,
+                                NM_CONNECTION_ERROR,
+                                NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                                _("interface name of software infiniband device with MAC address "
+                                  "must be unset (instead it is '%s')"),
+                                interface_name);
+                }
                 g_prefix_error(error,
                                "%s.%s: ",
                                NM_SETTING_CONNECTION_SETTING_NAME,
diff --git a/src/libnm-core-public/nm-version-macros.h b/src/libnm-core-public/nm-version-macros.h
index b10be844..07c259a7 100644
--- a/src/libnm-core-public/nm-version-macros.h
+++ b/src/libnm-core-public/nm-version-macros.h
@@ -22,7 +22,7 @@
  * Evaluates to the minor version number of NetworkManager which this source
  * is compiled against.
  */
-#define NM_MINOR_VERSION (37)
+#define NM_MINOR_VERSION (38)
 
 /**
  * NM_MICRO_VERSION:
@@ -30,7 +30,7 @@
  * Evaluates to the micro version number of NetworkManager which this source
  * compiled against.
  */
-#define NM_MICRO_VERSION (92)
+#define NM_MICRO_VERSION (0)
 
 /**
  * NM_CHECK_VERSION:
diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h
index 941312bd..daefa068 100644
--- a/src/libnm-glib-aux/nm-shared-utils.h
+++ b/src/libnm-glib-aux/nm-shared-utils.h
@@ -2127,6 +2127,12 @@ char *nm_utils_g_slist_strlist_join(const GSList *a, const char *separator);
 
 /*****************************************************************************/
 
+static inline gpointer
+nm_g_array_data(const GArray *arr)
+{
+    return arr ? arr->data : NULL;
+}
+
 static inline guint
 nm_g_array_len(const GArray *arr)
 {
diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c
index 8866a436..090af26d 100644
--- a/src/libnm-platform/nm-platform.c
+++ b/src/libnm-platform/nm-platform.c
@@ -4459,15 +4459,25 @@ gboolean
 nm_platform_ip_address_flush(NMPlatform *self, int addr_family, int ifindex)
 {
     gboolean success = TRUE;
+    int      IS_IPv4;
 
     _CHECK_SELF(self, klass, FALSE);
 
-    nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6));
+    nm_assert_addr_family_or_unspec(addr_family);
+
+    for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
+        gs_unref_ptrarray GPtrArray *addresses_prune = NULL;
+        const int                    addr_family2    = IS_IPv4 ? AF_INET : AF_INET6;
+
+        if (!NM_IN_SET(addr_family, AF_UNSPEC, addr_family2))
+            continue;
 
-    if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET))
-        success &= nm_platform_ip4_address_sync(self, ifindex, NULL);
-    if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6))
-        success &= nm_platform_ip6_address_sync(self, ifindex, NULL, TRUE);
+        addresses_prune =
+            nm_platform_ip_address_get_prune_list(self, addr_family2, ifindex, NULL, 0);
+
+        if (!nm_platform_ip_address_sync(self, addr_family2, ifindex, NULL, addresses_prune))
+            success = FALSE;
+    }
     return success;
 }
 
@@ -4509,17 +4519,31 @@ _err_inval_due_to_ipv6_tentative_pref_src(NMPlatform *self, const NMPObject *obj
     return TRUE;
 }
 
-GPtrArray *
-nm_platform_ip_address_get_prune_list(NMPlatform *self,
-                                      int         addr_family,
-                                      int         ifindex,
-                                      gboolean    exclude_ipv6_temporary_addrs)
+static guint
+_ipv6_temporary_addr_prefixes_keep_hash(gconstpointer ptr)
 {
-    const int                    IS_IPv4 = NM_IS_IPv4(addr_family);
-    const NMDedupMultiHeadEntry *head_entry;
-    NMPLookup                    lookup;
-    GPtrArray                   *result = NULL;
-    CList                       *iter;
+    return nm_hash_mem(1161670183u, ptr, 8);
+}
+
+static gboolean
+_ipv6_temporary_addr_prefixes_keep_equal(gconstpointer ptr_a, gconstpointer ptr_b)
+{
+    return !memcmp(ptr_a, ptr_b, 8);
+}
+
+GPtrArray *
+nm_platform_ip_address_get_prune_list(NMPlatform            *self,
+                                      int                    addr_family,
+                                      int                    ifindex,
+                                      const struct in6_addr *ipv6_temporary_addr_prefixes_keep,
+                                      guint                  ipv6_temporary_addr_prefixes_keep_len)
+{
+    gs_unref_hashtable GHashTable *ipv6_temporary_addr_prefixes_keep_idx = NULL;
+    const int                      IS_IPv4                               = NM_IS_IPv4(addr_family);
+    const NMDedupMultiHeadEntry   *head_entry;
+    NMPLookup                      lookup;
+    GPtrArray                     *result = NULL;
+    CList                         *iter;
 
     nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(NM_IS_IPv4(addr_family)), ifindex);
 
@@ -4532,9 +4556,40 @@ nm_platform_ip_address_get_prune_list(NMPlatform *self,
         const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj;
 
         if (!IS_IPv4) {
-            if (exclude_ipv6_temporary_addrs
-                && NM_FLAGS_HAS(NMP_OBJECT_CAST_IP_ADDRESS(obj)->n_ifa_flags, IFA_F_SECONDARY))
-                continue;
+            const NMPlatformIP6Address *a6 = NMP_OBJECT_CAST_IP6_ADDRESS(obj);
+
+            if (NM_FLAGS_HAS(a6->n_ifa_flags, IFA_F_SECONDARY)
+                && ipv6_temporary_addr_prefixes_keep_len > 0 && a6->plen == 64) {
+                gboolean keep = FALSE;
+                guint    i;
+
+                if (ipv6_temporary_addr_prefixes_keep_len < 10) {
+                    for (i = 0; i < ipv6_temporary_addr_prefixes_keep_len; i++) {
+                        if (memcmp(&ipv6_temporary_addr_prefixes_keep[i], &a6->address, 8) == 0) {
+                            keep = TRUE;
+                            break;
+                        }
+                    }
+                } else {
+                    /* We have a larger number of addresses. We want that our functions are O(n),
+                     * so build a lookup index. */
+                    if (!ipv6_temporary_addr_prefixes_keep_idx) {
+                        ipv6_temporary_addr_prefixes_keep_idx =
+                            g_hash_table_new(_ipv6_temporary_addr_prefixes_keep_hash,
+                                             _ipv6_temporary_addr_prefixes_keep_equal);
+                        for (i = 0; i < ipv6_temporary_addr_prefixes_keep_len; i++) {
+                            g_hash_table_add(ipv6_temporary_addr_prefixes_keep_idx,
+                                             (gpointer) &ipv6_temporary_addr_prefixes_keep[i]);
+                        }
+                    }
+                    if (g_hash_table_contains(ipv6_temporary_addr_prefixes_keep_idx, &a6->address))
+                        keep = TRUE;
+                }
+                if (keep) {
+                    /* This IPv6 temporary address has a prefix that we want to keep. */
+                    continue;
+                }
+            }
         }
 
         if (!result)
diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h
index 246d6ff6..5c72fade 100644
--- a/src/libnm-platform/nm-platform.h
+++ b/src/libnm-platform/nm-platform.h
@@ -2187,42 +2187,12 @@ gboolean nm_platform_ip_address_sync(NMPlatform *self,
                                      GPtrArray  *known_addresses,
                                      GPtrArray  *addresses_prune);
 
-GPtrArray *nm_platform_ip_address_get_prune_list(NMPlatform *self,
-                                                 int         addr_family,
-                                                 int         ifindex,
-                                                 gboolean    exclude_ipv6_temporary_addrs);
-
-static inline gboolean
-_nm_platform_ip_address_sync(NMPlatform *self,
-                             int         addr_family,
-                             int         ifindex,
-                             GPtrArray  *known_addresses,
-                             gboolean    full_sync)
-{
-    gs_unref_ptrarray GPtrArray *addresses_prune = NULL;
-
-    addresses_prune = nm_platform_ip_address_get_prune_list(self, addr_family, ifindex, !full_sync);
-    return nm_platform_ip_address_sync(self,
-                                       addr_family,
-                                       ifindex,
-                                       known_addresses,
-                                       addresses_prune);
-}
-
-static inline gboolean
-nm_platform_ip4_address_sync(NMPlatform *self, int ifindex, GPtrArray *known_addresses)
-{
-    return _nm_platform_ip_address_sync(self, AF_INET, ifindex, known_addresses, TRUE);
-}
-
-static inline gboolean
-nm_platform_ip6_address_sync(NMPlatform *self,
-                             int         ifindex,
-                             GPtrArray  *known_addresses,
-                             gboolean    full_sync)
-{
-    return _nm_platform_ip_address_sync(self, AF_INET6, ifindex, known_addresses, full_sync);
-}
+GPtrArray *
+nm_platform_ip_address_get_prune_list(NMPlatform            *self,
+                                      int                    addr_family,
+                                      int                    ifindex,
+                                      const struct in6_addr *ipv6_temporary_addr_prefixes_keep,
+                                      guint                  ipv6_temporary_addr_prefixes_keep_len);
 
 gboolean nm_platform_ip_address_flush(NMPlatform *self, int addr_family, int ifindex);
 
diff --git a/src/n-dhcp4/src/n-dhcp4-c-probe.c b/src/n-dhcp4/src/n-dhcp4-c-probe.c
index 7f20ac05..283c1693 100644
--- a/src/n-dhcp4/src/n-dhcp4-c-probe.c
+++ b/src/n-dhcp4/src/n-dhcp4-c-probe.c
@@ -995,14 +995,13 @@ static int n_dhcp4_client_probe_transition_nak(NDhcp4ClientProbe *probe) {
         case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
         case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
 
-                /* XXX */
-
                 r = n_dhcp4_client_probe_raise(probe,
                                                NULL,
                                                N_DHCP4_CLIENT_EVENT_RETRACTED);
                 if (r)
                         return r;
 
+                probe->current_lease = n_dhcp4_client_lease_unref(probe->current_lease);
                 probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
                 probe->ns_deferred = n_dhcp4_gettime(CLOCK_BOOTTIME) + probe->ns_nak_restart_delay;
                 probe->ns_nak_restart_delay = C_CLAMP(probe->ns_nak_restart_delay * 2u,
diff --git a/src/nm-cloud-setup/nmcs-provider-aliyun.c b/src/nm-cloud-setup/nmcs-provider-aliyun.c
index 31c9830d..1a5e5459 100644
--- a/src/nm-cloud-setup/nmcs-provider-aliyun.c
+++ b/src/nm-cloud-setup/nmcs-provider-aliyun.c
@@ -123,29 +123,26 @@ detect(NMCSProvider *provider, GTask *task)
 typedef enum {
     GET_CONFIG_FETCH_DONE_TYPE_SUBNET_VPC_CIDR_BLOCK,
     GET_CONFIG_FETCH_DONE_TYPE_PRIVATE_IPV4S,
+    GET_CONFIG_FETCH_DONE_TYPE_PRIMARY_IP_ADDRESS,
     GET_CONFIG_FETCH_DONE_TYPE_NETMASK,
     GET_CONFIG_FETCH_DONE_TYPE_GATEWAY,
 } GetConfigFetchDoneType;
 
 static void
-_get_config_fetch_done_cb(NMHttpClient          *http_client,
-                          GAsyncResult          *result,
-                          gpointer               user_data,
-                          GetConfigFetchDoneType fetch_type)
+_get_config_fetch_done_cb(NMHttpClient                   *http_client,
+                          GAsyncResult                   *result,
+                          NMCSProviderGetConfigIfaceData *config_iface_data,
+                          GetConfigFetchDoneType          fetch_type)
 {
-    NMCSProviderGetConfigTaskData  *get_config_data;
-    gs_unref_bytes GBytes          *response = NULL;
-    gs_free_error GError           *error    = NULL;
-    NMCSProviderGetConfigIfaceData *config_iface_data;
-    in_addr_t                       tmp_addr;
-    int                             tmp_prefix;
-    in_addr_t                       netmask_bin;
-    in_addr_t                       gateway_bin;
-    gs_free const char            **s_addrs = NULL;
-    gsize                           i;
-    gsize                           len;
-
-    nm_utils_user_data_unpack(user_data, &get_config_data, &config_iface_data);
+    gs_unref_bytes GBytes *response = NULL;
+    gs_free_error GError  *error    = NULL;
+    in_addr_t              tmp_addr;
+    int                    tmp_prefix;
+    in_addr_t              netmask_bin;
+    in_addr_t              gateway_bin;
+    gs_free const char   **s_addrs = NULL;
+    gsize                  i;
+    gsize                  len;
 
     nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error);
 
@@ -177,6 +174,16 @@ _get_config_fetch_done_cb(NMHttpClient          *http_client,
         }
         break;
 
+    case GET_CONFIG_FETCH_DONE_TYPE_PRIMARY_IP_ADDRESS:
+
+        if (nm_utils_parse_inaddr_bin(AF_INET, g_bytes_get_data(response, NULL), NULL, &tmp_addr)) {
+            nm_assert(config_iface_data->priv.aliyun.primary_ip_address == 0);
+            nm_assert(!config_iface_data->priv.aliyun.has_primary_ip_address);
+            config_iface_data->priv.aliyun.primary_ip_address     = tmp_addr;
+            config_iface_data->priv.aliyun.has_primary_ip_address = TRUE;
+        }
+        break;
+
     case GET_CONFIG_FETCH_DONE_TYPE_SUBNET_VPC_CIDR_BLOCK:
 
         if (nm_utils_parse_inaddr_prefix_bin(AF_INET,
@@ -212,9 +219,30 @@ _get_config_fetch_done_cb(NMHttpClient          *http_client,
         break;
     }
 
+    if (!config_iface_data->priv.aliyun.ipv4s_arr_ordered
+        && config_iface_data->priv.aliyun.has_primary_ip_address
+        && config_iface_data->ipv4s_len > 0) {
+        for (i = 0; i < config_iface_data->ipv4s_len; i++) {
+            if (config_iface_data->ipv4s_arr[i]
+                != config_iface_data->priv.aliyun.primary_ip_address)
+                continue;
+            if (i > 0) {
+                /* OK, at position [i] we found the primary address.
+                 * Move the elements from [0..(i-1)] to [1..i] and then set [0]. */
+                memmove(&config_iface_data->ipv4s_arr[1],
+                        &config_iface_data->ipv4s_arr[0],
+                        i * sizeof(in_addr_t));
+                config_iface_data->ipv4s_arr[0] = config_iface_data->priv.aliyun.primary_ip_address;
+            }
+            break;
+        }
+        config_iface_data->priv.aliyun.ipv4s_arr_ordered = TRUE;
+    }
+
 out:
-    get_config_data->n_pending--;
-    _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error));
+    config_iface_data->get_config_data->n_pending--;
+    _nmcs_provider_get_config_task_maybe_return(config_iface_data->get_config_data,
+                                                g_steal_pointer(&error));
 }
 
 static void
@@ -236,6 +264,17 @@ _get_config_fetch_done_cb_private_ipv4s(GObject *source, GAsyncResult *result, g
 }
 
 static void
+_get_config_fetch_done_cb_primary_ip_address(GObject      *source,
+                                             GAsyncResult *result,
+                                             gpointer      user_data)
+{
+    _get_config_fetch_done_cb(NM_HTTP_CLIENT(source),
+                              result,
+                              user_data,
+                              GET_CONFIG_FETCH_DONE_TYPE_PRIMARY_IP_ADDRESS);
+}
+
+static void
 _get_config_fetch_done_cb_netmask(GObject *source, GAsyncResult *result, gpointer user_data)
 {
     _get_config_fetch_done_cb(NM_HTTP_CLIENT(source),
@@ -297,6 +336,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
         gs_free char                   *uri2 = NULL;
         gs_free char                   *uri3 = NULL;
         gs_free char                   *uri4 = NULL;
+        gs_free char                   *uri5 = NULL;
 
         config_iface_data = g_hash_table_lookup(get_config_data->result_dict, v_hwaddr);
 
@@ -309,9 +349,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             }
 
             config_iface_data =
-                nmcs_provider_get_config_iface_data_create(get_config_data->result_dict,
-                                                           FALSE,
-                                                           v_hwaddr);
+                nmcs_provider_get_config_iface_data_create(get_config_data, FALSE, v_hwaddr);
         }
 
         nm_assert(config_iface_data->iface_idx == -1);
@@ -338,7 +376,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             NULL,
             NULL,
             _get_config_fetch_done_cb_vpc_cidr_block,
-            nm_utils_user_data_pack(get_config_data, config_iface_data));
+            config_iface_data);
 
         get_config_data->n_pending++;
         nm_http_client_poll_get(
@@ -355,13 +393,30 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             NULL,
             NULL,
             _get_config_fetch_done_cb_private_ipv4s,
-            nm_utils_user_data_pack(get_config_data, config_iface_data));
+            config_iface_data);
 
         get_config_data->n_pending++;
         nm_http_client_poll_get(
             http_client,
             (uri3 = _aliyun_uri_interfaces(v_mac_data->path,
                                            NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
+                                           "primary-ip-address")),
+            HTTP_TIMEOUT_MS,
+            512 * 1024,
+            10000,
+            1000,
+            NULL,
+            get_config_data->intern_cancellable,
+            NULL,
+            NULL,
+            _get_config_fetch_done_cb_primary_ip_address,
+            config_iface_data);
+
+        get_config_data->n_pending++;
+        nm_http_client_poll_get(
+            http_client,
+            (uri4 = _aliyun_uri_interfaces(v_mac_data->path,
+                                           NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
                                            "netmask")),
             HTTP_TIMEOUT_MS,
             512 * 1024,
@@ -372,12 +427,12 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             NULL,
             NULL,
             _get_config_fetch_done_cb_netmask,
-            nm_utils_user_data_pack(get_config_data, config_iface_data));
+            config_iface_data);
 
         get_config_data->n_pending++;
         nm_http_client_poll_get(
             http_client,
-            (uri4 = _aliyun_uri_interfaces(v_mac_data->path,
+            (uri5 = _aliyun_uri_interfaces(v_mac_data->path,
                                            NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/",
                                            "gateway")),
             HTTP_TIMEOUT_MS,
@@ -389,7 +444,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             NULL,
             NULL,
             _get_config_fetch_done_cb_gateway,
-            nm_utils_user_data_pack(get_config_data, config_iface_data));
+            config_iface_data);
     }
 
     _nmcs_provider_get_config_task_maybe_return(get_config_data, NULL);
diff --git a/src/nm-cloud-setup/nmcs-provider-azure.c b/src/nm-cloud-setup/nmcs-provider-azure.c
index 06f23ea7..9b27af28 100644
--- a/src/nm-cloud-setup/nmcs-provider-azure.c
+++ b/src/nm-cloud-setup/nmcs-provider-azure.c
@@ -387,9 +387,7 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data)
             goto out_done;
         }
         iface_data->iface_get_config =
-            nmcs_provider_get_config_iface_data_create(get_config_data->result_dict,
-                                                       FALSE,
-                                                       v_hwaddr);
+            nmcs_provider_get_config_iface_data_create(get_config_data, FALSE, v_hwaddr);
     } else {
         if (iface_data->iface_get_config->iface_idx >= 0) {
             _LOGI("interface[%" G_GSSIZE_FORMAT "]: duplicate MAC address %s returned",
diff --git a/src/nm-cloud-setup/nmcs-provider-ec2.c b/src/nm-cloud-setup/nmcs-provider-ec2.c
index ee4e2a95..d6fa0311 100644
--- a/src/nm-cloud-setup/nmcs-provider-ec2.c
+++ b/src/nm-cloud-setup/nmcs-provider-ec2.c
@@ -116,19 +116,15 @@ detect(NMCSProvider *provider, GTask *task)
 /*****************************************************************************/
 
 static void
-_get_config_fetch_done_cb(NMHttpClient *http_client,
-                          GAsyncResult *result,
-                          gpointer      user_data,
-                          gboolean      is_local_ipv4)
+_get_config_fetch_done_cb(NMHttpClient                   *http_client,
+                          GAsyncResult                   *result,
+                          NMCSProviderGetConfigIfaceData *config_iface_data,
+                          gboolean                        is_local_ipv4)
 {
-    NMCSProviderGetConfigTaskData  *get_config_data;
-    gs_unref_bytes GBytes          *response = NULL;
-    gs_free_error GError           *error    = NULL;
-    NMCSProviderGetConfigIfaceData *config_iface_data;
-    in_addr_t                       tmp_addr;
-    int                             tmp_prefix;
-
-    nm_utils_user_data_unpack(user_data, &get_config_data, &config_iface_data);
+    gs_unref_bytes GBytes *response = NULL;
+    gs_free_error GError  *error    = NULL;
+    in_addr_t              tmp_addr;
+    int                    tmp_prefix;
 
     nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error);
 
@@ -173,8 +169,9 @@ _get_config_fetch_done_cb(NMHttpClient *http_client,
     }
 
 out:
-    get_config_data->n_pending--;
-    _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error));
+    config_iface_data->get_config_data->n_pending--;
+    _nmcs_provider_get_config_task_maybe_return(config_iface_data->get_config_data,
+                                                g_steal_pointer(&error));
 }
 
 static void
@@ -244,9 +241,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
                 continue;
             }
             config_iface_data =
-                nmcs_provider_get_config_iface_data_create(get_config_data->result_dict,
-                                                           FALSE,
-                                                           v_hwaddr);
+                nmcs_provider_get_config_iface_data_create(get_config_data, FALSE, v_hwaddr);
         }
 
         nm_assert(config_iface_data->iface_idx == -1);
@@ -273,7 +268,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             NULL,
             NULL,
             _get_config_fetch_done_cb_subnet_ipv4_cidr_block,
-            nm_utils_user_data_pack(get_config_data, config_iface_data));
+            config_iface_data);
 
         get_config_data->n_pending++;
         nm_http_client_poll_get(
@@ -290,7 +285,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
             NULL,
             NULL,
             _get_config_fetch_done_cb_local_ipv4s,
-            nm_utils_user_data_pack(get_config_data, config_iface_data));
+            config_iface_data);
     }
 
     _nmcs_provider_get_config_task_maybe_return(get_config_data, NULL);
diff --git a/src/nm-cloud-setup/nmcs-provider-gcp.c b/src/nm-cloud-setup/nmcs-provider-gcp.c
index 0df2bdd6..a325f31a 100644
--- a/src/nm-cloud-setup/nmcs-provider-gcp.c
+++ b/src/nm-cloud-setup/nmcs-provider-gcp.c
@@ -282,9 +282,7 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data)
             goto out_done;
         }
         iface_data->iface_get_config =
-            nmcs_provider_get_config_iface_data_create(get_config_data->result_dict,
-                                                       FALSE,
-                                                       v_hwaddr);
+            nmcs_provider_get_config_iface_data_create(get_config_data, FALSE, v_hwaddr);
         is_requested = FALSE;
     } else {
         if (iface_data->iface_get_config->iface_idx >= 0) {
diff --git a/src/nm-cloud-setup/nmcs-provider.c b/src/nm-cloud-setup/nmcs-provider.c
index f14a3d02..fd9a61b8 100644
--- a/src/nm-cloud-setup/nmcs-provider.c
+++ b/src/nm-cloud-setup/nmcs-provider.c
@@ -174,24 +174,38 @@ nmcs_provider_detect_finish(NMCSProvider *self, GAsyncResult *result, GError **e
 /*****************************************************************************/
 
 NMCSProviderGetConfigIfaceData *
-nmcs_provider_get_config_iface_data_create(GHashTable *iface_datas,
-                                           gboolean    was_requested,
-                                           const char *hwaddr)
+nmcs_provider_get_config_iface_data_create(NMCSProviderGetConfigTaskData *get_config_data,
+                                           gboolean                       was_requested,
+                                           const char                    *hwaddr)
 {
     NMCSProviderGetConfigIfaceData *iface_data;
 
     nm_assert(hwaddr);
+    nm_assert(get_config_data);
+    nm_assert(NMCS_IS_PROVIDER(get_config_data->self));
 
     iface_data  = g_slice_new(NMCSProviderGetConfigIfaceData);
     *iface_data = (NMCSProviderGetConfigIfaceData){
-        .hwaddr        = g_strdup(hwaddr),
-        .iface_idx     = -1,
-        .was_requested = was_requested,
+        .get_config_data = get_config_data,
+        .hwaddr          = g_strdup(hwaddr),
+        .iface_idx       = -1,
+        .was_requested   = was_requested,
     };
 
+    /* "priv" is a union, and according to C, it might not be properly initialized
+     * that all union members are set to false/0/NULL/0.0. We need to know which
+     * union field we are going to use, and that depends on the type of "self".
+     * Also, knowing the type would allow us to initialize to something other than
+     * false/0/NULL/0.0. */
+    if (G_OBJECT_TYPE(get_config_data->self) == nmcs_provider_aliyun_get_type()) {
+        iface_data->priv.aliyun = (typeof(iface_data->priv.aliyun)){
+            .has_primary_ip_address = FALSE,
+        };
+    }
+
     /* the has does not own the key (iface_datta->hwaddr), the lifetime of the
      * key is associated with the iface_data instance. */
-    g_hash_table_replace(iface_datas, (char *) iface_data->hwaddr, iface_data);
+    g_hash_table_replace(get_config_data->result_dict, (char *) iface_data->hwaddr, iface_data);
 
     return iface_data;
 }
@@ -280,6 +294,8 @@ nmcs_provider_get_config(NMCSProvider       *self,
 
     get_config_data  = g_slice_new(NMCSProviderGetConfigTaskData);
     *get_config_data = (NMCSProviderGetConfigTaskData){
+        /* "self" is kept alive by "task". */
+        .self = self,
         .task = nm_g_task_new(self, cancellable, nmcs_provider_get_config, callback, user_data),
         .any  = any,
         .result_dict = g_hash_table_new_full(nm_str_hash, g_str_equal, NULL, _iface_data_free),
@@ -288,7 +304,7 @@ nmcs_provider_get_config(NMCSProvider       *self,
     nmcs_wait_for_objects_register(get_config_data->task);
 
     for (; hwaddrs && hwaddrs[0]; hwaddrs++)
-        nmcs_provider_get_config_iface_data_create(get_config_data->result_dict, TRUE, hwaddrs[0]);
+        nmcs_provider_get_config_iface_data_create(get_config_data, TRUE, hwaddrs[0]);
 
     if (cancellable) {
         gulong cancelled_id;
diff --git a/src/nm-cloud-setup/nmcs-provider.h b/src/nm-cloud-setup/nmcs-provider.h
index bce41dcb..502f1d03 100644
--- a/src/nm-cloud-setup/nmcs-provider.h
+++ b/src/nm-cloud-setup/nmcs-provider.h
@@ -9,11 +9,16 @@
 
 /*****************************************************************************/
 
+struct _NMCSProvider;
+struct _NMCSProviderGetConfigTaskData;
+
 typedef struct {
     /* And it's exactly the same pointer that is also the key for the iface_datas
      * dictionary. */
     const char *hwaddr;
 
+    struct _NMCSProviderGetConfigTaskData *get_config_data;
+
     in_addr_t *ipv4s_arr;
     gsize      ipv4s_len;
 
@@ -36,6 +41,18 @@ typedef struct {
      * nmcs_provider_get_config(). */
     bool was_requested : 1;
 
+    /* Usually we would want that the parent class NMCSProvider is not aware about
+     * the implementations. However, it's convenient to track implementation specific data
+     * here, thus we violate such separation. In practice, all subclasses are known
+     * at compile time, and it will be simpler this way. */
+    union {
+        struct {
+            in_addr_t primary_ip_address;
+            bool      has_primary_ip_address : 1;
+            bool      ipv4s_arr_ordered : 1;
+        } aliyun;
+    } priv;
+
 } NMCSProviderGetConfigIfaceData;
 
 static inline gboolean
@@ -45,10 +62,6 @@ nmcs_provider_get_config_iface_data_is_valid(const NMCSProviderGetConfigIfaceDat
            && ((config_data->has_ipv4s && config_data->has_cidr) || config_data->iproutes_len);
 }
 
-NMCSProviderGetConfigIfaceData *nmcs_provider_get_config_iface_data_create(GHashTable *iface_datas,
-                                                                           gboolean was_requested,
-                                                                           const char *hwaddr);
-
 /*****************************************************************************/
 
 typedef struct {
@@ -83,9 +96,11 @@ NM_AUTO_DEFINE_FCN0(NMCSProviderGetConfigResult *,
 
 /*****************************************************************************/
 
-typedef struct {
+typedef struct _NMCSProviderGetConfigTaskData {
     GTask *task;
 
+    struct _NMCSProvider *self;
+
     GHashTable *result_dict;
 
     /* this cancellable should be used for the provider implementation
@@ -105,6 +120,15 @@ typedef struct {
     bool any : 1;
 } NMCSProviderGetConfigTaskData;
 
+/*****************************************************************************/
+
+NMCSProviderGetConfigIfaceData *
+nmcs_provider_get_config_iface_data_create(NMCSProviderGetConfigTaskData *get_config_data,
+                                           gboolean                       was_requested,
+                                           const char                    *hwaddr);
+
+/*****************************************************************************/
+
 #define NMCS_TYPE_PROVIDER (nmcs_provider_get_type())
 #define NMCS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NMCS_TYPE_PROVIDER, NMCSProvider))
 #define NMCS_PROVIDER_CLASS(klass) \
@@ -118,7 +142,7 @@ typedef struct {
 
 struct _NMCSProviderPrivate;
 
-typedef struct {
+typedef struct _NMCSProvider {
     GObject                      parent;
     struct _NMCSProviderPrivate *_priv;
 } NMCSProvider;
@@ -167,4 +191,11 @@ void nmcs_provider_get_config(NMCSProvider       *provider,
 NMCSProviderGetConfigResult *
 nmcs_provider_get_config_finish(NMCSProvider *provider, GAsyncResult *result, GError **error);
 
+/*****************************************************************************/
+
+/* Forward declare the implemented gtype getters so we can use it at a few places without requiring
+ * to include the full header. The other parts of those headers should not be used aside where they
+ * are necessary. */
+GType nmcs_provider_aliyun_get_type(void);
+
 #endif /* __NMCS_PROVIDER_H__ */
diff --git a/src/nmcli/connections.c b/src/nmcli/connections.c
index ecf8e2e2..d093823b 100644
--- a/src/nmcli/connections.c
+++ b/src/nmcli/connections.c
@@ -513,8 +513,8 @@ _con_show_fcn_get_type(NMConnection *c, NMActiveConnection *ac, NMMetaAccessorGe
     return connection_type_to_display(s, get_type);
 }
 
-static const char *
-_connection_check_deprecated(NMConnection *c)
+const char *
+nmc_connection_check_deprecated(NMConnection *c)
 {
     NMSettingWirelessSecurity *s_wsec;
     const char                *key_mgmt;
@@ -541,7 +541,7 @@ _connection_to_color(NMConnection *c, NMActiveConnection *ac)
     if (ac)
         return nmc_active_connection_state_to_color(ac);
 
-    if (_connection_check_deprecated(c))
+    if (nmc_connection_check_deprecated(c))
         return NM_META_COLOR_CONNECTION_DEPRECATED;
 
     return NM_META_COLOR_CONNECTION_UNKNOWN;
@@ -1923,7 +1923,8 @@ con_show_get_items_cmp(gconstpointer pa, gconstpointer pb, gpointer user_data)
             }
         }
 
-        NM_CMP_DIRECT(!!_connection_check_deprecated(c_a), !!_connection_check_deprecated(c_b));
+        NM_CMP_DIRECT(!!nmc_connection_check_deprecated(c_a),
+                      !!nmc_connection_check_deprecated(c_b));
         NM_CMP_DIRECT_STRCMP0(nm_connection_get_uuid(c_a), nm_connection_get_uuid(c_b));
         NM_CMP_DIRECT_STRCMP0(nm_connection_get_path(c_a), nm_connection_get_path(c_b));
     }
@@ -5260,7 +5261,7 @@ connection_warnings(NmCli *nmc, NMConnection *connection)
     const char      *id;
     const char      *deprecated;
 
-    deprecated = _connection_check_deprecated(NM_CONNECTION(connection));
+    deprecated = nmc_connection_check_deprecated(NM_CONNECTION(connection));
     if (deprecated)
         g_printerr(_("Warning: %s.\n"), deprecated);
 
diff --git a/src/nmcli/connections.h b/src/nmcli/connections.h
index 782c4eaf..c610766a 100644
--- a/src/nmcli/connections.h
+++ b/src/nmcli/connections.h
@@ -10,6 +10,8 @@
 
 void monitor_connections(NmCli *nmc);
 
+const char *nmc_connection_check_deprecated(NMConnection *c);
+
 gboolean nmc_process_connection_properties(NmCli              *nmc,
                                            NMConnection       *connection,
                                            int                *argc,
diff --git a/src/nmcli/devices.c b/src/nmcli/devices.c
index 2bfc4cec..6fce9de7 100644
--- a/src/nmcli/devices.c
+++ b/src/nmcli/devices.c
@@ -1238,7 +1238,7 @@ compare_aps(gconstpointer a, gconstpointer b, gpointer user_data)
     NMAccessPoint *apb = *(NMAccessPoint **) b;
 
     /* Sort the deprecated WEP connections last. */
-    NM_CMP_DIRECT(_ap_is_wep(apb), _ap_is_wep(apa));
+    NM_CMP_DIRECT(_ap_is_wep(apa), _ap_is_wep(apb));
 
     NM_CMP_DIRECT(nm_access_point_get_strength(apb), nm_access_point_get_strength(apa));
     NM_CMP_DIRECT(nm_access_point_get_frequency(apa), nm_access_point_get_frequency(apb));
@@ -2127,6 +2127,7 @@ add_and_activate_cb(GObject *client, GAsyncResult *result, gpointer user_data)
     NmCli                                                 *nmc    = info->nmc;
     gs_unref_object NMActiveConnection                    *active = NULL;
     gs_free_error GError                                  *error  = NULL;
+    const char                                            *deprecated;
 
     if (info->create)
         active = nm_client_add_and_activate_connection_finish(NM_CLIENT(client), result, &error);
@@ -2152,6 +2153,11 @@ add_and_activate_cb(GObject *client, GAsyncResult *result, gpointer user_data)
         return;
     }
 
+    deprecated =
+        nmc_connection_check_deprecated(NM_CONNECTION(nm_active_connection_get_connection(active)));
+    if (deprecated)
+        g_printerr(_("Warning: %s.\n"), deprecated);
+
     if (nmc->nowait_flag) {
         quit();
         return;