about summary refs log tree commit diff
path: root/src/nm-policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-policy.c')
-rw-r--r--src/nm-policy.c556
1 files changed, 293 insertions, 263 deletions
diff --git a/src/nm-policy.c b/src/nm-policy.c
index e56fce0b..8dfb0ab0 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -44,6 +44,7 @@
 #include "nm-manager.h"
 #include "settings/nm-settings.h"
 #include "settings/nm-settings-connection.h"
+#include "settings/nm-agent-manager.h"
 #include "nm-dhcp4-config.h"
 #include "nm-dhcp6-config.h"
 #include "nm-config.h"
@@ -65,7 +66,9 @@ typedef struct {
 	NMManager *manager;
 	NMNetns *netns;
 	NMFirewallManager *firewall_manager;
-	GSList *pending_activation_checks;
+	CList pending_activation_checks;
+
+	NMAgentManager *agent_mgr;
 
 	GHashTable *devices;
 	GHashTable *pending_active_connections;
@@ -312,8 +315,9 @@ device_ip6_prefix_delegated (NMDevice *device,
 	NMPolicyPrivate *priv = user_data;
 	NMPolicy *self = _PRIV_TO_SELF (priv);
 	IP6PrefixDelegation *delegation = NULL;
-	const GSList *connections, *iter;
 	guint i;
+	const CList *tmp_list;
+	NMActiveConnection *ac;
 
 	_LOGI (LOGD_IP6, "ipv6-pd: received a prefix %s/%d from %s",
 	       nm_utils_inet6_ntop (&prefix->address, NULL),
@@ -344,10 +348,10 @@ device_ip6_prefix_delegated (NMDevice *device,
 	 * so traversing it from the beginning makes it likely for newly
 	 * activated connections that have no subnet assigned to be served
 	 * first. That is a simple yet fair policy, which is good. */
-	connections = nm_manager_get_active_connections (priv->manager);
-	for (iter = connections; iter; iter = g_slist_next (iter)) {
-		NMDevice *to_device = nm_active_connection_get_device (iter->data);
+	nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
+		NMDevice *to_device;
 
+		to_device = nm_active_connection_get_device (ac);
 		if (nm_device_needs_ip6_subnet (to_device))
 			ip6_subnet_from_delegation (delegation, to_device);
 	}
@@ -818,25 +822,25 @@ update_system_hostname (NMPolicy *self, const char *msg)
 
 static void
 update_default_ac (NMPolicy *self,
-                   NMActiveConnection *best,
-                   void (*set_active_func)(NMActiveConnection*, gboolean))
+                   int addr_family,
+                   NMActiveConnection *best)
 {
 	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
-	const GSList *connections, *iter;
+	const CList *tmp_list;
+	NMActiveConnection *ac;
 
 	/* Clear the 'default[6]' flag on all active connections that aren't the new
 	 * default active connection.  We'll set the new default after; this ensures
 	 * we don't ever have two marked 'default[6]' simultaneously.
 	 */
-	connections = nm_manager_get_active_connections (priv->manager);
-	for (iter = connections; iter; iter = g_slist_next (iter)) {
-		if (NM_ACTIVE_CONNECTION (iter->data) != best)
-			set_active_func (NM_ACTIVE_CONNECTION (iter->data), FALSE);
+	nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
+		if (ac != best)
+			nm_active_connection_set_default (ac, addr_family, FALSE);
 	}
 
 	/* Mark new default active connection */
 	if (best)
-		set_active_func (best, TRUE);
+		nm_active_connection_set_default (best, addr_family, TRUE);
 }
 
 static gpointer
@@ -850,19 +854,19 @@ get_best_ip_config (NMPolicy *self,
 	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
 	NMDevice *device;
 	gpointer conf;
-	const GSList *iter;
+	const CList *tmp_list;
+	NMActiveConnection *ac;
 
 	nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
 
-	for (iter = nm_manager_get_active_connections (priv->manager); iter; iter = iter->next) {
-		NMActiveConnection *active = NM_ACTIVE_CONNECTION (iter->data);
+	nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
 		NMVpnConnection *candidate;
 		NMVpnConnectionState vpn_state;
 
-		if (!NM_IS_VPN_CONNECTION (active))
+		if (!NM_IS_VPN_CONNECTION (ac))
 			continue;
 
-		candidate = NM_VPN_CONNECTION (active);
+		candidate = NM_VPN_CONNECTION (ac);
 
 		vpn_state = nm_vpn_connection_get_vpn_state (candidate);
 		if (vpn_state != NM_VPN_CONNECTION_STATE_ACTIVATED)
@@ -887,7 +891,7 @@ get_best_ip_config (NMPolicy *self,
 		 * best metric. */
 		NM_SET_OUT (out_device, NULL);
 		NM_SET_OUT (out_vpn, candidate);
-		NM_SET_OUT (out_ac, active);
+		NM_SET_OUT (out_ac, ac);
 		NM_SET_OUT (out_ip_iface, nm_vpn_connection_get_ip_iface (candidate, TRUE));
 		return conf;
 	}
@@ -919,26 +923,6 @@ get_best_ip_config (NMPolicy *self,
 }
 
 static void
-update_ip4_dns (NMPolicy *self, NMDnsManager *dns_mgr)
-{
-	NMIP4Config *ip4_config;
-	const char *ip_iface = NULL;
-	NMVpnConnection *vpn = NULL;
-	NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
-
-	ip4_config = get_best_ip_config (self, AF_INET, &ip_iface, NULL, NULL, &vpn);
-	if (ip4_config) {
-		if (vpn)
-			dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
-
-		/* Tell the DNS manager this config is preferred by re-adding it with
-		 * a different IP config type.
-		 */
-		nm_dns_manager_add_ip4_config (dns_mgr, ip_iface, ip4_config, dns_type);
-	}
-}
-
-static void
 update_ip4_routing (NMPolicy *self, gboolean force_update)
 {
 	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
@@ -946,6 +930,8 @@ update_ip4_routing (NMPolicy *self, gboolean force_update)
 	NMVpnConnection *vpn = NULL;
 	NMActiveConnection *best_ac = NULL;
 	const char *ip_iface = NULL;
+	const CList *tmp_list;
+	NMActiveConnection *ac;
 
 	/* Note that we might have an IPv4 VPN tunneled over an IPv6-only device,
 	 * so we can get (vpn != NULL && best == NULL).
@@ -965,23 +951,18 @@ update_ip4_routing (NMPolicy *self, gboolean force_update)
 		return;
 
 	if (best) {
-		const GSList *connections, *iter;
-
-		connections = nm_manager_get_active_connections (priv->manager);
-		for (iter = connections; iter; iter = g_slist_next (iter)) {
-			NMActiveConnection *active = iter->data;
-
-			if (   NM_IS_VPN_CONNECTION (active)
-			    && nm_vpn_connection_get_ip4_config (NM_VPN_CONNECTION (active))
-			    && !nm_active_connection_get_device (active))
-				nm_active_connection_set_device (active, best);
+		nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
+			if (   NM_IS_VPN_CONNECTION (ac)
+			    && nm_vpn_connection_get_ip4_config (NM_VPN_CONNECTION (ac))
+			    && !nm_active_connection_get_device (ac))
+				nm_active_connection_set_device (ac, best);
 		}
 	}
 
 	if (vpn)
 		best = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
 
-	update_default_ac (self, best_ac, nm_active_connection_set_default);
+	update_default_ac (self, AF_INET, best_ac);
 
 	if (!nm_g_object_ref_set (&priv->default_device4, best))
 		return;
@@ -997,50 +978,28 @@ static void
 update_ip6_dns_delegation (NMPolicy *self)
 {
 	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
-	const GSList *connections, *iter;
-
-	connections = nm_manager_get_active_connections (priv->manager);
-	for (iter = connections; iter; iter = g_slist_next (iter)) {
-		NMDevice *device = nm_active_connection_get_device (iter->data);
+	NMDevice *device;
+	NMActiveConnection *ac;
+	const CList *tmp_list;
 
+	nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
+		device = nm_active_connection_get_device (ac);
 		if (device && nm_device_needs_ip6_subnet (device))
 			nm_device_copy_ip6_dns_config (device, priv->default_device6);
 	}
 }
 
 static void
-update_ip6_dns (NMPolicy *self, NMDnsManager *dns_mgr)
-{
-	NMIP6Config *ip6_config;
-	const char *ip_iface = NULL;
-	NMVpnConnection *vpn = NULL;
-	NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
-
-	ip6_config = get_best_ip_config (self, AF_INET6, &ip_iface, NULL, NULL, &vpn);
-	if (ip6_config) {
-		if (vpn)
-			dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
-
-		/* Tell the DNS manager this config is preferred by re-adding it with
-		 * a different IP config type.
-		 */
-		nm_dns_manager_add_ip6_config (dns_mgr, ip_iface, ip6_config, dns_type);
-	}
-
-	update_ip6_dns_delegation (self);
-}
-
-static void
 update_ip6_prefix_delegation (NMPolicy *self)
 {
 	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
-	const GSList *connections, *iter;
+	NMDevice *device;
+	NMActiveConnection *ac;
+	const CList *tmp_list;
 
 	/* There's new default IPv6 connection, try to get a prefix for everyone. */
-	connections = nm_manager_get_active_connections (priv->manager);
-	for (iter = connections; iter; iter = g_slist_next (iter)) {
-		NMDevice *device = nm_active_connection_get_device (iter->data);
-
+	nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
+		device = nm_active_connection_get_device (ac);
 		if (device && nm_device_needs_ip6_subnet (device))
 			ip6_subnet_from_device (self, priv->default_device6, device);
 	}
@@ -1054,6 +1013,8 @@ update_ip6_routing (NMPolicy *self, gboolean force_update)
 	NMVpnConnection *vpn = NULL;
 	NMActiveConnection *best_ac = NULL;
 	const char *ip_iface = NULL;
+	NMActiveConnection *ac;
+	const CList *tmp_list;
 
 	/* Note that we might have an IPv6 VPN tunneled over an IPv4-only device,
 	 * so we can get (vpn != NULL && best == NULL).
@@ -1073,23 +1034,18 @@ update_ip6_routing (NMPolicy *self, gboolean force_update)
 		return;
 
 	if (best) {
-		const GSList *connections, *iter;
-
-		connections = nm_manager_get_active_connections (priv->manager);
-		for (iter = connections; iter; iter = g_slist_next (iter)) {
-			NMActiveConnection *active = iter->data;
-
-			if (   NM_IS_VPN_CONNECTION (active)
-			    && nm_vpn_connection_get_ip6_config (NM_VPN_CONNECTION (active))
-			    && !nm_active_connection_get_device (active))
-				nm_active_connection_set_device (active, best);
+		nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
+			if (   NM_IS_VPN_CONNECTION (ac)
+			    && nm_vpn_connection_get_ip6_config (NM_VPN_CONNECTION (ac))
+			    && !nm_active_connection_get_device (ac))
+				nm_active_connection_set_device (ac, best);
 		}
 	}
 
 	if (vpn)
 		best = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
 
-	update_default_ac (self, best_ac, nm_active_connection_set_default6);
+	update_default_ac (self, AF_INET6, best_ac);
 
 	if (!nm_g_object_ref_set (&priv->default_device6, best))
 		return;
@@ -1104,14 +1060,42 @@ update_ip6_routing (NMPolicy *self, gboolean force_update)
 }
 
 static void
+update_ip_dns (NMPolicy *self, int addr_family)
+{
+	gpointer ip_config;
+	const char *ip_iface = NULL;
+	NMVpnConnection *vpn = NULL;
+	NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
+
+	nm_assert_addr_family (addr_family);
+
+	ip_config = get_best_ip_config (self, addr_family, &ip_iface, NULL, NULL, &vpn);
+	if (ip_config) {
+		if (vpn)
+			dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
+
+		/* Tell the DNS manager this config is preferred by re-adding it with
+		 * a different IP config type.
+		 */
+		nm_dns_manager_add_ip_config (NM_POLICY_GET_PRIVATE (self)->dns_manager,
+		                              ip_iface,
+		                              ip_config,
+		                              dns_type);
+	}
+
+	if (addr_family == AF_INET6)
+		update_ip6_dns_delegation (self);
+}
+
+static void
 update_routing_and_dns (NMPolicy *self, gboolean force_update)
 {
 	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
 
 	nm_dns_manager_begin_updates (priv->dns_manager, __func__);
 
-	update_ip4_dns (self, priv->dns_manager);
-	update_ip6_dns (self, priv->dns_manager);
+	update_ip_dns (self, AF_INET);
+	update_ip_dns (self, AF_INET6);
 
 	update_ip4_routing (self, force_update);
 	update_ip6_routing (self, force_update);
@@ -1146,6 +1130,7 @@ check_activating_devices (NMPolicy *self)
 }
 
 typedef struct {
+	CList pending_lst;
 	NMPolicy *policy;
 	NMDevice *device;
 	guint autoactivate_id;
@@ -1154,14 +1139,10 @@ typedef struct {
 static void
 activate_data_free (ActivateData *data)
 {
-	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (data->policy);
-
 	nm_device_remove_pending_action (data->device, NM_PENDING_ACTION_AUTOACTIVATE, TRUE);
-	priv->pending_activation_checks = g_slist_remove (priv->pending_activation_checks, data);
-
+	c_list_unlink_stale (&data->pending_lst);
 	nm_clear_g_source (&data->autoactivate_id);
 	g_object_unref (data->device);
-
 	g_slice_free (ActivateData, data);
 }
 
@@ -1192,7 +1173,7 @@ pending_ac_state_changed (NMActiveConnection *ac, guint state, guint reason, NMP
 		 * loop.
 		 */
 		con = nm_active_connection_get_settings_connection (ac);
-		nm_settings_connection_autoconnect_blocked_reason_set (con, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED);
+		nm_settings_connection_autoconnect_blocked_reason_set (con, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, TRUE);
 		schedule_activate_check (self, nm_active_connection_get_device (ac));
 
 		/* Cleanup */
@@ -1213,7 +1194,7 @@ auto_activate_device (NMPolicy *self,
 	gs_free char *specific_object = NULL;
 	gs_free NMSettingsConnection **connections = NULL;
 	guint i, len;
-	GError *error = NULL;
+	gs_free_error GError *error = NULL;
 	NMAuthSubject *subject;
 	NMActiveConnection *ac;
 
@@ -1243,9 +1224,7 @@ auto_activate_device (NMPolicy *self,
 		NMSettingConnection *s_con;
 		const char *permission;
 
-		if (   !nm_settings_connection_is_visible (candidate)
-		    || nm_settings_connection_autoconnect_retries_get (candidate) == 0
-		    || nm_settings_connection_autoconnect_blocked_reason_get (candidate) != NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE)
+		if (nm_settings_connection_autoconnect_is_blocked (candidate))
 			continue;
 
 		s_con = nm_connection_get_setting_connection (NM_CONNECTION (candidate));
@@ -1278,13 +1257,12 @@ auto_activate_device (NMPolicy *self,
 	                                     NM_ACTIVATION_TYPE_MANAGED,
 	                                     &error);
 	if (!ac) {
-		_LOGI (LOGD_DEVICE, "connection '%s' auto-activation failed: (%d) %s",
+		_LOGI (LOGD_DEVICE, "connection '%s' auto-activation failed: %s",
 		       nm_settings_connection_get_id (best_connection),
-		       error->code,
 		       error->message);
-		g_error_free (error);
 		nm_settings_connection_autoconnect_blocked_reason_set (best_connection,
-		                                                       NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED);
+		                                                       NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED,
+		                                                       TRUE);
 		schedule_activate_check (self, device);
 		return;
 	}
@@ -1318,13 +1296,14 @@ auto_activate_device_cb (gpointer user_data)
 }
 
 static ActivateData *
-find_pending_activation (GSList *list, NMDevice *device)
+find_pending_activation (NMPolicy *self, NMDevice *device)
 {
-	GSList *iter;
+	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
+	ActivateData *data;
 
-	for (iter = list; iter; iter = g_slist_next (iter)) {
-		if (((ActivateData *) iter->data)->device == device)
-			return iter->data;
+	c_list_for_each_entry (data, &priv->pending_activation_checks, pending_lst) {
+		if (data->device == device)
+			return data;
 	}
 	return NULL;
 }
@@ -1422,48 +1401,56 @@ hostname_changed (NMHostnameManager *hostname_manager, GParamSpec *pspec, gpoint
 	update_system_hostname (self, "hostname changed");
 }
 
-static void
-reset_autoconnect_all (NMPolicy *self, NMDevice *device)
+static gboolean
+reset_autoconnect_all (NMPolicy *self,
+                       NMDevice *device, /* if present, only reset connections compatible with @device */
+                       gboolean only_no_secrets)
 {
 	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
-	gs_free NMSettingsConnection **connections = NULL;
+	NMSettingsConnection *const*connections = NULL;
 	guint i;
+	gboolean changed;
 
-	if (device) {
-		_LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections on %s",
-		       nm_device_get_iface (device));
-	} else
-		_LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections");
+	_LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections%s%s%s",
+	       device ? " on " : "",
+	       device ? nm_device_get_iface (device) : "",
+	       only_no_secrets ? " (only clear no-secrets flag)" : "");
 
-	connections = nm_settings_get_connections_sorted (priv->settings, NULL);
+	connections = nm_settings_get_connections (priv->settings, NULL);
 	for (i = 0; connections[i]; i++) {
 		NMSettingsConnection *connection = connections[i];
 
-		if (!device || nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) {
-			nm_settings_connection_autoconnect_retries_reset (connection);
-			nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE);
-		}
-	}
-}
-
-static void
-reset_autoconnect_for_failed_secrets (NMPolicy *self)
-{
-	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
-	gs_free NMSettingsConnection **connections = NULL;
-	guint i;
-
-	_LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections with failed secrets");
-
-	connections = nm_settings_get_connections_sorted (priv->settings, NULL);
-	for (i = 0; connections[i]; i++) {
-		NMSettingsConnection *connection = connections[i];
+		if (   device
+		    && !nm_device_check_connection_compatible (device, NM_CONNECTION (connection)))
+			continue;
 
-		if (nm_settings_connection_autoconnect_blocked_reason_get (connection) == NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS) {
+		if (only_no_secrets) {
+			/* we only reset the no-secrets blocked flag. */
+			if (nm_settings_connection_autoconnect_blocked_reason_set (connection,
+			                                                           NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS,
+			                                                           FALSE)) {
+				/* maybe the connection is still blocked afterwards for other reasons
+				 * and in the larger picture nothing changed. But it's too complicated
+				 * to find out exactly. Just assume, something changed to be sure. */
+				if (!nm_settings_connection_autoconnect_is_blocked (connection))
+					changed = TRUE;
+			}
+		} else {
+			/* we reset the tries-count and any blocked-reason */
+			if (nm_settings_connection_autoconnect_retries_get (connection) == 0)
+				changed = TRUE;
 			nm_settings_connection_autoconnect_retries_reset (connection);
-			nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE);
+
+			if (nm_settings_connection_autoconnect_blocked_reason_set (connection,
+			                                                             NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL
+			                                                           & ~NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST,
+			                                                           FALSE)) {
+				if (!nm_settings_connection_autoconnect_is_blocked (connection))
+					changed = TRUE;
+			}
 		}
 	}
+	return changed;
 }
 
 static void
@@ -1478,7 +1465,7 @@ sleeping_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data)
 
 	/* Reset retries on all connections so they'll checked on wakeup */
 	if (sleeping || !enabled)
-		reset_autoconnect_all (self, NULL);
+		reset_autoconnect_all (self, NULL, FALSE);
 }
 
 static void
@@ -1486,7 +1473,8 @@ schedule_activate_check (NMPolicy *self, NMDevice *device)
 {
 	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
 	ActivateData *data;
-	const GSList *active_connections, *iter;
+	NMActiveConnection *ac;
+	const CList *tmp_list;
 
 	if (nm_manager_get_state (priv->manager) == NM_STATE_ASLEEP)
 		return;
@@ -1494,12 +1482,11 @@ schedule_activate_check (NMPolicy *self, NMDevice *device)
 	if (!nm_device_autoconnect_allowed (device))
 		return;
 
-	if (find_pending_activation (priv->pending_activation_checks, device))
+	if (find_pending_activation (self, device))
 		return;
 
-	active_connections = nm_manager_get_active_connections (priv->manager);
-	for (iter = active_connections; iter; iter = iter->next) {
-		if (nm_active_connection_get_device (NM_ACTIVE_CONNECTION (iter->data)) == device)
+	nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
+		if (nm_active_connection_get_device (ac) == device)
 			return;
 	}
 
@@ -1509,18 +1496,7 @@ schedule_activate_check (NMPolicy *self, NMDevice *device)
 	data->policy = self;
 	data->device = g_object_ref (device);
 	data->autoactivate_id = g_idle_add (auto_activate_device_cb, data);
-	priv->pending_activation_checks = g_slist_append (priv->pending_activation_checks, data);
-}
-
-static void
-clear_pending_activate_check (NMPolicy *self, NMDevice *device)
-{
-	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
-	ActivateData *data;
-
-	data = find_pending_activation (priv->pending_activation_checks, device);
-	if (data && data->autoactivate_id)
-		activate_data_free (data);
+	c_list_link_tail (&priv->pending_activation_checks, &data->pending_lst);
 }
 
 static gboolean
@@ -1528,7 +1504,7 @@ reset_connections_retries (gpointer user_data)
 {
 	NMPolicy *self = (NMPolicy *) user_data;
 	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
-	gs_free NMSettingsConnection **connections = NULL;
+	NMSettingsConnection *const*connections = NULL;
 	guint i;
 	gint32 con_stamp, min_stamp, now;
 	gboolean changed = FALSE;
@@ -1537,11 +1513,11 @@ reset_connections_retries (gpointer user_data)
 
 	min_stamp = 0;
 	now = nm_utils_get_monotonic_timestamp_s ();
-	connections = nm_settings_get_connections_sorted (priv->settings, NULL);
+	connections = nm_settings_get_connections (priv->settings, NULL);
 	for (i = 0; connections[i]; i++) {
 		NMSettingsConnection *connection = connections[i];
 
-		con_stamp = nm_settings_connection_autoconnect_blocked_until_get (connection);
+		con_stamp = nm_settings_connection_autoconnect_retries_blocked_until (connection);
 		if (con_stamp == 0)
 			continue;
 
@@ -1564,6 +1540,29 @@ reset_connections_retries (gpointer user_data)
 }
 
 static void
+_connection_autoconnect_retries_set (NMPolicy *self,
+                                     NMSettingsConnection *connection,
+                                     int tries)
+{
+	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
+
+	nm_assert (NM_IS_SETTINGS_CONNECTION (connection));
+	nm_assert (tries >= 0);
+
+	nm_settings_connection_autoconnect_retries_set (connection, tries);
+
+	if (tries == 0) {
+		/* Schedule a handler to reset retries count */
+		if (!priv->reset_retries_id) {
+			gint32 retry_time = nm_settings_connection_autoconnect_retries_blocked_until (connection);
+
+			g_warn_if_fail (retry_time != 0);
+			priv->reset_retries_id = g_timeout_add_seconds (MAX (0, retry_time - nm_utils_get_monotonic_timestamp_s ()), reset_connections_retries, self);
+		}
+	}
+}
+
+static void
 activate_slave_connections (NMPolicy *self, NMDevice *device)
 {
 	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
@@ -1571,7 +1570,8 @@ activate_slave_connections (NMPolicy *self, NMDevice *device)
 	guint i;
 	NMActRequest *req;
 	gboolean internal_activation = FALSE;
-	gs_free NMSettingsConnection **connections = NULL;
+	NMSettingsConnection *const*connections;
+	gboolean changed;
 
 	master_device = nm_device_get_iface (device);
 	g_assert (master_device);
@@ -1595,38 +1595,37 @@ activate_slave_connections (NMPolicy *self, NMDevice *device)
 		internal_activation = subject && nm_auth_subject_is_internal (subject);
 	}
 
-	connections = nm_settings_get_connections_sorted (priv->settings, NULL);
+	changed = FALSE;
+	connections = nm_settings_get_connections (priv->settings, NULL);
 	for (i = 0; connections[i]; i++) {
-		NMConnection *slave;
+		NMSettingsConnection *connection = connections[i];
 		NMSettingConnection *s_slave_con;
 		const char *slave_master;
 
-		slave = NM_CONNECTION (connections[i]);
-
-		s_slave_con = nm_connection_get_setting_connection (slave);
-		g_assert (s_slave_con);
+		s_slave_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
 		slave_master = nm_setting_connection_get_master (s_slave_con);
 		if (!slave_master)
 			continue;
+		if (!NM_IN_STRSET (slave_master, master_device,
+		                                 master_uuid_applied,
+		                                 master_uuid_settings))
+			continue;
 
-		if (   nm_streq0 (slave_master, master_device)
-		    || nm_streq0 (slave_master, master_uuid_applied)
-		    || nm_streq0 (slave_master, master_uuid_settings)) {
-			NMSettingsConnection *settings = NM_SETTINGS_CONNECTION (slave);
-			NMSettingsAutoconnectBlockedReason reason;
-
-			if (!internal_activation)
-				nm_settings_connection_autoconnect_retries_reset (settings);
-
-			reason = nm_settings_connection_autoconnect_blocked_reason_get (settings);
-			if (reason == NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED) {
-				reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE;
-				nm_settings_connection_autoconnect_blocked_reason_set (settings, reason);
-			}
+		if (!internal_activation) {
+			if (nm_settings_connection_autoconnect_retries_get (connection) == 0)
+				changed = TRUE;
+			nm_settings_connection_autoconnect_retries_reset (connection);
+		}
+		if (nm_settings_connection_autoconnect_blocked_reason_set (connection,
+		                                                           NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED,
+		                                                           FALSE)) {
+			if (!nm_settings_connection_autoconnect_is_blocked (connection))
+				changed = TRUE;
 		}
 	}
 
-	schedule_activate_all (self);
+	if (changed)
+		schedule_activate_all (self);
 }
 
 static gboolean
@@ -1711,9 +1710,7 @@ device_state_changed (NMDevice *device,
 	NMPolicyPrivate *priv = user_data;
 	NMPolicy *self = _PRIV_TO_SELF (priv);
 	NMActiveConnection *ac;
-
 	NMSettingsConnection *connection = nm_device_get_settings_connection (device);
-
 	const char *ip_iface = nm_device_get_ip_iface (device);
 	NMIP4Config *ip4_config;
 	NMIP6Config *ip6_config;
@@ -1734,7 +1731,8 @@ device_state_changed (NMDevice *device,
 		 */
 		if (connection) {
 			nm_settings_connection_autoconnect_blocked_reason_set (connection,
-			                                                       NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED);
+			                                                       NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED,
+			                                                       TRUE);
 		}
 		break;
 	default:
@@ -1749,36 +1747,40 @@ device_state_changed (NMDevice *device,
 		if (   connection
 		    && old_state >= NM_DEVICE_STATE_PREPARE
 		    && old_state <= NM_DEVICE_STATE_ACTIVATED) {
+			gboolean block_no_secrets = FALSE;
 			int tries;
+			guint64 con_v;
 
-			tries = nm_settings_connection_autoconnect_retries_get (connection);
 			if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_NO_SECRETS) {
+				/* we want to block the connection from auto-connect if it failed due to no-secrets.
+				 * However, if a secret-agent registered, since the connection made the last
+				 * secret-request, we do not block it. The new secret-agent might not yet
+				 * been consulted, and it may be able to provide the secrets.
+				 *
+				 * We detect this by using a version-id of the agent-manager, which increments
+				 * whenever new agents register. */
+				con_v = nm_settings_connection_get_last_secret_agent_version_id (connection);
+				if (   con_v == 0
+				    || con_v != nm_agent_manager_get_agent_version_id (priv->agent_mgr))
+					block_no_secrets = TRUE;
+			}
+
+			if (block_no_secrets) {
 				_LOGD (LOGD_DEVICE, "connection '%s' now blocked from autoconnect due to no secrets",
 				       nm_settings_connection_get_id (connection));
-
-				nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS);
-			} else if (tries != 0) {
+				nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, TRUE);
+			} else {
+				tries = nm_settings_connection_autoconnect_retries_get (connection);
 				if (tries > 0) {
 					_LOGD (LOGD_DEVICE, "connection '%s' failed to autoconnect; %d tries left",
-					       nm_settings_connection_get_id (connection), tries);
-					nm_settings_connection_autoconnect_retries_set (connection, --tries);
-				} else {
+					       nm_settings_connection_get_id (connection), tries - 1);
+					_connection_autoconnect_retries_set (self, connection, tries - 1);
+				} else if (tries != 0) {
 					_LOGD (LOGD_DEVICE, "connection '%s' failed to autoconnect; infinite tries left",
 					       nm_settings_connection_get_id (connection));
 				}
 			}
 
-			if (nm_settings_connection_autoconnect_retries_get (connection) == 0) {
-				_LOGI (LOGD_DEVICE, "disabling autoconnect for connection '%s'.",
-				       nm_settings_connection_get_id (connection));
-				/* Schedule a handler to reset retries count */
-				if (!priv->reset_retries_id) {
-					gint32 retry_time = nm_settings_connection_autoconnect_blocked_until_get (connection);
-
-					g_warn_if_fail (retry_time != 0);
-					priv->reset_retries_id = g_timeout_add_seconds (MAX (0, retry_time - nm_utils_get_monotonic_timestamp_s ()), reset_connections_retries, self);
-				}
-			}
 			nm_connection_clear_secrets (NM_CONNECTION (connection));
 		}
 		break;
@@ -1800,10 +1802,10 @@ device_state_changed (NMDevice *device,
 
 		ip4_config = nm_device_get_ip4_config (device);
 		if (ip4_config)
-			nm_dns_manager_add_ip4_config (priv->dns_manager, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
+			nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
 		ip6_config = nm_device_get_ip6_config (device);
 		if (ip6_config)
-			nm_dns_manager_add_ip6_config (priv->dns_manager, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
+			nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
 
 		update_routing_and_dns (self, FALSE);
 
@@ -1815,13 +1817,25 @@ device_state_changed (NMDevice *device,
 			update_routing_and_dns (self, FALSE);
 		break;
 	case NM_DEVICE_STATE_DEACTIVATING:
-		if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_USER_REQUESTED) {
-			if (connection) {
-				/* The connection was deactivated, so block just this connection */
-				_LOGD (LOGD_DEVICE, "blocking autoconnect of connection '%s' by user request",
-				       nm_settings_connection_get_id (connection));
-				nm_settings_connection_autoconnect_blocked_reason_set (connection,
-				                                                       NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST);
+		if (connection) {
+			NMSettingsAutoconnectBlockedReason blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE;
+
+			switch (nm_device_state_reason_check (reason)) {
+			case NM_DEVICE_STATE_REASON_USER_REQUESTED:
+				 blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST;
+				break;
+			case NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED:
+				blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED;
+				break;
+			default:
+				break;
+			}
+			if (blocked_reason != NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE) {
+				_LOGD (LOGD_DEVICE, "blocking autoconnect of connection '%s': %s",
+				       nm_settings_connection_get_id (connection),
+				       NM_UTILS_LOOKUP_STR (nm_device_state_reason_to_str,
+				                            nm_device_state_reason_check (reason)));
+				nm_settings_connection_autoconnect_blocked_reason_set (connection, blocked_reason, TRUE);
 			}
 		}
 		ip6_remove_device_prefix_delegations (self, device);
@@ -1832,7 +1846,7 @@ device_state_changed (NMDevice *device,
 		 */
 		if (   nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_CARRIER
 		    && old_state == NM_DEVICE_STATE_UNAVAILABLE)
-			reset_autoconnect_all (self, device);
+			reset_autoconnect_all (self, device, FALSE);
 
 		if (old_state > NM_DEVICE_STATE_DISCONNECTED)
 			update_routing_and_dns (self, FALSE);
@@ -1858,7 +1872,7 @@ device_state_changed (NMDevice *device,
 	case NM_DEVICE_STATE_IP_CONFIG:
 		/* We must have secrets if we got here. */
 		if (connection)
-			nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE);
+			nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL, FALSE);
 		break;
 	case NM_DEVICE_STATE_SECONDARIES:
 		if (connection)
@@ -1903,17 +1917,17 @@ device_ip4_config_changed (NMDevice *device,
 	if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) {
 		if (old_config != new_config) {
 			if (old_config)
-				nm_dns_manager_remove_ip4_config (priv->dns_manager, old_config);
+				nm_dns_manager_remove_ip_config (priv->dns_manager, old_config);
 			if (new_config)
-				nm_dns_manager_add_ip4_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
+				nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
 		}
-		update_ip4_dns (self, priv->dns_manager);
+		update_ip_dns (self, AF_INET);
 		update_ip4_routing (self, TRUE);
 		update_system_hostname (self, "ip4 conf");
 	} else {
 		/* Old configs get removed immediately */
 		if (old_config)
-			nm_dns_manager_remove_ip4_config (priv->dns_manager, old_config);
+			nm_dns_manager_remove_ip_config (priv->dns_manager, old_config);
 	}
 
 	nm_dns_manager_end_updates (priv->dns_manager, __func__);
@@ -1939,17 +1953,17 @@ device_ip6_config_changed (NMDevice *device,
 	if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) {
 		if (old_config != new_config) {
 			if (old_config)
-				nm_dns_manager_remove_ip6_config (priv->dns_manager, old_config);
+				nm_dns_manager_remove_ip_config (priv->dns_manager, old_config);
 			if (new_config)
-				nm_dns_manager_add_ip6_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
+				nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
 		}
-		update_ip6_dns (self, priv->dns_manager);
+		update_ip_dns (self, AF_INET6);
 		update_ip6_routing (self, TRUE);
 		update_system_hostname (self, "ip6 conf");
 	} else {
 		/* Old configs get removed immediately */
 		if (old_config)
-			nm_dns_manager_remove_ip6_config (priv->dns_manager, old_config);
+			nm_dns_manager_remove_ip_config (priv->dns_manager, old_config);
 	}
 
 	nm_dns_manager_end_updates (priv->dns_manager, __func__);
@@ -2021,13 +2035,16 @@ device_removed (NMManager *manager, NMDevice *device, gpointer user_data)
 {
 	NMPolicyPrivate *priv = user_data;
 	NMPolicy *self = _PRIV_TO_SELF (priv);
+	ActivateData *data;
 
 	/* XXX is this needed? The delegations are cleaned up
 	 * on transition to deactivated too. */
 	ip6_remove_device_prefix_delegations (self, device);
 
 	/* Clear any idle callbacks for this device */
-	clear_pending_activate_check (self, device);
+	data = find_pending_activation (self, device);
+	if (data && data->autoactivate_id)
+		activate_data_free (data);
 
 	if (g_hash_table_remove (priv->devices, device))
 		devices_list_unregister (self, device);
@@ -2055,11 +2072,11 @@ vpn_connection_activated (NMPolicy *self, NMVpnConnection *vpn)
 
 	ip4_config = nm_vpn_connection_get_ip4_config (vpn);
 	if (ip4_config)
-		nm_dns_manager_add_ip4_config (priv->dns_manager, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_VPN);
+		nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_VPN);
 
 	ip6_config = nm_vpn_connection_get_ip6_config (vpn);
 	if (ip6_config)
-		nm_dns_manager_add_ip6_config (priv->dns_manager, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_VPN);
+		nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_VPN);
 
 	update_routing_and_dns (self, TRUE);
 
@@ -2078,13 +2095,13 @@ vpn_connection_deactivated (NMPolicy *self, NMVpnConnection *vpn)
 	ip4_config = nm_vpn_connection_get_ip4_config (vpn);
 	if (ip4_config) {
 		/* Remove the VPN connection's IP4 config from DNS */
-		nm_dns_manager_remove_ip4_config (priv->dns_manager, ip4_config);
+		nm_dns_manager_remove_ip_config (priv->dns_manager, ip4_config);
 	}
 
 	ip6_config = nm_vpn_connection_get_ip6_config (vpn);
 	if (ip6_config) {
 		/* Remove the VPN connection's IP6 config from DNS */
-		nm_dns_manager_remove_ip6_config (priv->dns_manager, ip6_config);
+		nm_dns_manager_remove_ip_config (priv->dns_manager, ip6_config);
 	}
 
 	update_routing_and_dns (self, TRUE);
@@ -2317,19 +2334,21 @@ connection_updated (NMSettings *settings,
 }
 
 static void
-_deactivate_if_active (NMManager *manager, NMSettingsConnection *connection)
+_deactivate_if_active (NMPolicy *self, NMSettingsConnection *connection)
 {
-	const GSList *active, *iter;
+	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
+	NMActiveConnection *ac;
+	const CList *tmp_list;
+	GError *error = NULL;
+
+	nm_assert (NM_IS_SETTINGS_CONNECTION (connection));
 
-	active = nm_manager_get_active_connections (manager);
-	for (iter = active; iter; iter = g_slist_next (iter)) {
-		NMActiveConnection *ac = iter->data;
+	nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
 		NMActiveConnectionState state = nm_active_connection_get_state (ac);
-		GError *error = NULL;
 
-		if (nm_active_connection_get_settings_connection (ac) == connection &&
-		    (state <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) {
-			if (!nm_manager_deactivate_connection (manager,
+		if (   nm_active_connection_get_settings_connection (ac) == connection
+		    && (state <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) {
+			if (!nm_manager_deactivate_connection (priv->manager,
 			                                       ac,
 			                                       NM_DEVICE_STATE_REASON_CONNECTION_REMOVED,
 			                                       &error)) {
@@ -2349,22 +2368,25 @@ connection_removed (NMSettings *settings,
                     gpointer user_data)
 {
 	NMPolicyPrivate *priv = user_data;
+	NMPolicy *self = _PRIV_TO_SELF (priv);
 
-	_deactivate_if_active (priv->manager, connection);
+	_deactivate_if_active (self, connection);
 }
 
 static void
-connection_visibility_changed (NMSettings *settings,
-                               NMSettingsConnection *connection,
-                               gpointer user_data)
+connection_flags_changed (NMSettings *settings,
+                          NMSettingsConnection *connection,
+                          gpointer user_data)
 {
 	NMPolicyPrivate *priv = user_data;
 	NMPolicy *self = _PRIV_TO_SELF (priv);
 
-	if (nm_settings_connection_is_visible (connection))
-		schedule_activate_all (self);
-	else
-		_deactivate_if_active (priv->manager, connection);
+	if (NM_FLAGS_HAS (nm_settings_connection_get_flags (connection),
+	                  NM_SETTINGS_CONNECTION_FLAGS_VISIBLE)) {
+		if (!nm_settings_connection_autoconnect_is_blocked (connection))
+			schedule_activate_all (self);
+	} else
+		_deactivate_if_active (self, connection);
 }
 
 static void
@@ -2372,15 +2394,14 @@ secret_agent_registered (NMSettings *settings,
                          NMSecretAgent *agent,
                          gpointer user_data)
 {
-	NMPolicyPrivate *priv = user_data;
-	NMPolicy *self = _PRIV_TO_SELF (priv);
+	NMPolicy *self = NM_POLICY (user_data);
 
 	/* The registered secret agent may provide some missing secrets. Thus we
 	 * reset retries count here and schedule activation, so that the
 	 * connections failed due to missing secrets may re-try auto-connection.
 	 */
-	reset_autoconnect_for_failed_secrets (self);
-	schedule_activate_all (self);
+	if (reset_autoconnect_all (self, NULL, TRUE))
+		schedule_activate_all (self);
 }
 
 NMDevice *
@@ -2476,6 +2497,8 @@ nm_policy_init (NMPolicy *self)
 	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
 	const char *hostname_mode;
 
+	c_list_init (&priv->pending_activation_checks);
+
 	priv->netns = g_object_ref (nm_netns_get ());
 
 	priv->hostname_manager = g_object_ref (nm_hostname_manager_get ());
@@ -2516,6 +2539,8 @@ constructed (GObject *object)
 	_LOGT (LOGD_DNS, "hostname-original: set to %s%s%s",
 	       NM_PRINT_FMT_QUOTE_STRING (priv->orig_hostname));
 
+	priv->agent_mgr = g_object_ref (nm_agent_manager_get ());
+
 	priv->firewall_manager = g_object_ref (nm_firewall_manager_get ());
 	g_signal_connect (priv->firewall_manager, NM_FIREWALL_MANAGER_STATE_CHANGED,
 	                  G_CALLBACK (firewall_state_changed), self);
@@ -2536,11 +2561,12 @@ constructed (GObject *object)
 	g_signal_connect (priv->manager, NM_MANAGER_ACTIVE_CONNECTION_ADDED,       (GCallback) active_connection_added, priv);
 	g_signal_connect (priv->manager, NM_MANAGER_ACTIVE_CONNECTION_REMOVED,     (GCallback) active_connection_removed, priv);
 
-	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED,              (GCallback) connection_added, priv);
-	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,            (GCallback) connection_updated, priv);
-	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,            (GCallback) connection_removed, priv);
-	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, (GCallback) connection_visibility_changed, priv);
-	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_AGENT_REGISTERED,              (GCallback) secret_agent_registered, priv);
+	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED,         (GCallback) connection_added, priv);
+	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,       (GCallback) connection_updated, priv);
+	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,       (GCallback) connection_removed, priv);
+	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_FLAGS_CHANGED, (GCallback) connection_flags_changed, priv);
+
+	g_signal_connect (priv->agent_mgr, NM_AGENT_MANAGER_AGENT_REGISTERED, G_CALLBACK (secret_agent_registered), self);
 
 	G_OBJECT_CLASS (nm_policy_parent_class)->constructed (object);
 
@@ -2564,9 +2590,9 @@ dispose (GObject *object)
 {
 	NMPolicy *self = NM_POLICY (object);
 	NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
-	const GSList *connections;
 	GHashTableIter h_iter;
 	NMDevice *device;
+	ActivateData *data, *data_safe;
 
 	nm_clear_g_cancellable (&priv->lookup.cancellable);
 	g_clear_object (&priv->lookup.addr);
@@ -2578,8 +2604,8 @@ dispose (GObject *object)
 	nm_clear_g_object (&priv->activating_device6);
 	g_clear_pointer (&priv->pending_active_connections, g_hash_table_unref);
 
-	while (priv->pending_activation_checks)
-		activate_data_free (priv->pending_activation_checks->data);
+	c_list_for_each_entry_safe (data, data_safe, &priv->pending_activation_checks, pending_lst)
+		activate_data_free (data);
 
 	g_slist_free_full (priv->pending_secondaries, (GDestroyNotify) pending_secondary_data_free);
 	priv->pending_secondaries = NULL;
@@ -2589,6 +2615,11 @@ dispose (GObject *object)
 		g_clear_object (&priv->firewall_manager);
 	}
 
+	if (priv->agent_mgr) {
+		g_signal_handlers_disconnect_by_func (priv->agent_mgr, secret_agent_registered, self);
+		g_clear_object (&priv->agent_mgr);
+	}
+
 	if (priv->dns_manager) {
 		nm_clear_g_signal_handler (priv->dns_manager, &priv->config_changed_id);
 		g_clear_object (&priv->dns_manager);
@@ -2604,8 +2635,7 @@ dispose (GObject *object)
 	 * will have called active_connection_removed() and thus we don't need
 	 * to clean anything up.  Assert that this is TRUE.
 	 */
-	connections = nm_manager_get_active_connections (priv->manager);
-	g_assert (connections == NULL);
+	nm_assert (c_list_is_empty (nm_manager_get_active_connections (priv->manager)));
 
 	nm_clear_g_source (&priv->reset_retries_id);
 	nm_clear_g_source (&priv->schedule_activate_all_id);