summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2017-07-12 17:57:30 +0200
committerMichael Biebl <biebl@debian.org>2017-07-12 17:57:30 +0200
commitb9f0451fa35393ceedf6d9d20b78c43578ebea5d (patch)
tree417afcdd717020ad44e25fadee4b89de23316e83 /src
parentc333f062ddcba9b35330647bf6cbd0a07f2d786e (diff)
New upstream version 1.8.2 upstream/1.8.2
Diffstat (limited to 'src')
-rw-r--r--src/devices/bluetooth/nm-bluez-device.c6
-rw-r--r--src/devices/nm-device-bond.c35
-rw-r--r--src/devices/nm-device-ethernet.c7
-rw-r--r--src/devices/nm-device-infiniband.c2
-rw-r--r--src/devices/nm-device-ip-tunnel.c2
-rw-r--r--src/devices/nm-device-logging.h22
-rw-r--r--src/devices/nm-device-private.h4
-rw-r--r--src/devices/nm-device-vlan.c2
-rw-r--r--src/devices/nm-device.c470
-rw-r--r--src/devices/nm-device.h36
-rw-r--r--src/devices/wifi/nm-device-wifi.c2
-rw-r--r--src/dhcp/nm-dhcp-utils.c37
-rw-r--r--src/dns/nm-dns-dnsmasq.c14
-rw-r--r--src/dns/nm-dns-manager.c68
-rw-r--r--src/dns/nm-dns-manager.h2
-rw-r--r--src/dns/nm-dns-plugin.c2
-rw-r--r--src/dns/nm-dns-plugin.h4
-rw-r--r--src/dns/nm-dns-systemd-resolved.c29
-rw-r--r--src/dns/nm-dns-unbound.c2
-rw-r--r--src/nm-active-connection.c46
-rw-r--r--src/nm-checkpoint.c11
-rw-r--r--src/nm-config.c78
-rw-r--r--src/nm-config.h8
-rw-r--r--src/nm-connectivity.c31
-rw-r--r--src/nm-ip4-config.c12
-rw-r--r--src/nm-logging.h31
-rw-r--r--src/nm-manager.c364
-rw-r--r--src/nm-pacrunner-manager.c2
-rw-r--r--src/platform/nm-linux-platform.c20
-rw-r--r--src/platform/nm-platform.c26
-rw-r--r--src/platform/nm-platform.h2
-rw-r--r--src/platform/tests/test-common.c2
-rw-r--r--src/platform/tests/test-general.c2
-rw-r--r--src/ppp/nm-ppp-manager.c144
-rw-r--r--src/settings/nm-settings-connection.c39
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c112
-rw-r--r--src/settings/plugins/ifcfg-rh/shvar.c22
-rw-r--r--src/settings/plugins/ifcfg-rh/shvar.h2
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-114
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1.cexpected23
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c62
-rw-r--r--src/supplicant/nm-supplicant-interface.c12
-rw-r--r--src/supplicant/tests/test-supplicant-config.c2
43 files changed, 1135 insertions, 678 deletions
diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c
index ebfa0d64..41ef74ca 100644
--- a/src/devices/bluetooth/nm-bluez-device.c
+++ b/src/devices/bluetooth/nm-bluez-device.c
@@ -1187,7 +1187,11 @@ dispose (GObject *object)
 	g_slist_free_full (priv->connections, g_object_unref);
 	priv->connections = NULL;
 
-	g_clear_object (&priv->adapter5);
+	if (priv->adapter5) {
+		g_signal_handlers_disconnect_by_func (priv->adapter5, adapter5_on_properties_changed, self);
+		g_clear_object (&priv->adapter5);
+	}
+
 	g_clear_object (&priv->dbus_connection);
 
 	G_OBJECT_CLASS (nm_bluez_device_parent_class)->dispose (object);
diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c
index 3325c948..d9c2ca64 100644
--- a/src/devices/nm-device-bond.c
+++ b/src/devices/nm-device-bond.c
@@ -137,17 +137,22 @@ set_bond_attr (NMDevice *device, NMBondMode mode, const char *attr, const char *
 	return ret;
 }
 
-/* Ignore certain bond options if they are zero (off/disabled) */
 static gboolean
-ignore_if_zero (const char *option, const char *value)
+ignore_option (NMSettingBond *s_bond, const char *option, const char *value)
 {
-	if (!NM_IN_STRSET (option, NM_SETTING_BOND_OPTION_ARP_INTERVAL,
-	                           NM_SETTING_BOND_OPTION_DOWNDELAY,
-	                           NM_SETTING_BOND_OPTION_MIIMON,
-	                           NM_SETTING_BOND_OPTION_UPDELAY))
-		return FALSE;
+	const char *defvalue;
+
+	if (nm_streq0 (option, NM_SETTING_BOND_OPTION_MIIMON)) {
+		/* The default value for miimon, when missing in the setting, is
+		 * 0 if arp_interval is != 0, and 100 otherwise. So, let's ignore
+		 * miimon=0 (which means that miimon is disabled) and accept any
+		 * other value. Adding miimon=100 does not cause any harm.
+		 */
+		defvalue = "0";
+	} else
+		defvalue = nm_setting_bond_get_option_default (s_bond, option);
 
-	return g_strcmp0 (value, "0") == 0 ? TRUE : FALSE;
+	return nm_streq0 (value, defvalue);
 }
 
 static void
@@ -155,6 +160,7 @@ update_connection (NMDevice *device, NMConnection *connection)
 {
 	NMSettingBond *s_bond = nm_connection_get_setting_bond (connection);
 	int ifindex = nm_device_get_ifindex (device);
+	NMBondMode mode = NM_BOND_MODE_UNKNOWN;
 	const char **options;
 
 	if (!s_bond) {
@@ -164,9 +170,8 @@ update_connection (NMDevice *device, NMConnection *connection)
 
 	/* Read bond options from sysfs and update the Bond setting to match */
 	options = nm_setting_bond_get_valid_options (s_bond);
-	while (options && *options) {
+	for (; *options; options++) {
 		gs_free char *value = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), ifindex, *options);
-		const char *defvalue = nm_setting_bond_get_option_default (s_bond, *options);
 		char *p;
 
 		if (   value
@@ -176,10 +181,15 @@ update_connection (NMDevice *device, NMConnection *connection)
 				*p = '\0';
 		}
 
+		if (value && nm_streq (*options, NM_SETTING_BOND_OPTION_MODE))
+			mode = _nm_setting_bond_mode_from_string (value);
+
+		if (!_nm_setting_bond_option_supported (*options, mode))
+			continue;
+
 		if (   value
 		    && value[0]
-		    && !ignore_if_zero (*options, value)
-		    && !nm_streq0 (value, defvalue)) {
+		    && !ignore_option (s_bond, *options, value)) {
 			/* Replace " " with "," for arp_ip_targets from the kernel */
 			if (strcmp (*options, NM_SETTING_BOND_OPTION_ARP_IP_TARGET) == 0) {
 				for (p = value; *p; p++) {
@@ -190,7 +200,6 @@ update_connection (NMDevice *device, NMConnection *connection)
 
 			nm_setting_bond_add_option (s_bond, *options, value);
 		}
-		options++;
 	}
 }
 
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index 4c5aeb5e..8a04d401 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -1597,12 +1597,11 @@ get_link_speed (NMDevice *device)
 }
 
 static void
-carrier_changed (NMDevice *device, gboolean carrier)
+carrier_changed_notify (NMDevice *device, gboolean carrier)
 {
 	if (carrier)
 		get_link_speed (device);
-
-	NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->carrier_changed (device, carrier);
+	NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->carrier_changed_notify (device, carrier);
 }
 
 static void
@@ -1764,7 +1763,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
 	parent_class->deactivate = deactivate;
 	parent_class->get_s390_subchannels = get_s390_subchannels;
 	parent_class->update_connection = update_connection;
-	parent_class->carrier_changed = carrier_changed;
+	parent_class->carrier_changed_notify = carrier_changed_notify;
 	parent_class->link_changed = link_changed;
 	parent_class->is_available = is_available;
 	parent_class->can_reapply_change = can_reapply_change;
diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c
index f7875d09..7e041270 100644
--- a/src/devices/nm-device-infiniband.c
+++ b/src/devices/nm-device-infiniband.c
@@ -139,7 +139,7 @@ get_configured_mtu (NMDevice *device, gboolean *out_is_user_config)
 		}
 	}
 	*out_is_user_config = (mtu != 0);
-	return mtu ?: NM_DEVICE_DEFAULT_MTU_INFINIBAND;
+	return mtu;
 }
 
 static gboolean
diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c
index 53b7cf4e..2f505ef4 100644
--- a/src/devices/nm-device-ip-tunnel.c
+++ b/src/devices/nm-device-ip-tunnel.c
@@ -767,7 +767,7 @@ get_configured_mtu (NMDevice *self, gboolean *out_is_user_config)
 		}
 	}
 	*out_is_user_config = (mtu != 0);
-	return mtu ?: NM_DEVICE_DEFAULT_MTU_WIRED;
+	return mtu;
 }
 
 static NMDeviceCapabilities
diff --git a/src/devices/nm-device-logging.h b/src/devices/nm-device-logging.h
index 419a4a51..f0c7e591 100644
--- a/src/devices/nm-device-logging.h
+++ b/src/devices/nm-device-logging.h
@@ -34,11 +34,21 @@ _nm_device_log_self_to_device (t *self) \
 #undef  _NMLOG_ENABLED
 #define _NMLOG_ENABLED(level, domain) ( nm_logging_enabled ((level), (domain)) )
 #define _NMLOG(level, domain, ...) \
-    nm_log_obj ((level), (domain), \
-                (self) ? nm_device_get_iface (_nm_device_log_self_to_device (self)) : NULL, \
-                NULL, (self), "device", \
-                "(%s): " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
-                (self) ? (nm_device_get_iface (_nm_device_log_self_to_device (self)) ?: "(null)") : "(none)" \
-                _NM_UTILS_MACRO_REST(__VA_ARGS__))
+	G_STMT_START { \
+		const NMLogLevel _level = (level); \
+		const NMLogDomain _domain = (domain); \
+		\
+		if (nm_logging_enabled (_level, _domain)) { \
+			typeof (*self) *const _self = (self); \
+			const char *const _ifname = _nm_device_get_iface (_nm_device_log_self_to_device (_self)); \
+			\
+			nm_log_obj (_level, _domain, \
+			            _ifname, NULL, \
+			            _self, "device", \
+			            "%s%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+			            NM_PRINT_FMT_QUOTED (_ifname, "(", _ifname, ")", "[null]") \
+			            _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+		} \
+	} G_STMT_END
 
 #endif /* __NETWORKMANAGER_DEVICE_LOGGING_H__ */
diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h
index a4067f9c..9eccafdc 100644
--- a/src/devices/nm-device-private.h
+++ b/src/devices/nm-device-private.h
@@ -116,10 +116,6 @@ gboolean nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const
 
 /*****************************************************************************/
 
-#define NM_DEVICE_DEFAULT_MTU_WIRED          ((guint32) 1500)
-#define NM_DEVICE_DEFAULT_MTU_WIRELESS       ((guint32) 1500)
-#define NM_DEVICE_DEFAULT_MTU_INFINIBAND     ((guint32) 0)
-
 gint64 nm_device_get_configured_mtu_from_connection_default (NMDevice *self,
                                                              const char *property_name);
 
diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c
index 06db6446..a74da8f2 100644
--- a/src/devices/nm-device-vlan.c
+++ b/src/devices/nm-device-vlan.c
@@ -586,7 +586,7 @@ get_configured_mtu (NMDevice *self, gboolean *out_is_user_config)
 	if (ifindex > 0)
 		mtu = nm_platform_link_get_mtu (nm_device_get_platform (NM_DEVICE (self)), ifindex);
 
-	return mtu ?: NM_DEVICE_DEFAULT_MTU_WIRED;
+	return mtu;
 }
 
 /*****************************************************************************/
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index da581a0d..fbf315ed 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -262,7 +262,10 @@ typedef struct _NMDevicePrivate {
 
 	NMUtilsStableType current_stable_id_type:3;
 
-	bool          is_nm_owned:1; /* whether the device is a device owned and created by NM */
+	bool          nm_owned:1; /* whether the device is a device owned and created by NM */
+
+	bool          assume_state_guess_assume:1;
+	char *        assume_state_connection_uuid;
 
 	GHashTable *  available_connections;
 	char *        hw_addr;
@@ -527,6 +530,9 @@ static gboolean dhcp6_start (NMDevice *self, gboolean wait_for_ll);
 static void nm_device_start_ip_check (NMDevice *self);
 static void realize_start_setup (NMDevice *self,
                                  const NMPlatformLink *plink,
+                                 gboolean assume_state_guess_assume,
+                                 const char *assume_state_connection_uuid,
+                                 gboolean set_nm_owned,
                                  NMUnmanFlagOp unmanaged_user_explicit);
 static void _commit_mtu (NMDevice *self, const NMIP4Config *config);
 static void dhcp_schedule_restart (NMDevice *self, int family, const char *reason);
@@ -551,8 +557,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (queued_state_to_string, NMDeviceState,
 	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_FAILED,       NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "failed"),
 );
 
-static const char *
-state_to_string (NMDeviceState state)
+const char *
+nm_device_state_to_str (NMDeviceState state)
 {
 	return queued_state_to_string (state) + NM_STRLEN (NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE);
 }
@@ -710,6 +716,52 @@ nm_device_sys_iface_state_set (NMDevice *self,
 
 /*****************************************************************************/
 
+void
+nm_device_assume_state_get (NMDevice *self,
+                            gboolean *out_assume_state_guess_assume,
+                            const char **out_assume_state_connection_uuid)
+{
+	NMDevicePrivate *priv;
+
+	g_return_if_fail (NM_IS_DEVICE (self));
+
+	priv = NM_DEVICE_GET_PRIVATE (self);
+	NM_SET_OUT (out_assume_state_guess_assume, priv->assume_state_guess_assume);
+	NM_SET_OUT (out_assume_state_connection_uuid, priv->assume_state_connection_uuid);
+}
+
+static void
+_assume_state_set (NMDevice *self,
+                   gboolean assume_state_guess_assume,
+                   const char *assume_state_connection_uuid)
+{
+	NMDevicePrivate *priv;
+
+	nm_assert (NM_IS_DEVICE (self));
+
+	priv = NM_DEVICE_GET_PRIVATE (self);
+	if (   priv->assume_state_guess_assume == !!assume_state_guess_assume
+	    && nm_streq0 (priv->assume_state_connection_uuid, assume_state_connection_uuid))
+		return;
+
+	_LOGD (LOGD_DEVICE, "assume-state: set guess-assume=%c, connection=%s%s%s",
+	       assume_state_guess_assume ? '1' : '0',
+	       NM_PRINT_FMT_QUOTE_STRING (assume_state_connection_uuid));
+	priv->assume_state_guess_assume = assume_state_guess_assume;
+	g_free (priv->assume_state_connection_uuid);
+	priv->assume_state_connection_uuid = g_strdup (assume_state_connection_uuid);
+}
+
+void
+nm_device_assume_state_reset (NMDevice *self)
+{
+	g_return_if_fail (NM_IS_DEVICE (self));
+
+	_assume_state_set (self, FALSE, NULL);
+}
+
+/*****************************************************************************/
+
 static void
 init_ip4_config_dns_priority (NMDevice *self, NMIP4Config *config)
 {
@@ -1775,10 +1827,13 @@ update_connectivity_state (NMDevice *self, NMConnectivityState state)
 		priv->connectivity_state = state;
 		_notify (self, PROP_CONNECTIVITY);
 
-		if (nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED) {
-			if (!ip4_config_merge_and_apply (self, NULL, TRUE))
+		if (   priv->state == NM_DEVICE_STATE_ACTIVATED
+		    && !nm_device_sys_iface_state_is_external (self)) {
+			if (   priv->default_route.v4_has
+			    && !ip4_config_merge_and_apply (self, NULL, TRUE))
 				_LOGW (LOGD_IP4, "Failed to update IPv4 default route metric");
-			if (!ip6_config_merge_and_apply (self, TRUE))
+			if (   priv->default_route.v6_has
+			    && !ip6_config_merge_and_apply (self, TRUE))
 				_LOGW (LOGD_IP6, "Failed to update IPv6 default route metric");
 		}
 	}
@@ -1858,7 +1913,7 @@ nm_device_check_connectivity (NMDevice *self,
 
 		/* Kick off a real connectivity check. */
 		nm_connectivity_check_async (nm_connectivity_get (),
-		                             nm_device_get_iface (self),
+		                             nm_device_get_ip_iface (self),
 		                             concheck_cb,
 		                             data);
 		return;
@@ -2069,7 +2124,7 @@ nm_device_master_release_one_slave (NMDevice *self, NMDevice *slave, gboolean co
 static gboolean
 can_unmanaged_external_down (NMDevice *self)
 {
-	return    !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned
+	return    !NM_DEVICE_GET_PRIVATE (self)->nm_owned
 	       && nm_device_is_software (self);
 }
 
@@ -2167,11 +2222,21 @@ nm_device_update_dynamic_ip_setup (NMDevice *self)
 	}
 }
 
+/*****************************************************************************/
+
+static void
+carrier_changed_notify (NMDevice *self, gboolean carrier)
+{
+	/* stub */
+}
+
 static void
 carrier_changed (NMDevice *self, gboolean carrier)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
+	NM_DEVICE_GET_CLASS (self)->carrier_changed_notify (self, carrier);
+
 	if (priv->state <= NM_DEVICE_STATE_UNMANAGED)
 		return;
 
@@ -2236,7 +2301,7 @@ carrier_changed (NMDevice *self, gboolean carrier)
 #define LINK_DISCONNECT_DELAY 4
 
 static gboolean
-link_disconnect_action_cb (gpointer user_data)
+carrier_disconnected_action_cb (gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
@@ -2244,21 +2309,19 @@ link_disconnect_action_cb (gpointer user_data)
 	_LOGD (LOGD_DEVICE, "link disconnected (calling deferred action) (id=%u)", priv->carrier_defer_id);
 
 	priv->carrier_defer_id = 0;
-
-	NM_DEVICE_GET_CLASS (self)->carrier_changed (self, FALSE);
-
+	carrier_changed (self, FALSE);
 	return FALSE;
 }
 
 static void
-link_disconnect_action_cancel (NMDevice *self)
+carrier_disconnected_action_cancel (NMDevice *self)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	guint id = priv->carrier_defer_id;
 
-	if (priv->carrier_defer_id) {
-		g_source_remove (priv->carrier_defer_id);
-		_LOGD (LOGD_DEVICE, "link disconnected (canceling deferred action) (id=%u)", priv->carrier_defer_id);
-		priv->carrier_defer_id = 0;
+	if (nm_clear_g_source (&priv->carrier_defer_id)) {
+		_LOGD (LOGD_DEVICE, "link disconnected (canceling deferred action) (id=%u)",
+		       id);
 	}
 }
 
@@ -2266,7 +2329,6 @@ void
 nm_device_set_carrier (NMDevice *self, gboolean carrier)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-	NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self);
 	NMDeviceState state = nm_device_get_state (self);
 
 	if (priv->carrier == carrier)
@@ -2277,25 +2339,51 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier)
 
 	if (priv->carrier) {
 		_LOGI (LOGD_DEVICE, "link connected");
-		link_disconnect_action_cancel (self);
-		klass->carrier_changed (self, TRUE);
+		carrier_disconnected_action_cancel (self);
+		carrier_changed (self, TRUE);
 
-		if (nm_clear_g_source (&priv->carrier_wait_id)) {
-			nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, TRUE);
+		if (priv->carrier_wait_id) {
+			nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE);
 			_carrier_wait_check_queued_act_request (self);
 		}
-	} else if (   state <= NM_DEVICE_STATE_DISCONNECTED
-	           && !priv->queued_act_request) {
-		_LOGD (LOGD_DEVICE, "link disconnected");
-		klass->carrier_changed (self, FALSE);
 	} else {
-		priv->carrier_defer_id = g_timeout_add_seconds (LINK_DISCONNECT_DELAY,
-		                                                link_disconnect_action_cb, self);
-		_LOGD (LOGD_DEVICE, "link disconnected (deferring action for %d seconds) (id=%u)",
-		       LINK_DISCONNECT_DELAY, priv->carrier_defer_id);
+		if (priv->carrier_wait_id)
+			nm_device_add_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE);
+		if (   state <= NM_DEVICE_STATE_DISCONNECTED
+		    && !priv->queued_act_request) {
+			_LOGD (LOGD_DEVICE, "link disconnected");
+			carrier_changed (self, FALSE);
+		} else {
+			priv->carrier_defer_id = g_timeout_add_seconds (LINK_DISCONNECT_DELAY,
+			                                                carrier_disconnected_action_cb, self);
+			_LOGD (LOGD_DEVICE, "link disconnected (deferring action for %d seconds) (id=%u)",
+			       LINK_DISCONNECT_DELAY, priv->carrier_defer_id);
+		}
+	}
+}
+
+static void
+nm_device_set_carrier_from_platform (NMDevice *self)
+{
+	if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) {
+		if (!nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) {
+			nm_device_set_carrier (self,
+			                       nm_platform_link_is_connected (nm_device_get_platform (self),
+			                                                      nm_device_get_ip_ifindex (self)));
+		}
+	} else {
+		NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+		/* Fake online link when carrier detection is not available. */
+		if (!priv->carrier) {
+			priv->carrier = TRUE;
+			_notify (self, PROP_CARRIER);
+		}
 	}
 }
 
+/*****************************************************************************/
+
 static void
 device_recheck_slave_status (NMDevice *self, const NMPlatformLink *plink)
 {
@@ -2427,7 +2515,7 @@ device_link_changed (NMDevice *self)
 	info = *pllink;
 
 	udi = nm_platform_link_get_udi (nm_device_get_platform (self), info.ifindex);
-	if (udi && g_strcmp0 (udi, priv->udi)) {
+	if (udi && !nm_streq0 (udi, priv->udi)) {
 		/* Update UDI to what udev gives us */
 		g_free (priv->udi);
 		priv->udi = g_strdup (udi);
@@ -2707,6 +2795,9 @@ link_type_compatible (NMDevice *self,
  * nm_device_realize_start():
  * @self: the #NMDevice
  * @plink: an existing platform link or %NULL
+ * @assume_state_guess_assume: set the guess_assume state.
+ * @assume_state_connection_uuid: set the connection uuid to assume.
+ * @set_nm_owned: for software device, if TRUE set nm-owned.
  * @unmanaged_user_explicit: the user-explicit unmanaged flag to apply
  *   on the device initially.
  * @out_compatible: %TRUE on return if @self is compatible with @plink
@@ -2724,6 +2815,9 @@ link_type_compatible (NMDevice *self,
 gboolean
 nm_device_realize_start (NMDevice *self,
                          const NMPlatformLink *plink,
+                         gboolean assume_state_guess_assume,
+                         const char *assume_state_connection_uuid,
+                         gboolean set_nm_owned,
                          NMUnmanFlagOp unmanaged_user_explicit,
                          gboolean *out_compatible,
                          GError **error)
@@ -2748,8 +2842,11 @@ nm_device_realize_start (NMDevice *self,
 		plink_copy = *plink;
 		plink = &plink_copy;
 	}
-	realize_start_setup (self, plink, unmanaged_user_explicit);
-
+	realize_start_setup (self, plink,
+	                     assume_state_guess_assume,
+	                     assume_state_connection_uuid,
+	                     set_nm_owned,
+	                     unmanaged_user_explicit);
 	return TRUE;
 }
 
@@ -2776,9 +2873,9 @@ nm_device_create_and_realize (NMDevice *self,
 	const NMPlatformLink *plink = NULL;
 
 	/* Must be set before device is realized */
-	priv->is_nm_owned = !nm_platform_link_get_by_ifname (nm_device_get_platform (self), priv->iface);
+	priv->nm_owned = !nm_platform_link_get_by_ifname (nm_device_get_platform (self), priv->iface);
 
-	_LOGD (LOGD_DEVICE, "create (is %snm-owned)", priv->is_nm_owned ? "" : "not ");
+	_LOGD (LOGD_DEVICE, "create (is %snm-owned)", priv->nm_owned ? "" : "not ");
 
 	/* Create any resources the device needs */
 	if (NM_DEVICE_GET_CLASS (self)->create_and_realize) {
@@ -2788,7 +2885,10 @@ nm_device_create_and_realize (NMDevice *self,
 		plink = &plink_copy;
 	}
 
-	realize_start_setup (self, plink, NM_UNMAN_FLAG_OP_FORGET);
+	realize_start_setup (self, plink,
+	                     FALSE, /* assume_state_guess_assume */
+	                     NULL,  /* assume_state_connection_uuid */
+	                     FALSE, NM_UNMAN_FLAG_OP_FORGET);
 	nm_device_realize_finish (self, plink);
 
 	if (nm_device_get_managed (self, FALSE)) {
@@ -2808,7 +2908,7 @@ update_device_from_platform_link (NMDevice *self, const NMPlatformLink *plink)
 	g_return_if_fail (plink != NULL);
 
 	udi = nm_platform_link_get_udi (nm_device_get_platform (self), plink->ifindex);
-	if (udi && !g_strcmp0 (udi, priv->udi)) {
+	if (udi && !nm_streq0 (udi, priv->udi)) {
 		g_free (priv->udi);
 		priv->udi = g_strdup (udi);
 		_notify (self, PROP_UDI);
@@ -2872,15 +2972,6 @@ config_changed (NMConfig *config,
 }
 
 static void
-check_carrier (NMDevice *self)
-{
-	int ifindex = nm_device_get_ip_ifindex (self);
-
-	if (!nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER))
-		nm_device_set_carrier (self, nm_platform_link_is_connected (nm_device_get_platform (self), ifindex));
-}
-
-static void
 realize_start_notify (NMDevice *self,
                       const NMPlatformLink *pllink)
 {
@@ -2893,6 +2984,10 @@ realize_start_notify (NMDevice *self,
  * realize_start_setup():
  * @self: the #NMDevice
  * @plink: the #NMPlatformLink if backed by a kernel netdevice
+ * @assume_state_guess_assume: set the guess_assume state.
+ * @assume_state_connection_uuid: set the connection uuid to assume.
+ * @set_nm_owned: if TRUE and device is a software-device, set nm-owned.
+ *    TRUE.
  * @unmanaged_user_explicit: the user-explict unmanaged flag to set.
  *
  * Update the device from backing resource properties (like hardware
@@ -2904,6 +2999,9 @@ realize_start_notify (NMDevice *self,
 static void
 realize_start_setup (NMDevice *self,
                      const NMPlatformLink *plink,
+                     gboolean assume_state_guess_assume,
+                     const char *assume_state_connection_uuid,
+                     gboolean set_nm_owned,
                      NMUnmanFlagOp unmanaged_user_explicit)
 {
 	NMDevicePrivate *priv;
@@ -2942,6 +3040,8 @@ realize_start_setup (NMDevice *self,
 		_notify (self, PROP_MTU);
 	}
 
+	_assume_state_set (self, assume_state_guess_assume, assume_state_connection_uuid);
+
 	nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_EXTERNAL);
 
 	if (plink) {
@@ -2987,6 +3087,13 @@ realize_start_setup (NMDevice *self,
 
 	_add_capabilities (self, capabilities);
 
+	if (   !priv->nm_owned
+	    && set_nm_owned
+	    && nm_device_is_software (self)) {
+		priv->nm_owned = TRUE;
+		_LOGD (LOGD_DEVICE, "set nm-owned from state file");
+	}
+
 	if (!priv->udi) {
 		/* Use a placeholder UDI until we get a real one */
 		priv->udi = g_strdup_printf ("/virtual/device/placeholder/%d", id++);
@@ -3010,16 +3117,7 @@ realize_start_setup (NMDevice *self,
 		                                            self);
 	}
 
-	if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) {
-		check_carrier (self);
-		_LOGD (LOGD_PLATFORM,
-		       "carrier is %s%s",
-		       priv->carrier ? "ON" : "OFF",
-		       priv->ignore_carrier ? " (but ignored)" : "");
-	} else {
-		/* Fake online link when carrier detection is not available. */
-		priv->carrier = TRUE;
-	}
+	nm_device_set_carrier_from_platform (self);
 
 	device_init_sriov_num_vfs (self);
 
@@ -3165,6 +3263,8 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
 
 	_LOGD (LOGD_DEVICE, "unrealize (ifindex %d)", ifindex > 0 ? ifindex : 0);
 
+	nm_device_assume_state_reset (self);
+
 	if (remove_resources) {
 		if (NM_DEVICE_GET_CLASS (self)->unrealize) {
 			if (!NM_DEVICE_GET_CLASS (self)->unrealize (self, error))
@@ -3326,9 +3426,9 @@ slave_state_changed (NMDevice *slave,
 	_LOGD (LOGD_DEVICE, "slave %s state change %d (%s) -> %d (%s)",
 	       nm_device_get_iface (slave),
 	       slave_old_state,
-	       state_to_string (slave_old_state),
+	       nm_device_state_to_str (slave_old_state),
 	       slave_new_state,
-	       state_to_string (slave_new_state));
+	       nm_device_state_to_str (slave_new_state));
 
 	/* Don't try to enslave slaves until the master is ready */
 	if (priv->state < NM_DEVICE_STATE_CONFIG)
@@ -4014,27 +4114,37 @@ nm_device_master_update_slave_connection (NMDevice *self,
 }
 
 NMConnection *
-nm_device_generate_connection (NMDevice *self, NMDevice *master)
+nm_device_generate_connection (NMDevice *self,
+                               NMDevice *master,
+                               gboolean *out_maybe_later,
+                               GError **error)
 {
 	NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self);
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	const char *ifname = nm_device_get_iface (self);
-	NMConnection *connection;
+	gs_unref_object NMConnection *connection = NULL;
 	NMSetting *s_con;
 	NMSetting *s_ip4;
 	NMSetting *s_ip6;
 	char uuid[37];
 	const char *ip4_method, *ip6_method;
-	GError *error = NULL;
+	GError *local = NULL;
 	const NMPlatformLink *pllink;
 
+	NM_SET_OUT (out_maybe_later, FALSE);
+
 	/* If update_connection() is not implemented, just fail. */
-	if (!klass->update_connection)
+	if (!klass->update_connection) {
+		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+		             "device class %s does not support generating a connection",
+		             G_OBJECT_TYPE_NAME (self));
 		return NULL;
+	}
 
 	/* Return NULL if device is unconfigured. */
 	if (!device_has_config (self)) {
-		_LOGD (LOGD_DEVICE, "device has no existing configuration");
+		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+		             "device has no existing configuration");
 		return NULL;
 	}
 
@@ -4057,12 +4167,11 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master)
 		if (!nm_device_master_update_slave_connection (master,
 		                                               self,
 		                                               connection,
-		                                               &error))
-		{
-			_LOGE (LOGD_DEVICE, "master device '%s' failed to update slave connection: %s",
-			       nm_device_get_iface (master), error->message);
-			g_error_free (error);
-			g_object_unref (connection);
+		                                               &local)) {
+			g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+			             "master device '%s' failed to update slave connection: %s",
+			             nm_device_get_iface (master), local->message);
+			g_error_free (local);
 			return NULL;
 		}
 	} else {
@@ -4075,7 +4184,6 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master)
 
 		pllink = nm_platform_link_get (nm_device_get_platform (self), priv->ifindex);
 		if (pllink && pllink->inet6_token.id) {
-			_LOGD (LOGD_IP6, "IPv6 tokenized identifier present");
 			g_object_set (s_ip6,
 			              NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, NM_IN6_ADDR_GEN_MODE_EUI64,
 			              NM_SETTING_IP6_CONFIG_TOKEN, nm_utils_inet6_interface_identifier_to_token (pllink->inet6_token, NULL),
@@ -4085,11 +4193,11 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master)
 
 	klass->update_connection (self, connection);
 
-	/* Check the connection in case of update_connection() bug. */
-	if (!nm_connection_verify (connection, &error)) {
-		_LOGE (LOGD_DEVICE, "Generated connection does not verify: %s", error->message);
-		g_clear_error (&error);
-		g_object_unref (connection);
+	if (!nm_connection_verify (connection, &local)) {
+		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+		             "generated connection does not verify: %s",
+		             local->message);
+		g_error_free (local);
 		return NULL;
 	}
 
@@ -4102,26 +4210,28 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master)
 	    && g_strcmp0 (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0
 	    && !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con))
 	    && !priv->slaves) {
-		_LOGD (LOGD_DEVICE, "ignoring generated connection (no IP and not in master-slave relationship)");
-		g_object_unref (connection);
-		connection = NULL;
+		NM_SET_OUT (out_maybe_later, TRUE);
+		g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+		                     "ignoring generated connection (no IP and not in master-slave relationship)");
+		return NULL;
 	}
 
 	/* Ignore any IPv6LL-only, not master connections without slaves,
 	 * unless they are in the assume-ipv6ll-only list.
 	 */
-	if (   connection
-	    && g_strcmp0 (ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0
+	if (   g_strcmp0 (ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0
 	    && g_strcmp0 (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0
 	    && !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con))
 	    && !priv->slaves
 	    && !nm_config_data_get_assume_ipv6ll_only (NM_CONFIG_GET_DATA, self)) {
 		_LOGD (LOGD_DEVICE, "ignoring generated connection (IPv6LL-only and not in master-slave relationship)");
-		g_object_unref (connection);
-		connection = NULL;
+		NM_SET_OUT (out_maybe_later, TRUE);
+		g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+		                    "ignoring generated connection (IPv6LL-only and not in master-slave relationship)");
+		return NULL;
 	}
 
-	return connection;
+	return g_steal_pointer (&connection);
 }
 
 gboolean
@@ -4291,10 +4401,9 @@ nm_device_emit_recheck_assume (gpointer user_data)
 	priv = NM_DEVICE_GET_PRIVATE (self);
 
 	priv->recheck_assume_id = 0;
-	if (!nm_device_get_act_request (self)) {
-		_LOGD (LOGD_DEVICE, "emit RECHECK_ASSUME signal");
+	if (!nm_device_get_act_request (self))
 		g_signal_emit (self, signals[RECHECK_ASSUME], 0);
-	}
+
 	return G_SOURCE_REMOVE;
 }
 
@@ -4333,7 +4442,7 @@ recheck_available (gpointer user_data)
 		_LOGD (LOGD_DEVICE, "is %savailable, %s %s",
 		       now_available ? "" : "not ",
 		       new_state == NM_DEVICE_STATE_UNAVAILABLE ? "no change required for" : "will transition to",
-		       state_to_string (new_state == NM_DEVICE_STATE_UNAVAILABLE ? state : new_state));
+		       nm_device_state_to_str (new_state == NM_DEVICE_STATE_UNAVAILABLE ? state : new_state));
 
 		priv->recheck_available.available_reason = NM_DEVICE_STATE_REASON_NONE;
 		priv->recheck_available.unavailable_reason = NM_DEVICE_STATE_REASON_NONE;
@@ -5472,8 +5581,15 @@ ip4_config_merge_and_apply (NMDevice *self,
 	composite = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
 	init_ip4_config_dns_priority (self, composite);
 
-	if (commit)
+	if (commit) {
 		ensure_con_ip4_config (self);
+		if (priv->queued_ip4_config_id) {
+			g_clear_object (&priv->ext_ip4_config);
+			priv->ext_ip4_config = nm_ip4_config_capture (nm_device_get_platform (self),
+			                                              nm_device_get_ip_ifindex (self),
+			                                              FALSE);
+		}
+	}
 
 	if (priv->dev_ip4_config) {
 		nm_ip4_config_merge (composite, priv->dev_ip4_config,
@@ -6200,7 +6316,6 @@ ip6_config_merge_and_apply (NMDevice *self,
 		}
 	}
 
-	/* If no config was passed in, create a new one */
 	composite = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
 	nm_ip6_config_set_privacy (composite,
 	                           priv->ndisc ?
@@ -6208,8 +6323,19 @@ ip6_config_merge_and_apply (NMDevice *self,
 	                           NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
 	init_ip6_config_dns_priority (self, composite);
 
-	if (commit)
+	if (commit) {
 		ensure_con_ip6_config (self);
+		if (priv->queued_ip6_config_id) {
+			g_clear_object (&priv->ext_ip6_config);
+			g_clear_object (&priv->ext_ip6_config_captured);
+			priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_platform (self),
+			                                                       nm_device_get_ip_ifindex (self),
+			                                                       FALSE,
+			                                                       NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
+			if (priv->ext_ip6_config_captured)
+				priv->ext_ip6_config = nm_ip6_config_new_cloned (priv->ext_ip6_config_captured);
+		}
+	}
 
 	/* Merge all the IP configs into the composite config */
 	if (priv->ac_ip6_config) {
@@ -7023,7 +7149,7 @@ nm_device_get_configured_mtu_for_wired (NMDevice *self, gboolean *out_is_user_co
 	}
 
 	*out_is_user_config = FALSE;
-	return NM_DEVICE_DEFAULT_MTU_WIRED;
+	return 0;
 }
 
 /*****************************************************************************/
@@ -7725,7 +7851,7 @@ act_stage3_ip6_config_start (NMDevice *self,
 	nm_platform_process_events (nm_device_get_platform (self));
 	g_clear_object (&priv->ext_ip6_config_captured);
 	priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_platform (self),
-	                                                       nm_device_get_ifindex (self),
+	                                                       nm_device_get_ip_ifindex (self),
 	                                                       FALSE,
 	                                                       NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
 
@@ -8649,9 +8775,9 @@ _update_ip4_address (NMDevice *self)
 }
 
 gboolean
-nm_device_get_is_nm_owned (NMDevice *self)
+nm_device_is_nm_owned (NMDevice *self)
 {
-	return NM_DEVICE_GET_PRIVATE (self)->is_nm_owned;
+	return NM_DEVICE_GET_PRIVATE (self)->nm_owned;
 }
 
 /*
@@ -8712,7 +8838,7 @@ delete_on_deactivate_check_and_schedule (NMDevice *self, int ifindex)
 
 	if (ifindex <= 0)
 		return;
-	if (!priv->is_nm_owned)
+	if (!priv->nm_owned)
 		return;
 	if (priv->queued_act_request)
 		return;
@@ -9035,10 +9161,12 @@ check_and_reapply_connection (NMDevice *self,
 	                    NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS,
 	                    &diffs);
 
-	if (diffs && nm_audit_manager_audit_enabled (nm_audit_manager_get ()))
-		*audit_args = nm_utils_format_con_diff_for_audit (diffs);
-	else
-		*audit_args = NULL;
+	if (audit_args) {
+		if (diffs && nm_audit_manager_audit_enabled (nm_audit_manager_get ()))
+			*audit_args = nm_utils_format_con_diff_for_audit (diffs);
+		else
+			*audit_args = NULL;
+	}
 
 	/**************************************************************************
 	 * check for unsupported changes and reject to reapply
@@ -9140,6 +9268,20 @@ check_and_reapply_connection (NMDevice *self,
 	return TRUE;
 }
 
+gboolean
+nm_device_reapply (NMDevice *self,
+                   NMConnection *connection,
+                   GError **error)
+{
+	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
+
+	return check_and_reapply_connection (self,
+	                                     connection,
+	                                     0,
+	                                     NULL,
+	                                     error);
+}
+
 typedef struct {
 	NMConnection *connection;
 	guint64 version_id;
@@ -10286,12 +10428,12 @@ static gboolean
 carrier_wait_timeout (gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
-	NM_DEVICE_GET_PRIVATE (self)->carrier_wait_id = 0;
-	nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, TRUE);
-
-	_carrier_wait_check_queued_act_request (self);
-
+	priv->carrier_wait_id = 0;
+	nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE);
+	if (!priv->carrier)
+		_carrier_wait_check_queued_act_request (self);
 	return G_SOURCE_REMOVE;
 }
 
@@ -10333,8 +10475,7 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware)
 	}
 
 	/* Store carrier immediately. */
-	if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT))
-		check_carrier (self);
+	nm_device_set_carrier_from_platform (self);
 
 	device_is_up = nm_device_is_up (self);
 	if (block && !device_is_up) {
@@ -10369,8 +10510,14 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware)
 	 * a timeout is reached.
 	 */
 	if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) {
-		if (!nm_clear_g_source (&priv->carrier_wait_id))
-			nm_device_add_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, TRUE);
+		/* we start a grace period of 5 seconds during which we will schedule
+		 * a pending action whenever we have no carrier.
+		 *
+		 * If during that time carrier goes away, we declare the interface
+		 * as not ready. */
+		nm_clear_g_source (&priv->carrier_wait_id);
+		if (!priv->carrier)
+			nm_device_add_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE);
 		priv->carrier_wait_id = g_timeout_add_seconds (5, carrier_wait_timeout, self);
 	}
 
@@ -11812,7 +11959,7 @@ nm_device_add_pending_action (NMDevice *self, const char *action, gboolean asser
 				       count + g_slist_length (iter), action);
 				g_return_val_if_reached (FALSE);
 			} else {
-				_LOGD (LOGD_DEVICE, "add_pending_action (%d): '%s' already pending (expected)",
+				_LOGT (LOGD_DEVICE, "add_pending_action (%d): '%s' already pending (expected)",
 				       count + g_slist_length (iter), action);
 			}
 			return FALSE;
@@ -11873,7 +12020,7 @@ nm_device_remove_pending_action (NMDevice *self, const char *action, gboolean as
 		_LOGW (LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending", count, action);
 		g_return_val_if_reached (FALSE);
 	} else
-		_LOGD (LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending (expected)", count, action);
+		_LOGT (LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending (expected)", count, action);
 
 	return FALSE;
 }
@@ -12058,11 +12205,6 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean
 		/* master: release slaves */
 		nm_device_master_release_slaves (self);
 
-		/* slave: mark no longer enslaved */
-		if (   priv->master
-		    && nm_platform_link_get_master (nm_device_get_platform (self), priv->ifindex) <= 0)
-			nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
-
 		/* Take out any entries in the routing table and any IP address the device had. */
 		ifindex = nm_device_get_ip_ifindex (self);
 		if (ifindex > 0) {
@@ -12071,6 +12213,11 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean
 		}
 	}
 
+	/* slave: mark no longer enslaved */
+	if (   priv->master
+	    && nm_platform_link_get_master (nm_device_get_platform (self), priv->ifindex) <= 0)
+		nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
+
 	if (priv->lldp_listener)
 		nm_lldp_listener_stop (priv->lldp_listener);
 
@@ -12411,24 +12558,20 @@ _set_state_full (NMDevice *self,
 	if (   (priv->state == state)
 	    && (   state != NM_DEVICE_STATE_UNAVAILABLE
 	        || !priv->firmware_missing)) {
-		_LOGD (LOGD_DEVICE, "state change: %s -> %s (reason '%s') [%d %d %d]%s",
-		       state_to_string (old_state),
-		       state_to_string (state),
+		_LOGD (LOGD_DEVICE, "state change: %s -> %s (reason '%s', internal state '%s'%s)",
+		       nm_device_state_to_str (old_state),
+		       nm_device_state_to_str (state),
 		       reason_to_string (reason),
-		       old_state,
-		       state,
-		       reason,
-		       priv->firmware_missing ? " (missing firmware)" : "");
+		       _sys_iface_state_to_str (priv->sys_iface_state),
+		       priv->firmware_missing ? ", missing firmware" : "");
 		return;
 	}
 
-	_LOGI (LOGD_DEVICE, "state change: %s -> %s (reason '%s') [%d %d %d]",
-	       state_to_string (old_state),
-	       state_to_string (state),
+	_LOGI (LOGD_DEVICE, "state change: %s -> %s (reason '%s', internal state '%s')",
+	       nm_device_state_to_str (old_state),
+	       nm_device_state_to_str (state),
 	       reason_to_string (reason),
-	       old_state,
-	       state,
-	       reason);
+	       _sys_iface_state_to_str (priv->sys_iface_state));
 
 	priv->in_state_changed = TRUE;
 
@@ -12453,6 +12596,9 @@ _set_state_full (NMDevice *self,
 	                        NM_DEVICE_SYS_IFACE_STATE_ASSUME))
 		nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_MANAGED);
 
+	if (state > NM_DEVICE_STATE_DISCONNECTED)
+		nm_device_assume_state_reset (self);
+
 	if (state <= NM_DEVICE_STATE_UNAVAILABLE) {
 		if (available_connections_del_all (self))
 			_notify (self, PROP_AVAILABLE_CONNECTIONS);
@@ -12745,7 +12891,7 @@ queued_state_set (gpointer user_data)
 	nm_assert (priv->queued_state.id);
 
 	_LOGD (LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s",
-	       state_to_string (priv->queued_state.state),
+	       nm_device_state_to_str (priv->queued_state.state),
 	       reason_to_string (priv->queued_state.reason),
 	       priv->queued_state.id,
 	       "change state");
@@ -12776,7 +12922,7 @@ nm_device_queue_state (NMDevice *self,
 
 	if (priv->queued_state.id && priv->queued_state.state == state) {
 		_LOGD (LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s%s%s%s",
-		       state_to_string (priv->queued_state.state),
+		       nm_device_state_to_str (priv->queued_state.state),
 		       reason_to_string (priv->queued_state.reason),
 		       priv->queued_state.id,
 		       "ignore queuing same state change",
@@ -12792,7 +12938,7 @@ nm_device_queue_state (NMDevice *self,
 	/* We should only ever have one delayed state transition at a time */
 	if (priv->queued_state.id) {
 		_LOGW (LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s",
-		       state_to_string (priv->queued_state.state),
+		       nm_device_state_to_str (priv->queued_state.state),
 		       reason_to_string (priv->queued_state.reason),
 		       priv->queued_state.id,
 		       "replace previously queued state change");
@@ -12805,7 +12951,7 @@ nm_device_queue_state (NMDevice *self,
 	priv->queued_state.id = g_idle_add (queued_state_set, self);
 
 	_LOGD (LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s",
-	       state_to_string (state),
+	       nm_device_state_to_str (state),
 	       reason_to_string (reason),
 	       priv->queued_state.id,
 	       "queue state change");
@@ -12820,7 +12966,7 @@ queued_state_clear (NMDevice *self)
 		return;
 
 	_LOGD (LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s",
-	       state_to_string (priv->queued_state.state),
+	       nm_device_state_to_str (priv->queued_state.state),
 	       reason_to_string (priv->queued_state.reason),
 	       priv->queued_state.id,
 	       "clear queued state change");
@@ -13726,6 +13872,8 @@ dispose (GObject *object)
 
 	nm_clear_g_cancellable (&priv->deactivating_cancellable);
 
+	nm_device_assume_state_reset (self);
+
 	_parent_set_ifindex (self, 0, FALSE);
 
 	platform = nm_device_get_platform (self);
@@ -13767,7 +13915,7 @@ dispose (GObject *object)
 
 	nm_clear_g_source (&priv->stats.timeout_id);
 
-	link_disconnect_action_cancel (self);
+	carrier_disconnected_action_cancel (self);
 
 	if (priv->ifindex > 0) {
 		priv->ifindex = 0;
@@ -13782,7 +13930,8 @@ dispose (GObject *object)
 
 	available_connections_del_all (self);
 
-	nm_clear_g_source (&priv->carrier_wait_id);
+	if (nm_clear_g_source (&priv->carrier_wait_id))
+		nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE);
 
 	_clear_queued_act_request (priv);
 
@@ -13854,14 +14003,11 @@ set_property (GObject *object, guint prop_id,
 
 	switch (prop_id) {
 	case PROP_UDI:
-		if (g_value_get_string (value)) {
-			g_free (priv->udi);
-			priv->udi = g_value_dup_string (value);
-		}
+		/* construct-only */
+		priv->udi = g_value_dup_string (value);
 		break;
 	case PROP_IFACE:
 		/* construct-only */
-		g_return_if_fail (!priv->iface);
 		priv->iface = g_value_dup_string (value);
 		break;
 	case PROP_DRIVER:
@@ -13885,9 +14031,14 @@ set_property (GObject *object, guint prop_id,
 			NMDeviceStateReason reason;
 
 			managed = g_value_get_boolean (value);
-			if (managed)
+			if (managed) {
 				reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED;
-			else {
+				if (NM_IN_SET_TYPED (NMDeviceSysIfaceState,
+				                     priv->sys_iface_state,
+				                     NM_DEVICE_SYS_IFACE_STATE_EXTERNAL,
+				                     NM_DEVICE_SYS_IFACE_STATE_REMOVED))
+					nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_ASSUME);
+			} else {
 				reason = NM_DEVICE_STATE_REASON_REMOVED;
 				nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_REMOVED);
 			}
@@ -13956,28 +14107,43 @@ get_property (GObject *object, guint prop_id,
 
 	switch (prop_id) {
 	case PROP_UDI:
-		g_value_set_string (value, priv->udi);
+		/* UDI is (depending on the device type) a path to sysfs and can contain
+		 * non-UTF-8.
+		 *   ip link add name $'d\xccf\\c' type dummy  */
+		g_value_take_string (value,
+		                     nm_utils_str_utf8safe_escape_cp (priv->udi,
+		                                                      NM_UTILS_STR_UTF8_SAFE_FLAG_NONE));
 		break;
 	case PROP_IFACE:
-		g_value_set_string (value, priv->iface);
+		g_value_take_string (value,
+		                     nm_utils_str_utf8safe_escape_cp (priv->iface,
+		                                                      NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL));
 		break;
 	case PROP_IP_IFACE:
-		if (ip_config_valid (priv->state))
-			g_value_set_string (value, nm_device_get_ip_iface (self));
-		else
+		if (ip_config_valid (priv->state)) {
+			g_value_take_string (value,
+			                     nm_utils_str_utf8safe_escape_cp (nm_device_get_ip_iface (self),
+			                                                      NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL));
+		} else
 			g_value_set_string (value, NULL);
 		break;
 	case PROP_IFINDEX:
 		g_value_set_int (value, priv->ifindex);
 		break;
 	case PROP_DRIVER:
-		g_value_set_string (value, priv->driver);
+		g_value_take_string (value,
+		                     nm_utils_str_utf8safe_escape_cp (priv->driver,
+		                                                      NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL));
 		break;
 	case PROP_DRIVER_VERSION:
-		g_value_set_string (value, priv->driver_version);
+		g_value_take_string (value,
+		                     nm_utils_str_utf8safe_escape_cp (priv->driver_version,
+		                                                      NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL));
 		break;
 	case PROP_FIRMWARE_VERSION:
-		g_value_set_string (value, priv->firmware_version);
+		g_value_take_string (value,
+		                     nm_utils_str_utf8safe_escape_cp (priv->firmware_version,
+		                                                      NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL));
 		break;
 	case PROP_CAPABILITIES:
 		g_value_set_uint (value, (priv->capabilities & ~NM_DEVICE_CAP_INTERNAL_MASK));
@@ -14161,7 +14327,7 @@ nm_device_class_init (NMDeviceClass *klass)
 	klass->can_unmanaged_external_down = can_unmanaged_external_down;
 	klass->realize_start_notify = realize_start_notify;
 	klass->unrealize_notify = unrealize_notify;
-	klass->carrier_changed = carrier_changed;
+	klass->carrier_changed_notify = carrier_changed_notify;
 	klass->get_ip_iface_identifier = get_ip_iface_identifier;
 	klass->unmanaged_on_quit = unmanaged_on_quit;
 	klass->deactivate_reset_hw_addr = deactivate_reset_hw_addr;
@@ -14172,7 +14338,7 @@ nm_device_class_init (NMDeviceClass *klass)
 	obj_properties[PROP_UDI] =
 	    g_param_spec_string (NM_DEVICE_UDI, "", "",
 	                         NULL,
-	                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
+	                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
 	                         G_PARAM_STATIC_STRINGS);
 	obj_properties[PROP_IFACE] =
 	    g_param_spec_string (NM_DEVICE_IFACE, "", "",
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index be328eb6..6d17d7c9 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -261,7 +261,7 @@ typedef struct {
 	gboolean        (*can_unmanaged_external_down)  (NMDevice *self);
 
 	/* Carrier state (IFF_LOWER_UP) */
-	void            (*carrier_changed) (NMDevice *, gboolean carrier);
+	void            (*carrier_changed_notify) (NMDevice *, gboolean carrier);
 
 	gboolean    (* get_ip_iface_identifier) (NMDevice *self, NMUtilsIPv6IfaceId *out_iid);
 
@@ -421,6 +421,15 @@ NMPlatform *nm_device_get_platform (NMDevice *self);
 
 const char *    nm_device_get_udi               (NMDevice *dev);
 const char *    nm_device_get_iface             (NMDevice *dev);
+
+static inline const char *
+_nm_device_get_iface (NMDevice *device)
+{
+	/* like nm_device_get_iface(), but gracefully accept NULL without
+	 * asserting. */
+	return device ? nm_device_get_iface (device) : NULL;
+}
+
 int             nm_device_get_ifindex           (NMDevice *dev);
 gboolean        nm_device_is_software           (NMDevice *dev);
 gboolean        nm_device_is_real               (NMDevice *dev);
@@ -487,7 +496,10 @@ void            nm_device_removed               (NMDevice *self, gboolean unconf
 gboolean        nm_device_is_available          (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags);
 gboolean        nm_device_has_carrier           (NMDevice *dev);
 
-NMConnection * nm_device_generate_connection (NMDevice *self, NMDevice *master);
+NMConnection * nm_device_generate_connection (NMDevice *self,
+                                              NMDevice *master,
+                                              gboolean *out_maybe_later,
+                                              GError **error);
 
 gboolean nm_device_master_update_slave_connection (NMDevice *master,
                                                    NMDevice *slave,
@@ -605,12 +617,24 @@ void nm_device_set_unmanaged_by_user_settings (NMDevice *self);
 void nm_device_set_unmanaged_by_user_udev (NMDevice *self);
 void nm_device_set_unmanaged_by_quitting (NMDevice *device);
 
-gboolean nm_device_get_is_nm_owned (NMDevice *device);
+gboolean nm_device_is_nm_owned (NMDevice *device);
 
 gboolean nm_device_has_capability (NMDevice *self, NMDeviceCapabilities caps);
 
+/*****************************************************************************/
+
+void nm_device_assume_state_get (NMDevice *self,
+                                 gboolean *out_assume_state_guess_assume,
+                                 const char **out_assume_state_connection_uuid);
+void nm_device_assume_state_reset (NMDevice *self);
+
+/*****************************************************************************/
+
 gboolean nm_device_realize_start      (NMDevice *device,
                                        const NMPlatformLink *plink,
+                                       gboolean assume_state_guess_assume,
+                                       const char *assume_state_connection_uuid,
+                                       gboolean set_nm_owned,
                                        NMUnmanFlagOp unmanaged_user_explicit,
                                        gboolean *out_compatible,
                                        GError **error);
@@ -675,6 +699,9 @@ const NMPlatformIP6Route *nm_device_get_ip6_default_route (NMDevice *self, gbool
 
 void nm_device_spawn_iface_helper (NMDevice *self);
 
+gboolean nm_device_reapply (NMDevice *self,
+                            NMConnection *connection,
+                            GError **error);
 void nm_device_reapply_settings_immediately (NMDevice *self);
 
 void nm_device_update_firewall_zone (NMDevice *self);
@@ -708,4 +735,7 @@ void nm_device_check_connectivity (NMDevice *self,
                                    gpointer user_data);
 NMConnectivityState nm_device_get_connectivity_state (NMDevice *self);
 
+
+const char *nm_device_state_to_str (NMDeviceState state);
+
 #endif /* __NETWORKMANAGER_DEVICE_H__ */
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index 7359be96..20692ed9 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -2742,7 +2742,7 @@ get_configured_mtu (NMDevice *device, gboolean *out_is_user_config)
 		}
 	}
 	*out_is_user_config = (mtu != 0);
-	return mtu ?: NM_DEVICE_DEFAULT_MTU_WIRELESS;
+	return mtu;
 }
 
 static gboolean
diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c
index e020ca33..e55a21b4 100644
--- a/src/dhcp/nm-dhcp-utils.c
+++ b/src/dhcp/nm-dhcp-utils.c
@@ -450,43 +450,6 @@ nm_dhcp_utils_ip4_config_from_options (int ifindex,
 		}
 	}
 
-	/*
-	 * RFC 2132, section 9.7
-	 *   DHCP clients use the contents of the 'server identifier' field
-	 *   as the destination address for any DHCP messages unicast to
-	 *   the DHCP server.
-	 *
-	 * Some ISP's provide leases from central servers that are on
-	 * different subnets that the address offered.  If the host
-	 * does not configure the interface as the default route, the
-	 * dhcp server may not be reachable via unicast, and a host
-	 * specific route is needed.
-	 **/
-	str = g_hash_table_lookup (options, "dhcp_server_identifier");
-	if (str) {
-		if (inet_pton (AF_INET, str, &tmp_addr) > 0) {
-
-			_LOG2I (LOGD_DHCP4, iface, "  server identifier %s", str);
-			if (   nm_utils_ip4_address_clear_host_address(tmp_addr, address.plen) != nm_utils_ip4_address_clear_host_address(address.address, address.plen)
-			    && !nm_ip4_config_get_direct_route_for_host (ip4_config, tmp_addr)) {
-				/* DHCP server not on assigned subnet and the no direct route was returned. Add route */
-				NMPlatformIP4Route route = { 0 };
-
-				route.network = tmp_addr;
-				route.plen = 32;
-				/* this will be a device route if gwaddr is 0 */
-				route.gateway = gwaddr;
-				route.rt_source = NM_IP_CONFIG_SOURCE_DHCP;
-				route.metric = priority;
-				nm_ip4_config_add_route (ip4_config, &route);
-				_LOG2D (LOGD_IP, iface, "adding route for server identifier: %s",
-				        nm_platform_ip4_route_to_string (&route, NULL, 0));
-			}
-		}
-		else
-			_LOG2W (LOGD_DHCP4, iface, "ignoring invalid server identifier '%s'", str);
-	}
-
 	str = g_hash_table_lookup (options, "dhcp_lease_time");
 	if (str) {
 		address.lifetime = address.preferred = strtoul (str, NULL, 10);
diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c
index 5223638e..a6204ae4 100644
--- a/src/dns/nm-dns-dnsmasq.c
+++ b/src/dns/nm-dns-dnsmasq.c
@@ -554,13 +554,15 @@ start_dnsmasq (NMDnsDnsmasq *self)
 
 static gboolean
 update (NMDnsPlugin *plugin,
-        const NMDnsIPConfigData **configs,
+        const GPtrArray *configs,
         const NMGlobalDnsConfig *global_config,
         const char *hostname)
 {
 	NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin);
 	NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self);
 	GVariantBuilder servers;
+	guint i;
+	int prio, first_prio;
 
 	start_dnsmasq (self);
 
@@ -569,9 +571,13 @@ update (NMDnsPlugin *plugin,
 	if (global_config)
 		add_global_config (self, &servers, global_config);
 	else {
-		while (*configs) {
-			add_ip_config_data (self, &servers, *configs);
-			configs++;
+		for (i = 0; i < configs->len; i++) {
+			prio = nm_dns_ip_config_data_get_dns_priority (configs->pdata[i]);
+			if (i == 0)
+				first_prio = prio;
+			else if (first_prio < 0 && first_prio != prio)
+				break;
+			add_ip_config_data (self, &servers, configs->pdata[i]);
 		}
 	}
 
diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c
index 1f7eb964..f443f340 100644
--- a/src/dns/nm-dns-manager.c
+++ b/src/dns/nm-dns-manager.c
@@ -197,6 +197,19 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_config_type_to_string, NMDnsIPConfigType,
 	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_VPN, "vpn"),
 );
 
+int
+nm_dns_ip_config_data_get_dns_priority (const NMDnsIPConfigData *config)
+{
+	g_return_val_if_fail (config, 0);
+
+	if (NM_IS_IP4_CONFIG (config->config))
+		return nm_ip4_config_get_dns_priority (config->config);
+	else if (NM_IS_IP6_CONFIG (config->config))
+		return nm_ip6_config_get_dns_priority (config->config);
+	else
+		g_return_val_if_reached (0);
+}
+
 static NMDnsIPConfigData *
 ip_config_data_new (gpointer config, NMDnsIPConfigType type, const char *iface)
 {
@@ -226,19 +239,10 @@ ip_config_data_destroy (gpointer ptr)
 static gint
 ip_config_data_compare (const NMDnsIPConfigData *a, const NMDnsIPConfigData *b)
 {
-	gboolean a_v4, b_v4;
-	gint a_prio, b_prio;
-
-	a_v4 = NM_IS_IP4_CONFIG (a->config);
-	b_v4 = NM_IS_IP4_CONFIG (b->config);
+	int a_prio, b_prio;
 
-	a_prio = a_v4 ?
-		nm_ip4_config_get_dns_priority ((NMIP4Config *) a->config) :
-		nm_ip6_config_get_dns_priority ((NMIP6Config *) a->config);
-
-	b_prio = b_v4 ?
-		nm_ip4_config_get_dns_priority ((NMIP4Config *) b->config) :
-		nm_ip6_config_get_dns_priority ((NMIP6Config *) b->config);
+	a_prio = nm_dns_ip_config_data_get_dns_priority (a);
+	b_prio = nm_dns_ip_config_data_get_dns_priority (b);
 
 	/* Configurations with lower priority value first */
 	if (a_prio < b_prio)
@@ -990,11 +994,9 @@ _collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no o
                            char ***out_options,
                            char ***out_nameservers,
                            char ***out_nis_servers,
-                           const char **out_nis_domain,
-                           NMDnsIPConfigData ***out_plugin_confs)
+                           const char **out_nis_domain)
 {
-	NMDnsIPConfigData **plugin_confs = NULL;
-	guint i, num, len;
+	guint i, j, num, len;
 	NMResolvConfData rc = {
 		.nameservers = g_ptr_array_new (),
 		.searches = g_ptr_array_new (),
@@ -1007,27 +1009,23 @@ _collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no o
 		merge_global_dns_config (&rc, global_config);
 	else {
 		nm_auto_free_gstring GString *tmp_gstring = NULL;
-		int prio, prev_prio = 0;
+		int prio, first_prio = 0;
 		NMDnsIPConfigData *current;
-		gboolean skip = FALSE, v4;
+		gboolean v4;
 
-		plugin_confs = g_new (NMDnsIPConfigData *, configs->len + 1);
+		for (i = 0, j = 0; i < configs->len; i++) {
+			gboolean skip = FALSE;
 
-		for (i = 0; i < configs->len; i++) {
 			current = configs->pdata[i];
-			v4 = NM_IS_IP4_CONFIG (current->config);
 
-			prio = v4 ?
-				nm_ip4_config_get_dns_priority ((NMIP4Config *) current->config) :
-				nm_ip6_config_get_dns_priority ((NMIP6Config *) current->config);
+			prio = nm_dns_ip_config_data_get_dns_priority (current);
 
-			if (prev_prio < 0 && prio != prev_prio) {
+			if (i == 0)
+				first_prio = prio;
+			else if (first_prio < 0 && first_prio != prio)
 				skip = TRUE;
-				plugin_confs[i] = NULL;
-			}
-
-			prev_prio = prio;
 
+			v4 = NM_IS_IP4_CONFIG (current->config);
 			if (   ( v4 && nm_ip4_config_get_num_nameservers ((NMIP4Config *) current->config))
 			    || (!v4 && nm_ip6_config_get_num_nameservers ((NMIP6Config *) current->config))) {
 				_LOGT ("config: %8d %-7s v%c %-16s %s: %s",
@@ -1039,12 +1037,9 @@ _collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no o
 				       get_nameserver_list (current->config, &tmp_gstring));
 			}
 
-			if (!skip) {
+			if (!skip)
 				merge_one_ip_config_data (&rc, current);
-				plugin_confs[i] = current;
-			}
 		}
-		plugin_confs[i] = NULL;
 	}
 
 	/* If the hostname is a FQDN ("dcbw.example.com"), then add the domain part of it
@@ -1078,7 +1073,6 @@ _collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no o
 	}
 	g_ptr_array_set_size (rc.searches, i);
 
-	*out_plugin_confs = plugin_confs;
 	*out_searches = _ptrarray_to_strv (rc.searches);
 	*out_options = _ptrarray_to_strv (rc.options);
 	*out_nameservers = _ptrarray_to_strv (rc.nameservers);
@@ -1102,7 +1096,6 @@ update_dns (NMDnsManager *self,
 	SpawnResult result = SR_ERROR;
 	NMConfigData *data;
 	NMGlobalDnsConfig *global_config;
-	gs_free NMDnsIPConfigData **plugin_confs = NULL;
 
 	g_return_val_if_fail (!error || !*error, FALSE);
 
@@ -1136,8 +1129,7 @@ update_dns (NMDnsManager *self,
 	compute_hash (self, global_config, priv->hash);
 
 	_collect_resolv_conf_data (self, global_config, priv->configs, priv->hostname,
-	                           &searches, &options, &nameservers, &nis_servers, &nis_domain,
-	                           &plugin_confs);
+	                           &searches, &options, &nameservers, &nis_servers, &nis_domain);
 
 	/* Let any plugins do their thing first */
 	if (priv->plugin) {
@@ -1155,7 +1147,7 @@ update_dns (NMDnsManager *self,
 
 		_LOGD ("update-dns: updating plugin %s", plugin_name);
 		if (!nm_dns_plugin_update (plugin,
-		                           (const NMDnsIPConfigData **) plugin_confs,
+		                           priv->configs,
 		                           global_config,
 		                           priv->hostname)) {
 			_LOGW ("update-dns: plugin %s update failed", plugin_name);
diff --git a/src/dns/nm-dns-manager.h b/src/dns/nm-dns-manager.h
index 899e4bb8..ee835927 100644
--- a/src/dns/nm-dns-manager.h
+++ b/src/dns/nm-dns-manager.h
@@ -44,6 +44,8 @@ typedef struct {
 	char *iface;
 } NMDnsIPConfigData;
 
+int nm_dns_ip_config_data_get_dns_priority (const NMDnsIPConfigData *config);
+
 #define NM_TYPE_DNS_MANAGER (nm_dns_manager_get_type ())
 #define NM_DNS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NM_TYPE_DNS_MANAGER, NMDnsManager))
 #define NM_DNS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NM_TYPE_DNS_MANAGER, NMDnsManagerClass))
diff --git a/src/dns/nm-dns-plugin.c b/src/dns/nm-dns-plugin.c
index 00729c93..5805b7d8 100644
--- a/src/dns/nm-dns-plugin.c
+++ b/src/dns/nm-dns-plugin.c
@@ -77,7 +77,7 @@ G_DEFINE_TYPE_EXTENDED (NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT, G_TYPE_FLAG_A
 
 gboolean
 nm_dns_plugin_update (NMDnsPlugin *self,
-                      const NMDnsIPConfigData **configs,
+                      const GPtrArray *configs,
                       const NMGlobalDnsConfig *global_config,
                       const char *hostname)
 {
diff --git a/src/dns/nm-dns-plugin.h b/src/dns/nm-dns-plugin.h
index 12109441..996695c0 100644
--- a/src/dns/nm-dns-plugin.h
+++ b/src/dns/nm-dns-plugin.h
@@ -50,7 +50,7 @@ typedef struct {
 	 * configuration.
 	 */
 	gboolean (*update) (NMDnsPlugin *self,
-	                    const NMDnsIPConfigData **configs,
+	                    const GPtrArray *configs,
 	                    const NMGlobalDnsConfig *global_config,
 	                    const char *hostname);
 
@@ -80,7 +80,7 @@ gboolean nm_dns_plugin_is_caching (NMDnsPlugin *self);
 const char *nm_dns_plugin_get_name (NMDnsPlugin *self);
 
 gboolean nm_dns_plugin_update (NMDnsPlugin *self,
-                               const NMDnsIPConfigData **configs,
+                               const GPtrArray *configs,
                                const NMGlobalDnsConfig *global_config,
                                const char *hostname);
 
diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c
index ed165618..fce1fef1 100644
--- a/src/dns/nm-dns-systemd-resolved.c
+++ b/src/dns/nm-dns-systemd-resolved.c
@@ -102,12 +102,12 @@ call_done (GObject *source, GAsyncResult *r, gpointer user_data)
 static void
 add_interface_configuration (NMDnsSystemdResolved *self,
                              GArray *interfaces,
-                             const NMDnsIPConfigData *data)
+                             const NMDnsIPConfigData *data,
+                             gboolean skip)
 {
 	int i;
 	InterfaceConfig *ic = NULL;
 	int ifindex;
-	NMDevice *device;
 
 	if (NM_IS_IP4_CONFIG (data->config))
 		ifindex = nm_ip4_config_get_ifindex (data->config);
@@ -116,8 +116,6 @@ add_interface_configuration (NMDnsSystemdResolved *self,
 	else
 		g_return_if_reached ();
 
-	device = nm_manager_get_device_by_ifindex (nm_manager_get (), ifindex);
-
 	for (i = 0; i < interfaces->len; i++) {
 		InterfaceConfig *tic = &g_array_index (interfaces, InterfaceConfig, i);
 		if (ifindex == tic->ifindex) {
@@ -133,7 +131,8 @@ add_interface_configuration (NMDnsSystemdResolved *self,
 		ic->ifindex = ifindex;
 	}
 
-	ic->configs = g_list_append (ic->configs, data->config);
+	if (!skip)
+		ic->configs = g_list_append (ic->configs, data->config);
 }
 
 static void
@@ -291,17 +290,25 @@ send_updates (NMDnsSystemdResolved *self)
 
 static gboolean
 update (NMDnsPlugin *plugin,
-        const NMDnsIPConfigData **configs,
+        const GPtrArray *configs,
         const NMGlobalDnsConfig *global_config,
         const char *hostname)
 {
 	NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED (plugin);
 	GArray *interfaces = g_array_new (TRUE, TRUE, sizeof (InterfaceConfig));
-	const NMDnsIPConfigData **c;
-	int i;
-
-	for (c = configs; *c != NULL; c++)
-		add_interface_configuration (self, interfaces, *c);
+	guint i;
+	int prio, first_prio = 0;
+
+	for (i = 0; i < configs->len; i++) {
+		gboolean skip = FALSE;
+
+		prio = nm_dns_ip_config_data_get_dns_priority (configs->pdata[i]);
+		if (i == 0)
+			first_prio = prio;
+		else if (first_prio < 0 && first_prio != prio)
+			skip = TRUE;
+		add_interface_configuration (self, interfaces, configs->pdata[i], skip);
+	}
 
 	free_pending_updates (self);
 
diff --git a/src/dns/nm-dns-unbound.c b/src/dns/nm-dns-unbound.c
index 6af4bad8..0b80055f 100644
--- a/src/dns/nm-dns-unbound.c
+++ b/src/dns/nm-dns-unbound.c
@@ -39,7 +39,7 @@ G_DEFINE_TYPE (NMDnsUnbound, nm_dns_unbound, NM_TYPE_DNS_PLUGIN)
 
 static gboolean
 update (NMDnsPlugin *plugin,
-        const NMDnsIPConfigData **configs,
+        const GPtrArray *configs,
         const NMGlobalDnsConfig *global_config,
         const char *hostname)
 {
diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c
index 19c0343f..862754f9 100644
--- a/src/nm-active-connection.c
+++ b/src/nm-active-connection.c
@@ -111,8 +111,7 @@ static void _device_cleanup (NMActiveConnection *self);
 static void _settings_connection_notify_flags (NMSettingsConnection *settings_connection,
                                                GParamSpec *param,
                                                NMActiveConnection *self);
-static void _set_activation_type (NMActiveConnection *self,
-                                  NMActivationType activation_type);
+static void _set_activation_type_managed (NMActiveConnection *self);
 
 /*****************************************************************************/
 
@@ -236,7 +235,7 @@ nm_active_connection_set_state (NMActiveConnection *self,
 		/* assuming connections mean to gracefully take over an externally
 		 * configured device. Once activation is complete, an assumed
 		 * activation *is* the same as a full activation. */
-		_set_activation_type (self, NM_ACTIVATION_TYPE_MANAGED);
+		_set_activation_type_managed (self);
 	}
 
 	old_state = priv->state;
@@ -755,13 +754,31 @@ _set_activation_type (NMActiveConnection *self,
 	if (priv->activation_type == activation_type)
 		return;
 
+	priv->activation_type = activation_type;
+
+	if (priv->settings_connection) {
+		if (activation_type == NM_ACTIVATION_TYPE_EXTERNAL)
+			g_signal_connect (priv->settings_connection, "notify::"NM_SETTINGS_CONNECTION_FLAGS, (GCallback) _settings_connection_notify_flags, self);
+		else
+			g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_notify_flags, self);
+	}
+}
+
+static void
+_set_activation_type_managed (NMActiveConnection *self)
+{
+	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+
+	if (priv->activation_type == NM_ACTIVATION_TYPE_MANAGED)
+		return;
+
 	_LOGD ("update activation type from %s to %s",
 	       nm_activation_type_to_string (priv->activation_type),
-	       nm_activation_type_to_string (activation_type));
-	priv->activation_type = activation_type;
+	       nm_activation_type_to_string (NM_ACTIVATION_TYPE_MANAGED));
 
-	if (   priv->activation_type == NM_ACTIVATION_TYPE_MANAGED
-	    && priv->device
+	_set_activation_type (self, NM_ACTIVATION_TYPE_MANAGED);
+
+	if (   priv->device
 	    && self == NM_ACTIVE_CONNECTION (nm_device_get_act_request (priv->device))
 	    && NM_IN_SET (nm_device_sys_iface_state_get (priv->device),
 	                  NM_DEVICE_SYS_IFACE_STATE_EXTERNAL,
@@ -776,6 +793,8 @@ _settings_connection_notify_flags (NMSettingsConnection *settings_connection,
                                    GParamSpec *param,
                                    NMActiveConnection *self)
 {
+	GError *error = NULL;
+
 	nm_assert (NM_IS_ACTIVE_CONNECTION (self));
 	nm_assert (NM_IS_SETTINGS_CONNECTION (settings_connection));
 	nm_assert (nm_active_connection_get_activation_type (self) == NM_ACTIVATION_TYPE_EXTERNAL);
@@ -784,9 +803,14 @@ _settings_connection_notify_flags (NMSettingsConnection *settings_connection,
 	if (nm_settings_connection_get_nm_generated (settings_connection))
 		return;
 
-	g_signal_handlers_disconnect_by_func (settings_connection, _settings_connection_notify_flags, self);
-	_set_activation_type (self, NM_ACTIVATION_TYPE_MANAGED);
-	nm_device_reapply_settings_immediately (nm_active_connection_get_device (self));
+	_set_activation_type_managed (self);
+	if (!nm_device_reapply (nm_active_connection_get_device (self),
+	                        NM_CONNECTION (nm_active_connection_get_settings_connection (self)),
+	                        &error)) {
+		_LOGW ("failed to reapply new device settings on previously externally managed device: %s",
+		       error->message);
+		g_error_free (error);
+	}
 }
 
 /*****************************************************************************/
@@ -1147,7 +1171,7 @@ set_property (GObject *object, guint prop_id,
 		                   NM_ACTIVATION_TYPE_ASSUME,
 		                   NM_ACTIVATION_TYPE_EXTERNAL))
 			g_return_if_reached ();
-		priv->activation_type = (NMActivationType) i;
+		_set_activation_type (self, (NMActivationType) i);
 		break;
 	case PROP_SPECIFIC_OBJECT:
 		tmp = g_value_get_string (value);
diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c
index 3f2f0eaa..d59bc574 100644
--- a/src/nm-checkpoint.c
+++ b/src/nm-checkpoint.c
@@ -275,6 +275,17 @@ activate:
 				_LOGD ("rollback: reactivating connection %s",
 				       nm_settings_connection_get_uuid (connection));
 				subject = nm_auth_subject_new_internal ();
+
+				/* Disconnect the device if needed. This necessary because now
+				 * the manager prevents the reactivation of the same connection by
+				 * an internal subject. */
+				if (   nm_device_get_state (device) > NM_DEVICE_STATE_DISCONNECTED
+				    && nm_device_get_state (device) < NM_DEVICE_STATE_DEACTIVATING) {
+					nm_device_state_changed (device,
+					                         NM_DEVICE_STATE_DEACTIVATING,
+					                         NM_DEVICE_STATE_REASON_NEW_ACTIVATION);
+				}
+
 				if (!nm_manager_activate_connection (priv->manager,
 				                                     connection,
 				                                     dev_checkpoint->applied_connection,
diff --git a/src/nm-config.c b/src/nm-config.c
index 2cdf8556..91c21de7 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -1872,6 +1872,14 @@ _nm_config_state_set (NMConfig *self,
 #define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED             "managed"
 #define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_PERM_HW_ADDR_FAKE   "perm-hw-addr-fake"
 #define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_CONNECTION_UUID     "connection-uuid"
+#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_NM_OWNED            "nm-owned"
+
+NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_device_state_managed_type_to_str, NMConfigDeviceStateManagedType,
+	NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNKNOWN,   "unknown"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED, "unmanaged"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED,   "managed"),
+);
 
 static NMConfigDeviceStateData *
 _config_device_state_data_new (int ifindex, GKeyFile *kf)
@@ -1882,26 +1890,29 @@ _config_device_state_data_new (int ifindex, GKeyFile *kf)
 	gs_free char *perm_hw_addr_fake = NULL;
 	gsize connection_uuid_len;
 	gsize perm_hw_addr_fake_len;
+	gint nm_owned = -1;
 	char *p;
 
 	nm_assert (ifindex > 0);
 
 	if (kf) {
-		gboolean managed;
-
-		managed = nm_config_keyfile_get_boolean (kf,
-		                                         DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
-		                                         DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED,
-		                                         FALSE);
-		managed_type = managed
-		               ? NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED
-		               : NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED;
-
-		if (managed) {
+		switch (nm_config_keyfile_get_boolean (kf,
+		                                       DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
+		                                       DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED,
+		                                       -1)) {
+		case TRUE:
+			managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED;
 			connection_uuid = nm_config_keyfile_get_value (kf,
 			                                               DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
 			                                               DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_CONNECTION_UUID,
 			                                               NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
+			break;
+		case FALSE:
+			managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED;
+			break;
+		case -1:
+			/* missing property in keyfile. */
+			break;
 		}
 
 		perm_hw_addr_fake = nm_config_keyfile_get_value (kf,
@@ -1915,6 +1926,11 @@ _config_device_state_data_new (int ifindex, GKeyFile *kf)
 			g_free (perm_hw_addr_fake);
 			perm_hw_addr_fake = normalized;
 		}
+
+		nm_owned = nm_config_keyfile_get_boolean (kf,
+		                                          DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
+		                                          DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_NM_OWNED,
+		                                          -1);
 	}
 
 	connection_uuid_len = connection_uuid ? strlen (connection_uuid) + 1 : 0;
@@ -1928,6 +1944,7 @@ _config_device_state_data_new (int ifindex, GKeyFile *kf)
 	device_state->managed = managed_type;
 	device_state->connection_uuid = NULL;
 	device_state->perm_hw_addr_fake = NULL;
+	device_state->nm_owned = nm_owned;
 
 	p = (char *) (&device_state[1]);
 	if (connection_uuid) {
@@ -1957,6 +1974,7 @@ nm_config_device_state_load (int ifindex)
 	NMConfigDeviceStateData *device_state;
 	char path[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR) + 60];
 	gs_unref_keyfile GKeyFile *kf = NULL;
+	const char *nm_owned_str;
 
 	g_return_val_if_fail (ifindex > 0, NULL);
 
@@ -1967,33 +1985,28 @@ nm_config_device_state_load (int ifindex)
 		g_clear_pointer (&kf, g_key_file_unref);
 
 	device_state = _config_device_state_data_new (ifindex, kf);
+	nm_owned_str = device_state->nm_owned == TRUE ?
+	               ", nm-owned=1" :
+	               (device_state->nm_owned == FALSE ? ", nm-owned=0" : "");
 
-	if (kf) {
-		_LOGT ("device-state: read #%d (%s); managed=%d%s%s%s%s%s%s",
-		       ifindex, path,
-		       device_state->managed,
-		       NM_PRINT_FMT_QUOTED (device_state->connection_uuid, ", connection-uuid=", device_state->connection_uuid, "", ""),
-		       NM_PRINT_FMT_QUOTED (device_state->perm_hw_addr_fake, ", perm-hw-addr-fake=", device_state->perm_hw_addr_fake, "", ""));
-	} else {
-		_LOGT ("device-state: read #%d (%s); no persistent state",
-		       ifindex, path);
-	}
+
+	_LOGT ("device-state: %s #%d (%s); managed=%s%s%s%s%s%s%s%s",
+	       kf ? "read" : "miss",
+	       ifindex, path,
+	       _device_state_managed_type_to_str (device_state->managed),
+	       NM_PRINT_FMT_QUOTED (device_state->connection_uuid, ", connection-uuid=", device_state->connection_uuid, "", ""),
+	       NM_PRINT_FMT_QUOTED (device_state->perm_hw_addr_fake, ", perm-hw-addr-fake=", device_state->perm_hw_addr_fake, "", ""),
+	       nm_owned_str);
 
 	return device_state;
 }
 
-NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_device_state_managed_type_to_str, NMConfigDeviceStateManagedType,
-	NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"),
-	NM_UTILS_LOOKUP_STR_ITEM (NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNKNOWN,   "unknown"),
-	NM_UTILS_LOOKUP_STR_ITEM (NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED, "unmanaged"),
-	NM_UTILS_LOOKUP_STR_ITEM (NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED,   "managed"),
-);
-
 gboolean
 nm_config_device_state_write (int ifindex,
                               NMConfigDeviceStateManagedType managed,
                               const char *perm_hw_addr_fake,
-                              const char *connection_uuid)
+                              const char *connection_uuid,
+                              gint nm_owned)
 {
 	char path[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR) + 60];
 	GError *local = NULL;
@@ -2028,6 +2041,13 @@ nm_config_device_state_write (int ifindex,
 		                       DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_CONNECTION_UUID,
 		                       connection_uuid);
 	}
+	if (nm_owned >= 0) {
+		g_key_file_set_boolean (kf,
+		                        DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
+		                        DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_NM_OWNED,
+		                        nm_owned);
+	}
+
 
 	if (!g_key_file_save_to_file (kf, path, &local)) {
 		_LOGW ("device-state: write #%d (%s) failed: %s", ifindex, path, local->message);
diff --git a/src/nm-config.h b/src/nm-config.h
index 283d6a1b..c5ff7c67 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -63,6 +63,7 @@
 #define NM_CONFIG_KEYFILE_KEY_MAIN_DHCP                     "dhcp"
 #define NM_CONFIG_KEYFILE_KEY_MAIN_DEBUG                    "debug"
 #define NM_CONFIG_KEYFILE_KEY_MAIN_HOSTNAME_MODE            "hostname-mode"
+#define NM_CONFIG_KEYFILE_KEY_MAIN_SLAVES_ORDER             "slaves-order"
 #define NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND               "backend"
 #define NM_CONFIG_KEYFILE_KEY_CONFIG_ENABLE                 "enable"
 #define NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS            ".was"
@@ -204,13 +205,18 @@ struct _NMConfigDeviceStateData {
 	const char *connection_uuid;
 
 	const char *perm_hw_addr_fake;
+
+	/* whether the device was nm-owned (0/1) or -1 for
+	 * non-software devices. */
+	gint nm_owned;
 };
 
 NMConfigDeviceStateData *nm_config_device_state_load (int ifindex);
 gboolean nm_config_device_state_write (int ifindex,
                                        NMConfigDeviceStateManagedType managed,
                                        const char *perm_hw_addr_fake,
-                                       const char *connection_uuid);
+                                       const char *connection_uuid,
+                                       gint nm_owned);
 void nm_config_device_state_prune_unseen (GHashTable *seen_ifindexes);
 
 /*****************************************************************************/
diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c
index 75bb7b63..6f16b28e 100644
--- a/src/nm-connectivity.c
+++ b/src/nm-connectivity.c
@@ -144,7 +144,7 @@ curl_check_connectivity (CURLM *mhandle, CURLMcode ret)
 			continue;
 
 		/* Here we have completed a session. Check easy session result. */
-		eret = curl_easy_getinfo (msg->easy_handle, CURLINFO_PRIVATE, &cb_data);
+		eret = curl_easy_getinfo (msg->easy_handle, CURLINFO_PRIVATE, (char **) &cb_data);
 		if (eret != CURLE_OK) {
 			_LOG2E ("curl cannot extract cb_data for easy handle %p, skipping msg", msg->easy_handle);
 			continue;
@@ -486,27 +486,28 @@ nm_connectivity_init (NMConnectivity *self)
 	NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
 	CURLcode retv;
 
+	retv = curl_global_init (CURL_GLOBAL_ALL);
+	if (retv == CURLE_OK)
+		priv->curl_mhandle = curl_multi_init ();
+
+	if (!priv->curl_mhandle)
+		 _LOGE ("unable to init cURL, connectivity check will not work");
+	else {
+		curl_multi_setopt (priv->curl_mhandle, CURLMOPT_SOCKETFUNCTION, multi_socket_cb);
+		curl_multi_setopt (priv->curl_mhandle, CURLMOPT_SOCKETDATA, self);
+		curl_multi_setopt (priv->curl_mhandle, CURLMOPT_TIMERFUNCTION, multi_timer_cb);
+		curl_multi_setopt (priv->curl_mhandle, CURLMOPT_TIMERDATA, self);
+		curl_multi_setopt (priv->curl_mhandle, CURLOPT_VERBOSE, 1);
+	}
+
 	priv->config = g_object_ref (nm_config_get ());
+
 	update_config (self, nm_config_get_data (priv->config));
 	g_signal_connect (G_OBJECT (priv->config),
 	                  NM_CONFIG_SIGNAL_CONFIG_CHANGED,
 	                  G_CALLBACK (config_changed_cb),
 	                  self);
 
-	retv = curl_global_init (CURL_GLOBAL_ALL);
-	if (retv == CURLE_OK)
-		priv->curl_mhandle = curl_multi_init ();
-
-	if (priv->curl_mhandle == NULL) {
-		 _LOGE ("cnable to init cURL, connectivity check will not work");
-		return;
-	}
-
-	curl_multi_setopt (priv->curl_mhandle, CURLMOPT_SOCKETFUNCTION, multi_socket_cb);
-	curl_multi_setopt (priv->curl_mhandle, CURLMOPT_SOCKETDATA, self);
-	curl_multi_setopt (priv->curl_mhandle, CURLMOPT_TIMERFUNCTION, multi_timer_cb);
-	curl_multi_setopt (priv->curl_mhandle, CURLMOPT_TIMERDATA, self);
-	curl_multi_setopt (priv->curl_mhandle, CURLOPT_VERBOSE, 1);
 }
 
 static void
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index 20532e86..ae6af9c3 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -248,6 +248,16 @@ notify_addresses (NMIP4Config *self)
 	_notify (self, PROP_ADDRESSES);
 }
 
+static gint
+sort_captured_addresses (gconstpointer a, gconstpointer b)
+{
+	const NMPlatformIP4Address *addr_a = a, *addr_b = b;
+
+	/* Primary addresses first */
+	return NM_FLAGS_HAS (addr_a->n_ifa_flags, IFA_F_SECONDARY) -
+	       NM_FLAGS_HAS (addr_b->n_ifa_flags, IFA_F_SECONDARY);
+}
+
 NMIP4Config *
 nm_ip4_config_capture (NMPlatform *platform, int ifindex, gboolean capture_resolv_conf)
 {
@@ -269,6 +279,8 @@ nm_ip4_config_capture (NMPlatform *platform, int ifindex, gboolean capture_resol
 	g_array_unref (priv->routes);
 
 	priv->addresses = nm_platform_ip4_address_get_all (platform, ifindex);
+	g_array_sort (priv->addresses, sort_captured_addresses);
+
 	priv->routes = nm_platform_ip4_route_get_all (platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
 
 	/* Extract gateway from default route */
diff --git a/src/nm-logging.h b/src/nm-logging.h
index ff1fac79..91a41412 100644
--- a/src/nm-logging.h
+++ b/src/nm-logging.h
@@ -306,6 +306,37 @@ gboolean nm_logging_syslog_enabled (void);
 #define _LOG2t_err(errsv, ...) G_STMT_START { if (FALSE) { _NMLOG2_err (errsv, LOGL_TRACE, __VA_ARGS__); } } G_STMT_END
 #endif
 
+#define _NMLOG3_ENABLED(level) ( nm_logging_enabled ((level), (_NMLOG3_DOMAIN)) )
+
+#define _LOG3T(...)          _NMLOG3 (LOGL_TRACE, __VA_ARGS__)
+#define _LOG3D(...)          _NMLOG3 (LOGL_DEBUG, __VA_ARGS__)
+#define _LOG3I(...)          _NMLOG3 (LOGL_INFO , __VA_ARGS__)
+#define _LOG3W(...)          _NMLOG3 (LOGL_WARN , __VA_ARGS__)
+#define _LOG3E(...)          _NMLOG3 (LOGL_ERR  , __VA_ARGS__)
+
+#define _LOG3T_ENABLED(...)  _NMLOG3_ENABLED (LOGL_TRACE, ##__VA_ARGS__)
+#define _LOG3D_ENABLED(...)  _NMLOG3_ENABLED (LOGL_DEBUG, ##__VA_ARGS__)
+#define _LOG3I_ENABLED(...)  _NMLOG3_ENABLED (LOGL_INFO , ##__VA_ARGS__)
+#define _LOG3W_ENABLED(...)  _NMLOG3_ENABLED (LOGL_WARN , ##__VA_ARGS__)
+#define _LOG3E_ENABLED(...)  _NMLOG3_ENABLED (LOGL_ERR  , ##__VA_ARGS__)
+
+#define _LOG3T_err(errsv, ...) _NMLOG3_err (errsv, LOGL_TRACE, __VA_ARGS__)
+#define _LOG3D_err(errsv, ...) _NMLOG3_err (errsv, LOGL_DEBUG, __VA_ARGS__)
+#define _LOG3I_err(errsv, ...) _NMLOG3_err (errsv, LOGL_INFO , __VA_ARGS__)
+#define _LOG3W_err(errsv, ...) _NMLOG3_err (errsv, LOGL_WARN , __VA_ARGS__)
+#define _LOG3E_err(errsv, ...) _NMLOG3_err (errsv, LOGL_ERR  , __VA_ARGS__)
+
+#ifdef NM_MORE_LOGGING
+#define _LOG3t_ENABLED(...)    _NMLOG3_ENABLED (LOGL_TRACE, ##__VA_ARGS__)
+#define _LOG3t(...)            _NMLOG3 (LOGL_TRACE, __VA_ARGS__)
+#define _LOG3t_err(errsv, ...) _NMLOG3_err (errsv, LOGL_TRACE, __VA_ARGS__)
+#else
+/* still call the logging macros to get compile time checks, but they will be optimized out. */
+#define _LOG3t_ENABLED(...)    ( FALSE && (_NMLOG3_ENABLED (LOGL_TRACE, ##__VA_ARGS__)) )
+#define _LOG3t(...)            G_STMT_START { if (FALSE) { _NMLOG3 (LOGL_TRACE, __VA_ARGS__); } } G_STMT_END
+#define _LOG3t_err(errsv, ...) G_STMT_START { if (FALSE) { _NMLOG3_err (errsv, LOGL_TRACE, __VA_ARGS__); } } G_STMT_END
+#endif
+
 extern void (*_nm_logging_clear_platform_logging_cache) (void);
 
 /*****************************************************************************/
diff --git a/src/nm-manager.c b/src/nm-manager.c
index a7402195..7662c2e3 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -222,19 +222,64 @@ NM_DEFINE_SINGLETON_INSTANCE (NMManager);
 #define _NMLOG_PREFIX_NAME      "manager"
 #define _NMLOG(level, domain, ...) \
     G_STMT_START { \
-        const NMLogLevel __level = (level); \
-        const NMLogDomain __domain = (domain); \
+        const NMLogLevel _level = (level); \
+        const NMLogDomain _domain = (domain); \
         \
-        if (nm_logging_enabled (__level, __domain)) { \
-            const NMManager *const __self = (self); \
-            char __sbuf[32]; \
+        if (nm_logging_enabled (_level, _domain)) { \
+            const NMManager *const _self = (self); \
+            char _sbuf[32]; \
             \
-            _nm_log (__level, __domain, 0, NULL, NULL, \
+            _nm_log (_level, _domain, 0, NULL, NULL, \
                      "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
                      _NMLOG_PREFIX_NAME, \
-                     (__self && __self != singleton_instance) \
-                         ? nm_sprintf_buf (__sbuf, "[%p]", __self) \
-                         : "" \
+                     ((_self && _self != singleton_instance) \
+                         ? nm_sprintf_buf (_sbuf, "[%p]", _self) \
+                         : "") \
+                     _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
+        } \
+    } G_STMT_END
+
+#define _NMLOG2(level, domain, device, ...) \
+    G_STMT_START { \
+        const NMLogLevel _level = (level); \
+        const NMLogDomain _domain = (domain); \
+        \
+        if (nm_logging_enabled (_level, _domain)) { \
+            const NMManager *const _self = (self); \
+            const char *const _ifname = _nm_device_get_iface (device); \
+            char _sbuf[32]; \
+            \
+            _nm_log (_level, _domain, 0, \
+                     _ifname, NULL, \
+                     "%s%s: %s%s%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+                     _NMLOG_PREFIX_NAME, \
+                     ((_self && _self != singleton_instance) \
+                         ? nm_sprintf_buf (_sbuf, "[%p]", _self) \
+                         : ""), \
+                     NM_PRINT_FMT_QUOTED (_ifname, "(", _ifname, "): ", "") \
+                     _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
+        } \
+    } G_STMT_END
+
+#define _NMLOG3(level, domain, connection, ...) \
+    G_STMT_START { \
+        const NMLogLevel _level = (level); \
+        const NMLogDomain _domain = (domain); \
+        \
+        if (nm_logging_enabled (_level, _domain)) { \
+            const NMManager *const _self = (self); \
+            NMConnection *const _connection = (connection); \
+            const char *const _con_id = _nm_connection_get_id (_connection); \
+            char _sbuf[32]; \
+            \
+            _nm_log (_level, _domain, 0, \
+                     NULL, _nm_connection_get_uuid (_connection), \
+                     "%s%s: %s%s%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+                     _NMLOG_PREFIX_NAME, \
+                     ((_self && _self != singleton_instance) \
+                         ? nm_sprintf_buf (_sbuf, "[%p]", _self) \
+                         : ""), \
+                     NM_PRINT_FMT_QUOTED (_con_id, "(", _con_id, ") ", "") \
                      _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
         } \
     } G_STMT_END
@@ -983,8 +1028,8 @@ remove_device (NMManager *self,
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	gboolean unmanage = FALSE;
 
-	_LOGD (LOGD_DEVICE, "(%s): removing device (allow_unmanage %d, managed %d)",
-	       nm_device_get_iface (device), allow_unmanage, nm_device_get_managed (device, FALSE));
+	_LOG2D (LOGD_DEVICE, device, "removing device (allow_unmanage %d, managed %d)",
+	        allow_unmanage, nm_device_get_managed (device, FALSE));
 
 	if (allow_unmanage && nm_device_get_managed (device, FALSE)) {
 
@@ -1238,8 +1283,8 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 
 	iface = nm_manager_get_connection_iface (self, connection, &parent, &error);
 	if (!iface) {
-		_LOGD (LOGD_DEVICE, "(%s) can't get a name of a virtual device: %s",
-		       nm_connection_get_id (connection), error->message);
+		_LOG3D (LOGD_DEVICE, connection, "can't get a name of a virtual device: %s",
+		        error->message);
 		g_error_free (error);
 		return NULL;
 	}
@@ -1250,8 +1295,8 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 
 		if (nm_device_check_connection_compatible (candidate, connection)) {
 			if (nm_device_is_real (candidate)) {
-				_LOGD (LOGD_DEVICE, "(%s) already created virtual interface name %s",
-				       nm_connection_get_id (connection), iface);
+				_LOG3D (LOGD_DEVICE, connection, "already created virtual interface name %s",
+				       iface);
 				return NULL;
 			}
 
@@ -1265,27 +1310,26 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 
 		factory = nm_device_factory_manager_find_factory_for_connection (connection);
 		if (!factory) {
-			_LOGE (LOGD_DEVICE, "(%s:%s) NetworkManager plugin for '%s' unavailable",
-			       nm_connection_get_id (connection), iface,
+			_LOG3E (LOGD_DEVICE, connection, "(%s) NetworkManager plugin for '%s' unavailable",
+			       iface,
 			       nm_connection_get_connection_type (connection));
 			return NULL;
 		}
 
 		device = nm_device_factory_create_device (factory, iface, NULL, connection, NULL, &error);
 		if (!device) {
-			_LOGW (LOGD_DEVICE, "(%s) factory can't create the device: %s",
-			       nm_connection_get_id (connection), error->message);
+			_LOG3W (LOGD_DEVICE, connection, "factory can't create the device: %s",
+			        error->message);
 			g_error_free (error);
 			return NULL;
 		}
 
-		_LOGD (LOGD_DEVICE, "(%s) create virtual device %s",
-		       nm_connection_get_id (connection),
+		_LOG3D (LOGD_DEVICE, connection, "create virtual device %s",
 		       nm_device_get_iface (device));
 
 		if (!add_device (self, device, &error)) {
-			_LOGW (LOGD_DEVICE, "(%s) can't register the device with manager: %s",
-			       nm_connection_get_id (connection), error->message);
+			_LOG3W (LOGD_DEVICE, connection, "can't register the device with manager: %s",
+			        error->message);
 			g_error_free (error);
 			g_object_unref (device);
 			return NULL;
@@ -1313,8 +1357,8 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 
 		/* Create any backing resources the device needs */
 		if (!nm_device_create_and_realize (device, connection, parent, &error)) {
-			_LOGW (LOGD_DEVICE, "(%s) couldn't create the device: %s",
-			       nm_connection_get_id (connection), error->message);
+			_LOG3W (LOGD_DEVICE, connection, "couldn't create the device: %s",
+			        error->message);
 			g_error_free (error);
 			remove_device (self, device, FALSE, TRUE);
 			return NULL;
@@ -1481,9 +1525,7 @@ manager_update_radio_enabled (NMManager *self,
 		NMDevice *device = NM_DEVICE (iter->data);
 
 		if (nm_device_get_rfkill_type (device) == rstate->rtype) {
-			_LOGD (LOGD_RFKILL, "(%s): setting radio %s",
-			       nm_device_get_iface (device),
-			       enabled ? "enabled" : "disabled");
+			_LOG2D (LOGD_RFKILL, device, "rfkill: setting radio %s", enabled ? "enabled" : "disabled");
 			nm_device_set_enabled (device, enabled);
 		}
 	}
@@ -1528,14 +1570,14 @@ manager_rfkill_update_one_type (NMManager *self,
 
 	/* Print out all states affecting device enablement */
 	if (rstate->desc) {
-		_LOGD (LOGD_RFKILL, "%s hw-enabled %d sw-enabled %d",
+		_LOGD (LOGD_RFKILL, "rfkill: %s hw-enabled %d sw-enabled %d",
 		       rstate->desc, rstate->hw_enabled, rstate->sw_enabled);
 	}
 
 	/* Log new killswitch state */
 	new_rfkilled = rstate->hw_enabled && rstate->sw_enabled;
 	if (old_rfkilled != new_rfkilled) {
-		_LOGI (LOGD_RFKILL, "%s now %s by radio killswitch",
+		_LOGI (LOGD_RFKILL, "rfkill: %s now %s by radio killswitch",
 		       rstate->desc,
 		       new_rfkilled ? "enabled" : "disabled");
 	}
@@ -1691,11 +1733,6 @@ done:
  * get_existing_connection:
  * @manager: #NMManager instance
  * @device: #NMDevice instance
- * @guess_assume: whether to employ a heuristic to search for a matching
- *   connection to assume.
- * @assume_connection_uuid: if present, try to assume a connection with this
- *   UUID. If no uuid is given or no matching connection is found, we
- *   only do external activation.
  * @out_generated: (allow-none): return TRUE, if the connection was generated.
  *
  * Returns: a #NMSettingsConnection to be assumed by the device, or %NULL if
@@ -1704,18 +1741,19 @@ done:
 static NMSettingsConnection *
 get_existing_connection (NMManager *self,
                          NMDevice *device,
-                         gboolean guess_assume,
-                         const char *assume_connection_uuid,
                          gboolean *out_generated)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMConnection *connection = NULL;
+	gs_unref_object NMConnection *connection = NULL;
 	NMSettingsConnection *added = NULL;
 	GError *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;
 
 	if (out_generated)
 		*out_generated = FALSE;
@@ -1728,13 +1766,15 @@ get_existing_connection (NMManager *self,
 		if (master_ifindex) {
 			master = nm_manager_get_device_by_ifindex (self, master_ifindex);
 			if (!master) {
-				_LOGD (LOGD_DEVICE, "(%s): cannot generate connection for slave before its master (%s/%d)",
-				       nm_device_get_iface (device), nm_platform_link_get_name (NM_PLATFORM_GET, master_ifindex), master_ifindex);
+				_LOG2D (LOGD_DEVICE, device, "assume: don't assume because "
+				        "cannot generate connection for slave before its master (%s/%d)",
+				        nm_platform_link_get_name (NM_PLATFORM_GET, master_ifindex), master_ifindex);
 				return NULL;
 			}
 			if (!nm_device_get_act_request (master)) {
-				_LOGD (LOGD_DEVICE, "(%s): cannot generate connection for slave before master %s activates",
-				       nm_device_get_iface (device), nm_device_get_iface (master));
+				_LOG2D (LOGD_DEVICE, device, "assume: don't assume because "
+				        "cannot generate connection for slave before master %s activates",
+				        nm_device_get_iface (master));
 				return NULL;
 			}
 		}
@@ -1746,9 +1786,19 @@ get_existing_connection (NMManager *self,
 	 * update_connection() implemented, otherwise nm_device_generate_connection()
 	 * returns NULL.
 	 */
-	connection = nm_device_generate_connection (device, master);
-	if (!connection)
+	connection = nm_device_generate_connection (device, master, &maybe_later, &error);
+	if (!connection) {
+		if (!maybe_later)
+			nm_device_assume_state_reset (device);
+		_LOG2D (LOGD_DEVICE, device, "assume: cannot generate connection: %s",
+		        error->message);
+		g_error_free (error);
 		return NULL;
+	}
+
+	nm_device_assume_state_get (device,
+	                            &assume_state_guess_assume,
+	                            &assume_state_connection_uuid);
 
 	/* Now we need to compare the generated connection to each configured
 	 * connection. The comparison function is the heart of the connection
@@ -1759,8 +1809,8 @@ get_existing_connection (NMManager *self,
 	 * When no configured connection matches the generated connection, we keep
 	 * the generated connection instead.
 	 */
-	if (   assume_connection_uuid
-	    && (connection_checked = nm_settings_get_connection_by_uuid (priv->settings, assume_connection_uuid))
+	if (   assume_state_connection_uuid
+	    && (connection_checked = nm_settings_get_connection_by_uuid (priv->settings, assume_state_connection_uuid))
 	    && !active_connection_find_first (self, connection_checked, NULL,
 	                                      NM_ACTIVE_CONNECTION_STATE_DEACTIVATING)
 	    && nm_device_check_connection_compatible (device, NM_CONNECTION (connection_checked))) {
@@ -1778,7 +1828,7 @@ get_existing_connection (NMManager *self,
 	} else
 		matched = NULL;
 
-	if (!matched && guess_assume) {
+	if (!matched && assume_state_guess_assume) {
 		gs_free NMSettingsConnection **connections = NULL;
 		guint len, i, j;
 
@@ -1808,84 +1858,73 @@ get_existing_connection (NMManager *self,
 	}
 
 	if (matched) {
-		_LOGI (LOGD_DEVICE, "(%s): found matching connection '%s' (%s)%s",
-		       nm_device_get_iface (device),
-		       nm_settings_connection_get_id (matched),
-		       nm_settings_connection_get_uuid (matched),
-		       assume_connection_uuid && nm_streq (assume_connection_uuid, nm_settings_connection_get_uuid (matched))
-		           ? " (indicated)" : " (guessed)");
-		g_object_unref (connection);
+		_LOG2I (LOGD_DEVICE, device, "assume: will attempt to assume matching connection '%s' (%s)%s",
+		        nm_settings_connection_get_id (matched),
+		        nm_settings_connection_get_uuid (matched),
+		        assume_state_connection_uuid && nm_streq (assume_state_connection_uuid, nm_settings_connection_get_uuid (matched))
+		            ? " (indicated)" : " (guessed)");
+		nm_device_assume_state_reset (device);
 		return matched;
 	}
 
-	_LOGD (LOGD_DEVICE, "(%s): generated connection '%s'",
-	       nm_device_get_iface (device),
-	       nm_connection_get_id (connection));
+	_LOG2D (LOGD_DEVICE, device, "assume: generated connection '%s' (%s)",
+	        nm_connection_get_id (connection),
+	        nm_connection_get_uuid (connection));
+
+	nm_device_assume_state_reset (device);
 
 	added = nm_settings_add_connection (priv->settings, connection, FALSE, &error);
-	if (added) {
-		nm_settings_connection_set_flags (NM_SETTINGS_CONNECTION (added),
-		                                  NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED |
-		                                  NM_SETTINGS_CONNECTION_FLAGS_VOLATILE,
-		                                  TRUE);
-		if (out_generated)
-			*out_generated = TRUE;
-	} else {
-		_LOGW (LOGD_SETTINGS, "(%s) Couldn't save generated connection '%s': %s",
-		       nm_device_get_iface (device),
+	if (!added) {
+		_LOG2W (LOGD_SETTINGS, device, "assume: failure to save generated connection '%s': %s",
 		       nm_connection_get_id (connection),
 		       error->message);
-		g_clear_error (&error);
+		g_error_free (error);
+		return NULL;
 	}
-	g_object_unref (connection);
 
-	return added ? added : NULL;
+	nm_settings_connection_set_flags (NM_SETTINGS_CONNECTION (added),
+	                                  NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED |
+	                                  NM_SETTINGS_CONNECTION_FLAGS_VOLATILE,
+	                                  TRUE);
+	NM_SET_OUT (out_generated, TRUE);
+	return added;
 }
 
 static gboolean
 recheck_assume_connection (NMManager *self,
-                           NMDevice *device,
-                           gboolean guess_assume,
-                           const char *assume_connection_uuid)
+                           NMDevice *device)
 {
 	NMSettingsConnection *connection;
 	gboolean was_unmanaged = FALSE;
 	gboolean generated = FALSE;
 	NMDeviceState state;
-	NMDeviceSysIfaceState if_state;
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 
 	g_return_val_if_fail (NM_IS_MANAGER (self), FALSE);
 	g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
 
-	if (nm_device_get_is_nm_owned (device))
-		return FALSE;
-
-	if (!nm_device_get_managed (device, FALSE))
+	if (!nm_device_get_managed (device, FALSE)) {
+		nm_device_assume_state_reset (device);
+		_LOG2D (LOGD_DEVICE, device, "assume: don't assume because %s", "not managed");
 		return FALSE;
+	}
 
 	state = nm_device_get_state (device);
-	if (state > NM_DEVICE_STATE_DISCONNECTED)
-		return FALSE;
-
-	if_state = nm_device_sys_iface_state_get (device);
-	if (!priv->startup  && (if_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED))
-		nm_assert (!guess_assume && (assume_connection_uuid == NULL));
-	else if (if_state != NM_DEVICE_SYS_IFACE_STATE_EXTERNAL)
-		return FALSE;
-
-	connection = get_existing_connection (self, device, guess_assume, assume_connection_uuid, &generated);
-	if (!connection) {
-		_LOGD (LOGD_DEVICE, "(%s): can't assume; no connection",
-		       nm_device_get_iface (device));
+	if (state > NM_DEVICE_STATE_DISCONNECTED) {
+		nm_device_assume_state_reset (device);
+		_LOG2D (LOGD_DEVICE, device, "assume: don't assume due to device state %s",
+		        nm_device_state_to_str (state));
 		return FALSE;
 	}
 
-	_LOGD (LOGD_DEVICE, "(%s): will attempt to assume connection",
-	       nm_device_get_iface (device));
+	connection = get_existing_connection (self, device, &generated);
+	/* log  no reason. get_existing_connection() already does it. */
+	if (!connection)
+		return FALSE;
 
-	if (!generated)
-		nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_ASSUME);
+	nm_device_sys_iface_state_set (device,
+	                               generated
+	                                   ? NM_DEVICE_SYS_IFACE_STATE_EXTERNAL
+	                                   : NM_DEVICE_SYS_IFACE_STATE_ASSUME);
 
 	/* Move device to DISCONNECTED to activate the connection */
 	if (state == NM_DEVICE_STATE_UNMANAGED) {
@@ -1915,7 +1954,7 @@ recheck_assume_connection (NMManager *self,
 		                                 &error);
 
 		if (!active) {
-			_LOGW (LOGD_DEVICE, "assumed connection %s failed to activate: %s",
+			_LOGW (LOGD_DEVICE, "assume: assumed connection %s failed to activate: %s",
 			       nm_connection_get_path (NM_CONNECTION (connection)),
 			       error->message);
 			g_error_free (error);
@@ -1927,9 +1966,7 @@ recheck_assume_connection (NMManager *self,
 			}
 
 			if (generated) {
-				_LOGD (LOGD_DEVICE, "(%s): connection assumption failed. Deleting generated connection",
-				       nm_device_get_iface (device));
-
+				_LOG2D (LOGD_DEVICE, device, "assume: deleting generated connection after assuming failed");
 				nm_settings_connection_delete (connection, NULL, NULL);
 			} else {
 				if (nm_device_sys_iface_state_get (device) == NM_DEVICE_SYS_IFACE_STATE_ASSUME)
@@ -1952,9 +1989,9 @@ recheck_assume_connection (NMManager *self,
 }
 
 static void
-recheck_assume_connection_cb (NMDevice *device, gpointer user_data)
+recheck_assume_connection_cb (NMManager *self, NMDevice *device)
 {
-	recheck_assume_connection (user_data, device, FALSE, NULL);
+	recheck_assume_connection (self, device);
 }
 
 static void
@@ -2047,19 +2084,19 @@ device_connectivity_changed (NMDevice *device,
 static void
 _device_realize_finish (NMManager *self,
                         NMDevice *device,
-                        const NMPlatformLink *plink,
-                        gboolean guess_assume,
-                        const char *connection_uuid_to_assume)
+                        const NMPlatformLink *plink)
 {
 	g_return_if_fail (NM_IS_MANAGER (self));
 	g_return_if_fail (NM_IS_DEVICE (device));
 
 	nm_device_realize_finish (device, plink);
 
-	if (!nm_device_get_managed (device, FALSE))
+	if (!nm_device_get_managed (device, FALSE)) {
+		nm_device_assume_state_reset (device);
 		return;
+	}
 
-	if (recheck_assume_connection (self, device, guess_assume, connection_uuid_to_assume))
+	if (recheck_assume_connection (self, device))
 		return;
 
 	/* if we failed to assume a connection for the managed device, but the device
@@ -2129,9 +2166,9 @@ add_device (NMManager *self, NMDevice *device, GError **error)
 	                  G_CALLBACK (device_removed_cb),
 	                  self);
 
-	g_signal_connect (device, NM_DEVICE_RECHECK_ASSUME,
-	                  G_CALLBACK (recheck_assume_connection_cb),
-	                  self);
+	g_signal_connect_data (device, NM_DEVICE_RECHECK_ASSUME,
+	                       G_CALLBACK (recheck_assume_connection_cb),
+	                       self, NULL, G_CONNECT_SWAPPED);
 
 	g_signal_connect (device, "notify::" NM_DEVICE_IP_IFACE,
 	                  G_CALLBACK (device_ip_iface_changed),
@@ -2183,7 +2220,7 @@ add_device (NMManager *self, NMDevice *device, GError **error)
 	                               manager_sleeping (self));
 
 	dbus_path = nm_exported_object_export (NM_EXPORTED_OBJECT (device));
-	_LOGI (LOGD_DEVICE, "(%s): new %s device (%s)", iface, type_desc, dbus_path);
+	_LOG2I (LOGD_DEVICE, device, "new %s device (%s)", type_desc, dbus_path);
 
 	nm_settings_device_added (priv->settings, device);
 	g_signal_emit (self, signals[INTERNAL_DEVICE_ADDED], 0, device);
@@ -2213,14 +2250,16 @@ factory_device_added_cb (NMDeviceFactory *factory,
 
 	if (nm_device_realize_start (device,
 	                             NULL,
+	                             FALSE, /* assume_state_guess_assume */
+	                             NULL,  /* assume_state_connection_uuid */
+	                             FALSE, /* set_nm_owned */
 	                             NM_UNMAN_FLAG_OP_FORGET,
 	                             NULL,
 	                             &error)) {
 		add_device (self, device, NULL);
-		_device_realize_finish (self, device, NULL, FALSE, NULL);
+		_device_realize_finish (self, device, NULL);
 	} else {
-		_LOGW (LOGD_DEVICE, "(%s): failed to realize device: %s",
-		       nm_device_get_iface (device), error->message);
+		_LOG2W (LOGD_DEVICE, device, "failed to realize device: %s", error->message);
 		g_error_free (error);
 	}
 }
@@ -2291,11 +2330,13 @@ platform_link_added (NMManager *self,
 			return;
 		} else if (nm_device_realize_start (candidate,
 		                                    plink,
+		                                    FALSE, /* assume_state_guess_assume */
+		                                    NULL,  /* assume_state_connection_uuid */
+		                                    FALSE, /* set_nm_owned */
 		                                    NM_UNMAN_FLAG_OP_FORGET,
 		                                    &compatible,
 		                                    &error)) {
-			/* Success */
-			_device_realize_finish (self, candidate, plink, FALSE, NULL);
+			_device_realize_finish (self, candidate, plink);
 			return;
 		}
 
@@ -2362,13 +2403,14 @@ platform_link_added (NMManager *self,
 
 		if (nm_device_realize_start (device,
 		                             plink,
+		                             guess_assume,
+		                             dev_state ? dev_state->connection_uuid : NULL,
+		                             dev_state ? (dev_state->nm_owned == 1) : FALSE,
 		                             unmanaged_user_explicit,
 		                             NULL,
 		                             &error)) {
 			add_device (self, device, NULL);
-			_device_realize_finish (self, device, plink,
-			                        guess_assume,
-			                        dev_state ? dev_state->connection_uuid : NULL);
+			_device_realize_finish (self, device, plink);
 		} else {
 			_LOGW (LOGD_DEVICE, "%s: failed to realize device: %s",
 			       plink->name, error->message);
@@ -2409,9 +2451,7 @@ _platform_link_cb_idle (PlatformLinkCbData *data)
 				nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_REMOVED);
 				/* Our software devices stick around until their connection is removed */
 				if (!nm_device_unrealize (device, FALSE, &error)) {
-					_LOGW (LOGD_DEVICE, "(%s): failed to unrealize: %s",
-					       nm_device_get_iface (device),
-					       error->message);
+					_LOG2W (LOGD_DEVICE, device, "failed to unrealize: %s", error->message);
 					g_clear_error (&error);
 					remove_device (self, device, FALSE, TRUE);
 				}
@@ -2459,10 +2499,14 @@ platform_query_devices (NMManager *self)
 	NMPlatformLink *links;
 	int i;
 	gboolean guess_assume;
+	const char *order;
 
 	guess_assume = nm_config_get_first_start (nm_config_get ());
-
-	links_array = nm_platform_link_get_all (NM_PLATFORM_GET);
+	order = nm_config_data_get_value_cached (NM_CONFIG_GET_DATA,
+	                                         NM_CONFIG_KEYFILE_GROUP_MAIN,
+	                                         NM_CONFIG_KEYFILE_KEY_MAIN_SLAVES_ORDER,
+	                                         NM_CONFIG_GET_VALUE_STRIP);
+	links_array = nm_platform_link_get_all (NM_PLATFORM_GET, !nm_streq0 (order, "index"));
 	links = (NMPlatformLink *) links_array->data;
 	for (i = 0; i < links_array->len; i++) {
 		gs_free NMConfigDeviceStateData *dev_state = NULL;
@@ -3016,7 +3060,7 @@ out:
 }
 
 static gint
-compare_slaves (gconstpointer a, gconstpointer b, gpointer _unused)
+compare_slaves (gconstpointer a, gconstpointer b, gpointer sort_by_name)
 {
 	const SlaveConnectionInfo *a_info = a;
 	const SlaveConnectionInfo *b_info = b;
@@ -3027,8 +3071,12 @@ compare_slaves (gconstpointer a, gconstpointer b, gpointer _unused)
 	if (!b_info->device)
 		return -1;
 
-	return g_strcmp0 (nm_device_get_iface (a_info->device),
-	                  nm_device_get_iface (b_info->device));
+	if (GPOINTER_TO_INT (sort_by_name)) {
+		return g_strcmp0 (nm_device_get_iface (a_info->device),
+		                  nm_device_get_iface (b_info->device));
+	}
+
+	return nm_device_get_ifindex (a_info->device) - nm_device_get_ifindex (b_info->device);
 }
 
 static void
@@ -3042,11 +3090,17 @@ autoconnect_slaves (NMManager *self,
 	if (should_connect_slaves (NM_CONNECTION (master_connection), master_device)) {
 		gs_free SlaveConnectionInfo *slaves = NULL;
 		guint i, n_slaves = 0;
+		const char *value;
 
 		slaves = find_slaves (self, master_connection, master_device, &n_slaves);
 		if (n_slaves > 1) {
+			value = nm_config_data_get_value_cached (NM_CONFIG_GET_DATA,
+			                                         NM_CONFIG_KEYFILE_GROUP_MAIN,
+			                                         NM_CONFIG_KEYFILE_KEY_MAIN_SLAVES_ORDER,
+			                                         NM_CONFIG_GET_VALUE_STRIP);
 			g_qsort_with_data (slaves, n_slaves, sizeof (slaves[0]),
-			                   compare_slaves, NULL);
+			                   compare_slaves,
+			                   GINT_TO_POINTER (!nm_streq0 (value, "index")));
 		}
 
 		for (i = 0; i < n_slaves; i++) {
@@ -3505,6 +3559,9 @@ _new_active_connection (NMManager *self,
 		                                   error);
 	}
 
+	if (device && (activation_type == NM_ACTIVATION_TYPE_MANAGED))
+		nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_MANAGED);
+
 	return (NMActiveConnection *) nm_act_request_new (settings_connection,
 	                                                  applied,
 	                                                  specific_object,
@@ -3541,10 +3598,36 @@ _internal_activation_auth_done (NMActiveConnection *active,
 {
 	NMManager *self = user_data1;
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMActiveConnection *candidate;
 	GError *error = NULL;
+	GSList *iter;
 
 	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
+	 * 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))) {
+		for (iter = priv->active_connections; iter; iter = iter->next) {
+			candidate = iter->data;
+			if (   nm_active_connection_get_device (candidate) == nm_active_connection_get_device (active)
+			    && nm_active_connection_get_settings_connection (candidate) == nm_active_connection_get_settings_connection (active)
+			    && NM_IN_SET (nm_active_connection_get_state (candidate),
+			                  NM_ACTIVE_CONNECTION_STATE_ACTIVATING,
+			                  NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) {
+				g_set_error (&error,
+				             NM_MANAGER_ERROR,
+				             NM_MANAGER_ERROR_CONNECTION_ALREADY_ACTIVE,
+				             "Connection '%s' is already active",
+				             nm_active_connection_get_settings_connection_id (active));
+				success = FALSE;
+				break;
+			}
+		}
+	}
+
 	if (success) {
 		if (_internal_activate_generic (self, active, &error)) {
 			g_object_unref (active);
@@ -4480,7 +4563,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
 				gboolean enabled = radio_enabled_for_rstate (rstate, TRUE);
 
 				if (rstate->desc) {
-					_LOGD (LOGD_RFKILL, "%s %s devices (hw_enabled %d, sw_enabled %d, user_enabled %d)",
+					_LOGD (LOGD_RFKILL, "rfkill: %s %s devices (hw_enabled %d, sw_enabled %d, user_enabled %d)",
 					       enabled ? "enabling" : "disabling",
 					       rstate->desc, rstate->hw_enabled, rstate->sw_enabled, rstate->user_enabled);
 				}
@@ -4990,6 +5073,7 @@ nm_manager_write_device_state (NMManager *self)
 	const GSList *devices;
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	gs_unref_hashtable GHashTable *seen_ifindexes = NULL;
+	gint nm_owned;
 
 	seen_ifindexes = g_hash_table_new (NULL, NULL);
 
@@ -5029,10 +5113,13 @@ nm_manager_write_device_state (NMManager *self)
 		if (perm_hw_addr_fake && !perm_hw_addr_is_fake)
 			perm_hw_addr_fake = NULL;
 
+		nm_owned = nm_device_is_software (device) ? nm_device_is_nm_owned (device) : -1;
+
 		if (nm_config_device_state_write (ifindex,
 		                                  managed_type,
 		                                  perm_hw_addr_fake,
-		                                  uuid))
+		                                  uuid,
+		                                  nm_owned))
 			g_hash_table_add (seen_ifindexes, GINT_TO_POINTER (ifindex));
 	}
 
@@ -5073,7 +5160,7 @@ nm_manager_start (NMManager *self, GError **error)
 		update_rstate_from_rfkill (priv->rfkill_mgr, rstate);
 
 		if (rstate->desc) {
-			_LOGI (LOGD_RFKILL, "%s %s by radio killswitch; %s by state file",
+			_LOGI (LOGD_RFKILL, "rfkill: %s %s by radio killswitch; %s by state file",
 			       rstate->desc,
 			       (rstate->hw_enabled && rstate->sw_enabled) ? "enabled" : "disabled",
 			       rstate->user_enabled ? "enabled" : "disabled");
@@ -5149,8 +5236,7 @@ handle_firmware_changed (gpointer user_data)
 
 		if (   nm_device_get_firmware_missing (candidate)
 		    && (state == NM_DEVICE_STATE_UNAVAILABLE)) {
-			_LOGI (LOGD_CORE, "(%s): firmware may now be available",
-			       nm_device_get_iface (candidate));
+			_LOG2I (LOGD_CORE, candidate, "firmware may now be available");
 
 			/* Re-set unavailable state to try bringing the device up again */
 			nm_device_state_changed (candidate,
@@ -5782,12 +5868,12 @@ rfkill_change (NMManager *self, const char *desc, RfKillType rtype, gboolean ena
 	fd = open ("/dev/rfkill", O_RDWR | O_CLOEXEC);
 	if (fd < 0) {
 		if (errno == EACCES)
-			_LOGW (LOGD_RFKILL, "(%s): failed to open killswitch device", desc);
+			_LOGW (LOGD_RFKILL, "rfkill: (%s): failed to open killswitch device", desc);
 		return;
 	}
 
 	if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0) {
-		_LOGW (LOGD_RFKILL, "(%s): failed to set killswitch device for "
+		_LOGW (LOGD_RFKILL, "rfkill: (%s): failed to set killswitch device for "
 		       "non-blocking operation", desc);
 		close (fd);
 		return;
@@ -5809,14 +5895,14 @@ rfkill_change (NMManager *self, const char *desc, RfKillType rtype, gboolean ena
 
 	len = write (fd, &event, sizeof (event));
 	if (len < 0) {
-		_LOGW (LOGD_RFKILL, "(%s): failed to change WiFi killswitch state: (%d) %s",
+		_LOGW (LOGD_RFKILL, "rfkill: (%s): failed to change WiFi killswitch state: (%d) %s",
 		       desc, errno, g_strerror (errno));
 	} else if (len == sizeof (event)) {
-		_LOGI (LOGD_RFKILL, "%s hardware radio set %s",
+		_LOGI (LOGD_RFKILL, "rfkill: %s hardware radio set %s",
 		       desc, enabled ? "enabled" : "disabled");
 	} else {
 		/* Failed to write full structure */
-		_LOGW (LOGD_RFKILL, "(%s): failed to change WiFi killswitch state", desc);
+		_LOGW (LOGD_RFKILL, "rfkill: (%s): failed to change WiFi killswitch state", desc);
 	}
 
 	close (fd);
@@ -5835,7 +5921,7 @@ manager_radio_user_toggled (NMManager *self,
 		return;
 
 	if (rstate->desc) {
-		_LOGD (LOGD_RFKILL, "(%s): setting radio %s by user",
+		_LOGD (LOGD_RFKILL, "rfkill: (%s): setting radio %s by user",
 		       rstate->desc,
 		       enabled ? "enabled" : "disabled");
 	}
diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c
index cfc028c2..87e0a364 100644
--- a/src/nm-pacrunner-manager.c
+++ b/src/nm-pacrunner-manager.c
@@ -250,6 +250,7 @@ pacrunner_send_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
 		_LOG2D (config, "sent");
 
 		if (config->removed) {
+			config_ref (config);
 			g_dbus_proxy_call (priv->pacrunner,
 			                   "DestroyProxyConfiguration",
 			                   g_variant_new ("(o)", config->path),
@@ -329,7 +330,6 @@ pacrunner_proxy_cb (GObject *source, GAsyncResult *res, gpointer user_data)
 	priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self);
 
 	priv->pacrunner = proxy;
-	nm_clear_g_cancellable (&priv->pacrunner_cancellable);
 
 	g_signal_connect (priv->pacrunner, "notify::g-name-owner",
 	                  G_CALLBACK (name_owner_changed_cb), self);
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 252f054d..487725e4 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -1529,6 +1529,23 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 	if (!obj->link.name[0])
 		goto errout;
 
+	if (!tb[IFLA_MTU]) {
+		/* Kernel has two places that send RTM_GETLINK messages:
+		 * net/core/rtnetlink.c and net/wireless/ext-core.c.
+		 * Unfotunatelly ext-core.c sets only IFLA_WIRELESS and
+		 * IFLA_IFNAME. This confuses code in this function, because
+		 * it cannot get complete set of data for the interface and
+		 * later incomplete object this function creates is used to
+		 * overwrite existing data in NM's cache.
+		 * Since ext-core.c doesn't set IFLA_MTU we can use it as a
+		 * signal to ignore incoming message.
+		 * To some extent this is a hack and correct approach is to
+		 * merge objects per-field.
+		 */
+		goto errout;
+	}
+	obj->link.mtu = nla_get_u32 (tb[IFLA_MTU]);
+
 	if (tb[IFLA_LINKINFO]) {
 		err = nla_parse_nested (li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], policy_link_info);
 		if (err < 0)
@@ -1609,9 +1626,6 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 		}
 	}
 
-	if (tb[IFLA_MTU])
-		obj->link.mtu = nla_get_u32 (tb[IFLA_MTU]);
-
 	switch (obj->link.type) {
 	case NM_LINK_TYPE_GRE:
 		lnk_data = _parse_lnk_gre (nl_info_kind, nl_info_data);
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 767187d9..a244ff39 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -437,7 +437,8 @@ nm_platform_sysctl_get_int_checked (NMPlatform *self, const char *pathid, int di
 
 static int
 _link_get_all_presort (gconstpointer  p_a,
-                       gconstpointer  p_b)
+                       gconstpointer  p_b,
+                       gpointer       sort_by_name)
 {
 	const NMPlatformLink *a = p_a;
 	const NMPlatformLink *b = p_b;
@@ -448,13 +449,16 @@ _link_get_all_presort (gconstpointer  p_a,
 	if (b->ifindex == 1)
 		return 1;
 
-	/* Initialized links first */
-	if (a->initialized > b->initialized)
-		return -1;
-	if (a->initialized < b->initialized)
-		return 1;
+	if (GPOINTER_TO_INT (sort_by_name)) {
+		/* Initialized links first */
+		if (a->initialized > b->initialized)
+			return -1;
+		if (a->initialized < b->initialized)
+			return 1;
 
-	return strcmp (a->name, b->name);
+		return strcmp (a->name, b->name);
+	} else
+		return a->ifindex - b->ifindex;
 }
 
 /**
@@ -465,7 +469,7 @@ _link_get_all_presort (gconstpointer  p_a,
  * owned by the caller and should be freed with g_array_unref().
  */
 GArray *
-nm_platform_link_get_all (NMPlatform *self)
+nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name)
 {
 	GArray *links, *result;
 	guint i, j, nresult;
@@ -479,9 +483,9 @@ nm_platform_link_get_all (NMPlatform *self)
 	if (!links || links->len == 0)
 		return links;
 
-	/* first sort the links by their ifindex. Below we will sort further by moving
-	 * children/slaves to the end. */
-	g_array_sort (links, _link_get_all_presort);
+	/* first sort the links by their ifindex or name. Below we will sort
+	 * further by moving children/slaves to the end. */
+	g_array_sort_with_data (links, _link_get_all_presort, GINT_TO_POINTER (sort_by_name));
 
 	unseen = g_hash_table_new (g_direct_hash, g_direct_equal);
 	for (i = 0; i < links->len; i++) {
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 43be17fa..1b8fa133 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -763,7 +763,7 @@ const NMPlatformLink *nm_platform_link_get (NMPlatform *self, int ifindex);
 const NMPlatformLink *nm_platform_link_get_by_ifname (NMPlatform *self, const char *ifname);
 const NMPlatformLink *nm_platform_link_get_by_address (NMPlatform *self, gconstpointer address, size_t length);
 
-GArray *nm_platform_link_get_all (NMPlatform *self);
+GArray *nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name);
 NMPlatformError nm_platform_link_dummy_add (NMPlatform *self, const char *name, const NMPlatformLink **out_link);
 NMPlatformError nm_platform_link_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len, const NMPlatformLink **out_link);
 NMPlatformError nm_platform_link_bond_add (NMPlatform *self, const char *name, const NMPlatformLink **out_link);
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index 04db862d..a9d0694d 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -185,7 +185,7 @@ link_callback (NMPlatform *platform, int obj_type_i, int ifindex, NMPlatformLink
 
 	/* Check the data */
 	g_assert (received->ifindex > 0);
-	links = nm_platform_link_get_all (NM_PLATFORM_GET);
+	links = nm_platform_link_get_all (NM_PLATFORM_GET, TRUE);
 	for (i = 0; i < links->len; i++) {
 		cached = &g_array_index (links, NMPlatformLink, i);
 		if (cached->ifindex == received->ifindex) {
diff --git a/src/platform/tests/test-general.c b/src/platform/tests/test-general.c
index 2ccfac7d..e772662c 100644
--- a/src/platform/tests/test-general.c
+++ b/src/platform/tests/test-general.c
@@ -48,7 +48,7 @@ test_link_get_all (void)
 
 	platform = nm_linux_platform_new (TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT);
 
-	links = nm_platform_link_get_all (platform);
+	links = nm_platform_link_get_all (platform, TRUE);
 }
 
 /*****************************************************************************/
diff --git a/src/ppp/nm-ppp-manager.c b/src/ppp/nm-ppp-manager.c
index c7836a8f..6343df8b 100644
--- a/src/ppp/nm-ppp-manager.c
+++ b/src/ppp/nm-ppp-manager.c
@@ -179,14 +179,6 @@ monitor_stats (NMPPPManager *manager)
 /*****************************************************************************/
 
 static void
-remove_timeout_handler (NMPPPManager *manager)
-{
-	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
-
-	nm_clear_g_source (&priv->ppp_timeout_handler);
-}
-
-static void
 cancel_get_secrets (NMPPPManager *self)
 {
 	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self);
@@ -365,7 +357,7 @@ impl_ppp_manager_set_state (NMPPPManager *manager,
                             GDBusMethodInvocation *context,
                             guint32 state)
 {
-	g_signal_emit (manager, signals[STATE_CHANGED], 0, state);
+	g_signal_emit (manager, signals[STATE_CHANGED], 0, (guint) state);
 
 	g_dbus_method_invocation_return_value (context, NULL);
 }
@@ -415,7 +407,7 @@ impl_ppp_manager_set_ip4_config (NMPPPManager *manager,
 
 	_LOGI ("(IPv4 Config Get) reply received.");
 
-	remove_timeout_handler (manager);
+	nm_clear_g_source (&priv->ppp_timeout_handler);
 
 	config = nm_ip4_config_new (nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface));
 
@@ -511,7 +503,7 @@ impl_ppp_manager_set_ip6_config (NMPPPManager *manager,
 
 	_LOGI ("(IPv6 Config Get) reply received.");
 
-	remove_timeout_handler (manager);
+	nm_clear_g_source (&priv->ppp_timeout_handler);
 
 	config = nm_ip6_config_new (nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface));
 
@@ -597,102 +589,62 @@ nm_cmd_line_add_int (NMCmdLine *cmd, int i)
 
 /*****************************************************************************/
 
-static void
-ppp_exit_code (guint pppd_exit_status, GPid pid)
-{
-	const char *msg;
-
-	switch (pppd_exit_status) {
-	case  1: 
-		msg = "Fatal pppd error"; 
-		break;
-	case  2: 
-		msg = "pppd options error"; 
-		break;
-	case  3: 
-		msg = "No root priv error"; 
-		break;
-	case  4: 
-		msg = "No ppp module error"; 
-		break;
-	case  5: 
-		msg = "pppd received a signal"; 
-		break;
-	case  6: 
-		msg = "Serial port lock failed"; 
-		break;
-	case  7: 
-		msg = "Serial port open failed"; 
-		break;
-	case  8: 
-		msg = "Connect script failed"; 
-		break;
-	case  9: 
-		msg = "Pty program error"; 
-		break;
-	case 10: 
-		msg = "PPP negotiation failed"; 
-		break;
-	case 11: 
-		msg = "Peer didn't authenticatie itself"; 
-		break;
-	case 12: 
-		msg = "Link idle: Idle Seconds reached."; 
-		break;
-	case 13: 
-		msg = "Connect time limit reached."; 
-		break;
-	case 14: 
-		msg = "Callback negotiated, call should come back.";
-		break;
-	case 15: 
-		msg = "Lack of LCP echo responses"; 
-		break;
-	case 16: 
-		msg = "A modem hung up the phone"; 
-		break;
-	case 17: 
-		msg = "Loopback detected"; 
-		break;
-	case 18: 
-		msg = "The init script failed"; 
-		break;
-	case 19: 
-		msg = "Authentication error.\n"
-			"We failed to authenticate ourselves to the peer.\n"
-			"Maybe bad account or password?";
-		break;
-	default:
-		msg = "Unknown error";
-	}
-
-	_LOGW ("pppd pid %d exited with error: %s", pid, msg);
-}
+NM_UTILS_LOOKUP_STR_DEFINE_STATIC (pppd_exit_code_to_str, int,
+	NM_UTILS_LOOKUP_DEFAULT ("Unknown error"),
+	NM_UTILS_LOOKUP_STR_ITEM ( 1, "Fatal pppd error");
+	NM_UTILS_LOOKUP_STR_ITEM ( 2, "pppd options error"),
+	NM_UTILS_LOOKUP_STR_ITEM ( 3, "No root priv error"),
+	NM_UTILS_LOOKUP_STR_ITEM ( 4, "No ppp module error"),
+	NM_UTILS_LOOKUP_STR_ITEM ( 5, "pppd received a signal"),
+	NM_UTILS_LOOKUP_STR_ITEM ( 6, "Serial port lock failed"),
+	NM_UTILS_LOOKUP_STR_ITEM ( 7, "Serial port open failed"),
+	NM_UTILS_LOOKUP_STR_ITEM ( 8, "Connect script failed"),
+	NM_UTILS_LOOKUP_STR_ITEM ( 9, "Pty program error"),
+	NM_UTILS_LOOKUP_STR_ITEM (10, "PPP negotiation failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (11, "Peer didn't authenticatie itself"),
+	NM_UTILS_LOOKUP_STR_ITEM (12, "Link idle: Idle Seconds reached."),
+	NM_UTILS_LOOKUP_STR_ITEM (13, "Connect time limit reached."),
+	NM_UTILS_LOOKUP_STR_ITEM (14, "Callback negotiated, call should come back."),
+	NM_UTILS_LOOKUP_STR_ITEM (15, "Lack of LCP echo responses"),
+	NM_UTILS_LOOKUP_STR_ITEM (16, "A modem hung up the phone"),
+	NM_UTILS_LOOKUP_STR_ITEM (17, "Loopback detected"),
+	NM_UTILS_LOOKUP_STR_ITEM (18, "The init script failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (19, "Authentication error. "
+	                              "We failed to authenticate ourselves to the peer. "
+	                              "Maybe bad account or password?"),
+);
 
 static void
-ppp_watch_cb (GPid pid, gint status, gpointer user_data)
+ppp_watch_cb (GPid pid, int status, gpointer user_data)
 {
 	NMPPPManager *manager = NM_PPP_MANAGER (user_data);
 	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
-	guint err;
+	int err;
+	const long long lpid = (long long) pid;
 
-	g_assert (pid == priv->pid);
+	g_return_if_fail (pid == priv->pid);
 
 	if (WIFEXITED (status)) {
 		err = WEXITSTATUS (status);
-		if (err != 0)
-			ppp_exit_code (err, priv->pid);
+		if (err) {
+			_LOGW ("pppd pid %lld exited with error %d: %s",
+			       lpid, err,
+			       pppd_exit_code_to_str (err));
+		} else
+			_LOGD ("pppd pid %lld exited with success", lpid);
 	} else if (WIFSTOPPED (status)) {
-		_LOGI ("pppd pid %d stopped unexpectedly with signal %d", priv->pid, WSTOPSIG (status));
+		_LOGW ("pppd pid %lld stopped unexpectedly with signal %d",
+		       lpid, WSTOPSIG (status));
 	} else if (WIFSIGNALED (status)) {
-		_LOGI ("pppd pid %d died with signal %d", priv->pid, WTERMSIG (status));
+		_LOGW ("pppd pid %lld died with signal %d",
+		       lpid, WTERMSIG (status));
 	} else
-		_LOGI ("pppd pid %d died from an unknown cause", priv->pid);
+		_LOGW ("pppd pid %lld died from an unknown cause", lpid);
 
-	_LOGD ("pppd pid %d cleaned up", priv->pid);
 	priv->pid = 0;
 	priv->ppp_watch_id = 0;
-	g_signal_emit (manager, signals[STATE_CHANGED], 0, NM_PPP_STATUS_DEAD);
+	_ppp_cleanup (manager);
+	g_signal_emit (manager, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_DEAD);
 }
 
 static gboolean
@@ -704,7 +656,7 @@ pppd_timed_out (gpointer data)
 	_ppp_cleanup (manager);
 	_ppp_kill (manager);
 
-	g_signal_emit (manager, signals[STATE_CHANGED], 0, NM_PPP_STATUS_DEAD);
+	g_signal_emit (manager, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_DEAD);
 
 	return FALSE;
 }
@@ -1016,7 +968,7 @@ _ppp_manager_start (NMPPPManager *manager,
 		goto out;
 	}
 
-	_LOGI ("pppd started with pid %d", priv->pid);
+	_LOGI ("pppd started with pid %lld", (long long) priv->pid);
 
 	priv->ppp_watch_id = g_child_watch_add (priv->pid, (GChildWatchFunc) ppp_watch_cb, manager);
 	priv->ppp_timeout_handler = g_timeout_add_seconds (timeout_secs, pppd_timed_out, manager);
@@ -1234,8 +1186,12 @@ static void
 dispose (GObject *object)
 {
 	NMPPPManager *self = (NMPPPManager *) object;
+	NMExportedObject *exported = NM_EXPORTED_OBJECT (self);
 	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self);
 
+	if (nm_exported_object_is_exported (exported))
+		nm_exported_object_unexport (exported);
+
 	_ppp_cleanup (self);
 	_ppp_kill (self);
 
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index 0cb2920c..45a1b664 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -2129,6 +2129,7 @@ nm_settings_connection_set_flags_all (NMSettingsConnection *self, NMSettingsConn
 
 	old_flags = priv->flags;
 	if (old_flags != flags) {
+		_LOGT ("update settings-connection flags to 0x%x (was 0x%x)", (guint) flags, (guint) priv->flags);
 		priv->flags = flags;
 		_notify (self, PROP_FLAGS);
 		if (NM_FLAGS_HAS (old_flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED) != NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED))
@@ -2316,33 +2317,35 @@ void
 nm_settings_connection_read_and_fill_timestamp (NMSettingsConnection *self)
 {
 	NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
+	gs_unref_keyfile GKeyFile *timestamps_file = NULL;
+	gs_free_error GError *error = NULL;
+	gs_free char *tmp_str = NULL;
 	const char *connection_uuid;
-	guint64 timestamp = 0;
-	GKeyFile *timestamps_file;
-	GError *err = NULL;
-	char *tmp_str;
+	gint64 timestamp;
 
 	g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self));
 
-	/* Get timestamp from database file */
 	timestamps_file = g_key_file_new ();
-	g_key_file_load_from_file (timestamps_file, SETTINGS_TIMESTAMPS_FILE, G_KEY_FILE_KEEP_COMMENTS, NULL);
+	if (!g_key_file_load_from_file (timestamps_file, SETTINGS_TIMESTAMPS_FILE, G_KEY_FILE_KEEP_COMMENTS, &error)) {
+		_LOGD ("failed to read connection timestamp: %s", error->message);
+		return;
+	}
+
 	connection_uuid = nm_settings_connection_get_uuid (self);
-	tmp_str = g_key_file_get_value (timestamps_file, "timestamps", connection_uuid, &err);
-	if (tmp_str) {
-		timestamp = g_ascii_strtoull (tmp_str, NULL, 10);
-		g_free (tmp_str);
+	tmp_str = g_key_file_get_value (timestamps_file, "timestamps", connection_uuid, &error);
+	if (!tmp_str) {
+		_LOGD ("failed to read connection timestamp: %s", error->message);
+		return;
 	}
 
-	/* Update connection's timestamp */
-	if (!err) {
-		priv->timestamp = timestamp;
-		priv->timestamp_set = TRUE;
-	} else {
-		_LOGD ("failed to read connection timestamp: %s", err->message);
-		g_clear_error (&err);
+	timestamp = _nm_utils_ascii_str_to_int64 (tmp_str, 10, 0, G_MAXINT64, -1);
+	if (timestamp < 0) {
+		_LOGD ("failed to read connection timestamp: %s", "invalid number");
+		return;
 	}
-	g_key_file_free (timestamps_file);
+
+	priv->timestamp = timestamp;
+	priv->timestamp_set = TRUE;
 }
 
 /**
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
index d6f33c49..d2b7ff67 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
@@ -1926,12 +1926,8 @@ get_route_attributes_string (NMIPRoute *route, int family)
 static gboolean
 write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError **error)
 {
-	const char *dest, *next_hop;
-	char **route_items;
-	gs_free char *route_contents = NULL;
+	nm_auto_free_gstring GString *contents = NULL;
 	NMIPRoute *route;
-	guint32 prefix;
-	gint64 metric;
 	guint32 i, num;
 
 	g_return_val_if_fail (filename != NULL, FALSE);
@@ -1945,36 +1941,34 @@ write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError
 		return TRUE;
 	}
 
-	route_items = g_malloc0 (sizeof (char *) * (num + 1));
+	contents = g_string_new ("");
+
 	for (i = 0; i < num; i++) {
+		const char *next_hop;
 		gs_free char *options = NULL;
+		gint64 metric;
 
 		route = nm_setting_ip_config_get_route (s_ip4, i);
-
-		dest = nm_ip_route_get_dest (route);
-		prefix = nm_ip_route_get_prefix (route);
 		next_hop = nm_ip_route_get_next_hop (route);
 		metric = nm_ip_route_get_metric (route);
-
 		options = get_route_attributes_string (route, AF_INET);
 
-		if (metric == -1) {
-			route_items[i] = g_strdup_printf ("%s/%u via %s%s%s\n",
-			                                  dest, prefix, next_hop,
-			                                  options ? " " : "",
-			                                  options ?: "");
-		} else {
-			route_items[i] = g_strdup_printf ("%s/%u via %s metric %u%s%s\n",
-			                                  dest, prefix, next_hop, (guint32) metric,
-			                                  options ? " " : "",
-			                                  options ?: "");
+		g_string_append_printf (contents, "%s/%u",
+		                        nm_ip_route_get_dest (route),
+		                        nm_ip_route_get_prefix (route));
+		if (next_hop)
+			g_string_append_printf (contents, " via %s", next_hop);
+		if (metric >= 0)
+			g_string_append_printf (contents, " metric %u", (guint) metric);
+		if (options) {
+			g_string_append_c (contents, ' ');
+			g_string_append (contents, options);
 		}
+
+		g_string_append_c (contents, '\n');
 	}
-	route_items[num] = NULL;
-	route_contents = g_strjoinv (NULL, route_items);
-	g_strfreev (route_items);
 
-	if (!g_file_set_contents (filename, route_contents, -1, NULL)) {
+	if (!g_file_set_contents (filename, contents->str, contents->len, NULL)) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
 		             "Writing route file '%s' failed", filename);
 		return FALSE;
@@ -2073,6 +2067,7 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	int timeout;
 	GString *searches;
 	const char *method = NULL;
+	gboolean has_netmask;
 
 	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	if (!s_ip4) {
@@ -2145,16 +2140,7 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 	else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED))
 		svSetValueStr (ifcfg, "BOOTPROTO", "shared");
 
-	/* Clear out un-numbered IP address fields */
-	svUnsetValue (ifcfg, "IPADDR");
-	svUnsetValue (ifcfg, "PREFIX");
-	svUnsetValue (ifcfg, "NETMASK");
-	svUnsetValue (ifcfg, "GATEWAY");
-	/* Clear out zero-indexed IP address fields */
-	svUnsetValue (ifcfg, "IPADDR0");
-	svUnsetValue (ifcfg, "PREFIX0");
-	svUnsetValue (ifcfg, "NETMASK0");
-	svUnsetValue (ifcfg, "GATEWAY0");
+	has_netmask = !!svFindFirstKeyWithPrefix (ifcfg, "NETMASK");
 
 	/* Write out IPADDR<n>, PREFIX<n>, GATEWAY<n> for current IP addresses
 	 * without labels. Unset obsolete NETMASK<n>.
@@ -2198,19 +2184,30 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
 		g_free (tmp);
 
 		/* If the legacy "NETMASK" is present, keep it. */
-		if (svGetValue (ifcfg, netmask_key, &tmp)) {
+		if (has_netmask) {
 			char buf[INET_ADDRSTRLEN];
 
-			g_free (tmp);
-			svSetValueStr (ifcfg, netmask_key, nm_utils_inet4_ntop (prefix, buf));
-		}
+			svSetValueStr (ifcfg, netmask_key,
+			               nm_utils_inet4_ntop (nm_utils_ip4_prefix_to_netmask (prefix), buf));
+		} else
+			svUnsetValue (ifcfg, netmask_key);
 
 		svUnsetValue (ifcfg, gw_key);
 		n++;
 	}
 
-	/* Clear remaining IPADDR<n..255>, etc */
-	for (i = n; i < 256; i++) {
+	svUnsetValue (ifcfg, "IPADDR0");
+	svUnsetValue (ifcfg, "PREFIX0");
+	svUnsetValue (ifcfg, "NETMASK0");
+	svUnsetValue (ifcfg, "GATEWAY0");
+	if (n == 0) {
+		svUnsetValue (ifcfg, "IPADDR");
+		svUnsetValue (ifcfg, "PREFIX");
+		svUnsetValue (ifcfg, "NETMASK");
+		i = 1;
+	} else
+		i = n;
+	for (; i < 256; i++) {
 		nm_sprintf_buf (addr_key, "IPADDR%u", i);
 		nm_sprintf_buf (prefix_key, "PREFIX%u", i);
 		nm_sprintf_buf (netmask_key, "NETMASK%u", i);
@@ -2492,32 +2489,33 @@ write_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **erro
 	}
 
 	contents = g_string_new ("");
+
 	for (i = 0; i < num; i++) {
 		gs_free char *options = NULL;
+		const char *next_hop;
+		gint64 metric;
 
 		route = nm_setting_ip_config_get_route (s_ip6, i);
+		next_hop = nm_ip_route_get_next_hop (route);
+		metric = nm_ip_route_get_metric (route);
 		options = get_route_attributes_string (route, AF_INET6);
 
-		if (nm_ip_route_get_metric (route) == -1) {
-			g_string_append_printf (contents, "%s/%u via %s%s%s",
-			                                  nm_ip_route_get_dest (route),
-			                                  nm_ip_route_get_prefix (route),
-			                                  nm_ip_route_get_next_hop (route),
-			                                  options ? " " : "",
-			                                  options ?: "");
-		} else {
-			g_string_append_printf (contents, "%s/%u via %s metric %u%s%s",
-			                                  nm_ip_route_get_dest (route),
-			                                  nm_ip_route_get_prefix (route),
-			                                  nm_ip_route_get_next_hop (route),
-			                                  (unsigned) nm_ip_route_get_metric (route),
-			                                  options ? " " : "",
-			                                  options ?: "");
+		g_string_append_printf (contents, "%s/%u",
+		                        nm_ip_route_get_dest (route),
+		                        nm_ip_route_get_prefix (route));
+		if (next_hop)
+			g_string_append_printf (contents, " via %s", next_hop);
+		if (metric >= 0)
+			g_string_append_printf (contents, " metric %u", (guint) metric);
+		if (options) {
+			g_string_append_c (contents, ' ');
+			g_string_append (contents, options);
 		}
-		g_string_append (contents, "\n");
+
+		g_string_append_c (contents, '\n');
 	}
 
-	if (!g_file_set_contents (filename, contents->str, -1, NULL)) {
+	if (!g_file_set_contents (filename, contents->str, contents->len, NULL)) {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
 		             "Writing route6 file '%s' failed", filename);
 		return FALSE;
diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c
index 9fce5aa1..47ad5a23 100644
--- a/src/settings/plugins/ifcfg-rh/shvar.c
+++ b/src/settings/plugins/ifcfg-rh/shvar.c
@@ -905,6 +905,28 @@ svGetKeys (shvarFile *s)
 
 /*****************************************************************************/
 
+const char *
+svFindFirstKeyWithPrefix (shvarFile *s, const char *key_prefix)
+{
+	const GList *current;
+	const shvarLine *l;
+
+	g_return_val_if_fail (s, NULL);
+	g_return_val_if_fail (key_prefix, NULL);
+
+	for (current = s->lineList; current; current = current->next) {
+		l = current->data;
+		if (   l->key
+		    && l->line
+		    && g_str_has_prefix (l->key, key_prefix))
+			return l->key;
+	}
+
+	return NULL;
+}
+
+/*****************************************************************************/
+
 static const char *
 _svGetValue (shvarFile *s, const char *key, char **to_free)
 {
diff --git a/src/settings/plugins/ifcfg-rh/shvar.h b/src/settings/plugins/ifcfg-rh/shvar.h
index 9d8c2364..a13920a1 100644
--- a/src/settings/plugins/ifcfg-rh/shvar.h
+++ b/src/settings/plugins/ifcfg-rh/shvar.h
@@ -44,6 +44,8 @@ shvarFile *svCreateFile (const char *name);
 /* Open the file <name>, return shvarFile on success, NULL on failure */
 shvarFile *svOpenFile (const char *name, GError **error);
 
+const char *svFindFirstKeyWithPrefix (shvarFile *s, const char *key_prefix);
+
 /* Get the value associated with the key, and leave the current pointer
  * pointing at the line containing the value.  The char* returned MUST
  * be freed by the caller.
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1
new file mode 100644
index 00000000..ecb36c37
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1
@@ -0,0 +1,14 @@
+DNS1="192.0.2.1"
+IPADDR="102.0.2.2"
+GATEWAY="192.0.2.1"
+NETMASK="255.254.0.0"
+BOOTPROTO="static"
+DEVICE="eth1"
+ONBOOT="yes"
+IPV6INIT="yes"
+
+#bogus
+PREFIX1=25
+NETMASK0=255.255.0.0
+
+#end
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1.cexpected
new file mode 100644
index 00000000..5dfdce4d
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1.cexpected
@@ -0,0 +1,23 @@
+DNS1=192.0.2.1
+IPADDR=102.0.2.2
+GATEWAY=192.0.2.1
+NETMASK=255.254.0.0
+BOOTPROTO="static"
+DEVICE=eth1
+ONBOOT=yes
+IPV6INIT=yes
+
+#bogus
+
+#end
+TYPE=Ethernet
+PROXY_METHOD=none
+BROWSER_ONLY=no
+PREFIX=15
+DEFROUTE=yes
+IPV4_FAILURE_FATAL=no
+IPV6_AUTOCONF=yes
+IPV6_DEFROUTE=yes
+IPV6_FAILURE_FATAL=no
+NAME="System netmask-1"
+UUID=${UUID}
diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index babb068d..496a164b 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -399,6 +399,47 @@ _writer_new_connection_fail (NMConnection *connection,
 
 /*****************************************************************************/
 
+static void
+test_read_netmask_1 (void)
+{
+	nmtst_auto_unlinkfile char *testfile = NULL;
+	gs_unref_object NMConnection *connection = NULL;
+	gs_free char *content = NULL;
+	NMSettingConnection *s_con;
+	NMSettingIPConfig *s_ip4;
+	NMIPAddress *ip4_addr;
+	const char *FILENAME = TEST_IFCFG_DIR "/network-scripts/ifcfg-netmask-1";
+
+	connection = _connection_from_file (FILENAME, NULL, TYPE_ETHERNET, NULL);
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "System netmask-1");
+
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
+	g_assert (s_ip4);
+	g_assert_cmpuint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 1);
+	ip4_addr = nm_setting_ip_config_get_address (s_ip4, 0);
+	g_assert (ip4_addr);
+	g_assert_cmpstr (nm_ip_address_get_address (ip4_addr), ==, "102.0.2.2");
+	g_assert_cmpint (nm_ip_address_get_prefix (ip4_addr), ==, 15);
+
+	nmtst_assert_connection_verifies_without_normalization (connection);
+
+	content = nmtst_file_get_contents (FILENAME);
+
+	testfile = g_strdup (TEST_SCRATCH_DIR "/network-scripts/ifcfg-netmask-1.copy");
+
+	nmtst_file_set_contents (testfile, content);
+
+	_writer_update_connection (connection,
+	                           TEST_SCRATCH_DIR "/network-scripts/",
+	                           testfile,
+	                           TEST_IFCFG_DIR "/network-scripts/ifcfg-netmask-1.cexpected");
+}
+
+/*****************************************************************************/
+
 static gboolean
 verify_cert_or_key (NMSetting8021x *s_compare,
                     const char *file,
@@ -4928,15 +4969,16 @@ test_write_wired_aliases (void)
 			if (!g_strcmp0 (addrstr, ip[j]))
 				break;
 		}
-		g_assert (j < num_addresses);
-
-		g_assert_cmpint (nm_ip_address_get_prefix (addr), ==, 24);
-		if (label[j])
-			g_assert_cmpstr (g_variant_get_string (nm_ip_address_get_attribute (addr, "label"), NULL), ==, label[j]);
-		else
-			g_assert (nm_ip_address_get_attribute (addr, "label") == NULL);
-
-		ip[j] = NULL;
+		if (j >= num_addresses)
+			g_assert_not_reached ();
+		else {
+			g_assert_cmpint (nm_ip_address_get_prefix (addr), ==, 24);
+			if (label[j])
+				g_assert_cmpstr (g_variant_get_string (nm_ip_address_get_attribute (addr, "label"), NULL), ==, label[j]);
+			else
+				g_assert (nm_ip_address_get_attribute (addr, "label") == NULL);
+			ip[j] = NULL;
+		}
 	}
 
 	for (i = 0; i < num_addresses; i++)
@@ -9348,6 +9390,8 @@ int main (int argc, char **argv)
 	nmtst_add_test_func (TPATH "read-static",           test_read_wired_static, TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-static",           "System test-wired-static",           GINT_TO_POINTER (TRUE));
 	nmtst_add_test_func (TPATH "read-static-bootproto", test_read_wired_static, TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-static-bootproto", "System test-wired-static-bootproto", GINT_TO_POINTER (FALSE));
 
+	g_test_add_func (TPATH "read-netmask-1", test_read_netmask_1);
+
 	g_test_add_func (TPATH "read-dhcp", test_read_wired_dhcp);
 	g_test_add_func (TPATH "read-dhcp-plus-ip", test_read_wired_dhcp_plus_ip);
 	g_test_add_func (TPATH "read-shared-plus-ip", test_read_wired_shared_plus_ip);
diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c
index 71f1f9aa..ab8a0670 100644
--- a/src/supplicant/nm-supplicant-interface.c
+++ b/src/supplicant/nm-supplicant-interface.c
@@ -228,15 +228,17 @@ bss_proxy_acquired_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_da
 	GVariant *props = NULL;
 	const char *object_path;
 	BssData *bss_data;
+	gboolean success;
 
-	g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error);
-	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+	success = g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error);
+	if (   !success
+	    && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 		return;
 
 	self = NM_SUPPLICANT_INTERFACE (user_data);
 	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
-	if (error) {
+	if (!success) {
 		_LOGD ("failed to acquire BSS proxy: (%s)", error->message);
 		g_hash_table_remove (priv->bss_proxies,
 		                     g_dbus_proxy_get_object_path (proxy));
@@ -1120,7 +1122,7 @@ nm_supplicant_interface_disconnect (NMSupplicantInterface * self)
 
 	/* Cancel all pending calls related to a prior connection attempt */
 	if (priv->assoc_data) {
-		gs_free GError *error = NULL;
+		gs_free_error GError *error = NULL;
 
 		nm_utils_error_set_cancelled (&error, FALSE, "NMSupplicantInterface");
 		assoc_return (self, error, "abort due to disconnect");
@@ -1597,7 +1599,7 @@ dispose (GObject *object)
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
 
 	if (priv->assoc_data) {
-		gs_free GError *error = NULL;
+		gs_free_error GError *error = NULL;
 
 		nm_utils_error_set_cancelled (&error, TRUE, "NMSupplicantInterface");
 		assoc_return (self, error, "cancelled due to dispose of supplicant interface");
diff --git a/src/supplicant/tests/test-supplicant-config.c b/src/supplicant/tests/test-supplicant-config.c
index fd91e921..ef6f2c64 100644
--- a/src/supplicant/tests/test-supplicant-config.c
+++ b/src/supplicant/tests/test-supplicant-config.c
@@ -525,7 +525,7 @@ test_wifi_eap (void)
 	nm_connection_add_setting (connection, NM_SETTING (s_8021x));
 	nm_setting_802_1x_add_eap_method (s_8021x, "tls");
 	nm_setting_802_1x_set_client_cert (s_8021x, TEST_CERT_DIR "/test-cert.p12", NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, NULL);
-	nm_setting_802_1x_set_ca_cert (s_8021x, TEST_CERT_DIR "/test-ca-cert.pem", NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, NULL);
+	g_assert (nm_setting_802_1x_set_ca_cert (s_8021x, TEST_CERT_DIR "/test-ca-cert.pem", NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, NULL));
 	nm_setting_802_1x_set_private_key (s_8021x, TEST_CERT_DIR "/test-cert.p12", NULL, NM_SETTING_802_1X_CK_SCHEME_PATH, NULL, NULL);
 
 	/* IP4 setting */