about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2018-05-11 22:09:26 +0200
committerMichael Biebl <biebl@debian.org>2018-05-11 22:09:26 +0200
commit341d403947279cd347ebd975cae8977703c0b1f3 (patch)
tree34fa6425901e37182b353e7c95dd1d1ec8bc41ec /src
parent962a081193fcc84bbcead3dac6ebe36ccf4415ed (diff)
parentee9c73a923909e23a649407be77e25235d769e25 (diff)
Update upstream source from tag 'upstream/1.10.8'
Update to upstream version '1.10.8'
with Debian dir 3c3431643bdd2871afa3e1131ed2320f988f564d
Diffstat (limited to 'src')
-rw-r--r--src/devices/nm-device.c270
-rw-r--r--src/devices/tests/test-arping.c40
-rw-r--r--src/nm-act-request.c5
-rw-r--r--src/nm-act-request.h1
-rw-r--r--src/nm-active-connection.c25
-rw-r--r--src/nm-active-connection.h13
-rw-r--r--src/nm-checkpoint.c4
-rw-r--r--src/nm-connectivity.c15
-rw-r--r--src/nm-manager.c91
-rw-r--r--src/nm-manager.h1
-rw-r--r--src/nm-policy.c3
-rw-r--r--src/nm-session-monitor.c5
-rw-r--r--src/nm-types.h7
-rw-r--r--src/platform/nmp-object.h3
-rw-r--r--src/vpn/nm-vpn-connection.c2
-rw-r--r--src/vpn/nm-vpn-connection.h1
16 files changed, 294 insertions, 192 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index b8828d14..e79bc541 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -83,9 +83,8 @@ _LOG_DECLARE_SELF (NMDevice);
 
 /*****************************************************************************/
 
-#define DHCP_RESTART_TIMEOUT   120
-#define DHCP_NUM_TRIES_MAX     3
 #define DEFAULT_AUTOCONNECT    TRUE
+#define DHCP_GRACE_PERIOD_SEC  480
 
 #define CARRIER_WAIT_TIME_MS 6000
 #define CARRIER_WAIT_TIME_AFTER_MTU_MS 10000
@@ -387,10 +386,9 @@ typedef struct _NMDevicePrivate {
 		NMDhcpClient *  client;
 		gulong          state_sigid;
 		NMDhcp4Config * config;
-		guint           restart_id;
-		guint           num_tries_left;
 		char *          pac_url;
 		bool            was_active;
+		guint           grace_id;
 	} dhcp4;
 
 	struct {
@@ -461,10 +459,9 @@ typedef struct _NMDevicePrivate {
 		NMIP6Config *    ip6_config;
 		/* Event ID of the current IP6 config from DHCP */
 		char *           event_id;
-		guint            restart_id;
-		guint            num_tries_left;
 		guint            needed_prefixes;
 		bool             was_active;
+		guint            grace_id;
 	} dhcp6;
 
 	gboolean needs_ip6_subnet;
@@ -486,7 +483,7 @@ typedef struct _NMDevicePrivate {
 
 	NMLldpListener *lldp_listener;
 	NMConnectivityState connectivity_state;
-	guint concheck_periodic_id;
+	gulong concheck_periodic_id;
 	guint64 concheck_seq;
 
 	guint check_delete_unrealized_id;
@@ -556,7 +553,6 @@ static void realize_start_setup (NMDevice *self,
                                  NMUnmanFlagOp unmanaged_user_explicit);
 static void _set_mtu (NMDevice *self, guint32 mtu);
 static void _commit_mtu (NMDevice *self, const NMIP4Config *config);
-static void dhcp_schedule_restart (NMDevice *self, int addr_family, const char *reason);
 static void _cancel_activation (NMDevice *self);
 
 /*****************************************************************************/
@@ -879,19 +875,36 @@ nm_device_ipv4_sysctl_set (NMDevice *self, const char *property, const char *val
 }
 
 static guint32
-nm_device_ipv4_sysctl_get_uint32 (NMDevice *self, const char *property, guint32 fallback)
+nm_device_ipv4_sysctl_get_effective_uint32 (NMDevice *self, const char *property, guint32 fallback)
 {
 	char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
+	gint64 v, v_all;
 
 	if (!nm_device_get_ip_ifindex (self))
 		return fallback;
 
-	return nm_platform_sysctl_get_int_checked (nm_device_get_platform (self),
-	                                           NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET, buf, nm_device_get_ip_iface (self), property)),
-	                                           10,
-	                                           0,
-	                                           G_MAXUINT32,
-	                                           fallback);
+	v = nm_platform_sysctl_get_int_checked (nm_device_get_platform (self),
+	                                        NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET,
+	                                                                                                  buf,
+	                                                                                                  nm_device_get_ip_iface (self),
+	                                                                                                  property)),
+	                                        10,
+	                                        0,
+	                                        G_MAXUINT32,
+	                                        -1);
+
+	v_all = nm_platform_sysctl_get_int_checked (nm_device_get_platform (self),
+	                                            NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET,
+	                                                                                                      buf,
+	                                                                                                      "all",
+	                                                                                                      property)),
+	                                            10,
+	                                            0,
+	                                            G_MAXUINT32,
+	                                            -1);
+
+	v = NM_MAX (v, v_all);
+	return v > -1 ? (guint32) v : fallback;
 }
 
 gboolean
@@ -2126,8 +2139,7 @@ concheck_periodic_update (NMDevice *self)
 		nm_device_check_connectivity (self, NULL, NULL);
 	} else if (!check_enable && priv->concheck_periodic_id) {
 		/* The default route has gone off, and so has connectivity. */
-		g_signal_handler_disconnect (nm_connectivity_get (), priv->concheck_periodic_id);
-		priv->concheck_periodic_id = 0;
+		nm_clear_g_signal_handler (nm_connectivity_get (), &priv->concheck_periodic_id);
 		update_connectivity_state (self, NM_CONNECTIVITY_NONE);
 	}
 #else
@@ -2424,12 +2436,12 @@ carrier_changed (NMDevice *self, gboolean carrier)
 			* is restored. */
 			if (priv->state == NM_DEVICE_STATE_ACTIVATED)
 				nm_device_update_dynamic_ip_setup (self);
-			else {
-				if (nm_device_activate_ip4_state_in_wait (self))
-					nm_device_activate_stage3_ip4_start (self);
-				if (nm_device_activate_ip6_state_in_wait (self))
-					nm_device_activate_stage3_ip6_start (self);
-			}
+			/* If needed, also resume IP configuration that is
+			 * waiting for carrier. */
+			if (nm_device_activate_ip4_state_in_wait (self))
+				nm_device_activate_stage3_ip4_start (self);
+			if (nm_device_activate_ip6_state_in_wait (self))
+				nm_device_activate_stage3_ip6_start (self);
 			return;
 		}
 		/* fall-through and change state of device */
@@ -2981,7 +2993,7 @@ ip4_rp_filter_update (NMDevice *self)
 
 	if (   priv->v4_has_shadowed_routes
 	    || nm_device_get_best_default_route (self, AF_INET)) {
-		if (nm_device_ipv4_sysctl_get_uint32 (self, "rp_filter", 0) != 1) {
+		if (nm_device_ipv4_sysctl_get_effective_uint32 (self, "rp_filter", 0) != 1) {
 			/* Don't touch the rp_filter if it's not strict. */
 			return;
 		}
@@ -5881,7 +5893,7 @@ dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
-	nm_clear_g_source (&priv->dhcp4.restart_id);
+	nm_clear_g_source (&priv->dhcp4.grace_id);
 	g_clear_pointer (&priv->dhcp4.pac_url, g_free);
 
 	if (priv->dhcp4.client) {
@@ -6026,20 +6038,17 @@ dhcp4_lease_change (NMDevice *self, NMIP4Config *config)
 }
 
 static gboolean
-dhcp4_restart_cb (gpointer user_data)
+dhcp4_grace_period_expired (gpointer user_data)
 {
 	NMDevice *self = user_data;
-	NMDevicePrivate *priv;
-
-	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
 
-	priv = NM_DEVICE_GET_PRIVATE (self);
-	priv->dhcp4.restart_id = 0;
+	_LOGI (LOGD_DHCP4, "DHCPv4: grace period expired");
 
-	if (dhcp4_start (self) == NM_ACT_STAGE_RETURN_FAILURE)
-		dhcp_schedule_restart (self, AF_INET, NULL);
+	nm_device_ip_method_failed (self, AF_INET,
+	                            NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
+	/* If the device didn't fail, the DHCP client will continue */
 
-	return FALSE;
+	return G_SOURCE_REMOVE;
 }
 
 static void
@@ -6047,44 +6056,48 @@ dhcp4_fail (NMDevice *self, gboolean timeout)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
-	_LOGD (LOGD_DHCP4, "DHCPv4 failed: timeout %d, num tries left %u",
-	       timeout, priv->dhcp4.num_tries_left);
-
-	dhcp4_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE);
+	_LOGD (LOGD_DHCP4, "DHCPv4 failed%s", timeout ? " (timeout)" : "");
 
-	/* Don't fail if there are static addresses configured on
-	 * the device, instead retry after some time.
+	/* Keep client running if there are static addresses configured
+	 * on the interface.
 	 */
 	if (   priv->ip4_state == IP_DONE
 	    && priv->con_ip4_config
-	    && nm_ip4_config_get_num_addresses (priv->con_ip4_config) > 0) {
-		dhcp_schedule_restart (self, AF_INET, "device has IP addresses");
+	    && nm_ip4_config_get_num_addresses (priv->con_ip4_config) > 0)
+		goto clear_config;
+
+	/* Fail the method in case of timeout or failure during initial
+	 * configuration.
+	 */
+	if (   !priv->dhcp4.was_active
+	    && (timeout || priv->ip4_state == IP_CONF)) {
+		dhcp4_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE);
+		nm_device_activate_schedule_ip4_config_timeout (self);
 		return;
 	}
 
-	if (   priv->dhcp4.num_tries_left == DHCP_NUM_TRIES_MAX
-	    && (timeout || (priv->ip4_state == IP_CONF))
-	    && !priv->dhcp4.was_active)
-		nm_device_activate_schedule_ip4_config_timeout (self);
-	else if (   priv->dhcp4.num_tries_left < DHCP_NUM_TRIES_MAX
-	         || priv->ip4_state == IP_DONE
-	         || priv->dhcp4.was_active) {
-		/* Don't fail immediately when the lease expires but try to
-		 * restart DHCP for a predefined number of times.
-		 */
-		if (priv->dhcp4.num_tries_left) {
-			priv->dhcp4.num_tries_left--;
-			dhcp_schedule_restart (self, AF_INET, "lease expired");
-		} else {
-			nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
-			/* We failed the ipv4 method but schedule again the retries if the ipv6 method is
-			 * configured, keeping the connection up.
-			 */
-			if (nm_device_get_state (self) != NM_DEVICE_STATE_FAILED)
-				dhcp_schedule_restart (self, AF_INET, "renewal failed");
-		}
-	} else
-		g_warn_if_reached ();
+	/* In any other case (expired lease, assumed connection, etc.),
+	 * start a grace period in which we keep the client running,
+	 * hoping that it will regain a lease.
+	 */
+	if (!priv->dhcp4.grace_id) {
+		priv->dhcp4.grace_id = g_timeout_add_seconds (DHCP_GRACE_PERIOD_SEC,
+		                                              dhcp4_grace_period_expired,
+		                                              self);
+		_LOGI (LOGD_DHCP4,
+		       "DHCPv4: %u seconds grace period started",
+		       DHCP_GRACE_PERIOD_SEC);
+		goto clear_config;
+	}
+	return;
+
+clear_config:
+	/* The previous configuration is no longer valid */
+	if (priv->dhcp4.config) {
+		nm_exported_object_clear_and_unexport (&priv->dhcp4.config);
+		priv->dhcp4.config = nm_dhcp4_config_new ();
+		_notify (self, PROP_DHCP4_CONFIG);
+	}
 }
 
 static void
@@ -6124,6 +6137,8 @@ dhcp4_state_changed (NMDhcpClient *client,
 			break;
 		}
 
+		nm_clear_g_source (&priv->dhcp4.grace_id);
+
 		/* After some failures, we have been able to renew the lease:
 		 * update the ip state
 		 */
@@ -6136,7 +6151,6 @@ dhcp4_state_changed (NMDhcpClient *client,
 
 		nm_dhcp4_config_set_options (priv->dhcp4.config, options);
 		_notify (self, PROP_DHCP4_CONFIG);
-		priv->dhcp4.num_tries_left = DHCP_NUM_TRIES_MAX;
 
 		if (priv->ip4_state == IP_CONF) {
 			connection = nm_device_get_applied_connection (self);
@@ -6507,7 +6521,6 @@ act_stage3_ip4_config_start (NMDevice *self,
 	}
 
 	method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
-	priv->dhcp4.num_tries_left = DHCP_NUM_TRIES_MAX;
 
 	/* Start IPv4 addressing based on the method requested */
 	if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0) {
@@ -6562,7 +6575,7 @@ dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release)
 	priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE;
 	g_clear_object (&priv->dhcp6.ip6_config);
 	g_clear_pointer (&priv->dhcp6.event_id, g_free);
-	nm_clear_g_source (&priv->dhcp6.restart_id);
+	nm_clear_g_source (&priv->dhcp6.grace_id);
 
 	if (priv->dhcp6.client) {
 		nm_clear_g_signal_handler (priv->dhcp6.client, &priv->dhcp6.state_sigid);
@@ -6746,53 +6759,17 @@ dhcp6_lease_change (NMDevice *self)
 }
 
 static gboolean
-dhcp6_restart_cb (gpointer user_data)
+dhcp6_grace_period_expired (gpointer user_data)
 {
 	NMDevice *self = user_data;
-	NMDevicePrivate *priv;
-
-	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
-
-	priv = NM_DEVICE_GET_PRIVATE (self);
-	priv->dhcp6.restart_id = 0;
 
-	if (!dhcp6_start (self, FALSE))
-		dhcp_schedule_restart (self, AF_INET6, NULL);
+	_LOGI (LOGD_DHCP6, "DHCPv6: grace period expired");
 
-	return FALSE;
-}
-
-static void
-dhcp_schedule_restart (NMDevice *self,
-                       int addr_family,
-                       const char *reason)
-{
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-	guint tries_left;
-	char tries_str[255];
-
-	nm_assert_addr_family (addr_family);
-
-	tries_left =   (addr_family == AF_INET)
-	             ? priv->dhcp4.num_tries_left
-	             : priv->dhcp6.num_tries_left;
+	nm_device_ip_method_failed (self, AF_INET6,
+	                            NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
+	/* If the device didn't fail, the DHCP client will continue */
 
-	_LOGI ((addr_family == AF_INET) ? LOGD_DHCP4 : LOGD_DHCP6,
-	       "scheduling DHCPv%c restart in %u seconds%s%s%s%s",
-	       nm_utils_addr_family_to_char (addr_family),
-	       DHCP_RESTART_TIMEOUT,
-	       (tries_left != DHCP_NUM_TRIES_MAX)
-	         ? nm_sprintf_buf (tries_str, ", %u tries left", tries_left + 1)
-	         : "",
-	       NM_PRINT_FMT_QUOTED (reason, " (reason: ", reason, ")", ""));
-
-	if (addr_family == AF_INET) {
-		priv->dhcp4.restart_id = g_timeout_add_seconds (DHCP_RESTART_TIMEOUT,
-		                                                dhcp4_restart_cb, self);
-	} else {
-		priv->dhcp6.restart_id = g_timeout_add_seconds (DHCP_RESTART_TIMEOUT,
-		                                                dhcp6_restart_cb, self);
-	}
+	return G_SOURCE_REMOVE;
 }
 
 static void
@@ -6801,51 +6778,57 @@ dhcp6_fail (NMDevice *self, gboolean timeout)
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	gboolean is_dhcp_managed;
 
-	_LOGD (LOGD_DHCP6, "DHCPv6 failed: timeout %d, num tries left %u",
-           timeout, priv->dhcp6.num_tries_left);
+	_LOGD (LOGD_DHCP6, "DHCPv6 failed%s", timeout ? " (timeout)" : "");
 
 	is_dhcp_managed = (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED);
-	dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE);
 
-	if (is_dhcp_managed || priv->dhcp6.num_tries_left < DHCP_NUM_TRIES_MAX) {
-		/* Don't fail if there are static addresses configured on
-		 * the device, instead retry after some time.
+	if (is_dhcp_managed) {
+		/* Keep client running if there are static addresses configured
+		 * on the interface.
 		 */
 		if (   priv->ip6_state == IP_DONE
 		    && priv->con_ip6_config
-		    && nm_ip6_config_get_num_addresses (priv->con_ip6_config)) {
-			dhcp_schedule_restart (self, AF_INET6, "device has IP addresses");
+		    && nm_ip6_config_get_num_addresses (priv->con_ip6_config))
+			goto clear_config;
+
+		/* Fail the method in case of timeout or failure during initial
+		 * configuration.
+		 */
+		if (   !priv->dhcp6.was_active
+		    && (timeout || priv->ip6_state == IP_CONF)) {
+			dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE);
+			nm_device_activate_schedule_ip6_config_timeout (self);
 			return;
 		}
 
-		if (   priv->dhcp6.num_tries_left == DHCP_NUM_TRIES_MAX
-		    && (timeout || (priv->ip6_state == IP_CONF))
-		    && !priv->dhcp6.was_active)
-			nm_device_activate_schedule_ip6_config_timeout (self);
-		else if (   priv->dhcp6.num_tries_left < DHCP_NUM_TRIES_MAX
-		         || priv->ip6_state == IP_DONE
-		         || priv->dhcp6.was_active) {
-			/* Don't fail immediately when the lease expires but try to
-			 * restart DHCP for a predefined number of times.
-			 */
-			if (priv->dhcp6.num_tries_left) {
-				priv->dhcp6.num_tries_left--;
-				dhcp_schedule_restart (self, AF_INET6, "lease expired");
-			} else {
-				nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
-				/* We failed the ipv6 method but schedule again the retries if the ipv4 method is
-				 * configured, keeping the connection up.
-				 */
-				if (nm_device_get_state (self) != NM_DEVICE_STATE_FAILED)
-					dhcp_schedule_restart (self, AF_INET6, "renewal failed");
-			}
-		} else
-			g_warn_if_reached ();
+		/* In any other case (expired lease, assumed connection, etc.),
+		 * start a grace period in which we keep the client running,
+		 * hoping that it will regain a lease.
+		 */
+		if (!priv->dhcp6.grace_id) {
+			priv->dhcp6.grace_id = g_timeout_add_seconds (DHCP_GRACE_PERIOD_SEC,
+			                                              dhcp6_grace_period_expired,
+			                                              self);
+			_LOGI (LOGD_DHCP6,
+			       "DHCPv6: %u seconds grace period started",
+			       DHCP_GRACE_PERIOD_SEC);
+			goto clear_config;
+		}
 	} else {
 		/* not a hard failure; just live with the RA info */
+		dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE);
 		if (priv->ip6_state == IP_CONF)
 			nm_device_activate_schedule_ip6_config_result (self);
 	}
+	return;
+
+clear_config:
+	/* The previous configuration is no longer valid */
+	if (priv->dhcp6.config) {
+		nm_exported_object_clear_and_unexport (&priv->dhcp6.config);
+		priv->dhcp6.config = nm_dhcp6_config_new ();
+		_notify (self, PROP_DHCP6_CONFIG);
+	}
 }
 
 static void
@@ -6881,6 +6864,7 @@ dhcp6_state_changed (NMDhcpClient *client,
 
 	switch (state) {
 	case NM_DHCP_STATE_BOUND:
+		nm_clear_g_source (&priv->dhcp6.grace_id);
 		/* If the server sends multiple IPv6 addresses, we receive a state
 		 * changed event for each of them. Use the event ID to merge IPv6
 		 * addresses from the same transaction into a single configuration.
@@ -6911,8 +6895,6 @@ dhcp6_state_changed (NMDhcpClient *client,
 		if (priv->ip6_state == IP_FAIL)
 			_set_ip_state (self, AF_INET6, IP_CONF);
 
-		priv->dhcp6.num_tries_left = DHCP_NUM_TRIES_MAX;
-
 		if (priv->ip6_state == IP_CONF) {
 			if (priv->dhcp6.ip6_config == NULL) {
 				nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_DHCP_FAILED);
@@ -8090,8 +8072,6 @@ act_stage3_ip6_config_start (NMDevice *self,
 	}
 
 	priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE;
-	priv->dhcp6.num_tries_left = DHCP_NUM_TRIES_MAX;
-
 	method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
 
 	if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0) {
diff --git a/src/devices/tests/test-arping.c b/src/devices/tests/test-arping.c
index bcbc1140..f0537545 100644
--- a/src/devices/tests/test-arping.c
+++ b/src/devices/tests/test-arping.c
@@ -65,12 +65,22 @@ test_arping_common (test_fixture *fixture, TestInfo *info)
 	gs_unref_object NMArpingManager *manager = NULL;
 	GMainLoop *loop;
 	int i;
+	const guint WAIT_TIME_OPTIMISTIC = 50;
+	guint wait_time;
+	gulong signal_id;
 
 	if (!nm_utils_find_helper ("arping", NULL, NULL)) {
 		g_test_skip ("arping binary is missing");
 		return;
 	}
 
+	/* first, try with a short waittime. We hope that this is long enough
+	 * to successfully complete the test. Only if that's not the case, we
+	 * assume the computer is currently busy (high load) and we retry with
+	 * a longer timeout. */
+	wait_time = WAIT_TIME_OPTIMISTIC;
+again:
+
 	manager = nm_arping_manager_new (fixture->ifindex0);
 	g_assert (manager != NULL);
 
@@ -83,18 +93,32 @@ test_arping_common (test_fixture *fixture, TestInfo *info)
 	}
 
 	loop = g_main_loop_new (NULL, FALSE);
-	g_signal_connect (manager, NM_ARPING_MANAGER_PROBE_TERMINATED,
-	                  G_CALLBACK (arping_manager_probe_terminated), loop);
-	g_assert (nm_arping_manager_start_probe (manager, 250, NULL));
+	signal_id = g_signal_connect (manager, NM_ARPING_MANAGER_PROBE_TERMINATED,
+	                              G_CALLBACK (arping_manager_probe_terminated), loop);
+	g_assert (nm_arping_manager_start_probe (manager, wait_time, NULL));
 	g_assert (nmtst_main_loop_run (loop, 2000));
+	g_signal_handler_disconnect (manager, signal_id);
+	g_main_loop_unref (loop);
 
 	for (i = 0; info->addresses[i]; i++) {
-		g_assert_cmpint (nm_arping_manager_check_address (manager, info->addresses[i]),
-		                 ==,
-		                 info->expected_result[i]);
+		gboolean val;
+
+		val = nm_arping_manager_check_address (manager, info->addresses[i]);
+		if (val == info->expected_result[i])
+			continue;
+
+		if (wait_time == WAIT_TIME_OPTIMISTIC) {
+			/* probably we just had a glitch and the system took longer than
+			 * expected. Re-verify with a large timeout this time. */
+			wait_time = 1000;
+			g_clear_object (&manager);
+			goto again;
+		}
+
+		g_error ("expected check for address #%d (%s) to %s, but it didn't",
+		         i, nm_utils_inet4_ntop (info->addresses[i], NULL),
+		         info->expected_result[i] ? "detect no duplicated" : "detect a duplicate");
 	}
-
-	g_main_loop_unref (loop);
 }
 
 static void
diff --git a/src/nm-act-request.c b/src/nm-act-request.c
index 87070794..dd73947d 100644
--- a/src/nm-act-request.c
+++ b/src/nm-act-request.c
@@ -541,7 +541,8 @@ nm_act_request_init (NMActRequest *req)
  * @specific_object: the object path of the specific object (ie, WiFi access point,
  *    etc) that will be used to activate @connection and @device
  * @subject: the #NMAuthSubject representing the requestor of the activation
- * @activation_type: the #NMActivationType.
+ * @activation_type: the #NMActivationType
+ * @activation_reason: the reason for activation
  * @device: the device/interface to configure according to @connection
  *
  * Creates a new device-based activation request. If an applied connection is
@@ -555,6 +556,7 @@ nm_act_request_new (NMSettingsConnection *settings_connection,
                     const char *specific_object,
                     NMAuthSubject *subject,
                     NMActivationType activation_type,
+                    NMActivationReason activation_reason,
                     NMDevice *device)
 {
 	g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL);
@@ -568,6 +570,7 @@ nm_act_request_new (NMSettingsConnection *settings_connection,
 	                                      NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object,
 	                                      NM_ACTIVE_CONNECTION_INT_SUBJECT, subject,
 	                                      NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE, (int) activation_type,
+	                                      NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON, (int) activation_reason,
 	                                      NULL);
 }
 
diff --git a/src/nm-act-request.h b/src/nm-act-request.h
index 5d1c9dfd..a8f09271 100644
--- a/src/nm-act-request.h
+++ b/src/nm-act-request.h
@@ -41,6 +41,7 @@ NMActRequest *nm_act_request_new          (NMSettingsConnection *settings_connec
                                            const char *specific_object,
                                            NMAuthSubject *subject,
                                            NMActivationType activation_type,
+                                           NMActivationReason activation_reason,
                                            NMDevice *device);
 
 NMSettingsConnection *nm_act_request_get_settings_connection (NMActRequest *req);
diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c
index 65f57565..c3f92464 100644
--- a/src/nm-active-connection.c
+++ b/src/nm-active-connection.c
@@ -54,6 +54,7 @@ typedef struct _NMActiveConnectionPrivate {
 	bool master_ready:1;
 
 	NMActivationType activation_type:3;
+	NMActivationReason activation_reason:3;
 
 	NMAuthSubject *subject;
 	NMActiveConnection *master;
@@ -92,6 +93,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMActiveConnection,
 	PROP_INT_MASTER,
 	PROP_INT_MASTER_READY,
 	PROP_INT_ACTIVATION_TYPE,
+	PROP_INT_ACTIVATION_REASON,
 );
 
 enum {
@@ -882,6 +884,14 @@ _set_activation_type_managed (NMActiveConnection *self)
 		nm_device_sys_iface_state_set (priv->device, NM_DEVICE_SYS_IFACE_STATE_MANAGED);
 }
 
+NMActivationReason
+nm_active_connection_get_activation_reason (NMActiveConnection *self)
+{
+	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NM_ACTIVATION_REASON_UNSET);
+
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->activation_reason;
+}
+
 /*****************************************************************************/
 
 static void
@@ -1281,6 +1291,12 @@ set_property (GObject *object, guint prop_id,
 			g_return_if_reached ();
 		_set_activation_type (self, (NMActivationType) i);
 		break;
+	case PROP_INT_ACTIVATION_REASON:
+		/* construct-only */
+		i = g_value_get_int (value);
+		priv->activation_reason = i;
+		nm_assert (priv->activation_reason == ((NMActivationReason) i));
+		break;
 	case PROP_SPECIFIC_OBJECT:
 		/* construct-only */
 		tmp = g_value_get_string (value);
@@ -1551,6 +1567,15 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
 	                       G_PARAM_CONSTRUCT_ONLY |
 	                       G_PARAM_STATIC_STRINGS);
 
+	obj_properties[PROP_INT_ACTIVATION_REASON] =
+	     g_param_spec_int (NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON, "", "",
+	                       NM_ACTIVATION_REASON_UNSET,
+	                       NM_ACTIVATION_REASON_USER_REQUEST,
+	                       NM_ACTIVATION_REASON_UNSET,
+	                       G_PARAM_WRITABLE |
+	                       G_PARAM_CONSTRUCT_ONLY |
+	                       G_PARAM_STATIC_STRINGS);
+
 	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	signals[DEVICE_CHANGED] =
diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h
index 3015b5c5..9b6a49ef 100644
--- a/src/nm-active-connection.h
+++ b/src/nm-active-connection.h
@@ -54,11 +54,12 @@
 /* Internal non-exported properties */
 #define NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION "int-settings-connection"
 #define NM_ACTIVE_CONNECTION_INT_APPLIED_CONNECTION  "int-applied-connection"
-#define NM_ACTIVE_CONNECTION_INT_DEVICE         "int-device"
-#define NM_ACTIVE_CONNECTION_INT_SUBJECT        "int-subject"
-#define NM_ACTIVE_CONNECTION_INT_MASTER         "int-master"
-#define NM_ACTIVE_CONNECTION_INT_MASTER_READY   "int-master-ready"
-#define NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE "int-activation-type"
+#define NM_ACTIVE_CONNECTION_INT_DEVICE              "int-device"
+#define NM_ACTIVE_CONNECTION_INT_SUBJECT             "int-subject"
+#define NM_ACTIVE_CONNECTION_INT_MASTER              "int-master"
+#define NM_ACTIVE_CONNECTION_INT_MASTER_READY        "int-master-ready"
+#define NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE     "int-activation-type"
+#define NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON   "int-activation-reason"
 
 /* Signals */
 #define NM_ACTIVE_CONNECTION_STATE_CHANGED           "state-changed"
@@ -185,6 +186,8 @@ void          nm_active_connection_set_parent (NMActiveConnection *self,
 
 NMActivationType nm_active_connection_get_activation_type (NMActiveConnection *self);
 
+NMActivationReason nm_active_connection_get_activation_reason (NMActiveConnection *self);
+
 void          nm_active_connection_clear_secrets (NMActiveConnection *self);
 
 #endif /* __NETWORKMANAGER_ACTIVE_CONNECTION_H__ */
diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c
index d606dee3..bc57d449 100644
--- a/src/nm-checkpoint.c
+++ b/src/nm-checkpoint.c
@@ -47,6 +47,7 @@ typedef struct {
 	NMDeviceState state;
 	bool realized:1;
 	NMUnmanFlagOp unmanaged_explicit;
+	NMActivationReason activation_reason;
 } DeviceCheckpoint;
 
 NM_GOBJECT_PROPERTIES_DEFINE_BASE (
@@ -301,6 +302,7 @@ activate:
 				                                     device,
 				                                     subject,
 				                                     NM_ACTIVATION_TYPE_MANAGED,
+				                                     dev_checkpoint->activation_reason,
 				                                     &local_error)) {
 					_LOGW ("rollback: reactivation of connection %s/%s failed: %s",
 					       nm_connection_get_id ((NMConnection *) connection),
@@ -410,6 +412,8 @@ device_checkpoint_create (NMDevice *device,
 		g_return_val_if_fail (act_request, NULL);
 		dev_checkpoint->ac_version_id =
 			nm_active_connection_version_id_get (NM_ACTIVE_CONNECTION (act_request));
+		dev_checkpoint->activation_reason =
+		    nm_active_connection_get_activation_reason (NM_ACTIVE_CONNECTION (act_request));
 	}
 
 	return dev_checkpoint;
diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c
index 4ccc5719..8861f261 100644
--- a/src/nm-connectivity.c
+++ b/src/nm-connectivity.c
@@ -199,7 +199,7 @@ multi_timer_cb (CURLM *multi, long timeout_ms, void *userdata)
 
 	nm_clear_g_source (&priv->curl_timer);
 	if (timeout_ms != -1)
-		priv->curl_timer = g_timeout_add (timeout_ms * 1000, curl_timeout_cb, self);
+		priv->curl_timer = g_timeout_add (timeout_ms, curl_timeout_cb, self);
 
 	return 0;
 }
@@ -257,12 +257,15 @@ multi_socket_cb (CURL *e_handle, curl_socket_t s, int what, void *userdata, void
 		} else
 			nm_clear_g_source (&fdp->ev);
 
-		if (what & CURL_POLL_IN)
-			condition |= G_IO_IN;
-		if (what & CURL_POLL_OUT)
-			condition |= G_IO_OUT;
+		if (what == CURL_POLL_IN)
+			condition = G_IO_IN;
+		else if (what == CURL_POLL_OUT)
+			condition = G_IO_OUT;
+		else if (condition == CURL_POLL_INOUT)
+			condition = G_IO_IN | G_IO_OUT;
 
-		fdp->ev = g_io_add_watch (fdp->ch, condition, curl_socketevent_cb, self);
+		if (condition)
+			fdp->ev = g_io_add_watch (fdp->ch, condition, curl_socketevent_cb, self);
 		curl_multi_assign (priv->curl_mhandle, s, fdp);
 	}
 
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 8391dbf2..f3bbebd0 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -278,6 +278,7 @@ static NMActiveConnection *_new_active_connection (NMManager *self,
                                                    NMDevice *device,
                                                    NMAuthSubject *subject,
                                                    NMActivationType activation_type,
+                                                   NMActivationReason activation_reason,
                                                    GError **error);
 
 static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data);
@@ -1180,6 +1181,10 @@ manager_device_state_changed (NMDevice *device,
 	NMManager *self = NM_MANAGER (user_data);
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 
+	if (   old_state == NM_DEVICE_STATE_UNMANAGED
+	    && new_state > NM_DEVICE_STATE_UNMANAGED)
+		retry_connections_for_parent_device (self, device);
+
 	switch (new_state) {
 	case NM_DEVICE_STATE_UNMANAGED:
 	case NM_DEVICE_STATE_UNAVAILABLE:
@@ -2112,13 +2117,14 @@ get_existing_connection (NMManager *self,
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingsConnection *added = NULL;
 	GError *error = NULL;
+	gs_free_error GError *gen_error = NULL;
 	NMDevice *master = NULL;
 	int ifindex = nm_device_get_ifindex (device);
 	NMSettingsConnection *matched;
 	NMSettingsConnection *connection_checked = NULL;
 	gboolean assume_state_guess_assume = FALSE;
 	const char *assume_state_connection_uuid = NULL;
-	gboolean maybe_later;
+	gboolean maybe_later, only_by_uuid = FALSE;
 
 	if (out_generated)
 		*out_generated = FALSE;
@@ -2151,14 +2157,18 @@ get_existing_connection (NMManager *self,
 	 * update_connection() implemented, otherwise nm_device_generate_connection()
 	 * returns NULL.
 	 */
-	connection = nm_device_generate_connection (device, master, &maybe_later, &error);
+	connection = nm_device_generate_connection (device, master, &maybe_later, &gen_error);
 	if (!connection) {
-		if (!maybe_later)
+		if (maybe_later) {
+			/* The device can generate a connection, but it failed for now.
+			 * Give it a chance to match a connection from the state file. */
+			only_by_uuid = TRUE;
+		} else {
 			nm_device_assume_state_reset (device);
-		_LOG2D (LOGD_DEVICE, device, "assume: cannot generate connection: %s",
-		        error->message);
-		g_error_free (error);
-		return NULL;
+			_LOG2D (LOGD_DEVICE, device, "assume: cannot generate connection: %s",
+			        gen_error->message);
+			return NULL;
+		}
 	}
 
 	nm_device_assume_state_get (device,
@@ -2179,21 +2189,31 @@ get_existing_connection (NMManager *self,
 	    && !active_connection_find_first (self, connection_checked, NULL,
 	                                      NM_ACTIVE_CONNECTION_STATE_DEACTIVATING)
 	    && nm_device_check_connection_compatible (device, NM_CONNECTION (connection_checked))) {
-		NMConnection *const connections[] = {
-			NM_CONNECTION (connection_checked),
-			NULL,
-		};
-
-		matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection (connections,
-		                                                             connection,
-		                                                             TRUE,
-		                                                             nm_device_has_carrier (device),
-		                                                             nm_device_get_route_metric (device, AF_INET),
-		                                                             nm_device_get_route_metric (device, AF_INET6),
-		                                                             NULL, NULL));
+
+		if (connection) {
+			NMConnection *const connections[] = {
+				NM_CONNECTION (connection_checked),
+				NULL,
+			};
+
+			matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection (connections,
+			                                                             connection,
+			                                                             TRUE,
+			                                                             nm_device_has_carrier (device),
+			                                                             nm_device_get_route_metric (device, AF_INET),
+			                                                             nm_device_get_route_metric (device, AF_INET6),
+			                                                             NULL, NULL));
+		} else
+			matched = connection_checked;
 	} else
 		matched = NULL;
 
+	if (!matched && only_by_uuid) {
+		_LOG2D (LOGD_DEVICE, device, "assume: cannot generate connection: %s",
+		        gen_error->message);
+		return NULL;
+	}
+
 	if (!matched && assume_state_guess_assume) {
 		gs_free NMSettingsConnection **connections = NULL;
 		guint len, i, j;
@@ -2318,6 +2338,7 @@ recheck_assume_connection (NMManager *self,
 		active = _new_active_connection (self, NM_CONNECTION (connection), NULL, NULL,
 		                                 device, subject,
 		                                 generated ? NM_ACTIVATION_TYPE_EXTERNAL : NM_ACTIVATION_TYPE_ASSUME,
+		                                 NM_ACTIVATION_REASON_AUTOCONNECT,
 		                                 &error);
 
 		if (!active) {
@@ -3154,6 +3175,7 @@ find_master (NMManager *self,
  * @device: the #NMDevice, if any, which will activate @connection
  * @master_connection: the master connection, or %NULL
  * @master_device: the master device, or %NULL
+ * @activation_reason: the reason for activation
  * @error: the error, if an error occurred
  *
  * Determines whether a given #NMConnection depends on another connection to
@@ -3181,6 +3203,7 @@ ensure_master_active_connection (NMManager *self,
                                  NMDevice *device,
                                  NMSettingsConnection *master_connection,
                                  NMDevice *master_device,
+                                 NMActivationReason activation_reason,
                                  GError **error)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
@@ -3244,6 +3267,7 @@ ensure_master_active_connection (NMManager *self,
 					                                            master_device,
 					                                            subject,
 					                                            NM_ACTIVATION_TYPE_MANAGED,
+					                                            activation_reason,
 					                                            error);
 					return master_ac;
 				}
@@ -3290,6 +3314,7 @@ ensure_master_active_connection (NMManager *self,
 			                                            candidate,
 			                                            subject,
 			                                            NM_ACTIVATION_TYPE_MANAGED,
+			                                            activation_reason,
 			                                            error);
 			return master_ac;
 		}
@@ -3512,6 +3537,7 @@ autoconnect_slaves (NMManager *self,
 			                                slave->device,
 			                                subject,
 			                                NM_ACTIVATION_TYPE_MANAGED,
+			                                NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES,
 			                                &local_err);
 			if (local_err) {
 				_LOGW (LOGD_CORE, "Slave connection activation failed: %s", local_err->message);
@@ -3686,7 +3712,10 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
 			}
 
 			parent_ac = nm_manager_activate_connection (self, parent_con, NULL, NULL, parent,
-			                                            subject, NM_ACTIVATION_TYPE_MANAGED, error);
+			                                            subject,
+			                                            NM_ACTIVATION_TYPE_MANAGED,
+			                                            nm_active_connection_get_activation_reason (active),
+			                                            error);
 			if (!parent_ac) {
 				g_prefix_error (error, "%s failed to activate parent: ", nm_device_get_iface (device));
 				return FALSE;
@@ -3747,6 +3776,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
 			                                             device,
 			                                             master_connection,
 			                                             master_device,
+			                                             nm_active_connection_get_activation_reason (active),
 			                                             error);
 			if (!master_ac) {
 				if (master_device) {
@@ -3849,6 +3879,7 @@ _new_vpn_active_connection (NMManager *self,
                             NMSettingsConnection *settings_connection,
                             const char *specific_object,
                             NMAuthSubject *subject,
+                            NMActivationReason activation_reason,
                             GError **error)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
@@ -3884,6 +3915,7 @@ _new_vpn_active_connection (NMManager *self,
 	return (NMActiveConnection *) nm_vpn_connection_new (settings_connection,
 	                                                     device,
 	                                                     nm_exported_object_get_path (NM_EXPORTED_OBJECT (parent)),
+	                                                     activation_reason,
 	                                                     subject);
 }
 
@@ -3895,6 +3927,7 @@ _new_active_connection (NMManager *self,
                         NMDevice *device,
                         NMAuthSubject *subject,
                         NMActivationType activation_type,
+                        NMActivationReason activation_reason,
                         GError **error)
 {
 	NMSettingsConnection *settings_connection = NULL;
@@ -3929,6 +3962,7 @@ _new_active_connection (NMManager *self,
 		                                   settings_connection,
 		                                   specific_object,
 		                                   subject,
+		                                   activation_reason,
 		                                   error);
 	}
 
@@ -3940,6 +3974,7 @@ _new_active_connection (NMManager *self,
 	                                                  specific_object,
 	                                                  subject,
 	                                                  activation_type,
+	                                                  activation_reason,
 	                                                  device);
 }
 
@@ -3958,13 +3993,15 @@ _internal_activation_auth_done (NMActiveConnection *active,
 
 	priv->authorizing_connections = g_slist_remove (priv->authorizing_connections, active);
 
-	/* Don't continue with the activation if an equivalent active connection
-	 * already exists.  We also check this earlier, but there we may fail to
+	/* Don't continue with an internal activation if an equivalent active
+	 * connection already exists. Note that slave autoconnections always force a
+	 * reconnection.  We also check this earlier, but there we may fail to
 	 * detect a duplicate if the existing active connection is undergoing
 	 * authorization in impl_manager_activate_connection().
 	 */
 	if (   success
-	    && nm_auth_subject_is_internal (nm_active_connection_get_subject (active))) {
+	    && nm_auth_subject_is_internal (nm_active_connection_get_subject (active))
+	    && nm_active_connection_get_activation_reason (active) != NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES) {
 		c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) {
 			if (   nm_active_connection_get_device (ac) == nm_active_connection_get_device (active)
 			    && nm_active_connection_get_settings_connection (ac) == nm_active_connection_get_settings_connection (active)
@@ -4003,6 +4040,7 @@ _internal_activation_auth_done (NMActiveConnection *active,
  * @subject: the subject which requested activation
  * @activation_type: whether to assume the connection. That is, take over gracefully,
  *   non-destructible.
+ * @activation_reason: the reason for activation
  * @error: return location for an error
  *
  * Begins a new internally-initiated activation of @connection on @device.
@@ -4023,6 +4061,7 @@ nm_manager_activate_connection (NMManager *self,
                                 NMDevice *device,
                                 NMAuthSubject *subject,
                                 NMActivationType activation_type,
+                                NMActivationReason activation_reason,
                                 GError **error)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
@@ -4059,7 +4098,8 @@ nm_manager_activate_connection (NMManager *self,
 		    && g_strcmp0 (nm_active_connection_get_specific_object (active), specific_object) == 0
 		    && nm_active_connection_get_device (active) == device
 		    && nm_auth_subject_is_internal (nm_active_connection_get_subject (active))
-		    && nm_auth_subject_is_internal (subject))
+		    && nm_auth_subject_is_internal (subject)
+		    && nm_active_connection_get_activation_reason (active) == activation_reason)
 			return active;
 	}
 
@@ -4070,6 +4110,7 @@ nm_manager_activate_connection (NMManager *self,
 	                                 device,
 	                                 subject,
 	                                 activation_type,
+	                                 activation_reason,
 	                                 error);
 	if (active) {
 		priv->authorizing_connections = g_slist_prepend (priv->authorizing_connections, active);
@@ -4313,6 +4354,7 @@ impl_manager_activate_connection (NMManager *self,
 	                                 device,
 	                                 subject,
 	                                 NM_ACTIVATION_TYPE_MANAGED,
+	                                 NM_ACTIVATION_REASON_USER_REQUEST,
 	                                 &error);
 	if (!active)
 		goto error;
@@ -4542,6 +4584,7 @@ impl_manager_add_and_activate_connection (NMManager *self,
 	                                 device,
 	                                 subject,
 	                                 NM_ACTIVATION_TYPE_MANAGED,
+	                                 NM_ACTIVATION_REASON_USER_REQUEST,
 	                                 &error);
 	if (!active)
 		goto error;
diff --git a/src/nm-manager.h b/src/nm-manager.h
index b4587e08..da838532 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -136,6 +136,7 @@ NMActiveConnection *nm_manager_activate_connection     (NMManager *manager,
                                                         NMDevice *device,
                                                         NMAuthSubject *subject,
                                                         NMActivationType activation_type,
+                                                        NMActivationReason activation_reason,
                                                         GError **error);
 
 gboolean            nm_manager_deactivate_connection   (NMManager *manager,
diff --git a/src/nm-policy.c b/src/nm-policy.c
index b73e04cb..2bf25d50 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -1255,6 +1255,7 @@ auto_activate_device (NMPolicy *self,
 	                                     device,
 	                                     subject,
 	                                     NM_ACTIVATION_TYPE_MANAGED,
+	                                     NM_ACTIVATION_REASON_AUTOCONNECT,
 	                                     &error);
 	if (!ac) {
 		_LOGI (LOGD_DEVICE, "connection '%s' auto-activation failed: %s",
@@ -1677,6 +1678,7 @@ activate_secondary_connections (NMPolicy *self,
 		                                     device,
 		                                     nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (req)),
 		                                     NM_ACTIVATION_TYPE_MANAGED,
+		                                     nm_active_connection_get_activation_reason (NM_ACTIVE_CONNECTION (req)),
 		                                     &error);
 		if (ac)
 			secondary_ac_list = g_slist_append (secondary_ac_list, g_object_ref (ac));
@@ -2148,6 +2150,7 @@ vpn_connection_retry_after_failure (NMVpnConnection *vpn, NMPolicy *self)
 	                                     NULL,
 	                                     nm_active_connection_get_subject (ac),
 	                                     NM_ACTIVATION_TYPE_MANAGED,
+	                                     nm_active_connection_get_activation_reason (ac),
 	                                     &error)) {
 		_LOGW (LOGD_DEVICE, "VPN '%s' reconnect failed: %s",
 		       nm_settings_connection_get_id (connection),
diff --git a/src/nm-session-monitor.c b/src/nm-session-monitor.c
index 20781bd4..e7d1d742 100644
--- a/src/nm-session-monitor.c
+++ b/src/nm-session-monitor.c
@@ -137,7 +137,10 @@ st_sd_init (NMSessionMonitor *monitor)
 static void
 st_sd_finalize (NMSessionMonitor *monitor)
 {
-	g_clear_pointer (&monitor->sd.monitor, sd_login_monitor_unref);
+	if (monitor->sd.monitor) {
+		sd_login_monitor_unref (monitor->sd.monitor);
+		monitor->sd.monitor = NULL;
+	}
 	g_source_remove (monitor->sd.watch);
 }
 #endif /* SESSION_TRACKING_SYSTEMD */
diff --git a/src/nm-types.h b/src/nm-types.h
index 02163f87..794b0a1c 100644
--- a/src/nm-types.h
+++ b/src/nm-types.h
@@ -76,6 +76,13 @@ typedef enum {
 } NMActivationType;
 
 typedef enum {
+	NM_ACTIVATION_REASON_UNSET = 0,
+	NM_ACTIVATION_REASON_AUTOCONNECT = 1,
+	NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES = 2,
+	NM_ACTIVATION_REASON_USER_REQUEST = 3,
+} NMActivationReason;
+
+typedef enum {
 	/* In priority order; higher number == higher priority */
 
 	NM_IP_CONFIG_SOURCE_UNKNOWN                 = 0,
diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h
index e3862f2d..e17b17b0 100644
--- a/src/platform/nmp-object.h
+++ b/src/platform/nmp-object.h
@@ -457,11 +457,10 @@ nmp_object_ref (const NMPObject *obj)
 	return (const NMPObject *) nm_dedup_multi_obj_ref ((const NMDedupMultiObj *) obj);
 }
 
-static inline const NMPObject *
+static inline void
 nmp_object_unref (const NMPObject *obj)
 {
 	nm_dedup_multi_obj_unref ((const NMDedupMultiObj *) obj);
-	return NULL;
 }
 
 #define nm_clear_nmp_object(ptr) \
diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c
index 6c600c46..12ee0059 100644
--- a/src/vpn/nm-vpn-connection.c
+++ b/src/vpn/nm-vpn-connection.c
@@ -858,6 +858,7 @@ NMVpnConnection *
 nm_vpn_connection_new (NMSettingsConnection *settings_connection,
                        NMDevice *parent_device,
                        const char *specific_object,
+                       NMActivationReason activation_reason,
                        NMAuthSubject *subject)
 {
 	g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL);
@@ -868,6 +869,7 @@ nm_vpn_connection_new (NMSettingsConnection *settings_connection,
 	                                         NM_ACTIVE_CONNECTION_INT_DEVICE, parent_device,
 	                                         NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object,
 	                                         NM_ACTIVE_CONNECTION_INT_SUBJECT, subject,
+	                                         NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON, activation_reason,
 	                                         NM_ACTIVE_CONNECTION_VPN, TRUE,
 	                                         NULL);
 }
diff --git a/src/vpn/nm-vpn-connection.h b/src/vpn/nm-vpn-connection.h
index 038d0efd..b287c334 100644
--- a/src/vpn/nm-vpn-connection.h
+++ b/src/vpn/nm-vpn-connection.h
@@ -53,6 +53,7 @@ GType nm_vpn_connection_get_type (void);
 NMVpnConnection * nm_vpn_connection_new (NMSettingsConnection *settings_connection,
                                          NMDevice *parent_device,
                                          const char *specific_object,
+                                         NMActivationReason activation_reason,
                                          NMAuthSubject *subject);
 
 void                 nm_vpn_connection_activate        (NMVpnConnection *self,