summary refs log tree commit diff
path: root/src/devices
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2016-03-01 16:55:22 +0100
committerMichael Biebl <biebl@debian.org>2016-03-01 16:55:22 +0100
commitc2de0d98ba39e0a1a970d066fd19be786092f376 (patch)
tree3838363c06a6019db6cf1f882ea34ebded63c38b /src/devices
parent494f296a3baab08522617b24b1f126d8f9a17502 (diff)
Imported Upstream version 1.1.91 upstream/1.1.91
Diffstat (limited to 'src/devices')
-rw-r--r--src/devices/adsl/nm-atm-manager.c3
-rw-r--r--src/devices/adsl/nm-device-adsl.c10
-rw-r--r--src/devices/bluetooth/nm-bluez-common.h2
-rw-r--r--src/devices/bluetooth/nm-bluez-device.c17
-rw-r--r--src/devices/bluetooth/nm-bluez-device.h3
-rw-r--r--src/devices/bluetooth/nm-bluez-manager.c10
-rw-r--r--src/devices/bluetooth/nm-bluez4-adapter.c3
-rw-r--r--src/devices/bluetooth/nm-bluez4-manager.c3
-rw-r--r--src/devices/bluetooth/nm-bluez5-dun.c3
-rw-r--r--src/devices/bluetooth/nm-bluez5-manager.c3
-rw-r--r--src/devices/bluetooth/nm-bt-error.c3
-rw-r--r--src/devices/bluetooth/nm-device-bt.c3
-rw-r--r--src/devices/nm-arping-manager.c449
-rw-r--r--src/devices/nm-arping-manager.h53
-rw-r--r--src/devices/nm-device-bond.c11
-rw-r--r--src/devices/nm-device-bridge.c11
-rw-r--r--src/devices/nm-device-ethernet-utils.c6
-rw-r--r--src/devices/nm-device-ethernet.c113
-rw-r--r--src/devices/nm-device-factory.c62
-rw-r--r--src/devices/nm-device-factory.h19
-rw-r--r--src/devices/nm-device-generic.c4
-rw-r--r--src/devices/nm-device-infiniband.c22
-rw-r--r--src/devices/nm-device-ip-tunnel.c25
-rw-r--r--src/devices/nm-device-macvlan.c57
-rw-r--r--src/devices/nm-device-private.h1
-rw-r--r--src/devices/nm-device-tun.c18
-rw-r--r--src/devices/nm-device-veth.c5
-rw-r--r--src/devices/nm-device-vlan.c53
-rw-r--r--src/devices/nm-device-vxlan.c34
-rw-r--r--src/devices/nm-device.c2399
-rw-r--r--src/devices/nm-device.h86
-rw-r--r--src/devices/nm-lldp-listener.c105
-rw-r--r--src/devices/nm-lldp-listener.h3
-rw-r--r--src/devices/team/nm-device-team.c17
-rw-r--r--src/devices/team/nm-team-factory.c3
-rw-r--r--src/devices/tests/Makefile.am18
-rw-r--r--src/devices/tests/Makefile.in88
-rw-r--r--src/devices/tests/test-arping.c139
-rw-r--r--src/devices/tests/test-lldp.c44
-rw-r--r--src/devices/wifi/nm-device-olpc-mesh.c3
-rw-r--r--src/devices/wifi/nm-device-wifi.c109
-rw-r--r--src/devices/wifi/nm-wifi-ap-utils.c11
-rw-r--r--src/devices/wifi/nm-wifi-ap.c3
-rw-r--r--src/devices/wifi/nm-wifi-factory.c13
-rw-r--r--src/devices/wifi/tests/test-wifi-ap-utils.c5
-rw-r--r--src/devices/wwan/nm-device-modem.c3
-rw-r--r--src/devices/wwan/nm-modem-broadband.c25
-rw-r--r--src/devices/wwan/nm-modem-manager.c3
-rw-r--r--src/devices/wwan/nm-modem.c7
-rw-r--r--src/devices/wwan/nm-wwan-factory.c3
50 files changed, 2612 insertions, 1481 deletions
diff --git a/src/devices/adsl/nm-atm-manager.c b/src/devices/adsl/nm-atm-manager.c
index d3f1423f..a3fa4901 100644
--- a/src/devices/adsl/nm-atm-manager.c
+++ b/src/devices/adsl/nm-atm-manager.c
@@ -18,13 +18,12 @@
  * Copyright (C) 2009 - 2013 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 #include <gudev/gudev.h>
 #include <gmodule.h>
 
-#include "nm-default.h"
 #include "nm-atm-manager.h"
 #include "nm-setting-adsl.h"
 #include "nm-device-adsl.h"
diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c
index dd9a1203..e7a91e0a 100644
--- a/src/devices/adsl/nm-device-adsl.c
+++ b/src/devices/adsl/nm-device-adsl.c
@@ -18,7 +18,7 @@
  * Pantelis Koukousoulas <pktoss@gmail.com>
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <sys/socket.h>
 #include <linux/atmdev.h>
@@ -32,7 +32,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "nm-default.h"
 #include "nm-device-adsl.h"
 #include "nm-device-private.h"
 #include "nm-enum-types.h"
@@ -449,7 +448,6 @@ act_stage3_ip4_config_start (NMDevice *device,
 {
 	NMDeviceAdsl *self = NM_DEVICE_ADSL (device);
 	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
-	NMConnection *connection;
 	NMSettingAdsl *s_adsl;
 	NMActRequest *req;
 	GError *err = NULL;
@@ -458,11 +456,7 @@ act_stage3_ip4_config_start (NMDevice *device,
 
 	req = nm_device_get_act_request (device);
 	g_assert (req);
-
-	connection = nm_act_request_get_applied_connection (req);
-	g_assert (req);
-
-	s_adsl = nm_connection_get_setting_adsl (connection);
+	s_adsl = (NMSettingAdsl *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_ADSL);
 	g_assert (s_adsl);
 
 	/* PPPoE uses the NAS interface, not the ATM interface */
diff --git a/src/devices/bluetooth/nm-bluez-common.h b/src/devices/bluetooth/nm-bluez-common.h
index 4262fa76..67810b94 100644
--- a/src/devices/bluetooth/nm-bluez-common.h
+++ b/src/devices/bluetooth/nm-bluez-common.h
@@ -21,8 +21,6 @@
 #ifndef __NETWORKMANAGER_BLUEZ_COMMON_H__
 #define __NETWORKMANAGER_BLUEZ_COMMON_H__
 
-#include "config.h"
-
 #define BLUETOOTH_CONNECT_DUN "dun"
 #define BLUETOOTH_CONNECT_NAP "nap"
 
diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c
index b7032143..71226813 100644
--- a/src/devices/bluetooth/nm-bluez-device.c
+++ b/src/devices/bluetooth/nm-bluez-device.c
@@ -19,11 +19,10 @@
  * Copyright (C) 2013 Intel Corporation.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 
-#include "nm-default.h"
 #include "nm-core-internal.h"
 
 #include "nm-bt-error.h"
@@ -1014,7 +1013,7 @@ nm_bluez_device_new (const char *path,
 	const char *interface_name = NULL;
 
 	g_return_val_if_fail (path != NULL, NULL);
-	g_return_val_if_fail (provider != NULL, NULL);
+	g_return_val_if_fail (NM_IS_CONNECTION_PROVIDER (provider), NULL);
 	g_return_val_if_fail (bluez_version == 4 || bluez_version == 5, NULL);
 
 	self = (NMBluezDevice *) g_object_new (NM_TYPE_BLUEZ_DEVICE,
@@ -1028,7 +1027,7 @@ nm_bluez_device_new (const char *path,
 	priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);
 
 	priv->bluez_version = bluez_version;
-	priv->provider = provider;
+	priv->provider = g_object_ref (provider);
 	g_return_val_if_fail (bluez_version == 5 || (bluez_version == 4 && adapter_address), NULL);
 	if (adapter_address)
 		set_adapter_address (self, adapter_address);
@@ -1102,9 +1101,11 @@ dispose (GObject *object)
 	}
 #endif
 
-	g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_added, self);
-	g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_removed, self);
-	g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_updated, self);
+	if (priv->provider) {
+		g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_added, self);
+		g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_removed, self);
+		g_signal_handlers_disconnect_by_func (priv->provider, cp_connection_updated, self);
+	}
 
 	g_slist_free_full (priv->connections, g_object_unref);
 	priv->connections = NULL;
@@ -1120,6 +1121,8 @@ dispose (GObject *object)
 		nm_settings_connection_delete (NM_SETTINGS_CONNECTION (to_delete), NULL, NULL);
 		g_object_unref (to_delete);
 	}
+
+	g_clear_object (&priv->provider);
 }
 
 static void
diff --git a/src/devices/bluetooth/nm-bluez-device.h b/src/devices/bluetooth/nm-bluez-device.h
index 0e54fcb0..c9560540 100644
--- a/src/devices/bluetooth/nm-bluez-device.h
+++ b/src/devices/bluetooth/nm-bluez-device.h
@@ -21,9 +21,6 @@
 #ifndef __NETWORKMANAGER_BLUEZ_DEVICE_H__
 #define __NETWORKMANAGER_BLUEZ_DEVICE_H__
 
-
-#include "config.h"
-#include "nm-default.h"
 #include "nm-connection.h"
 #include "nm-connection-provider.h"
 
diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c
index 6903356c..f66b5abe 100644
--- a/src/devices/bluetooth/nm-bluez-manager.c
+++ b/src/devices/bluetooth/nm-bluez-manager.c
@@ -18,14 +18,13 @@
  * Copyright (C) 2013 - 2014 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <signal.h>
 #include <string.h>
 #include <stdlib.h>
 #include <gmodule.h>
 
-#include "nm-default.h"
 #include "nm-bluez-manager.h"
 #include "nm-device-factory.h"
 #include "nm-setting-bluetooth.h"
@@ -397,6 +396,10 @@ dispose (GObject *object)
 	cleanup_checking (self, TRUE);
 
 	priv->bluez_version = 0;
+
+	g_clear_object (&priv->provider);
+
+	G_OBJECT_CLASS (nm_bluez_manager_parent_class)->dispose (object);
 }
 
 static void
@@ -404,8 +407,7 @@ nm_bluez_manager_init (NMBluezManager *self)
 {
 	NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE (self);
 
-	priv->provider = nm_connection_provider_get ();
-	g_assert (priv->provider);
+	priv->provider = g_object_ref (nm_connection_provider_get ());
 }
 
 static NMDevice *
diff --git a/src/devices/bluetooth/nm-bluez4-adapter.c b/src/devices/bluetooth/nm-bluez4-adapter.c
index 04ae833a..deeebcb6 100644
--- a/src/devices/bluetooth/nm-bluez4-adapter.c
+++ b/src/devices/bluetooth/nm-bluez4-adapter.c
@@ -18,11 +18,10 @@
  * Copyright (C) 2009 - 2012 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 
-#include "nm-default.h"
 #include "nm-dbus-interface.h"
 #include "nm-bluez4-adapter.h"
 #include "nm-bluez-device.h"
diff --git a/src/devices/bluetooth/nm-bluez4-manager.c b/src/devices/bluetooth/nm-bluez4-manager.c
index c5ba120c..146612a8 100644
--- a/src/devices/bluetooth/nm-bluez4-manager.c
+++ b/src/devices/bluetooth/nm-bluez4-manager.c
@@ -19,13 +19,12 @@
  * Copyright (C) 2007 - 2013 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <signal.h>
 #include <string.h>
 #include <stdlib.h>
 
-#include "nm-default.h"
 #include "nm-bluez-manager.h"
 #include "nm-bluez4-manager.h"
 #include "nm-bluez4-adapter.h"
diff --git a/src/devices/bluetooth/nm-bluez5-dun.c b/src/devices/bluetooth/nm-bluez5-dun.c
index 875a662f..4c93feba 100644
--- a/src/devices/bluetooth/nm-bluez5-dun.c
+++ b/src/devices/bluetooth/nm-bluez5-dun.c
@@ -18,7 +18,7 @@
  * Copyright (C) 2014 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <sys/socket.h>
 #include <bluetooth/sdp.h>
@@ -32,7 +32,6 @@
 
 #include "nm-bluez5-dun.h"
 #include "nm-bt-error.h"
-#include "nm-default.h"
 #include "NetworkManagerUtils.h"
 
 struct _NMBluez5DunContext {
diff --git a/src/devices/bluetooth/nm-bluez5-manager.c b/src/devices/bluetooth/nm-bluez5-manager.c
index c9f5828d..e44e87d8 100644
--- a/src/devices/bluetooth/nm-bluez5-manager.c
+++ b/src/devices/bluetooth/nm-bluez5-manager.c
@@ -20,13 +20,12 @@
  * Copyright (C) 2013 Intel Corporation.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <signal.h>
 #include <string.h>
 #include <stdlib.h>
 
-#include "nm-default.h"
 #include "nm-bluez-manager.h"
 #include "nm-bluez5-manager.h"
 #include "nm-bluez-device.h"
diff --git a/src/devices/bluetooth/nm-bt-error.c b/src/devices/bluetooth/nm-bt-error.c
index 9c35d8b6..18391187 100644
--- a/src/devices/bluetooth/nm-bt-error.c
+++ b/src/devices/bluetooth/nm-bt-error.c
@@ -18,9 +18,8 @@
  * Copyright (C) 2014 Red Hat, Inc.
  */
 
-#include "config.h"
-
 #include "nm-default.h"
+
 #include "nm-bt-error.h"
 
 GQuark
diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c
index 1e3f9cdc..e151b795 100644
--- a/src/devices/bluetooth/nm-device-bt.c
+++ b/src/devices/bluetooth/nm-device-bt.c
@@ -18,12 +18,11 @@
  * Copyright (C) 2009 - 2011 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <stdio.h>
 #include <string.h>
 
-#include "nm-default.h"
 #include "nm-bluez-common.h"
 #include "nm-bluez-device.h"
 #include "nm-device-bt.h"
diff --git a/src/devices/nm-arping-manager.c b/src/devices/nm-arping-manager.c
new file mode 100644
index 00000000..dfb20b4b
--- /dev/null
+++ b/src/devices/nm-arping-manager.c
@@ -0,0 +1,449 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "nm-arping-manager.h"
+#include "nm-platform.h"
+#include "nm-utils.h"
+#include "NetworkManagerUtils.h"
+
+typedef enum {
+	STATE_INIT,
+	STATE_PROBING,
+	STATE_PROBE_DONE,
+	STATE_ANNOUNCING,
+} State;
+
+typedef struct {
+	int            ifindex;
+	State          state;
+	GHashTable    *addresses;
+	guint          completed;
+	guint          timer;
+	guint          round2_id;
+} NMArpingManagerPrivate;
+
+typedef struct {
+	in_addr_t address;
+	GPid pid;
+	guint watch;
+	gboolean duplicate;
+	NMArpingManager *manager;
+} AddressInfo;
+
+enum {
+	PROBE_TERMINATED,
+	LAST_SIGNAL,
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (NMArpingManager, nm_arping_manager, G_TYPE_OBJECT)
+
+#define NM_ARPING_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_ARPING_MANAGER, NMArpingManagerPrivate))
+
+#define _NMLOG_DOMAIN         LOGD_IP4
+#define _NMLOG_PREFIX_NAME    "arping"
+#define _NMLOG(level, ...) \
+    G_STMT_START { \
+        char _sbuf[64]; \
+        \
+        nm_log ((level), _NMLOG_DOMAIN, \
+                "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+                _NMLOG_PREFIX_NAME, \
+                self ? nm_sprintf_buf (_sbuf, "[%p,%d]", \
+                                       self, \
+                                       NM_ARPING_MANAGER_GET_PRIVATE (self)->ifindex) : "" \
+                _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
+    } G_STMT_END
+
+/**
+ * nm_arping_manager_add_address:
+ * @self: a #NMArpingManager
+ * @address: an IP address
+ *
+ * Add @address to the list of IP addresses to probe.
+
+ * Returns: %TRUE on success, %FALSE if the address was already in the list
+ */
+gboolean
+nm_arping_manager_add_address (NMArpingManager *self, in_addr_t address)
+{
+	NMArpingManagerPrivate *priv;
+	AddressInfo *info;
+
+	g_return_val_if_fail (NM_IS_ARPING_MANAGER (self), FALSE);
+	priv = NM_ARPING_MANAGER_GET_PRIVATE (self);
+	g_return_val_if_fail (priv->state == STATE_INIT, FALSE);
+
+	if (g_hash_table_lookup (priv->addresses, GUINT_TO_POINTER (address))) {
+		_LOGD ("address already exists");
+		return FALSE;
+	}
+
+	info = g_slice_new0 (AddressInfo);
+	info->address = address;
+	info->manager = self;
+
+	g_hash_table_insert (priv->addresses, GUINT_TO_POINTER (address), info);
+
+	return TRUE;
+}
+
+static void
+arping_watch_cb (GPid pid, gint status, gpointer user_data)
+{
+	AddressInfo *info = user_data;
+	NMArpingManager *self = info->manager;
+	NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self);
+	const char *addr;
+
+	info->pid = 0;
+	info->watch = 0;
+	addr = nm_utils_inet4_ntop (info->address, NULL);
+
+	if (WIFEXITED (status)) {
+		if (WEXITSTATUS (status) != 0) {
+			_LOGD ("%s already used in the %s network",
+			       addr, nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex));
+			info->duplicate = TRUE;
+		} else
+			_LOGD ("DAD succeeded for %s", addr);
+	} else {
+		_LOGD ("stopped unexpectedly with status %d for %s", status, addr);
+	}
+
+	if (++priv->completed == g_hash_table_size (priv->addresses)) {
+		priv->state = STATE_PROBE_DONE;
+		nm_clear_g_source (&priv->timer);
+		g_signal_emit (self, signals[PROBE_TERMINATED], 0);
+	}
+}
+
+static gboolean
+arping_timeout_cb (gpointer user_data)
+{
+	NMArpingManager *self = user_data;
+	NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self);
+	GHashTableIter iter;
+	AddressInfo *info;
+
+	priv->timer = 0;
+
+	g_hash_table_iter_init (&iter, priv->addresses);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) {
+		nm_clear_g_source (&info->watch);
+		if (info->pid) {
+			_LOGD ("DAD timed out for %s",
+			       nm_utils_inet4_ntop (info->address, NULL));
+			nm_utils_kill_child_async (info->pid, SIGTERM, LOGD_IP4,
+			                           "arping", 1000, NULL, NULL);
+			info->pid = 0;
+		}
+	}
+
+	priv->state = STATE_PROBE_DONE;
+	g_signal_emit (self, signals[PROBE_TERMINATED], 0);
+
+	return G_SOURCE_REMOVE;
+}
+
+/**
+ * nm_arping_manager_start_probe:
+ * @self: a #NMArpingManager
+ * @timeout: maximum probe duration in milliseconds
+ * @error: location to store error, or %NULL
+ *
+ * Start probing IP addresses for duplicates; when the probe terminates a
+ * PROBE_TERMINATED signal is emitted.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ */
+gboolean
+nm_arping_manager_start_probe (NMArpingManager *self, guint timeout, GError **error)
+{
+	const char *argv[] = { NULL, "-D", "-q", "-I", NULL, "-c", NULL, "-w", NULL, NULL, NULL };
+	NMArpingManagerPrivate *priv;
+	GHashTableIter iter;
+	AddressInfo *info;
+	gs_free char *timeout_str = NULL;
+
+	g_return_val_if_fail (NM_IS_ARPING_MANAGER (self), FALSE);
+	g_return_val_if_fail (!error || !*error, FALSE);
+	g_return_val_if_fail (timeout, FALSE);
+
+	priv = NM_ARPING_MANAGER_GET_PRIVATE (self);
+	g_return_val_if_fail (priv->state == STATE_INIT, FALSE);
+
+	argv[4] = nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex);
+	if (!argv[4]) {
+		/* The device was probably just removed. */
+		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+		             "can't find a name for ifindex %d", priv->ifindex);
+		return FALSE;
+	}
+
+	priv->completed = 0;
+
+	argv[0] = nm_utils_find_helper ("arping", NULL, NULL);
+	if (!argv[0]) {
+		g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
+		                     "arping could not be found");
+		return FALSE;
+	}
+
+	timeout_str = g_strdup_printf ("%u", timeout / 1000 + 2);
+	argv[6] = timeout_str;
+	argv[8] = timeout_str;
+
+	g_hash_table_iter_init (&iter, priv->addresses);
+
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) {
+		gs_free char *tmp_str = NULL;
+		gboolean success;
+
+		argv[9] = nm_utils_inet4_ntop (info->address, NULL);
+		_LOGD ("run %s", (tmp_str = g_strjoinv (" ", (char **) argv)));
+
+		success = g_spawn_async (NULL, (char **) argv, NULL,
+		                         G_SPAWN_STDOUT_TO_DEV_NULL |
+		                         G_SPAWN_STDERR_TO_DEV_NULL |
+		                         G_SPAWN_DO_NOT_REAP_CHILD,
+		                         NULL, NULL, &info->pid, NULL);
+
+		info->watch = g_child_watch_add (info->pid, arping_watch_cb, info);
+	}
+
+	priv->timer = g_timeout_add (timeout, arping_timeout_cb, self);
+	priv->state = STATE_PROBING;
+
+	return TRUE;
+}
+
+/**
+ * nm_arping_manager_reset:
+ * @self: a #NMArpingManager
+ *
+ * Stop any operation in progress and reset @self to the initial state.
+ */
+void
+nm_arping_manager_reset (NMArpingManager *self)
+{
+	NMArpingManagerPrivate *priv;
+
+	g_return_if_fail (NM_IS_ARPING_MANAGER (self));
+	priv = NM_ARPING_MANAGER_GET_PRIVATE (self);
+
+	nm_clear_g_source (&priv->timer);
+	nm_clear_g_source (&priv->round2_id);
+	g_hash_table_remove_all (priv->addresses);
+
+	priv->state = STATE_INIT;
+}
+
+/**
+ * nm_arping_manager_destroy:
+ * @self: the #NMArpingManager
+ *
+ * Calls nm_arping_manager_reset() and unrefs @self.
+ */
+void
+nm_arping_manager_destroy (NMArpingManager *self)
+{
+	g_return_if_fail (NM_IS_ARPING_MANAGER (self));
+
+	nm_arping_manager_reset (self);
+	g_object_unref (self);
+}
+
+/**
+ * nm_arping_manager_check_address:
+ * @self: a #NMArpingManager
+ * @address: an IP address
+ *
+ * Check if an IP address is duplicate. @address must have been added with
+ * nm_arping_manager_add_address().
+ *
+ * Returns: %TRUE if the address is not duplicate, %FALSE otherwise
+ */
+gboolean
+nm_arping_manager_check_address (NMArpingManager *self, in_addr_t address)
+{
+	NMArpingManagerPrivate *priv;
+	AddressInfo *info;
+
+	g_return_val_if_fail (NM_IS_ARPING_MANAGER (self), FALSE);
+	priv = NM_ARPING_MANAGER_GET_PRIVATE (self);
+	g_return_val_if_fail (   priv->state == STATE_INIT
+	                      || priv->state == STATE_PROBE_DONE, FALSE);
+
+	info = g_hash_table_lookup (priv->addresses, GUINT_TO_POINTER (address));
+	g_return_val_if_fail (info, FALSE);
+
+	return !info->duplicate;
+}
+
+static void
+send_announcements (NMArpingManager *self, const char *mode_arg)
+{
+	NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self);
+	const char *argv[] = { NULL, mode_arg, "-q", "-I", NULL, "-c", "1", NULL, NULL };
+	int ip_arg = G_N_ELEMENTS (argv) - 2;
+	GError *error = NULL;
+	GHashTableIter iter;
+	AddressInfo *info;
+
+	argv[4] = nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex);
+	if (!argv[4]) {
+		/* The device was probably just removed. */
+		_LOGW ("can't find a name for ifindex %d", priv->ifindex);
+		return;
+	}
+
+	argv[0] = nm_utils_find_helper ("arping", NULL, NULL);
+	if (!argv[0]) {
+		_LOGW ("arping could not be found; no ARPs will be sent");
+		return;
+	}
+
+	g_hash_table_iter_init (&iter, priv->addresses);
+
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) {
+		gs_free char *tmp_str = NULL;
+		gboolean success;
+
+		if (info->duplicate)
+			continue;
+
+		argv[ip_arg] = nm_utils_inet4_ntop (info->address, NULL);
+		_LOGD ("run %s", (tmp_str = g_strjoinv (" ", (char **) argv)));
+
+		success = g_spawn_async (NULL, (char **) argv, NULL,
+		                         G_SPAWN_STDOUT_TO_DEV_NULL |
+		                         G_SPAWN_STDERR_TO_DEV_NULL,
+		                         NULL, NULL, NULL, &error);
+		if (!success) {
+			_LOGW ("could not send ARP for address %s: %s", argv[ip_arg],
+			       error->message);
+			g_clear_error (&error);
+		}
+	}
+}
+
+static gboolean
+arp_announce_round2 (gpointer self)
+{
+	NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self);
+
+	priv->round2_id = 0;
+	send_announcements (self, "-U");
+	priv->state = STATE_INIT;
+	g_hash_table_remove_all (priv->addresses);
+
+	return G_SOURCE_REMOVE;
+}
+
+/**
+ * nm_arping_manager_announce_addresses:
+ * @self: a #NMArpingManager
+ *
+ * Start announcing addresses.
+ */
+void
+nm_arping_manager_announce_addresses (NMArpingManager *self)
+{
+	NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self);
+
+	g_return_if_fail (   priv->state == STATE_INIT
+	                  || priv->state == STATE_PROBE_DONE);
+
+	send_announcements (self, "-A");
+	nm_clear_g_source (&priv->round2_id);
+	priv->round2_id = g_timeout_add_seconds (2, arp_announce_round2, self);
+	priv->state = STATE_ANNOUNCING;
+}
+
+static void
+destroy_address_info (gpointer data)
+{
+	AddressInfo *info = (AddressInfo *) data;
+
+	nm_clear_g_source (&info->watch);
+
+	if (info->pid) {
+		nm_utils_kill_child_async (info->pid, SIGTERM, LOGD_IP4, "arping",
+		                           1000, NULL, NULL);
+	}
+
+	g_slice_free (AddressInfo, info);
+}
+
+static void
+dispose (GObject *object)
+{
+	NMArpingManager *self = NM_ARPING_MANAGER (object);
+	NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self);
+
+	nm_clear_g_source (&priv->timer);
+	nm_clear_g_source (&priv->round2_id);
+	g_clear_pointer (&priv->addresses, g_hash_table_destroy);
+
+	G_OBJECT_CLASS (nm_arping_manager_parent_class)->dispose (object);
+}
+
+static void
+nm_arping_manager_init (NMArpingManager *self)
+{
+	NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self);
+
+	priv->addresses = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+	                                         NULL, destroy_address_info);
+	priv->state = STATE_INIT;
+}
+
+NMArpingManager *
+nm_arping_manager_new (int ifindex)
+{
+	NMArpingManager *self;
+	NMArpingManagerPrivate *priv;
+
+	self = g_object_new (NM_TYPE_ARPING_MANAGER, NULL);
+	priv = NM_ARPING_MANAGER_GET_PRIVATE (self);
+	priv->ifindex = ifindex;
+
+	return self;
+}
+
+static void
+nm_arping_manager_class_init (NMArpingManagerClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (NMArpingManagerPrivate));
+
+	object_class->dispose = dispose;
+
+	signals[PROBE_TERMINATED] =
+		g_signal_new (NM_ARPING_MANAGER_PROBE_TERMINATED,
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              0, NULL, NULL, NULL,
+		              G_TYPE_NONE, 0);
+}
diff --git a/src/devices/nm-arping-manager.h b/src/devices/nm-arping-manager.h
new file mode 100644
index 00000000..4a4f8d4b
--- /dev/null
+++ b/src/devices/nm-arping-manager.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ */
+
+#ifndef __NM_ARPING_MANAGER__
+#define __NM_ARPING_MANAGER__
+
+#include <netinet/in.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_ARPING_MANAGER            (nm_arping_manager_get_type ())
+#define NM_ARPING_MANAGER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ARPING_MANAGER, NMArpingManager))
+#define NM_ARPING_MANAGER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_ARPING_MANAGER, NMArpingManagerClass))
+#define NM_IS_ARPING_MANAGER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_ARPING_MANAGER))
+#define NM_IS_ARPING_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_ARPING_MANAGER))
+#define NM_ARPING_MANAGER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_ARPING_MANAGER, NMArpingManagerClass))
+
+#define NM_ARPING_MANAGER_PROBE_TERMINATED  "probe-terminated"
+
+struct _NMArpingManager {
+	GObject parent;
+};
+
+typedef struct {
+	GObjectClass parent;
+} NMArpingManagerClass;
+
+GType nm_arping_manager_get_type (void);
+
+NMArpingManager *nm_arping_manager_new (int ifindex);
+void nm_arping_manager_destroy (NMArpingManager *self);
+gboolean nm_arping_manager_add_address (NMArpingManager *self, in_addr_t address);
+gboolean nm_arping_manager_start_probe (NMArpingManager *self, guint timeout, GError **error);
+gboolean nm_arping_manager_check_address (NMArpingManager *self, in_addr_t address);
+void nm_arping_manager_announce_addresses (NMArpingManager *self);
+void nm_arping_manager_reset (NMArpingManager *self);
+
+G_END_DECLS
+
+#endif /* __NM_ARPING_MANAGER__ */
diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c
index dfd1de6d..cef104e6 100644
--- a/src/devices/nm-device-bond.c
+++ b/src/devices/nm-device-bond.c
@@ -18,12 +18,11 @@
  * Copyright 2011 - 2012 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <errno.h>
 #include <stdlib.h>
 
-#include "nm-default.h"
 #include "nm-device-bond.h"
 #include "NetworkManagerUtils.h"
 #include "nm-device-private.h"
@@ -75,7 +74,6 @@ check_connection_available (NMDevice *device,
 static gboolean
 check_connection_compatible (NMDevice *device, NMConnection *connection)
 {
-	const char *iface;
 	NMSettingBond *s_bond;
 
 	if (!NM_DEVICE_CLASS (nm_device_bond_parent_class)->check_connection_compatible (device, connection))
@@ -85,11 +83,6 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 	if (!s_bond || !nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME))
 		return FALSE;
 
-	/* Bond connections must specify the virtual interface name */
-	iface = nm_connection_get_interface_name (connection);
-	if (!iface || strcmp (nm_device_get_iface (device), iface))
-		return FALSE;
-
 	/* FIXME: match bond properties like mode, etc? */
 
 	return TRUE;
@@ -457,7 +450,7 @@ create_and_realize (NMDevice *device,
 	g_assert (iface);
 
 	plerr = nm_platform_link_bond_add (NM_PLATFORM_GET, iface, out_plink);
-	if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+	if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 		             "Failed to create bond interface '%s' for '%s': %s",
 		             iface,
diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c
index 843c5be4..cc72b003 100644
--- a/src/devices/nm-device-bridge.c
+++ b/src/devices/nm-device-bridge.c
@@ -18,11 +18,10 @@
  * Copyright 2011 - 2015 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <stdlib.h>
 
-#include "nm-default.h"
 #include "nm-device-bridge.h"
 #include "NetworkManagerUtils.h"
 #include "nm-device-private.h"
@@ -73,7 +72,6 @@ check_connection_available (NMDevice *device,
 static gboolean
 check_connection_compatible (NMDevice *device, NMConnection *connection)
 {
-	const char *iface;
 	NMSettingBridge *s_bridge;
 	const char *mac_address;
 
@@ -84,11 +82,6 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 	if (!s_bridge || !nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME))
 		return FALSE;
 
-	/* Bridge connections must specify the virtual interface name */
-	iface = nm_connection_get_interface_name (connection);
-	if (!iface || strcmp (nm_device_get_iface (device), iface))
-		return FALSE;
-
 	mac_address = nm_setting_bridge_get_mac_address (s_bridge);
 	if (mac_address && nm_device_is_real (device)) {
 		const char *hw_addr;
@@ -405,7 +398,7 @@ create_and_realize (NMDevice *device,
 	                                     hwaddr ? mac_address : NULL,
 	                                     hwaddr ? ETH_ALEN : 0,
 	                                     out_plink);
-	if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+	if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 		             "Failed to create bridge interface '%s' for '%s': %s",
 		             iface,
diff --git a/src/devices/nm-device-ethernet-utils.c b/src/devices/nm-device-ethernet-utils.c
index 9165de31..d034ddfc 100644
--- a/src/devices/nm-device-ethernet-utils.c
+++ b/src/devices/nm-device-ethernet-utils.c
@@ -16,12 +16,12 @@
  * (C) Copyright 2011 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 
-#include <nm-connection.h>
-#include "nm-default.h"
+#include "nm-connection.h"
+
 #include "nm-device-ethernet-utils.h"
 
 char *
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index a2396ec8..2fb84276 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -19,7 +19,7 @@
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <netinet/in.h>
 #include <string.h>
@@ -29,7 +29,6 @@
 
 #include <gudev/gudev.h>
 
-#include "nm-default.h"
 #include "nm-device-ethernet.h"
 #include "nm-device-private.h"
 #include "nm-activation-request.h"
@@ -64,8 +63,6 @@ G_DEFINE_TYPE (NMDeviceEthernet, nm_device_ethernet, NM_TYPE_DEVICE)
 #define PPPOE_RECONNECT_DELAY 7
 #define PPPOE_ENCAP_OVERHEAD  8 /* 2 bytes for PPP, 6 for PPPoE */
 
-static NMSetting *device_get_setting (NMDevice *device, GType setting_type);
-
 typedef struct Supplicant {
 	NMSupplicantManager *mgr;
 	NMSupplicantInterface *iface;
@@ -429,52 +426,18 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 	return TRUE;
 }
 
-/* FIXME: Move it to nm-device.c and then get rid of all foo_device_get_setting() all around.
-   It's here now to keep the patch short. */
-static NMSetting *
-device_get_setting (NMDevice *device, GType setting_type)
-{
-	NMActRequest *req;
-	NMSetting *setting = NULL;
-
-	req = nm_device_get_act_request (device);
-	if (req) {
-		NMConnection *connection;
-
-		connection = nm_act_request_get_applied_connection (req);
-		if (connection)
-			setting = nm_connection_get_setting (connection, setting_type);
-	}
-
-	return setting;
-}
-
 /*****************************************************************************/
 /* 802.1X */
 
 static void
-remove_supplicant_timeouts (NMDeviceEthernet *self)
+supplicant_interface_clear_handlers (NMDeviceEthernet *self)
 {
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
 
-	nm_clear_g_source (&priv->supplicant.con_timeout_id);
 	nm_clear_g_source (&priv->supplicant_timeout_id);
-}
-
-static void
-remove_supplicant_interface_error_handler (NMDeviceEthernet *self)
-{
-	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-
-	if (priv->supplicant.iface_error_id != 0) {
-		g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_error_id);
-		priv->supplicant.iface_error_id = 0;
-	}
-
-	if (priv->supplicant.iface_con_error_cb_id > 0) {
-		g_source_remove (priv->supplicant.iface_con_error_cb_id);
-		priv->supplicant.iface_con_error_cb_id = 0;
-	}
+	nm_clear_g_source (&priv->supplicant.con_timeout_id);
+	nm_clear_g_source (&priv->supplicant.iface_con_error_cb_id);
+	nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.iface_error_id);
 }
 
 static void
@@ -482,18 +445,13 @@ supplicant_interface_release (NMDeviceEthernet *self)
 {
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
 
-	remove_supplicant_timeouts (self);
-	remove_supplicant_interface_error_handler (self);
+	supplicant_interface_clear_handlers (self);
 
-	if (priv->supplicant.iface_state_id > 0) {
-		g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_state_id);
-		priv->supplicant.iface_state_id = 0;
-	}
+	nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.iface_state_id);
 
 	if (priv->supplicant.iface) {
 		nm_supplicant_interface_disconnect (priv->supplicant.iface);
-		nm_supplicant_manager_iface_release (priv->supplicant.mgr, priv->supplicant.iface);
-		priv->supplicant.iface = NULL;
+		g_clear_object (&priv->supplicant.iface);
 	}
 }
 
@@ -656,8 +614,7 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
 		}
 		break;
 	case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED:
-		remove_supplicant_interface_error_handler (self);
-		remove_supplicant_timeouts (self);
+		supplicant_interface_clear_handlers (self);
 
 		/* If this is the initial association during device activation,
 		 * schedule the next activation stage.
@@ -677,7 +634,6 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
 		break;
 	case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
 		supplicant_interface_release (self);
-		remove_supplicant_timeouts (self);
 
 		if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) {
 			nm_device_state_changed (device,
@@ -804,14 +760,15 @@ supplicant_interface_init (NMDeviceEthernet *self)
 {
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
 
-	/* Create supplicant interface */
-	priv->supplicant.iface = nm_supplicant_manager_iface_get (priv->supplicant.mgr,
-	                                                          nm_device_get_iface (NM_DEVICE (self)),
-	                                                          FALSE);
+	supplicant_interface_release (self);
+
+	priv->supplicant.iface = nm_supplicant_manager_create_interface (priv->supplicant.mgr,
+	                                                                 nm_device_get_iface (NM_DEVICE (self)),
+	                                                                 FALSE);
+
 	if (!priv->supplicant.iface) {
 		_LOGE (LOGD_DEVICE | LOGD_ETHER,
 		       "Couldn't initialize supplicant interface");
-		supplicant_interface_release (self);
 		return FALSE;
 	}
 
@@ -850,7 +807,6 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 {
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-	NMActRequest *req;
 	NMSettingWired *s_wired;
 	const char *cloned_mac;
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
@@ -859,15 +815,11 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 
 	ret = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage1_prepare (dev, reason);
 	if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
-		req = nm_device_get_act_request (NM_DEVICE (self));
-		g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-		s_wired = (NMSettingWired *) device_get_setting (dev, NM_TYPE_SETTING_WIRED);
+		s_wired = (NMSettingWired *) nm_device_get_applied_setting (dev, NM_TYPE_SETTING_WIRED);
 		if (s_wired) {
 			/* Set device MAC address if the connection wants to change it */
 			cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
-			if (cloned_mac)
-				nm_device_set_hw_addr (dev, cloned_mac, "set", LOGD_ETHER);
+			nm_device_set_hw_addr (dev, cloned_mac, "set", LOGD_ETHER);
 		}
 
 		/* If we're re-activating a PPPoE connection a short while after
@@ -878,7 +830,8 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 		if (priv->last_pppoe_time) {
 			gint32 delay = nm_utils_get_monotonic_timestamp_s () - priv->last_pppoe_time;
 
-			if (delay < PPPOE_RECONNECT_DELAY && device_get_setting (dev, NM_TYPE_SETTING_PPPOE)) {
+			if (   delay < PPPOE_RECONNECT_DELAY
+			    && nm_device_get_applied_setting (dev, NM_TYPE_SETTING_PPPOE)) {
 				_LOGI (LOGD_DEVICE, "delaying PPPoE reconnect for %d seconds to ensure peer is ready...",
 				       delay);
 				g_assert (!priv->pppoe_wait_id);
@@ -980,7 +933,6 @@ static NMActStageReturn
 pppoe_stage3_ip4_config_start (NMDeviceEthernet *self, NMDeviceStateReason *reason)
 {
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-	NMConnection *connection;
 	NMSettingPppoe *s_pppoe;
 	NMActRequest *req;
 	GError *err = NULL;
@@ -989,10 +941,7 @@ pppoe_stage3_ip4_config_start (NMDeviceEthernet *self, NMDeviceStateReason *reas
 	req = nm_device_get_act_request (NM_DEVICE (self));
 	g_assert (req);
 
-	connection = nm_act_request_get_applied_connection (req);
-	g_assert (req);
-
-	s_pppoe = nm_connection_get_setting_pppoe (connection);
+	s_pppoe = (NMSettingPppoe *) nm_device_get_applied_setting (self, NM_TYPE_SETTING_PPPOE);
 	g_assert (s_pppoe);
 
 	priv->ppp_manager = nm_ppp_manager_new (nm_device_get_iface (NM_DEVICE (self)));
@@ -1064,7 +1013,7 @@ dcb_configure (NMDevice *device)
 
 	dcb_timeout_cleanup (device);
 
-	s_dcb = (NMSettingDcb *) device_get_setting (device, NM_TYPE_SETTING_DCB);
+	s_dcb = (NMSettingDcb *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_DCB);
 	g_assert (s_dcb);
 	if (!nm_dcb_setup (nm_device_get_iface (device), s_dcb, &error)) {
 		_LOGW (LOGD_DCB, "Activation: (ethernet) failed to enable DCB/FCoE: %s",
@@ -1210,7 +1159,7 @@ wake_on_lan_enable (NMDevice *device)
 	const char *password = NULL;
 	gs_free char *value = NULL;
 
-	s_wired = (NMSettingWired *) device_get_setting (device, NM_TYPE_SETTING_WIRED);
+	s_wired = (NMSettingWired *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRED);
 	if (s_wired) {
 		wol = nm_setting_wired_get_wake_on_lan (s_wired);
 		password = nm_setting_wired_get_wake_on_lan_password (s_wired);
@@ -1255,7 +1204,8 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 
 	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
-	s_con = NM_SETTING_CONNECTION (device_get_setting (device, NM_TYPE_SETTING_CONNECTION));
+	s_con = NM_SETTING_CONNECTION (nm_device_get_applied_setting (device,
+	                                                              NM_TYPE_SETTING_CONNECTION));
 	g_assert (s_con);
 
 	dcb_timeout_cleanup (device);
@@ -1268,7 +1218,8 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 	if (!strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME)) {
 		NMSetting8021x *security;
 
-		security = (NMSetting8021x *) device_get_setting (device, NM_TYPE_SETTING_802_1X);
+		security = (NMSetting8021x *) nm_device_get_applied_setting (device,
+		                                                             NM_TYPE_SETTING_802_1X);
 		if (security) {
 			/* FIXME: for now 802.1x is mutually exclusive with DCB */
 			return nm_8021x_stage2_config (self, reason);
@@ -1278,7 +1229,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 	wake_on_lan_enable (device);
 
 	/* DCB and FCoE setup */
-	s_dcb = (NMSettingDcb *) device_get_setting (device, NM_TYPE_SETTING_DCB);
+	s_dcb = (NMSettingDcb *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_DCB);
 	if (s_dcb) {
 		/* lldpad really really wants the carrier to be up */
 		if (nm_platform_link_is_connected (NM_PLATFORM_GET, nm_device_get_ifindex (device))) {
@@ -1307,7 +1258,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 	                           NM_SETTING_PPPOE_SETTING_NAME)) {
 		NMSettingPpp *s_ppp;
 
-		s_ppp = (NMSettingPpp *) device_get_setting (device, NM_TYPE_SETTING_PPP);
+		s_ppp = (NMSettingPpp *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_PPP);
 		if (s_ppp) {
 			guint32 mtu = 0, mru = 0, mxu;
 
@@ -1337,7 +1288,7 @@ act_stage3_ip4_config_start (NMDevice *device,
 
 	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
-	s_con = NM_SETTING_CONNECTION (device_get_setting (device, NM_TYPE_SETTING_CONNECTION));
+	s_con = NM_SETTING_CONNECTION (nm_device_get_applied_setting (device, NM_TYPE_SETTING_CONNECTION));
 	g_assert (s_con);
 
 	connection_type = nm_setting_connection_get_connection_type (s_con);
@@ -1396,7 +1347,7 @@ deactivate (NMDevice *device)
 	dcb_carrier_cleanup (device);
 
 	/* Tear down DCB/FCoE if it was enabled */
-	s_dcb = (NMSettingDcb *) device_get_setting (device, NM_TYPE_SETTING_DCB);
+	s_dcb = (NMSettingDcb *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_DCB);
 	if (s_dcb) {
 		if (!nm_dcb_cleanup (nm_device_get_iface (device), &error)) {
 			_LOGW (LOGD_DEVICE | LOGD_HW, "failed to disable DCB/FCoE: %s",
@@ -1406,7 +1357,7 @@ deactivate (NMDevice *device)
 	}
 
 	/* Set last PPPoE connection time */
-	if (device_get_setting (device, NM_TYPE_SETTING_PPPOE))
+	if (nm_device_get_applied_setting (device, NM_TYPE_SETTING_PPPOE))
 		NM_DEVICE_ETHERNET_GET_PRIVATE (device)->last_pppoe_time = nm_utils_get_monotonic_timestamp_s ();
 
 	/* Reset MAC address back to initial address */
@@ -1653,6 +1604,8 @@ dispose (GObject *object)
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object);
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
 
+	supplicant_interface_release (self);
+
 	nm_clear_g_source (&priv->pppoe_wait_id);
 
 	dcb_timeout_cleanup (NM_DEVICE (self));
diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c
index 75731b14..bd0ec002 100644
--- a/src/devices/nm-device-factory.c
+++ b/src/devices/nm-device-factory.c
@@ -18,17 +18,16 @@
  * Copyright (C) 2014 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <errno.h>
 #include <string.h>
-
 #include <gmodule.h>
 
 #include "nm-device-factory.h"
-#include "nm-default.h"
 #include "nm-platform.h"
+#include "nm-utils.h"
 
 const NMLinkType _nm_device_factory_no_default_links[] = { NM_LINK_TYPE_NONE };
 const char *_nm_device_factory_no_default_settings[] = { NULL };
@@ -156,35 +155,46 @@ nm_device_factory_get_connection_parent (NMDeviceFactory *factory,
 	return NULL;
 }
 
-static char *
-get_virtual_iface_name (NMDeviceFactory *factory,
-                        NMConnection *connection,
-                        const char *parent_iface)
-{
-	const char *iface;
-
-	/* For any other virtual connection, NMSettingConnection:interface-name is
-	 * the virtual device name.
-	 */
-	iface = nm_connection_get_interface_name (connection);
-	g_return_val_if_fail (iface != NULL, NULL);
-	return g_strdup (iface);
-}
-
 char *
-nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory,
-                                          NMConnection *connection,
-                                          const char *parent_iface)
+nm_device_factory_get_connection_iface (NMDeviceFactory *factory,
+                                        NMConnection *connection,
+                                        const char *parent_iface,
+                                        GError **error)
 {
+	NMDeviceFactoryInterface *klass;
+	char *ifname;
+
 	g_return_val_if_fail (factory != NULL, NULL);
 	g_return_val_if_fail (connection != NULL, NULL);
+	g_return_val_if_fail (!error || !*error, NULL);
 
-	if (!nm_connection_is_virtual (connection))
+	klass = NM_DEVICE_FACTORY_GET_INTERFACE (factory);
+
+	if (klass->get_connection_iface)
+		ifname = klass->get_connection_iface (factory, connection, parent_iface);
+	else
+		ifname = g_strdup (nm_connection_get_interface_name (connection));
+
+	if (!ifname) {
+		g_set_error (error,
+		             NM_MANAGER_ERROR,
+		             NM_MANAGER_ERROR_FAILED,
+		             "failed to determine interface name: error determine name for %s",
+		             nm_connection_get_connection_type (connection));
 		return NULL;
+	}
 
-	if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_virtual_iface_name)
-		return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_virtual_iface_name (factory, connection, parent_iface);
-	return NULL;
+	if (!nm_utils_iface_valid_name (ifname)) {
+		g_set_error (error,
+		             NM_MANAGER_ERROR,
+		             NM_MANAGER_ERROR_FAILED,
+		             "failed to determine interface name: name \"%s\" is invalid",
+		             ifname);
+		g_free (ifname);
+		return NULL;
+	}
+
+	return ifname;
 }
 
 /*******************************************************************/
@@ -192,8 +202,6 @@ nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory,
 static void
 nm_device_factory_default_init (NMDeviceFactoryInterface *factory_iface)
 {
-	factory_iface->get_virtual_iface_name = get_virtual_iface_name;
-
 	/* Signals */
 	signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED,
 	                                      NM_TYPE_DEVICE_FACTORY,
diff --git a/src/devices/nm-device-factory.h b/src/devices/nm-device-factory.h
index 9b7cb35a..ae78968a 100644
--- a/src/devices/nm-device-factory.h
+++ b/src/devices/nm-device-factory.h
@@ -101,19 +101,19 @@ typedef struct {
 	                                       NMConnection *connection);
 
 	/**
-	 * get_virtual_iface_name:
+	 * get_connection_iface:
 	 * @factory: the #NMDeviceFactory
-	 * @connection: the #NMConnection to return the virtual interface name for
-	 * @parent_iface: parent interface name
+	 * @connection: the #NMConnection to return the interface name for
+	 * @parent_iface: optional parent interface name for virtual devices
 	 *
 	 * Given a connection, returns the interface name that a device activating
 	 * that connection would have.
 	 *
 	 * Returns: the interface name, or %NULL
 	 */
-	char * (*get_virtual_iface_name) (NMDeviceFactory *factory,
-	                                  NMConnection *connection,
-	                                  const char *parent_iface);
+	char * (*get_connection_iface) (NMDeviceFactory *factory,
+	                                NMConnection *connection,
+	                                const char *parent_iface);
 
 	/**
 	 * create_device:
@@ -175,9 +175,10 @@ void       nm_device_factory_get_supported_types (NMDeviceFactory *factory,
 const char *nm_device_factory_get_connection_parent (NMDeviceFactory *factory,
                                                      NMConnection *connection);
 
-char *     nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory,
-                                                     NMConnection *connection,
-                                                     const char *parent_iface);
+char *     nm_device_factory_get_connection_iface (NMDeviceFactory *factory,
+                                                   NMConnection *connection,
+                                                   const char *parent_iface,
+                                                   GError **error);
 
 void       nm_device_factory_start       (NMDeviceFactory *factory);
 
diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c
index 2e9c134a..d90840d2 100644
--- a/src/devices/nm-device-generic.c
+++ b/src/devices/nm-device-generic.c
@@ -18,7 +18,7 @@
  * Copyright 2013 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include "nm-device-generic.h"
 #include "nm-device-private.h"
@@ -138,7 +138,7 @@ constructor (GType type,
 	                                                                       n_construct_params,
 	                                                                       construct_params);
 
-	nm_device_set_unmanaged_flags_initial (NM_DEVICE (object), NM_UNMANAGED_DEFAULT, TRUE);
+	nm_device_set_unmanaged_flags ((NMDevice *) object, NM_UNMANAGED_BY_DEFAULT, TRUE);
 
 	return object;
 }
diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c
index 45df49fe..79bcb57c 100644
--- a/src/devices/nm-device-infiniband.c
+++ b/src/devices/nm-device-infiniband.c
@@ -18,11 +18,10 @@
  * Copyright 2011 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <linux/if_infiniband.h>
 
-#include "nm-default.h"
 #include "nm-device-infiniband.h"
 #include "NetworkManagerUtils.h"
 #include "nm-device-private.h"
@@ -69,8 +68,6 @@ static NMActStageReturn
 act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 {
 	NMActStageReturn ret;
-	NMActRequest *req;
-	NMConnection *connection;
 	NMSettingInfiniband *s_infiniband;
 	const char *transport_mode;
 	char *mode_path;
@@ -82,12 +79,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 	if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
 		return ret;
 
-	req = nm_device_get_act_request (dev);
-	g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	connection = nm_act_request_get_applied_connection (req);
-	g_assert (connection);
-	s_infiniband = nm_connection_get_setting_infiniband (connection);
+	s_infiniband = (NMSettingInfiniband *) nm_device_get_applied_setting (dev, NM_TYPE_SETTING_INFINIBAND);
 	g_assert (s_infiniband);
 
 	transport_mode = nm_setting_infiniband_get_transport_mode (s_infiniband);
@@ -272,7 +264,7 @@ create_and_realize (NMDevice *device,
 	}
 
 	plerr = nm_platform_link_infiniband_add (NM_PLATFORM_GET, parent_ifindex, p_key, out_plink);
-	if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+	if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 		             "Failed to create InfiniBand P_Key interface '%s' for '%s': %s",
 		             nm_device_get_iface (device),
@@ -406,9 +398,9 @@ get_connection_parent (NMDeviceFactory *factory, NMConnection *connection)
 }
 
 static char *
-get_virtual_iface_name (NMDeviceFactory *factory,
-                        NMConnection *connection,
-                        const char *parent_iface)
+get_connection_iface (NMDeviceFactory *factory,
+                      NMConnection *connection,
+                      const char *parent_iface)
 {
 	NMSettingInfiniband *s_infiniband;
 
@@ -430,6 +422,6 @@ NM_DEVICE_FACTORY_DEFINE_INTERNAL (INFINIBAND, Infiniband, infiniband,
 	NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_INFINIBAND_SETTING_NAME),
 	factory_iface->create_device = create_device;
 	factory_iface->get_connection_parent = get_connection_parent;
-	factory_iface->get_virtual_iface_name = get_virtual_iface_name;
+	factory_iface->get_connection_iface = get_connection_iface;
 	)
 
diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c
index 6d0df059..0ba813eb 100644
--- a/src/devices/nm-device-ip-tunnel.c
+++ b/src/devices/nm-device-ip-tunnel.c
@@ -18,7 +18,7 @@
  * Copyright 2015 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 #include <netinet/in.h>
@@ -28,7 +28,6 @@
 
 #include "nm-device-ip-tunnel.h"
 #include "nm-device-private.h"
-#include "nm-default.h"
 #include "nm-manager.h"
 #include "nm-platform.h"
 #include "nm-device-factory.h"
@@ -554,13 +553,13 @@ platform_link_to_tunnel_mode (const NMPlatformLink *link)
 		else if (lnk->proto == IPPROTO_IPV6)
 			return NM_IP_TUNNEL_MODE_IP6IP6;
 		else
-			return NM_IP_TUNNEL_MODE_UKNOWN;
+			return NM_IP_TUNNEL_MODE_UNKNOWN;
 	case NM_LINK_TYPE_IPIP:
 		return NM_IP_TUNNEL_MODE_IPIP;
 	case NM_LINK_TYPE_SIT:
 		return NM_IP_TUNNEL_MODE_SIT;
 	default:
-		g_return_val_if_reached (NM_IP_TUNNEL_MODE_UKNOWN);
+		g_return_val_if_reached (NM_IP_TUNNEL_MODE_UNKNOWN);
 	}
 }
 
@@ -661,7 +660,7 @@ create_and_realize (NMDevice *device,
 		}
 
 		plerr = nm_platform_link_gre_add (NM_PLATFORM_GET, iface, &lnk_gre, out_plink);
-		if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+		if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 			g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 			             "Failed to create GRE interface '%s' for '%s': %s",
 			             iface,
@@ -687,7 +686,7 @@ create_and_realize (NMDevice *device,
 		lnk_sit.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel);
 
 		plerr = nm_platform_link_sit_add (NM_PLATFORM_GET, iface, &lnk_sit, out_plink);
-		if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+		if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 			g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 					"Failed to create SIT interface '%s' for '%s': %s",
 					iface,
@@ -713,7 +712,7 @@ create_and_realize (NMDevice *device,
 		lnk_ipip.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel);
 
 		plerr = nm_platform_link_ipip_add (NM_PLATFORM_GET, iface, &lnk_ipip, out_plink);
-		if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+		if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 			g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 					"Failed to create IPIP interface '%s' for '%s': %s",
 					iface,
@@ -742,7 +741,7 @@ create_and_realize (NMDevice *device,
 		lnk_ip6tnl.proto = nm_setting_ip_tunnel_get_mode (s_ip_tunnel) == NM_IP_TUNNEL_MODE_IPIP6 ? IPPROTO_IPIP : IPPROTO_IPV6;
 
 		plerr = nm_platform_link_ip6tnl_add (NM_PLATFORM_GET, iface, &lnk_ip6tnl, out_plink);
-		if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+		if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 			g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 			             "Failed to create IPIP interface '%s' for '%s': %s",
 			             iface,
@@ -997,7 +996,7 @@ create_device (NMDeviceFactory *factory,
 		mode = platform_link_to_tunnel_mode (plink);
 	}
 
-	if (mode == NM_IP_TUNNEL_MODE_UKNOWN)
+	if (mode == NM_IP_TUNNEL_MODE_UNKNOWN)
 		return NULL;
 
 	return (NMDevice *) g_object_new (NM_TYPE_DEVICE_IP_TUNNEL,
@@ -1023,9 +1022,9 @@ get_connection_parent (NMDeviceFactory *factory, NMConnection *connection)
 }
 
 static char *
-get_virtual_iface_name (NMDeviceFactory *factory,
-                        NMConnection *connection,
-                        const char *parent_iface)
+get_connection_iface (NMDeviceFactory *factory,
+                      NMConnection *connection,
+                      const char *parent_iface)
 {
 	const char *ifname;
 	NMSettingIPTunnel *s_ip_tunnel;
@@ -1048,5 +1047,5 @@ NM_DEVICE_FACTORY_DEFINE_INTERNAL (IP_TUNNEL, IPTunnel, ip_tunnel,
 	NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_IP_TUNNEL_SETTING_NAME),
 	factory_iface->create_device = create_device;
 	factory_iface->get_connection_parent = get_connection_parent;
-	factory_iface->get_virtual_iface_name = get_virtual_iface_name;
+	factory_iface->get_connection_iface = get_connection_iface;
 )
diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c
index 8123a793..2dc9d4f6 100644
--- a/src/devices/nm-device-macvlan.c
+++ b/src/devices/nm-device-macvlan.c
@@ -18,11 +18,10 @@
  * Copyright 2013 - 2015 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 
-#include "nm-default.h"
 #include "nm-device-macvlan.h"
 #include "nm-device-private.h"
 #include "nm-connection-provider.h"
@@ -127,7 +126,7 @@ parent_state_changed (NMDevice *parent,
 	if (reason == NM_DEVICE_STATE_REASON_CARRIER)
 		return;
 
-	nm_device_set_unmanaged_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason);
+	nm_device_set_unmanaged_by_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent, FALSE), reason);
 }
 
 static void
@@ -139,8 +138,7 @@ nm_device_macvlan_set_parent (NMDeviceMacvlan *self, NMDevice *parent)
 	if (parent == priv->parent)
 		return;
 
-	if (priv->parent_state_id)
-		nm_clear_g_signal_handler (priv->parent, &priv->parent_state_id);
+	nm_clear_g_signal_handler (priv->parent, &priv->parent_state_id);
 
 	g_clear_object (&priv->parent);
 
@@ -152,10 +150,10 @@ nm_device_macvlan_set_parent (NMDeviceMacvlan *self, NMDevice *parent)
 		                                          device);
 
 		/* Set parent-dependent unmanaged flag */
-		nm_device_set_unmanaged_flags (device,
-		                               NM_UNMANAGED_PARENT,
-		                               !nm_device_get_managed (parent),
-		                               NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED);
+		nm_device_set_unmanaged_by_flags (device,
+		                                  NM_UNMANAGED_PARENT,
+		                                  !nm_device_get_managed (parent, FALSE),
+		                                  NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED);
 	}
 
 	/* Recheck availability now that the parent has changed */
@@ -239,7 +237,7 @@ create_and_realize (NMDevice *device,
 	lnk.tap = nm_setting_macvlan_get_tap (s_macvlan);
 
 	plerr = nm_platform_link_macvlan_add (NM_PLATFORM_GET, iface, parent_ifindex, &lnk, out_plink);
-	if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+	if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 		             "Failed to create %s interface '%s' for '%s': %s",
 		             lnk.tap ? "macvtap" : "macvlan",
@@ -377,7 +375,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 {
 	NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device);
 	NMSettingMacvlan *s_macvlan;
-	const char *parent, *iface = NULL;
+	const char *parent = NULL;
 
 	if (!NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->check_connection_compatible (device, connection))
 		return FALSE;
@@ -410,13 +408,6 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 		}
 	}
 
-	/* Ensure the interface name matches */
-	iface = nm_connection_get_interface_name (connection);
-	if (iface) {
-		if (g_strcmp0 (nm_device_get_ip_iface (device), iface) != 0)
-			return FALSE;
-	}
-
 	return TRUE;
 }
 
@@ -503,8 +494,6 @@ update_connection (NMDevice *device, NMConnection *connection)
 static NMActStageReturn
 act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 {
-	NMActRequest *req;
-	NMConnection *connection;
 	NMSettingWired *s_wired;
 	const char *cloned_mac;
 	NMActStageReturn ret;
@@ -515,18 +504,11 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 	if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
 		return ret;
 
-	req = nm_device_get_act_request (dev);
-	g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	connection = nm_act_request_get_applied_connection (req);
-	g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	s_wired = nm_connection_get_setting_wired (connection);
+	s_wired = (NMSettingWired *) nm_device_get_applied_setting (dev, NM_TYPE_SETTING_WIRED);
 	if (s_wired) {
 		/* Set device MAC address if the connection wants to change it */
 		cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
-		if (cloned_mac)
-			nm_device_set_hw_addr (dev, cloned_mac, "set", LOGD_HW);
+		nm_device_set_hw_addr (dev, cloned_mac, "set", LOGD_HW);
 	}
 
 	return TRUE;
@@ -621,6 +603,14 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
+dispose (GObject *object)
+{
+	nm_device_macvlan_set_parent (NM_DEVICE_MACVLAN (object), NULL);
+
+	G_OBJECT_CLASS (nm_device_macvlan_parent_class)->dispose (object);
+}
+
+static void
 nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -630,6 +620,7 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass)
 
 	NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP)
 
+	object_class->dispose = dispose;
 	object_class->get_property = get_property;
 	object_class->set_property = set_property;
 
@@ -744,9 +735,9 @@ get_connection_parent (NMDeviceFactory *factory, NMConnection *connection)
 }
 
 static char *
-get_virtual_iface_name (NMDeviceFactory *factory,
-                        NMConnection *connection,
-                        const char *parent_iface)
+get_connection_iface (NMDeviceFactory *factory,
+                      NMConnection *connection,
+                      const char *parent_iface)
 {
 	NMSettingMacvlan *s_macvlan;
 	const char *ifname;
@@ -768,6 +759,6 @@ NM_DEVICE_FACTORY_DEFINE_INTERNAL (MACVLAN, Macvlan, macvlan,
 	NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_MACVLAN_SETTING_NAME),
 	factory_iface->create_device = create_device;
 	factory_iface->get_connection_parent = get_connection_parent;
-	factory_iface->get_virtual_iface_name = get_virtual_iface_name;
+	factory_iface->get_connection_iface = get_connection_iface;
 	)
 
diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h
index 5010e906..602c2c85 100644
--- a/src/devices/nm-device-private.h
+++ b/src/devices/nm-device-private.h
@@ -95,7 +95,6 @@ void nm_device_master_check_slave_physical_port (NMDevice *self, NMDevice *slave
 
 void nm_device_set_carrier (NMDevice *self, gboolean carrier);
 
-void nm_device_emit_recheck_auto_activate (NMDevice *device);
 void nm_device_queue_recheck_assume (NMDevice *device);
 void nm_device_queue_recheck_available (NMDevice *device,
                                         NMDeviceStateReason available_reason,
diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c
index 91ef8fe7..a8ae3edc 100644
--- a/src/devices/nm-device-tun.c
+++ b/src/devices/nm-device-tun.c
@@ -18,13 +18,12 @@
  * Copyright 2013 - 2015 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 
-#include "nm-default.h"
 #include "nm-activation-request.h"
 #include "nm-device-tun.h"
 #include "nm-device-private.h"
@@ -222,7 +221,7 @@ create_and_realize (NMDevice *device,
 	                                  nm_setting_tun_get_vnet_hdr (s_tun),
 	                                  nm_setting_tun_get_multi_queue (s_tun),
 	                                  out_plink);
-	if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+	if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 		             "Failed to create TUN/TAP interface '%s' for '%s': %s",
 		             iface,
@@ -285,8 +284,6 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
 {
 	NMDeviceTun *self = NM_DEVICE_TUN (device);
 	NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self);
-	NMActRequest *req;
-	NMConnection *connection;
 	NMSettingWired *s_wired;
 	const char *cloned_mac;
 	NMActStageReturn ret;
@@ -301,18 +298,11 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
 	if (g_strcmp0 (priv->mode, "tap"))
 		return NM_ACT_STAGE_RETURN_SUCCESS;
 
-	req = nm_device_get_act_request (device);
-	g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	connection = nm_act_request_get_applied_connection (req);
-	g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	s_wired = nm_connection_get_setting_wired (connection);
+	s_wired = (NMSettingWired *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRED);
 	if (s_wired) {
 		/* Set device MAC address if the connection wants to change it */
 		cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
-		if (cloned_mac)
-			nm_device_set_hw_addr (device, cloned_mac, "set", LOGD_DEVICE);
+		nm_device_set_hw_addr (device, cloned_mac, "set", LOGD_DEVICE);
 	}
 
 	return NM_ACT_STAGE_RETURN_SUCCESS;
diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c
index a1bf0d21..ff198a7d 100644
--- a/src/devices/nm-device-veth.c
+++ b/src/devices/nm-device-veth.c
@@ -18,7 +18,7 @@
  * Copyright 2013 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <errno.h>
 #include <stdlib.h>
@@ -29,7 +29,6 @@
 
 #include "nm-device-veth.h"
 #include "nm-device-private.h"
-#include "nm-default.h"
 #include "nm-manager.h"
 #include "nm-platform.h"
 #include "nm-device-factory.h"
@@ -188,7 +187,7 @@ create_device (NMDeviceFactory *factory,
 	return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VETH,
 	                                  NM_DEVICE_IFACE, iface,
 	                                  NM_DEVICE_TYPE_DESC, "Veth",
-	                                  NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET,
+	                                  NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VETH,
 	                                  NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_VETH,
 	                                  NULL);
 }
diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c
index f8710412..e6e3708b 100644
--- a/src/devices/nm-device-vlan.c
+++ b/src/devices/nm-device-vlan.c
@@ -18,11 +18,10 @@
  * Copyright 2011 - 2012 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <sys/socket.h>
 
-#include "nm-default.h"
 #include "nm-device-vlan.h"
 #include "nm-manager.h"
 #include "nm-utils.h"
@@ -77,7 +76,7 @@ parent_state_changed (NMDevice *parent,
 	if (reason == NM_DEVICE_STATE_REASON_CARRIER)
 		return;
 
-	nm_device_set_unmanaged_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason);
+	nm_device_set_unmanaged_by_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent, FALSE), reason);
 }
 
 static void
@@ -115,7 +114,8 @@ parent_hwaddr_changed (NMDevice *parent,
 			 * removing the IPv6 configuration; reapply it.
 			 */
 			s_ip6 = nm_connection_get_setting_ip6_config (connection);
-			nm_device_reactivate_ip6_config (NM_DEVICE (self), s_ip6, s_ip6);
+			if (s_ip6)
+				nm_device_reactivate_ip6_config (NM_DEVICE (self), s_ip6, s_ip6);
 		}
 	}
 }
@@ -144,10 +144,10 @@ nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent)
 		                                           G_CALLBACK (parent_hwaddr_changed), device);
 
 		/* Set parent-dependent unmanaged flag */
-		nm_device_set_unmanaged_flags (device,
-		                               NM_UNMANAGED_PARENT,
-		                               !nm_device_get_managed (parent),
-		                               NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED);
+		nm_device_set_unmanaged_by_flags (device,
+		                                  NM_UNMANAGED_PARENT,
+		                                  !nm_device_get_managed (parent, FALSE),
+		                                  NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED);
 	}
 
 	/* Recheck availability now that the parent has changed */
@@ -237,7 +237,7 @@ create_and_realize (NMDevice *device,
 	                                   vlan_id,
 	                                   nm_setting_vlan_get_flags (s_vlan),
 	                                   out_plink);
-	if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+	if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 		             "Failed to create VLAN interface '%s' for '%s': %s",
 		             iface,
@@ -389,7 +389,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 {
 	NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
 	NMSettingVlan *s_vlan;
-	const char *parent, *iface = NULL;
+	const char *parent = NULL;
 
 	if (!NM_DEVICE_CLASS (nm_device_vlan_parent_class)->check_connection_compatible (device, connection))
 		return FALSE;
@@ -415,16 +415,6 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 		}
 	}
 
-	/* Ensure the interface name matches.  If not specified we assume a match
-	 * since both the parent interface and the VLAN ID matched by the time we
-	 * get here.
-	 */
-	iface = nm_connection_get_interface_name (connection);
-	if (iface) {
-		if (g_strcmp0 (nm_device_get_ip_iface (device), iface) != 0)
-			return FALSE;
-	}
-
 	return TRUE;
 }
 
@@ -546,8 +536,6 @@ update_connection (NMDevice *device, NMConnection *connection)
 static NMActStageReturn
 act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 {
-	NMActRequest *req;
-	NMConnection *connection;
 	NMSettingVlan *s_vlan;
 	NMSettingWired *s_wired;
 	const char *cloned_mac;
@@ -559,21 +547,14 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 	if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
 		return ret;
 
-	req = nm_device_get_act_request (dev);
-	g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	connection = nm_act_request_get_applied_connection (req);
-	g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	s_wired = nm_connection_get_setting_wired (connection);
+	s_wired = (NMSettingWired *) nm_device_get_applied_setting (dev, NM_TYPE_SETTING_WIRED);
 	if (s_wired) {
 		/* Set device MAC address if the connection wants to change it */
 		cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
-		if (cloned_mac)
-			nm_device_set_hw_addr (dev, cloned_mac, "set", LOGD_VLAN);
+		nm_device_set_hw_addr (dev, cloned_mac, "set", LOGD_VLAN);
 	}
 
-	s_vlan = nm_connection_get_setting_vlan (connection);
+	s_vlan = (NMSettingVlan *) nm_device_get_applied_setting (dev, NM_TYPE_SETTING_VLAN);
 	if (s_vlan) {
 		gs_free NMVlanQosMapping *ingress_map = NULL;
 		gs_free NMVlanQosMapping *egress_map = NULL;
@@ -765,9 +746,9 @@ get_connection_parent (NMDeviceFactory *factory, NMConnection *connection)
 }
 
 static char *
-get_virtual_iface_name (NMDeviceFactory *factory,
-                        NMConnection *connection,
-                        const char *parent_iface)
+get_connection_iface (NMDeviceFactory *factory,
+                      NMConnection *connection,
+                      const char *parent_iface)
 {
 	const char *ifname;
 	NMSettingVlan *s_vlan;
@@ -796,6 +777,6 @@ NM_DEVICE_FACTORY_DEFINE_INTERNAL (VLAN, Vlan, vlan,
 	NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_VLAN_SETTING_NAME),
 	factory_iface->create_device = create_device;
 	factory_iface->get_connection_parent = get_connection_parent;
-	factory_iface->get_virtual_iface_name = get_virtual_iface_name;
+	factory_iface->get_connection_iface = get_connection_iface;
 	)
 
diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c
index aab90539..79942458 100644
--- a/src/devices/nm-device-vxlan.c
+++ b/src/devices/nm-device-vxlan.c
@@ -18,11 +18,10 @@
  * Copyright 2013 - 2015 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 
-#include "nm-default.h"
 #include "nm-device-vxlan.h"
 #include "nm-device-private.h"
 #include "nm-manager.h"
@@ -224,7 +223,7 @@ create_and_realize (NMDevice *device,
 	props.l3miss = nm_setting_vxlan_get_l3_miss (s_vxlan);
 
 	plerr = nm_platform_link_vxlan_add (NM_PLATFORM_GET, iface, &props, out_plink);
-	if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+	if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 		             "Failed to create VXLAN interface '%s' for '%s': %s",
 		             iface,
@@ -296,7 +295,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 {
 	NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (device);
 	NMSettingVxlan *s_vxlan;
-	const char *iface, *parent;
+	const char *parent;
 
 	if (!NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->check_connection_compatible (device, connection))
 		return FALSE;
@@ -305,12 +304,6 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 	if (!s_vxlan)
 		return FALSE;
 
-	iface = nm_connection_get_interface_name (connection);
-	if (iface) {
-		if (g_strcmp0 (nm_device_get_ip_iface (device), iface) != 0)
-			return FALSE;
-	}
-
 	if (nm_device_is_real (device)) {
 		parent = nm_setting_vxlan_get_parent (s_vxlan);
 		if (   parent
@@ -510,8 +503,6 @@ update_connection (NMDevice *device, NMConnection *connection)
 static NMActStageReturn
 act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
 {
-	NMActRequest *req;
-	NMConnection *connection;
 	NMSettingWired *s_wired;
 	const char *cloned_mac;
 	NMActStageReturn ret;
@@ -522,18 +513,11 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
 	if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
 		return ret;
 
-	req = nm_device_get_act_request (device);
-	g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	connection = nm_act_request_get_applied_connection (req);
-	g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	s_wired = nm_connection_get_setting_wired (connection);
+	s_wired = (NMSettingWired *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRED);
 	if (s_wired) {
 		/* Set device MAC address if the connection wants to change it */
 		cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
-		if (cloned_mac)
-			nm_device_set_hw_addr (device, cloned_mac, "set", LOGD_DEVICE);
+		nm_device_set_hw_addr (device, cloned_mac, "set", LOGD_DEVICE);
 	}
 
 	return NM_ACT_STAGE_RETURN_SUCCESS;
@@ -818,9 +802,9 @@ get_connection_parent (NMDeviceFactory *factory, NMConnection *connection)
 }
 
 static char *
-get_virtual_iface_name (NMDeviceFactory *factory,
-                        NMConnection *connection,
-                        const char *parent_iface)
+get_connection_iface (NMDeviceFactory *factory,
+                      NMConnection *connection,
+                      const char *parent_iface)
 {
 	const char *ifname;
 	NMSettingVxlan *s_vxlan;
@@ -842,6 +826,6 @@ NM_DEVICE_FACTORY_DEFINE_INTERNAL (VXLAN, Vxlan, vxlan,
 	NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_VXLAN_SETTING_NAME),
 	factory_iface->create_device = create_device;
 	factory_iface->get_connection_parent = get_connection_parent;
-	factory_iface->get_virtual_iface_name = get_virtual_iface_name;
+	factory_iface->get_connection_iface = get_connection_iface;
 	)
 
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 93782a45..cdd3f7cb 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -19,7 +19,7 @@
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <netinet/in.h>
 #include <string.h>
@@ -34,7 +34,6 @@
 #include <netlink/route/addr.h>
 #include <linux/if_addr.h>
 
-#include "nm-default.h"
 #include "nm-device.h"
 #include "nm-device-private.h"
 #include "NetworkManagerUtils.h"
@@ -64,6 +63,7 @@
 #include "nm-lldp-listener.h"
 #include "sd-ipv4ll.h"
 #include "nm-audit-manager.h"
+#include "nm-arping-manager.h"
 
 #include "nm-device-logging.h"
 _LOG_DECLARE_SELF (NMDevice);
@@ -94,8 +94,7 @@ enum {
 };
 static guint signals[LAST_SIGNAL] = { 0 };
 
-enum {
-	PROP_0,
+NM_GOBJECT_PROPERTIES_DEFINE (NMDevice,
 	PROP_UDI,
 	PROP_IFACE,
 	PROP_IP_IFACE,
@@ -132,8 +131,7 @@ enum {
 	PROP_LLDP_NEIGHBORS,
 	PROP_REAL,
 	PROP_SLAVES,
-	LAST_PROP
-};
+);
 
 #define DEFAULT_AUTOCONNECT TRUE
 
@@ -193,10 +191,16 @@ typedef struct {
 	int ifindex;
 } DeleteOnDeactivateData;
 
+typedef void (*ArpingCallback) (NMDevice *, NMIP4Config **, gboolean);
+
+typedef struct {
+	ArpingCallback callback;
+	NMDevice *device;
+	NMIP4Config **configs;
+} ArpingData;
+
 typedef struct _NMDevicePrivate {
 	gboolean in_state_changed;
-	gboolean initialized;
-	gboolean platform_link_initialized;
 
 	guint device_link_changed_id;
 	guint device_ip_link_changed_id;
@@ -234,7 +238,7 @@ typedef struct _NMDevicePrivate {
 	char *        physical_port_id;
 	guint         dev_id;
 
-	gboolean                managed_touched_by_user;
+	NMUnmanagedFlags        unmanaged_mask;
 	NMUnmanagedFlags        unmanaged_flags;
 	gboolean                is_nm_owned; /* whether the device is a device owned and created by NM */
 	DeleteOnDeactivateData *delete_on_deactivate_data; /* data for scheduled cleanup when deleting link (g_idle_add) */
@@ -300,7 +304,6 @@ typedef struct _NMDevicePrivate {
 	NMDhcp4Config * dhcp4_config;
 	guint           dhcp4_restart_id;
 
-	guint           arp_round2_id;
 	PingInfo        gw_ping;
 
 	/* dnsmasq stuff for shared connections */
@@ -315,12 +318,19 @@ typedef struct _NMDevicePrivate {
 	sd_ipv4ll *    ipv4ll;
 	guint          ipv4ll_timeout;
 
+	/* IPv4 DAD stuff */
+	struct {
+		GSList *          dad_list;
+		NMArpingManager * announcing;
+	} arping;
+
 	/* IP6 configuration info */
 	NMIP6Config *  ip6_config;
 	IpState        ip6_state;
 	NMIP6Config *  con_ip6_config; /* config from the setting */
 	NMIP6Config *  wwan_ip6_config;
 	NMIP6Config *  ext_ip6_config; /* Stuff added outside NM */
+	NMIP6Config *  ext_ip6_config_captured; /* Configuration captured from platform. */
 	GSList *       vpn6_configs;   /* VPNs which use this device */
 	gboolean       nm_ipv6ll; /* TRUE if NM handles the device's IPv6LL address */
 	guint32        ip6_mtu;
@@ -390,13 +400,10 @@ static void nm_device_slave_notify_enslave (NMDevice *self, gboolean success);
 static void nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason);
 
 static gboolean addrconf6_start_with_link_ready (NMDevice *self);
-static gboolean dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection);
 static NMActStageReturn linklocal6_start (NMDevice *self);
 
 static void _carrier_wait_check_queued_act_request (NMDevice *self);
 
-static gboolean nm_device_get_default_unmanaged (NMDevice *self);
-
 static const char *_activation_func_to_string (ActivationHandleFunc func);
 static void activation_source_handle_cb (NMDevice *self, int family);
 
@@ -408,10 +415,6 @@ static void _set_state_full (NMDevice *self,
 static gboolean queued_ip4_config_change (gpointer user_data);
 static gboolean queued_ip6_config_change (gpointer user_data);
 
-static void _set_unmanaged_flags (NMDevice *self,
-                                  NMUnmanagedFlags flags,
-                                  gboolean unmanaged);
-
 /***********************************************************/
 
 #define QUEUED_PREFIX "queued state change to "
@@ -446,74 +449,75 @@ state_to_string (NMDeviceState state)
 	return queued_state_to_string (state) + strlen (QUEUED_PREFIX);
 }
 
-NM_UTILS_STRING_LOOKUP_TABLE_DEFINE_STATIC (_reason_to_string, NMDeviceStateReason, NULL,
-	[NM_DEVICE_STATE_REASON_UNKNOWN]                  = "unknown",
-	[NM_DEVICE_STATE_REASON_NONE]                     = "none",
-	[NM_DEVICE_STATE_REASON_NOW_MANAGED]              = "managed",
-	[NM_DEVICE_STATE_REASON_NOW_UNMANAGED]            = "unmanaged",
-	[NM_DEVICE_STATE_REASON_CONFIG_FAILED]            = "config-failed",
-	[NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE]    = "ip-config-unavailable",
-	[NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED]        = "ip-config-expired",
-	[NM_DEVICE_STATE_REASON_NO_SECRETS]               = "no-secrets",
-	[NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT]    = "supplicant-disconnect",
-	[NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED] = "supplicant-config-failed",
-	[NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED]        = "supplicant-failed",
-	[NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT]       = "supplicant-timeout",
-	[NM_DEVICE_STATE_REASON_PPP_START_FAILED]         = "ppp-start-failed",
-	[NM_DEVICE_STATE_REASON_PPP_DISCONNECT]           = "ppp-disconnect",
-	[NM_DEVICE_STATE_REASON_PPP_FAILED]               = "ppp-failed",
-	[NM_DEVICE_STATE_REASON_DHCP_START_FAILED]        = "dhcp-start-failed",
-	[NM_DEVICE_STATE_REASON_DHCP_ERROR]               = "dhcp-error",
-	[NM_DEVICE_STATE_REASON_DHCP_FAILED]              = "dhcp-failed",
-	[NM_DEVICE_STATE_REASON_SHARED_START_FAILED]      = "sharing-start-failed",
-	[NM_DEVICE_STATE_REASON_SHARED_FAILED]            = "sharing-failed",
-	[NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED]      = "autoip-start-failed",
-	[NM_DEVICE_STATE_REASON_AUTOIP_ERROR]             = "autoip-error",
-	[NM_DEVICE_STATE_REASON_AUTOIP_FAILED]            = "autoip-failed",
-	[NM_DEVICE_STATE_REASON_MODEM_BUSY]               = "modem-busy",
-	[NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE]       = "modem-no-dialtone",
-	[NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER]         = "modem-no-carrier",
-	[NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT]       = "modem-dial-timeout",
-	[NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED]        = "modem-dial-failed",
-	[NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED]        = "modem-init-failed",
-	[NM_DEVICE_STATE_REASON_GSM_APN_FAILED]           = "gsm-apn-failed",
-	[NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING] = "gsm-registration-idle",
-	[NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED]  = "gsm-registration-denied",
-	[NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT] = "gsm-registration-timeout",
-	[NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED]  = "gsm-registration-failed",
-	[NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED]     = "gsm-pin-check-failed",
-	[NM_DEVICE_STATE_REASON_FIRMWARE_MISSING]         = "firmware-missing",
-	[NM_DEVICE_STATE_REASON_REMOVED]                  = "removed",
-	[NM_DEVICE_STATE_REASON_SLEEPING]                 = "sleeping",
-	[NM_DEVICE_STATE_REASON_CONNECTION_REMOVED]       = "connection-removed",
-	[NM_DEVICE_STATE_REASON_USER_REQUESTED]           = "user-requested",
-	[NM_DEVICE_STATE_REASON_CARRIER]                  = "carrier-changed",
-	[NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED]       = "connection-assumed",
-	[NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE]     = "supplicant-available",
-	[NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND]          = "modem-not-found",
-	[NM_DEVICE_STATE_REASON_BT_FAILED]                = "bluetooth-failed",
-	[NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED]     = "gsm-sim-not-inserted",
-	[NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED]     = "gsm-sim-pin-required",
-	[NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED]     = "gsm-sim-puk-required",
-	[NM_DEVICE_STATE_REASON_GSM_SIM_WRONG]            = "gsm-sim-wrong",
-	[NM_DEVICE_STATE_REASON_INFINIBAND_MODE]          = "infiniband-mode",
-	[NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED]        = "dependency-failed",
-	[NM_DEVICE_STATE_REASON_BR2684_FAILED]            = "br2684-bridge-failed",
-	[NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE] = "modem-manager-unavailable",
-	[NM_DEVICE_STATE_REASON_SSID_NOT_FOUND]           = "ssid-not-found",
-	[NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED] = "secondary-connection-failed",
-	[NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED]          = "dcb-fcoe-failed",
-	[NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED]     = "teamd-control-failed",
-	[NM_DEVICE_STATE_REASON_MODEM_FAILED]             = "modem-failed",
-	[NM_DEVICE_STATE_REASON_MODEM_AVAILABLE]          = "modem-available",
-	[NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT]        = "sim-pin-incorrect",
-	[NM_DEVICE_STATE_REASON_NEW_ACTIVATION]           = "new-activation",
-	[NM_DEVICE_STATE_REASON_PARENT_CHANGED]           = "parent-changed",
-	[NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED]   = "parent-managed-changed",
+NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_reason_to_string, NMDeviceStateReason,
+	NM_UTILS_LOOKUP_DEFAULT (NULL),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_UNKNOWN,                        "unknown"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_NONE,                           "none"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_NOW_MANAGED,                    "managed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_NOW_UNMANAGED,                  "unmanaged"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_CONFIG_FAILED,                  "config-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE,          "ip-config-unavailable"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED,              "ip-config-expired"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_NO_SECRETS,                     "no-secrets"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT,          "supplicant-disconnect"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED,       "supplicant-config-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED,              "supplicant-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT,             "supplicant-timeout"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PPP_START_FAILED,               "ppp-start-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PPP_DISCONNECT,                 "ppp-disconnect"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PPP_FAILED,                     "ppp-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_DHCP_START_FAILED,              "dhcp-start-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_DHCP_ERROR,                     "dhcp-error"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_DHCP_FAILED,                    "dhcp-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SHARED_START_FAILED,            "sharing-start-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SHARED_FAILED,                  "sharing-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED,            "autoip-start-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_AUTOIP_ERROR,                   "autoip-error"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_AUTOIP_FAILED,                  "autoip-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_BUSY,                     "modem-busy"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE,             "modem-no-dialtone"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER,               "modem-no-carrier"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT,             "modem-dial-timeout"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED,              "modem-dial-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED,              "modem-init-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_APN_FAILED,                 "gsm-apn-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING, "gsm-registration-idle"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED,        "gsm-registration-denied"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT,       "gsm-registration-timeout"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED,        "gsm-registration-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED,           "gsm-pin-check-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_FIRMWARE_MISSING,               "firmware-missing"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_REMOVED,                        "removed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SLEEPING,                       "sleeping"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_CONNECTION_REMOVED,             "connection-removed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_USER_REQUESTED,                 "user-requested"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_CARRIER,                        "carrier-changed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED,             "connection-assumed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,           "supplicant-available"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND,                "modem-not-found"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_BT_FAILED,                      "bluetooth-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED,           "gsm-sim-not-inserted"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED,           "gsm-sim-pin-required"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED,           "gsm-sim-puk-required"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_SIM_WRONG,                  "gsm-sim-wrong"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_INFINIBAND_MODE,                "infiniband-mode"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED,              "dependency-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_BR2684_FAILED,                  "br2684-bridge-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE,      "modem-manager-unavailable"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SSID_NOT_FOUND,                 "ssid-not-found"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED,    "secondary-connection-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED,                "dcb-fcoe-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED,           "teamd-control-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_FAILED,                   "modem-failed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_AVAILABLE,                "modem-available"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT,              "sim-pin-incorrect"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_NEW_ACTIVATION,                 "new-activation"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PARENT_CHANGED,                 "parent-changed"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED,         "parent-managed-changed"),
 );
 
 #define reason_to_string(reason) \
-	NM_UTILS_STRING_LOOKUP_TABLE (_reason_to_string, reason)
+	NM_UTILS_LOOKUP_STR (_reason_to_string, reason)
 
 /***********************************************************/
 
@@ -649,7 +653,7 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface)
 
 	/* Emit change notification */
 	if (g_strcmp0 (old_ip_iface, priv->ip_iface))
-		g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE);
+		_notify (self, PROP_IP_IFACE);
 	g_free (old_ip_iface);
 }
 
@@ -772,6 +776,7 @@ nm_device_get_priority (NMDevice *self)
 	switch (nm_device_get_device_type (self)) {
 	/* 50 is reserved for VPN (NM_VPN_ROUTE_METRIC_DEFAULT) */
 	case NM_DEVICE_TYPE_ETHERNET:
+	case NM_DEVICE_TYPE_VETH:
 		return 100;
 	case NM_DEVICE_TYPE_INFINIBAND:
 		return 150;
@@ -981,6 +986,26 @@ nm_device_has_unmodified_applied_connection (NMDevice *self, NMSettingCompareFla
 	return nm_active_connection_has_unmodified_applied_connection ((NMActiveConnection *) priv->act_request, compare_flags);
 }
 
+NMSetting *
+nm_device_get_applied_setting (NMDevice *device, GType setting_type)
+{
+	NMActRequest *req;
+	NMSetting *setting = NULL;
+
+	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
+
+	req = nm_device_get_act_request (device);
+	if (req) {
+		NMConnection *connection;
+
+		connection = nm_act_request_get_applied_connection (req);
+		if (connection)
+			setting = nm_connection_get_setting (connection, setting_type);
+	}
+
+	return setting;
+}
+
 RfKillType
 nm_device_get_rfkill_type (NMDevice *self)
 {
@@ -1158,6 +1183,7 @@ nm_device_master_release_one_slave (NMDevice *self, NMDevice *slave, gboolean co
 	 * when slaves change.
 	 */
 	nm_device_update_hw_address (self);
+	nm_device_set_unmanaged_by_flags (slave, NM_UNMANAGED_IS_SLAVE, NM_UNMAN_FLAG_OP_FORGET, NM_DEVICE_STATE_REASON_REMOVED);
 }
 
 /**
@@ -1173,54 +1199,6 @@ can_unmanaged_external_down (NMDevice *self)
 	return nm_device_is_software (self) && !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned;
 }
 
-/**
- * nm_device_finish_init:
- * @self: the master device
- *
- * Whatever needs to be done post-initialization, when the device has a DBus
- * object name.
- */
-void
-nm_device_finish_init (NMDevice *self)
-{
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-
-	g_assert (priv->initialized == FALSE);
-
-	/* Do not manage externally created software devices until they are IFF_UP */
-	if (   NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)
-	    && priv->ifindex > 0
-	    && (   !priv->up
-	        || !priv->platform_link_initialized))
-		nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_EXTERNAL_DOWN, TRUE);
-
-	if (priv->master)
-		nm_device_master_enslave_slave (priv->master, self, NULL);
-
-	if (priv->ifindex > 0) {
-		if (priv->ifindex == 1) {
-			/* Unmanaged the loopback device with an explicit NM_UNMANAGED_LOOPBACK flag.
-			 * Later we might want to manage 'lo' too. Currently that doesn't work because
-			 * NetworkManager might down the interface or remove the 127.0.0.1 address. */
-			nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_LOOPBACK, TRUE);
-		} else if (priv->platform_link_initialized || (priv->is_nm_owned && nm_device_is_software (self))) {
-			gboolean platform_unmanaged = FALSE;
-
-			if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged))
-				nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_DEFAULT, platform_unmanaged);
-		} else {
-			/* Hardware and externally-created software links stay unmanaged
-			 * until they are fully initialized by the platform. NM created
-			 * links must be available for activation immediately and thus
-			 * do not get the PLATFORM_INIT unmanaged flag set.
-			 */
-			nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_PLATFORM_INIT, TRUE);
-		}
-	}
-
-	priv->initialized = TRUE;
-}
-
 static void
 update_dynamic_ip_setup (NMDevice *self)
 {
@@ -1272,7 +1250,7 @@ carrier_changed (NMDevice *self, gboolean carrier)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
-	if (!nm_device_get_managed (self))
+	if (priv->state <= NM_DEVICE_STATE_UNMANAGED)
 		return;
 
 	nm_device_recheck_available_connections (self);
@@ -1304,8 +1282,6 @@ carrier_changed (NMDevice *self, gboolean carrier)
 	}
 
 	if (carrier) {
-		g_warn_if_fail (priv->state >= NM_DEVICE_STATE_UNAVAILABLE);
-
 		if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) {
 			nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED,
 			                       NM_DEVICE_STATE_REASON_CARRIER);
@@ -1324,8 +1300,6 @@ carrier_changed (NMDevice *self, gboolean carrier)
 			update_dynamic_ip_setup (self);
 		}
 	} else {
-		g_return_if_fail (priv->state >= NM_DEVICE_STATE_UNAVAILABLE);
-
 		if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) {
 			if (nm_device_queued_state_peek (self) >= NM_DEVICE_STATE_DISCONNECTED)
 				nm_device_queued_state_clear (self);
@@ -1378,7 +1352,7 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier)
 		return;
 
 	priv->carrier = carrier;
-	g_object_notify (G_OBJECT (self), NM_DEVICE_CARRIER);
+	_notify (self, PROP_CARRIER);
 
 	if (priv->carrier) {
 		_LOGI (LOGD_DEVICE, "link connected");
@@ -1450,7 +1424,6 @@ device_link_changed (NMDevice *self)
 	NMPlatformLink info;
 	const NMPlatformLink *pllink;
 	int ifindex;
-	gboolean just_initialized = FALSE;
 	gboolean was_up;
 
 	priv->device_link_changed_id = 0;
@@ -1467,26 +1440,26 @@ device_link_changed (NMDevice *self)
 		/* Update UDI to what udev gives us */
 		g_free (priv->udi);
 		priv->udi = g_strdup (udi);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_UDI);
+		_notify (self, PROP_UDI);
 	}
 
 	if (g_strcmp0 (info.driver, priv->driver)) {
 		/* Update driver to what udev gives us */
 		g_free (priv->driver);
 		priv->driver = g_strdup (info.driver);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER);
+		_notify (self, PROP_DRIVER);
 	}
 
 	/* Update MTU if it has changed. */
 	if (priv->mtu != info.mtu) {
 		priv->mtu = info.mtu;
-		g_object_notify (G_OBJECT (self), NM_DEVICE_MTU);
+		_notify (self, PROP_MTU);
 	}
 
 	if (info.driver && g_strcmp0 (priv->driver, info.driver) != 0) {
 		g_free (priv->driver);
 		priv->driver = g_strdup (info.driver);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER);
+		_notify (self, PROP_DRIVER);
 	}
 
 	if (info.name[0] && strcmp (priv->iface, info.name) != 0) {
@@ -1498,9 +1471,9 @@ device_link_changed (NMDevice *self)
 		/* If the device has no explicit ip_iface, then changing iface changes ip_iface too. */
 		ip_ifname_changed = !priv->ip_iface;
 
-		g_object_notify (G_OBJECT (self), NM_DEVICE_IFACE);
+		_notify (self, PROP_IFACE);
 		if (ip_ifname_changed)
-			g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE);
+			_notify (self, PROP_IP_IFACE);
 
 		/* Re-match available connections against the new interface name */
 		nm_device_recheck_available_connections (self);
@@ -1524,71 +1497,62 @@ device_link_changed (NMDevice *self)
 	if (ip_ifname_changed)
 		update_dynamic_ip_setup (self);
 
-	if (priv->ifindex > 0 && !priv->platform_link_initialized && info.initialized) {
-		gboolean platform_unmanaged = FALSE;
-
-		priv->platform_link_initialized = TRUE;
-
-		if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged)) {
-			nm_device_set_unmanaged_flags (self,
-			                               NM_UNMANAGED_DEFAULT,
-			                               platform_unmanaged,
-			                               NM_DEVICE_STATE_REASON_USER_REQUESTED);
-		}
-
-		nm_device_set_unmanaged_flags (self,
-		                               NM_UNMANAGED_PLATFORM_INIT,
-		                               FALSE,
-		                               NM_DEVICE_STATE_REASON_NOW_MANAGED);
-
-		just_initialized = TRUE;
-	}
-
 	was_up = priv->up;
-	priv->up = NM_FLAGS_HAS (info.flags, IFF_UP);
+	priv->up = NM_FLAGS_HAS (info.n_ifi_flags, IFF_UP);
+
+	if (   priv->ifindex > 0
+	    && info.initialized
+	    && nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) {
+		NMDeviceStateReason reason;
+
+		nm_device_set_unmanaged_by_user_udev (self);
+
+		/* If the devices that need an external IFF_UP go managed below,
+		 * it means they're already up. In that case we should use an "assumed"
+		 * reason to prevent the cleanup sequence from being run on transition
+		 * from "unmanaged" to "unavailable". */
+		if (   priv->up
+		    && !nm_device_get_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN)
+		    && NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)) {
+			/* Ensure the assume check is queued before any queued state changes
+			 * from the transition to UNAVAILABLE.
+			 */
+			nm_device_queue_recheck_assume (self);
+			reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED;
+		} else
+			reason = NM_DEVICE_STATE_REASON_NOW_MANAGED;
 
-	if (   priv->platform_link_initialized
-	    && (   just_initialized
-	        || priv->up != was_up)) {
+		nm_device_set_unmanaged_by_flags (self, NM_UNMANAGED_PLATFORM_INIT, FALSE, reason);
+	}
 
+	if (   priv->ifindex > 0
+	    && priv->up != was_up
+	    && NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)) {
 		/* Manage externally-created software interfaces only when they are IFF_UP */
-		g_assert (priv->ifindex > 0);
-		if (NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)) {
-			gboolean external_down = !!nm_device_get_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN);
-
-			if (external_down && NM_FLAGS_HAS (info.flags, IFF_UP)) {
-				if (nm_device_get_state (self) < NM_DEVICE_STATE_DISCONNECTED) {
-					/* Ensure the assume check is queued before any queued state changes
-					 * from the transition to UNAVAILABLE.
-					 */
-					nm_device_queue_recheck_assume (self);
-
-					/* Resetting the EXTERNAL_DOWN flag may change the device's state
-					 * to UNAVAILABLE.  To ensure that the state change doesn't touch
-					 * the device before assumption occurs, pass
-					 * NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED as the reason.
-					 */
-					nm_device_set_unmanaged_flags (self,
-					                               NM_UNMANAGED_EXTERNAL_DOWN,
-					                               FALSE,
-					                               NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
-				} else {
-					/* Don't trigger a state change; if the device is in a
-					 * state higher than UNAVAILABLE, it is already IFF_UP
-					 * or an explicit activation request was received.
-					 */
-					_set_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN, FALSE);
-				}
-			} else if (!external_down && !NM_FLAGS_HAS (info.flags, IFF_UP) && nm_device_get_state (self) <= NM_DEVICE_STATE_DISCONNECTED) {
-				/* If the device is already disconnected and is set !IFF_UP,
-				 * unmanage it.
-				 */
-				nm_device_set_unmanaged_flags (self,
-				                               NM_UNMANAGED_EXTERNAL_DOWN,
-				                               TRUE,
-				                               NM_DEVICE_STATE_REASON_USER_REQUESTED);
-			}
+		if (   priv->up
+		    && nm_device_get_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN)) {
+			/* Ensure the assume check is queued before any queued state changes
+			 * from the transition to UNAVAILABLE.
+			 */
+			nm_device_queue_recheck_assume (self);
 		}
+
+		/* In case of @priv->up, resetting the EXTERNAL_DOWN flag may change the device's
+		 * state to UNAVAILABLE. To ensure that the state change doesn't touch
+		 * the device before assumption occurs, pass NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED
+		 * as the reason.
+		 *
+		 * In case of !@priv->up, and the device is already unmanaged for other reasons, the
+		 * state-change-reason has no effect.
+		 * If the device is managed for an explict user-request, the state-change-reason
+		 * also has no effect, because the device stays managed.
+		 *
+		 * The state-change-reason only has effect if the device was assumed
+		 * and is now to be unmanaged. */
+		nm_device_set_unmanaged_by_flags (self,
+		                                  NM_UNMANAGED_EXTERNAL_DOWN,
+		                                  !priv->up,
+		                                  NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
 	}
 
 	device_recheck_slave_status (self, &info);
@@ -1617,7 +1581,7 @@ device_ip_link_changed (NMDevice *self)
 		g_free (priv->ip_iface);
 		priv->ip_iface = g_strdup (pllink->name);
 
-		g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE);
+		_notify (self, PROP_IP_IFACE);
 		update_dynamic_ip_setup (self);
 	}
 	return G_SOURCE_REMOVE;
@@ -1782,7 +1746,11 @@ nm_device_create_and_realize (NMDevice *self,
 	realize_start_setup (self, plink);
 	nm_device_realize_finish (self, plink);
 
-	g_return_val_if_fail (nm_device_check_connection_compatible (self, connection), TRUE);
+	if (nm_device_get_managed (self, FALSE)) {
+		nm_device_state_changed (self,
+		                         NM_DEVICE_STATE_UNAVAILABLE,
+		                         NM_DEVICE_STATE_REASON_NOW_MANAGED);
+	}
 	return TRUE;
 }
 
@@ -1798,25 +1766,24 @@ update_device_from_platform_link (NMDevice *self, const NMPlatformLink *plink)
 	if (udi && !g_strcmp0 (udi, priv->udi)) {
 		g_free (priv->udi);
 		priv->udi = g_strdup (udi);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_UDI);
+		_notify (self, PROP_UDI);
 	}
 
 	if (!g_strcmp0 (plink->name, priv->iface)) {
 		g_free (priv->iface);
 		priv->iface = g_strdup (plink->name);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_IFACE);
+		_notify (self, PROP_IFACE);
 	}
 
 	priv->ifindex = plink->ifindex;
-	g_object_notify (G_OBJECT (self), NM_DEVICE_IFINDEX);
+	_notify (self, PROP_IFINDEX);
 
-	priv->up = NM_FLAGS_HAS (plink->flags, IFF_UP);
+	priv->up = NM_FLAGS_HAS (plink->n_ifi_flags, IFF_UP);
 	if (plink->driver && g_strcmp0 (plink->driver, priv->driver) != 0) {
 		g_free (priv->driver);
 		priv->driver = g_strdup (plink->driver);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER);
+		_notify (self, PROP_DRIVER);
 	}
-	priv->platform_link_initialized = plink->initialized;
 }
 
 static void
@@ -1874,6 +1841,7 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
 
 	/* The device should not be realized */
 	g_return_if_fail (!priv->real);
+	g_return_if_fail (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT));
 	g_return_if_fail (priv->ip_ifindex <= 0);
 	g_return_if_fail (priv->ip_iface == NULL);
 
@@ -1891,7 +1859,7 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
 
 	if (priv->ifindex > 0) {
 		priv->physical_port_id = nm_platform_link_get_physical_port_id (NM_PLATFORM_GET, priv->ifindex);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_PHYSICAL_PORT_ID);
+		_notify (self, PROP_PHYSICAL_PORT_ID);
 
 		priv->dev_id = nm_platform_link_get_dev_id (NM_PLATFORM_GET, priv->ifindex);
 
@@ -1899,7 +1867,7 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
 			priv->capabilities |= NM_DEVICE_CAP_IS_SOFTWARE;
 
 		priv->mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET, priv->ifindex);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_MTU);
+		_notify (self, PROP_MTU);
 
 		nm_platform_link_get_driver_info (NM_PLATFORM_GET,
 		                                  priv->ifindex,
@@ -1907,9 +1875,9 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
 		                                  &priv->driver_version,
 		                                  &priv->firmware_version);
 		if (priv->driver_version)
-			g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER_VERSION);
+			_notify (self, PROP_DRIVER_VERSION);
 		if (priv->firmware_version)
-			g_object_notify (G_OBJECT (self), NM_DEVICE_FIRMWARE_VERSION);
+			_notify (self, PROP_FIRMWARE_VERSION);
 
 		if (nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET))
 			priv->nm_ipv6ll = nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, priv->ifindex);
@@ -1921,7 +1889,7 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
 	if (!priv->udi) {
 		/* Use a placeholder UDI until we get a real one */
 		priv->udi = g_strdup_printf ("/virtual/device/placeholder/%d", id++);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_UDI);
+		_notify (self, PROP_UDI);
 	}
 
 	/* trigger initial ip config change to initialize ip-config */
@@ -1951,9 +1919,26 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
 		priv->carrier = TRUE;
 	}
 
-	g_object_notify (G_OBJECT (self), NM_DEVICE_CAPABILITIES);
+	_notify (self, PROP_CAPABILITIES);
 
 	klass->realize_start_notify (self, plink);
+
+	/* Do not manage externally created software devices until they are IFF_UP */
+	if (   priv->ifindex > 0
+	    && plink
+	    && !priv->up
+	    && NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self))
+		nm_device_set_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN, TRUE);
+
+	/* Unmanaged the loopback device with an explicit NM_UNMANAGED_LOOPBACK flag.
+	 * Later we might want to manage 'lo' too. Currently that doesn't work because
+	 * NetworkManager might down the interface or remove the 127.0.0.1 address. */
+	nm_device_set_unmanaged_flags (self, NM_UNMANAGED_LOOPBACK, priv->ifindex == 1);
+
+	nm_device_set_unmanaged_by_user_udev (self);
+
+	nm_device_set_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT,
+	                               plink && !plink->initialized);
 }
 
 /**
@@ -1977,17 +1962,15 @@ nm_device_realize_finish (NMDevice *self, const NMPlatformLink *plink)
 
 	g_return_if_fail (!priv->real);
 
-	if (plink) {
-		update_device_from_platform_link (self, plink);
+	if (plink)
 		device_recheck_slave_status (self, plink);
-	}
 
 	priv->real = TRUE;
-	g_object_notify (G_OBJECT (self), NM_DEVICE_REAL);
+	_notify (self, PROP_REAL);
 
 	nm_device_recheck_available_connections (self);
 
-	/* Balanced by a freeze in realize_start_setup() */
+	/* Balanced by a freeze in realize_start_setup(). */
 	g_object_thaw_notify (G_OBJECT (self));
 }
 
@@ -2000,7 +1983,7 @@ unrealize_notify (NMDevice *self)
 }
 
 static gboolean
-available_connection_check_delete_unrealized_on_idle (gpointer user_data)
+available_connections_check_delete_unrealized_on_idle (gpointer user_data)
 {
 	NMDevice *self = user_data;
 	NMDevicePrivate *priv;
@@ -2019,7 +2002,7 @@ available_connection_check_delete_unrealized_on_idle (gpointer user_data)
 }
 
 static void
-available_connection_check_delete_unrealized (NMDevice *self)
+available_connections_check_delete_unrealized (NMDevice *self)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
@@ -2028,7 +2011,7 @@ available_connection_check_delete_unrealized (NMDevice *self)
 
 	if (   g_hash_table_size (priv->available_connections) == 0
 	    && !nm_device_is_real (self))
-		priv->check_delete_unrealized_id = g_idle_add (available_connection_check_delete_unrealized_on_idle, self);
+		priv->check_delete_unrealized_id = g_idle_add (available_connections_check_delete_unrealized_on_idle, self);
 }
 
 /**
@@ -2078,32 +2061,32 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
 
 	if (priv->ifindex > 0) {
 		priv->ifindex = 0;
-		g_object_notify (G_OBJECT (self), NM_DEVICE_IFINDEX);
+		_notify (self, PROP_IFINDEX);
 	}
 	priv->ip_ifindex = 0;
 	if (priv->ip_iface) {
 		g_clear_pointer (&priv->ip_iface, g_free);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE);
+		_notify (self, PROP_IP_IFACE);
 	}
 	if (priv->driver_version) {
 		g_clear_pointer (&priv->driver_version, g_free);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER_VERSION);
+		_notify (self, PROP_DRIVER_VERSION);
 	}
 	if (priv->firmware_version) {
 		g_clear_pointer (&priv->firmware_version, g_free);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_FIRMWARE_VERSION);
+		_notify (self, PROP_FIRMWARE_VERSION);
 	}
 	if (priv->udi) {
 		g_clear_pointer (&priv->udi, g_free);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_UDI);
+		_notify (self, PROP_UDI);
 	}
 	if (priv->hw_addr) {
 		g_clear_pointer (&priv->hw_addr, g_free);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_HW_ADDRESS);
+		_notify (self, PROP_HW_ADDRESS);
 	}
 	if (priv->physical_port_id) {
 		g_clear_pointer (&priv->physical_port_id, g_free);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_PHYSICAL_PORT_ID);
+		_notify (self, PROP_PHYSICAL_PORT_ID);
 	}
 
 	g_clear_pointer (&priv->perm_hw_addr, g_free);
@@ -2112,15 +2095,27 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
 	priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED;
 	if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities)
 		priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self);
-	g_object_notify (G_OBJECT (self), NM_DEVICE_CAPABILITIES);
+	_notify (self, PROP_CAPABILITIES);
 
 	priv->real = FALSE;
-	g_object_notify (G_OBJECT (self), NM_DEVICE_REAL);
+	_notify (self, PROP_REAL);
 
 	nm_device_set_autoconnect (self, DEFAULT_AUTOCONNECT);
 
 	g_object_thaw_notify (G_OBJECT (self));
 
+	nm_device_set_unmanaged_flags (self,
+	                               NM_UNMANAGED_PLATFORM_INIT,
+	                               TRUE);
+
+	nm_device_set_unmanaged_flags (self,
+	                               NM_UNMANAGED_PARENT |
+	                               NM_UNMANAGED_LOOPBACK |
+	                               NM_UNMANAGED_USER_UDEV |
+	                               NM_UNMANAGED_EXTERNAL_DOWN |
+	                               NM_UNMANAGED_IS_SLAVE,
+	                               NM_UNMAN_FLAG_OP_FORGET);
+
 	nm_device_state_changed (self,
 	                         NM_DEVICE_STATE_UNMANAGED,
 	                         remove_resources ?
@@ -2295,10 +2290,13 @@ nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure)
 
 		/* no need to emit
 		 *
-		 *   g_object_notify (G_OBJECT (slave), NM_DEVICE_MASTER);
+		 *   _notify (slave, PROP_MASTER);
 		 *
 		 * because slave_priv->is_enslaved is not true, thus the value
 		 * didn't change yet. */
+
+		g_warn_if_fail (!NM_FLAGS_HAS (slave_priv->unmanaged_mask, NM_UNMANAGED_IS_SLAVE));
+		nm_device_set_unmanaged_by_flags (slave, NM_UNMANAGED_IS_SLAVE, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
 	} else
 		g_return_if_fail (slave_priv->master == self);
 
@@ -2476,8 +2474,8 @@ nm_device_slave_notify_enslave (NMDevice *self, gboolean success)
 				_LOGI (LOGD_DEVICE, "enslaved to %s", nm_device_get_iface (priv->master));
 
 			priv->is_enslaved = TRUE;
-			g_object_notify (G_OBJECT (self), NM_DEVICE_MASTER);
-			g_object_notify (G_OBJECT (priv->master), NM_DEVICE_SLAVES);
+			_notify (self, PROP_MASTER);
+			_notify (priv->master, PROP_SLAVES);
 		} else if (activating) {
 			_LOGW (LOGD_DEVICE, "Activation: connection '%s' could not be enslaved",
 			       nm_connection_get_id (connection));
@@ -2535,8 +2533,8 @@ nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason)
 
 	if (priv->is_enslaved) {
 		priv->is_enslaved = FALSE;
-		g_object_notify (G_OBJECT (self), NM_DEVICE_MASTER);
-		g_object_notify (G_OBJECT (priv->master), NM_DEVICE_SLAVES);
+		_notify (self, PROP_MASTER);
+		_notify (priv->master, PROP_SLAVES);
 	}
 }
 
@@ -2662,19 +2660,12 @@ nm_device_set_autoconnect (NMDevice *self, gboolean autoconnect)
 
 	g_return_if_fail (NM_IS_DEVICE (self));
 
-	priv = NM_DEVICE_GET_PRIVATE (self);
-	if (priv->autoconnect == autoconnect)
-		return;
+	autoconnect = !!autoconnect;
 
-	if (autoconnect) {
-		/* Default-unmanaged devices never autoconnect */
-		if (!nm_device_get_default_unmanaged (self)) {
-			priv->autoconnect = TRUE;
-			g_object_notify (G_OBJECT (self), NM_DEVICE_AUTOCONNECT);
-		}
-	} else {
-		priv->autoconnect = FALSE;
-		g_object_notify (G_OBJECT (self), NM_DEVICE_AUTOCONNECT);
+	priv = NM_DEVICE_GET_PRIVATE (self);
+	if (priv->autoconnect != autoconnect) {
+		priv->autoconnect = autoconnect;
+		_notify (self, PROP_AUTOCONNECT);
 	}
 }
 
@@ -2980,15 +2971,18 @@ nm_device_complete_connection (NMDevice *self,
 static gboolean
 check_connection_compatible (NMDevice *self, NMConnection *connection)
 {
-	NMSettingConnection *s_con;
-	const char *config_iface, *device_iface;
+	const char *device_iface = nm_device_get_iface (self);
+	gs_free char *conn_iface = nm_manager_get_connection_iface (nm_manager_get (),
+	                                                            connection,
+	                                                            NULL, NULL);
 
-	s_con = nm_connection_get_setting_connection (connection);
-	g_assert (s_con);
+	/* We always need a interface name for virtual devices, but for
+	 * physical ones a connection without interface name is fine for
+	 * any device. */
+	if (!conn_iface)
+		return !nm_connection_is_virtual (connection);
 
-	config_iface = nm_setting_connection_get_interface_name (s_con);
-	device_iface = nm_device_get_iface (self);
-	if (config_iface && strcmp (config_iface, device_iface) != 0)
+	if (strcmp (conn_iface, device_iface) != 0)
 		return FALSE;
 
 	return TRUE;
@@ -3401,7 +3395,7 @@ lldp_neighbors_changed (NMLldpListener *lldp_listener, GParamSpec *pspec,
 {
 	NMDevice *self = NM_DEVICE (user_data);
 
-	g_object_notify (G_OBJECT (self), NM_DEVICE_LLDP_NEIGHBORS);
+	_notify (self, PROP_LLDP_NEIGHBORS);
 }
 
 static gboolean
@@ -3457,7 +3451,7 @@ activate_stage1_device_prepare (NMDevice *self)
 	priv->ip4_state = priv->ip6_state = IP_NONE;
 
 	/* Notify the new ActiveConnection along with the state change */
-	g_object_notify (G_OBJECT (self), NM_DEVICE_ACTIVE_CONNECTION);
+	_notify (self, PROP_ACTIVE_CONNECTION);
 
 	nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE);
 
@@ -3629,12 +3623,12 @@ nm_device_activate_schedule_stage2_device_config (NMDevice *self)
 }
 
 /*
- * nm_device_check_ip_failed
+ * check_ip_failed
  *
  * Progress the device to appropriate state if both IPv4 and IPv6 failed
  */
 static void
-nm_device_check_ip_failed (NMDevice *self, gboolean may_fail)
+check_ip_failed (NMDevice *self, gboolean may_fail)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMDeviceState state;
@@ -3664,6 +3658,212 @@ nm_device_check_ip_failed (NMDevice *self, gboolean may_fail)
 	                         NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
 }
 
+/*
+ * check_ip_done
+ *
+ * Progress the device to ip connectivity check state if IPv4 or IPv6 succeeded
+ */
+static void
+check_ip_done (NMDevice *self)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+	if (nm_device_get_state (self) != NM_DEVICE_STATE_IP_CONFIG)
+		return;
+
+	if (priv->ip4_state != IP_DONE && !get_ip_config_may_fail (self, AF_INET))
+		return;
+
+	if (priv->ip6_state != IP_DONE && !get_ip_config_may_fail (self, AF_INET6))
+		return;
+
+	nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE);
+}
+
+/*********************************************/
+/* IPv4 DAD stuff */
+
+static guint
+get_ipv4_dad_timeout (NMDevice *self)
+{
+	NMConnection *connection;
+	NMSettingIPConfig *s_ip4 = NULL;
+	gs_free char *value = NULL;
+	gint ret = 0;
+
+	connection = nm_device_get_applied_connection (self);
+	if (connection)
+		s_ip4 = nm_connection_get_setting_ip4_config (connection);
+
+	if (s_ip4) {
+		ret = nm_setting_ip_config_get_dad_timeout (s_ip4);
+
+		if (ret < 0) {
+			value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
+			                                               "ipv4.dad-timeout", self);
+			ret = _nm_utils_ascii_str_to_int64 (value, 10, -1,
+			                                    NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX,
+			                                    -1);
+			ret = ret < 0 ? 0 : ret;
+		}
+	}
+
+	return ret;
+}
+
+static void
+arping_data_destroy (gpointer ptr, GClosure *closure)
+{
+	ArpingData *data = ptr;
+	int i;
+
+	if (data) {
+		for (i = 0; data->configs && data->configs[i]; i++)
+			g_object_unref (data->configs[i]);
+		g_free (data->configs);
+		g_slice_free (ArpingData, data);
+	}
+}
+
+static void
+ipv4_manual_method_apply (NMDevice *self, NMIP4Config **configs, gboolean success)
+{
+	NMIP4Config *empty;
+
+	if (success) {
+		empty = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
+		nm_device_activate_schedule_ip4_config_result (self, empty);
+		g_object_unref (empty);
+	} else {
+		nm_device_queue_state (self, NM_DEVICE_STATE_FAILED,
+		                       NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+	}
+}
+
+static void
+arping_manager_probe_terminated (NMArpingManager *arping_manager, ArpingData *data)
+{
+	NMDevice *self;
+	NMDevicePrivate *priv;
+	const NMPlatformIP4Address *address;
+	gboolean result, success = TRUE;
+	int i, j;
+
+	g_assert (data);
+	self = data->device;
+	priv = NM_DEVICE_GET_PRIVATE (self);
+
+	for (i = 0; data->configs && data->configs[i]; i++) {
+		for (j = 0; j < nm_ip4_config_get_num_addresses (data->configs[i]); j++) {
+			address = nm_ip4_config_get_address (data->configs[i], j);
+			result = nm_arping_manager_check_address (arping_manager, address->address);
+			success &= result;
+
+			_NMLOG (result ? LOGL_DEBUG : LOGL_WARN,
+			        LOGD_DEVICE,
+			        "IPv4 DAD result: address %s is %s",
+			        nm_utils_inet4_ntop (address->address, NULL),
+			        result ? "unique" : "duplicate");
+		}
+	}
+
+	data->callback (self, data->configs, success);
+
+	priv->arping.dad_list = g_slist_remove (priv->arping.dad_list, arping_manager);
+	nm_arping_manager_destroy (arping_manager);
+}
+
+/**
+ * ipv4_dad_start:
+ * @self: device instance
+ * @configs: NULL-terminated array of IPv4 configurations
+ * @cb: callback function
+ *
+ * Start IPv4 DAD on device @self, check addresses in @configs and call @cb
+ * when the procedure ends. @cb will be called in any case, even if DAD can't
+ * be started. @configs will be unreferenced after @cb has been called.
+ */
+static void
+ipv4_dad_start (NMDevice *self, NMIP4Config **configs, ArpingCallback cb)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMArpingManager *arping_manager;
+	const NMPlatformIP4Address *address;
+	ArpingData *data;
+	guint timeout;
+	gboolean ret, addr_found;
+	const guint8 *hw_addr;
+	size_t hw_addr_len = 0;
+	GError *error = NULL;
+	guint i, j;
+
+	g_return_if_fail (NM_IS_DEVICE (self));
+	g_return_if_fail (configs);
+	g_return_if_fail (cb);
+
+	for (i = 0, addr_found = FALSE; configs[i]; i++) {
+		if (nm_ip4_config_get_num_addresses (configs[i]) > 0) {
+			addr_found = TRUE;
+			break;
+		}
+	}
+
+	timeout = get_ipv4_dad_timeout (self);
+	hw_addr = nm_platform_link_get_address (NM_PLATFORM_GET,
+	                                        nm_device_get_ip_ifindex (self),
+	                                        &hw_addr_len);
+
+	if (   !timeout
+	    || !hw_addr
+	    || !hw_addr_len
+	    || !addr_found
+	    || nm_device_uses_assumed_connection (self)) {
+
+		/* DAD not needed, signal success */
+		cb (self, configs, TRUE);
+
+		for (i = 0; configs[i]; i++)
+			g_object_unref (configs[i]);
+		g_free (configs);
+
+		return;
+	}
+
+	/* don't take additional references of @arping_manager that outlive @self.
+	 * Otherwise, the callback can be invoked on a dangling pointer as we don't
+	 * disconnect the handler. */
+	arping_manager = nm_arping_manager_new (nm_device_get_ip_ifindex (self));
+	priv->arping.dad_list = g_slist_append (priv->arping.dad_list, arping_manager);
+
+	data = g_slice_new0 (ArpingData);
+	data->configs = configs;
+	data->callback = cb;
+	data->device = self;
+
+	for (i = 0; configs[i]; i++) {
+		for (j = 0; j < nm_ip4_config_get_num_addresses (configs[i]); j++) {
+			address = nm_ip4_config_get_address (configs[i], j);
+			nm_arping_manager_add_address (arping_manager, address->address);
+		}
+	}
+
+	g_signal_connect_data (arping_manager, NM_ARPING_MANAGER_PROBE_TERMINATED,
+	                       G_CALLBACK (arping_manager_probe_terminated), data,
+	                       arping_data_destroy, 0);
+
+	ret = nm_arping_manager_start_probe (arping_manager, timeout, &error);
+
+	if (!ret) {
+		_LOGW (LOGD_DEVICE, "arping probe failed: %s", error->message);
+
+		/* DAD could not be started, signal success */
+		cb (self, configs, TRUE);
+
+		priv->arping.dad_list = g_slist_remove (priv->arping.dad_list, arping_manager);
+		nm_arping_manager_destroy (arping_manager);
+	}
+}
+
 /*********************************************/
 /* IPv4LL stuff */
 
@@ -3738,14 +3938,14 @@ nm_device_handle_ipv4ll_event (sd_ipv4ll *ll, int event, void *data)
 		if (r < 0) {
 			_LOGE (LOGD_AUTOIP4, "invalid IPv4 link-local address received, error %d.", r);
 			priv->ip4_state = IP_FAIL;
-			nm_device_check_ip_failed (self, FALSE);
+			check_ip_failed (self, FALSE);
 			return;
 		}
 
 		if ((address.s_addr & IPV4LL_NETMASK) != IPV4LL_NETWORK) {
 			_LOGE (LOGD_AUTOIP4, "invalid address %08x received (not link-local).", address.s_addr);
 			priv->ip4_state = IP_FAIL;
-			nm_device_check_ip_failed (self, FALSE);
+			check_ip_failed (self, FALSE);
 			return;
 		}
 
@@ -3753,7 +3953,7 @@ nm_device_handle_ipv4ll_event (sd_ipv4ll *ll, int event, void *data)
 		if (config == NULL) {
 			_LOGE (LOGD_AUTOIP4, "failed to get IPv4LL config");
 			priv->ip4_state = IP_FAIL;
-			nm_device_check_ip_failed (self, FALSE);
+			check_ip_failed (self, FALSE);
 			return;
 		}
 
@@ -3764,7 +3964,7 @@ nm_device_handle_ipv4ll_event (sd_ipv4ll *ll, int event, void *data)
 			if (!ip4_config_merge_and_apply (self, config, TRUE, NULL)) {
 				_LOGE (LOGD_AUTOIP4, "failed to update IP4 config for autoip change.");
 				priv->ip4_state = IP_FAIL;
-				nm_device_check_ip_failed (self, FALSE);
+				check_ip_failed (self, FALSE);
 			}
 		} else
 			g_assert_not_reached ();
@@ -3774,7 +3974,7 @@ nm_device_handle_ipv4ll_event (sd_ipv4ll *ll, int event, void *data)
 	default:
 		_LOGW (LOGD_AUTOIP4, "IPv4LL address no longer valid after event %d.", event);
 		priv->ip4_state = IP_FAIL;
-		nm_device_check_ip_failed (self, FALSE);
+		check_ip_failed (self, FALSE);
 	}
 }
 
@@ -3985,7 +4185,7 @@ dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release)
 
 	if (priv->dhcp4_config) {
 		nm_exported_object_clear_and_unexport (&priv->dhcp4_config);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP4_CONFIG);
+		_notify (self, PROP_DHCP4_CONFIG);
 	}
 }
 
@@ -4156,6 +4356,8 @@ END_ADD_DEFAULT_ROUTE:
 		priv->default_route.v4_has = _device_get_default_route_from_platform (self, AF_INET, (NMPlatformIPRoute *) &priv->default_route.v4);
 	}
 
+	nm_ip4_config_addresses_sort (composite);
+
 	/* Allow setting MTU etc */
 	if (commit) {
 		if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit)
@@ -4253,6 +4455,17 @@ dhcp4_fail (NMDevice *self, gboolean timeout)
 }
 
 static void
+dhcp4_dad_cb (NMDevice *self, NMIP4Config **configs, gboolean success)
+{
+	if (success)
+		nm_device_activate_schedule_ip4_config_result (self, configs[1]);
+	else {
+		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED,
+		                         NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+	}
+}
+
+static void
 dhcp4_state_changed (NMDhcpClient *client,
                      NMDhcpState state,
                      NMIP4Config *ip4_config,
@@ -4262,6 +4475,8 @@ dhcp4_state_changed (NMDhcpClient *client,
 {
 	NMDevice *self = NM_DEVICE (user_data);
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMIP4Config *manual, **configs;
+	NMConnection *connection;
 
 	g_return_if_fail (nm_dhcp_client_get_ipv6 (client) == FALSE);
 	g_return_if_fail (!ip4_config || NM_IS_IP4_CONFIG (ip4_config));
@@ -4279,11 +4494,23 @@ dhcp4_state_changed (NMDhcpClient *client,
 		}
 
 		nm_dhcp4_config_set_options (priv->dhcp4_config, options);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP4_CONFIG);
+		_notify (self, PROP_DHCP4_CONFIG);
 
-		if (priv->ip4_state == IP_CONF)
-			nm_device_activate_schedule_ip4_config_result (self, ip4_config);
-		else if (priv->ip4_state == IP_DONE) {
+		if (priv->ip4_state == IP_CONF) {
+			connection = nm_device_get_applied_connection (self);
+			g_assert (connection);
+
+			manual = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
+			nm_ip4_config_merge_setting (manual,
+			                             nm_connection_get_setting_ip4_config (connection),
+			                             nm_device_get_ip4_route_metric (self));
+
+			configs = g_new0 (NMIP4Config *, 3);
+			configs[0] = manual;
+			configs[1] = g_object_ref (ip4_config);
+
+			ipv4_dad_start (self, configs, dhcp4_dad_cb);
+		} else if (priv->ip4_state == IP_DONE) {
 			dhcp4_lease_change (self, ip4_config);
 			nm_device_update_metered (self);
 		}
@@ -4312,7 +4539,7 @@ dhcp4_get_timeout (NMDevice *self, NMSettingIP4Config *s_ip4)
 	gs_free char *value = NULL;
 	int timeout;
 
-	timeout = nm_setting_ip4_config_get_dhcp_timeout (s_ip4);
+	timeout = nm_setting_ip_config_get_dhcp_timeout (NM_SETTING_IP_CONFIG (s_ip4));
 	if (timeout)
 		return timeout;
 
@@ -4629,10 +4856,17 @@ act_stage3_ip4_config_start (NMDevice *self,
 	else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL) == 0)
 		ret = ipv4ll_start (self, reason);
 	else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL) == 0) {
-		/* Use only IPv4 config from the connection data */
-		*out_config = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
-		g_assert (*out_config);
-		ret = NM_ACT_STAGE_RETURN_SUCCESS;
+		NMIP4Config **configs, *config;
+
+		config = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
+		nm_ip4_config_merge_setting (config,
+		                             nm_connection_get_setting_ip4_config (connection),
+		                             nm_device_get_ip4_route_metric (self));
+
+		configs = g_new0 (NMIP4Config *, 2);
+		configs[0] = config;
+		ipv4_dad_start (self, configs, ipv4_manual_method_apply);
+		ret = NM_ACT_STAGE_RETURN_POSTPONE;
 	} else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) {
 		*out_config = shared4_new_config (self, connection, reason);
 		if (*out_config) {
@@ -4676,7 +4910,7 @@ dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release)
 
 	if (priv->dhcp6_config) {
 		nm_exported_object_clear_and_unexport (&priv->dhcp6_config);
-		g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP6_CONFIG);
+		_notify (self, PROP_DHCP6_CONFIG);
 	}
 }
 
@@ -5011,7 +5245,7 @@ dhcp6_state_changed (NMDhcpClient *client,
 				priv->dhcp6_ip6_config = g_object_ref (ip6_config);
 				priv->dhcp6_event_id = g_strdup (event_id);
 				nm_dhcp6_config_set_options (priv->dhcp6_config, options);
-				g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP6_CONFIG);
+				_notify (self, PROP_DHCP6_CONFIG);
 			}
 		}
 
@@ -5057,9 +5291,7 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
 	GByteArray *tmp = NULL;
 	const guint8 *hw_addr;
 	size_t hw_addr_len = 0;
-	const struct in6_addr *ll_addr = NULL;
-	NMIP6Config *ip6_config;
-	int i;
+	const NMPlatformIP6Address *ll_addr = NULL;
 
 	g_assert (connection);
 	s_ip6 = nm_connection_get_setting_ip6_config (connection);
@@ -5071,22 +5303,16 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
 		g_byte_array_append (tmp, hw_addr, hw_addr_len);
 	}
 
-	ip6_config = priv->ext_ip6_config;
-	for (i = 0; ip6_config && i < nm_ip6_config_get_num_addresses (ip6_config); i++) {
-		const NMPlatformIP6Address *addr = nm_ip6_config_get_address (ip6_config, i);
+	if (priv->ext_ip6_config_captured)
+		ll_addr = nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE);
 
-		if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) {
-			ll_addr = &addr->address;
-			break;
-		}
-	}
 	g_return_val_if_fail (ll_addr, FALSE);
 
 	priv->dhcp6_client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (),
 	                                                nm_device_get_ip_iface (self),
 	                                                nm_device_get_ip_ifindex (self),
 	                                                tmp,
-	                                                ll_addr,
+	                                                &ll_addr->address,
 	                                                nm_connection_get_uuid (connection),
 	                                                nm_device_get_ip6_route_metric (self),
 	                                                nm_setting_ip_config_get_dhcp_send_hostname (s_ip6),
@@ -5169,27 +5395,6 @@ nm_device_dhcp6_renew (NMDevice *self, gboolean release)
 
 /******************************************/
 
-static gboolean
-have_ip6_address (const NMIP6Config *ip6_config, gboolean linklocal)
-{
-	guint i;
-
-	if (!ip6_config)
-		return FALSE;
-
-	linklocal = !!linklocal;
-
-	for (i = 0; i < nm_ip6_config_get_num_addresses (ip6_config); i++) {
-		const NMPlatformIP6Address *addr = nm_ip6_config_get_address (ip6_config, i);
-
-		if ((IN6_IS_ADDR_LINKLOCAL (&addr->address) == linklocal) &&
-		    !(addr->flags & IFA_F_TENTATIVE))
-			return TRUE;
-	}
-
-	return FALSE;
-}
-
 static void
 linklocal6_cleanup (NMDevice *self)
 {
@@ -5223,7 +5428,7 @@ linklocal6_complete (NMDevice *self)
 	const char *method;
 
 	g_assert (priv->linklocal6_timeout_id);
-	g_assert (have_ip6_address (priv->ip6_config, TRUE));
+	g_assert (nm_ip6_config_get_address_first_nontentative (priv->ip6_config, TRUE));
 
 	linklocal6_cleanup (self);
 
@@ -5271,7 +5476,7 @@ check_and_add_ipv6ll_addr (NMDevice *self)
 
 			addr = nm_ip6_config_get_address (priv->ip6_config, i);
 			if (   IN6_IS_ADDR_LINKLOCAL (&addr->address)
-			    && !(addr->flags & IFA_F_DADFAILED)) {
+			    && !(addr->n_ifa_flags & IFA_F_DADFAILED)) {
 				/* Already have an LL address, nothing to do */
 				return;
 			}
@@ -5288,9 +5493,9 @@ check_and_add_ipv6ll_addr (NMDevice *self)
 	if (s_ip6 && nm_setting_ip6_config_get_addr_gen_mode (s_ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) {
 		if (!nm_utils_ipv6_addr_set_stable_privacy (&lladdr,
 		                                            nm_device_get_iface (self),
-			                                    nm_connection_get_uuid (connection),
+		                                            nm_connection_get_uuid (connection),
 		                                            priv->linklocal6_dad_counter++,
-			                                    &error)) {
+		                                            &error)) {
 			_LOGW (LOGD_IP6, "linklocal6: failed to generate an address: %s", error->message);
 			g_clear_error (&error);
 			linklocal6_failed (self);
@@ -5340,7 +5545,8 @@ linklocal6_start (NMDevice *self)
 
 	linklocal6_cleanup (self);
 
-	if (have_ip6_address (priv->ip6_config, TRUE))
+	if (   priv->ip6_config
+	    && nm_ip6_config_get_address_first_nontentative (priv->ip6_config, TRUE))
 		return NM_ACT_STAGE_RETURN_FINISH;
 
 	connection = nm_device_get_applied_connection (self);
@@ -5421,7 +5627,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self)
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	int i;
 	int system_support;
-	guint ifa_flags = 0x00;
+	guint32 ifa_flags = 0x00;
 
 	/*
 	 * Check, whether kernel is recent enough to help user space handling RA.
@@ -5477,7 +5683,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self)
 			if (address.preferred > address.lifetime)
 				address.preferred = address.lifetime;
 			address.source = NM_IP_CONFIG_SOURCE_RDISC;
-			address.flags = ifa_flags;
+			address.n_ifa_flags = ifa_flags;
 
 			nm_ip6_config_add_address (priv->ac_ip6_config, &address);
 		}
@@ -5575,7 +5781,8 @@ rdisc_ra_timeout (NMRDisc *rdisc, NMDevice *self)
 		 * IPv6 configuration, like manual IPv6 addresses or external IPv6
 		 * config, consider that sufficient for IPv6 success.
 		 */
-		if (have_ip6_address (priv->ip6_config, FALSE))
+		if (   priv->ip6_config
+		    && nm_ip6_config_get_address_first_nontentative (priv->ip6_config, FALSE))
 			nm_device_activate_schedule_ip6_config_result (self);
 		else
 			nm_device_activate_schedule_ip6_config_timeout (self);
@@ -5769,7 +5976,7 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable)
 
 		if (enable) {
 			/* Bounce IPv6 to ensure the kernel stops IPv6LL address generation */
-			value = nm_platform_sysctl_get (NM_PLATFORM_GET, 
+			value = nm_platform_sysctl_get (NM_PLATFORM_GET,
 			                                nm_utils_ip6_property_path (nm_device_get_ip_iface (self), "disable_ipv6"));
 			if (g_strcmp0 (value, "0") == 0)
 				nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1");
@@ -6054,8 +6261,7 @@ nm_device_activate_stage3_ip6_start (NMDevice *self)
 	} else if (ret == NM_ACT_STAGE_RETURN_FINISH) {
 		/* Early finish, nothing more to do */
 		priv->ip6_state = IP_DONE;
-		if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG)
-			nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE);
+		check_ip_done (self);
 	} else if (ret == NM_ACT_STAGE_RETURN_WAIT) {
 		/* Wait for something to try IP config again */
 		priv->ip6_state = IP_WAIT;
@@ -6116,7 +6322,7 @@ activate_stage3_ip_config_start (NMDevice *self)
 	    && !nm_device_activate_stage3_ip6_start (self))
 		return;
 
-	nm_device_check_ip_failed (self, TRUE);
+	check_ip_failed (self, TRUE);
 }
 
 static gboolean
@@ -6251,7 +6457,7 @@ activate_stage4_ip4_config_timeout (NMDevice *self)
 
 	priv->ip4_state = IP_FAIL;
 
-	nm_device_check_ip_failed (self, FALSE);
+	check_ip_failed (self, FALSE);
 }
 
 
@@ -6311,7 +6517,7 @@ activate_stage4_ip6_config_timeout (NMDevice *self)
 
 	priv->ip6_state = IP_FAIL;
 
-	nm_device_check_ip_failed (self, FALSE);
+	check_ip_failed (self, FALSE);
 }
 
 
@@ -6410,16 +6616,16 @@ start_sharing (NMDevice *self, NMIP4Config *config)
 	req = nm_device_get_act_request (self);
 	g_assert (req);
 
-	add_share_rule (req, "filter", "INPUT --in-interface %s --protocol tcp --destination-port 53 --jump ACCEPT", ip_iface);
-	add_share_rule (req, "filter", "INPUT --in-interface %s --protocol udp --destination-port 53 --jump ACCEPT", ip_iface);
-	add_share_rule (req, "filter", "INPUT --in-interface %s --protocol tcp --destination-port 67 --jump ACCEPT", ip_iface);
-	add_share_rule (req, "filter", "INPUT --in-interface %s --protocol udp --destination-port 67 --jump ACCEPT", ip_iface);
-	add_share_rule (req, "filter", "FORWARD --in-interface %s --jump REJECT", ip_iface);
-	add_share_rule (req, "filter", "FORWARD --out-interface %s --jump REJECT", ip_iface);
-	add_share_rule (req, "filter", "FORWARD --in-interface %s --out-interface %s --jump ACCEPT", ip_iface, ip_iface);
-	add_share_rule (req, "filter", "FORWARD --source %s/%s --in-interface %s --jump ACCEPT", str_addr, str_mask, ip_iface);
-	add_share_rule (req, "filter", "FORWARD --destination %s/%s --out-interface %s --match state --state ESTABLISHED,RELATED --jump ACCEPT", str_addr, str_mask, ip_iface);
 	add_share_rule (req, "nat", "POSTROUTING --source %s/%s ! --destination %s/%s --jump MASQUERADE", str_addr, str_mask, str_addr, str_mask);
+	add_share_rule (req, "filter", "FORWARD --destination %s/%s --out-interface %s --match state --state ESTABLISHED,RELATED --jump ACCEPT", str_addr, str_mask, ip_iface);
+	add_share_rule (req, "filter", "FORWARD --source %s/%s --in-interface %s --jump ACCEPT", str_addr, str_mask, ip_iface);
+	add_share_rule (req, "filter", "FORWARD --in-interface %s --out-interface %s --jump ACCEPT", ip_iface, ip_iface);
+	add_share_rule (req, "filter", "FORWARD --out-interface %s --jump REJECT", ip_iface);
+	add_share_rule (req, "filter", "FORWARD --in-interface %s --jump REJECT", ip_iface);
+	add_share_rule (req, "filter", "INPUT --in-interface %s --protocol udp --destination-port 67 --jump ACCEPT", ip_iface);
+	add_share_rule (req, "filter", "INPUT --in-interface %s --protocol tcp --destination-port 67 --jump ACCEPT", ip_iface);
+	add_share_rule (req, "filter", "INPUT --in-interface %s --protocol udp --destination-port 53 --jump ACCEPT", ip_iface);
+	add_share_rule (req, "filter", "INPUT --in-interface %s --protocol tcp --destination-port 53 --jump ACCEPT", ip_iface);
 
 	nm_act_request_set_shared (req, TRUE);
 
@@ -6438,77 +6644,14 @@ start_sharing (NMDevice *self, NMIP4Config *config)
 }
 
 static void
-send_arps (NMDevice *self, const char *mode_arg)
-{
-	const char *argv[] = { NULL, mode_arg, "-q", "-I", nm_device_get_ip_iface (self), "-c", "1", NULL, NULL };
-	int ip_arg = G_N_ELEMENTS (argv) - 2;
-	NMConnection *connection;
-	NMSettingIPConfig *s_ip4;
-	int i, num;
-	NMIPAddress *addr;
-	GError *error = NULL;
-
-	connection = nm_device_get_applied_connection (self);
-	if (!connection)
-		return;
-	s_ip4 = nm_connection_get_setting_ip4_config (connection);
-	if (!s_ip4)
-		return;
-	num = nm_setting_ip_config_get_num_addresses (s_ip4);
-	if (num == 0)
-		return;
-
-	argv[0] = nm_utils_find_helper ("arping", NULL, NULL);
-	if (!argv[0]) {
-		_LOGW (LOGD_DEVICE | LOGD_IP4, "arping could not be found; no ARPs will be sent");
-		return;
-	}
-
-	for (i = 0; i < num; i++) {
-		gs_free char *tmp_str = NULL;
-		gboolean success;
-
-		addr = nm_setting_ip_config_get_address (s_ip4, i);
-		argv[ip_arg] = nm_ip_address_get_address (addr);
-
-		_LOGD (LOGD_DEVICE | LOGD_IP4,
-		       "arping: run %s", (tmp_str = g_strjoinv (" ", (char **) argv)));
-		success = g_spawn_async (NULL, (char **) argv, NULL,
-		                         G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
-		                         NULL, NULL, NULL, &error);
-		if (!success) {
-			_LOGW (LOGD_DEVICE | LOGD_IP4,
-			       "arping: could not send ARP for local address %s: %s",
-			       argv[ip_arg], error->message);
-			g_clear_error (&error);
-		}
-	}
-}
-
-static gboolean
-arp_announce_round2 (gpointer user_data)
-{
-	NMDevice *self = user_data;
-	NMDevicePrivate *priv;
-
-	g_return_val_if_fail (NM_IS_DEVICE (self), G_SOURCE_REMOVE);
-
-	priv = NM_DEVICE_GET_PRIVATE (self);
-	priv->arp_round2_id = 0;
-
-	if (   priv->state >= NM_DEVICE_STATE_IP_CONFIG
-	    && priv->state <= NM_DEVICE_STATE_ACTIVATED)
-		send_arps (self, "-U");
-
-	return G_SOURCE_REMOVE;
-}
-
-static void
 arp_cleanup (NMDevice *self)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
-	nm_clear_g_source (&priv->arp_round2_id);
+	if (priv->arping.announcing) {
+		nm_arping_manager_destroy (priv->arping.announcing);
+		priv->arping.announcing = NULL;
+	}
 }
 
 static void
@@ -6517,10 +6660,19 @@ arp_announce (NMDevice *self)
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMConnection *connection;
 	NMSettingIPConfig *s_ip4;
-	int num;
+	guint num, i;
+	const guint8 *hw_addr;
+	size_t hw_addr_len = 0;
 
 	arp_cleanup (self);
 
+	hw_addr = nm_platform_link_get_address (NM_PLATFORM_GET,
+	                                        nm_device_get_ip_ifindex (self),
+	                                        &hw_addr_len);
+
+	if (!hw_addr_len || !hw_addr)
+		return;
+
 	/* We only care about manually-configured addresses; DHCP- and autoip-configured
 	 * ones should already have been seen on the network at this point.
 	 */
@@ -6534,8 +6686,19 @@ arp_announce (NMDevice *self)
 	if (num == 0)
 		return;
 
-	send_arps (self, "-A");
-	priv->arp_round2_id = g_timeout_add_seconds (2, arp_announce_round2, self);
+	priv->arping.announcing = nm_arping_manager_new (nm_device_get_ip_ifindex (self));
+
+	for (i = 0; i < num; i++) {
+		NMIPAddress *ip = nm_setting_ip_config_get_address (s_ip4, i);
+		in_addr_t addr;
+
+		if (inet_pton (AF_INET, nm_ip_address_get_address (ip), &addr) == 1)
+			nm_arping_manager_add_address (priv->arping.announcing, addr);
+		else
+			g_warn_if_reached ();
+	}
+
+	nm_arping_manager_announce_addresses (priv->arping.announcing);
 }
 
 static void
@@ -6597,13 +6760,11 @@ activate_stage5_ip4_config_commit (NMDevice *self)
 
 	arp_announce (self);
 
-	/* Enter the IP_CHECK state if this is the first method to complete */
-	priv->ip4_state = IP_DONE;
-
 	nm_device_remove_pending_action (self, PENDING_ACTION_DHCP4, FALSE);
 
-	if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG)
-		nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE);
+	/* Enter the IP_CHECK state if this is the first method to complete */
+	priv->ip4_state = IP_DONE;
+	check_ip_done (self);
 }
 
 static void
@@ -6690,26 +6851,24 @@ activate_stage5_ip6_config_commit (NMDevice *self)
 				 * then ensure dispatcher scripts get the DHCP lease information.
 				 */
 				nm_dispatcher_call (DISPATCHER_ACTION_DHCP6_CHANGE,
-						    nm_device_get_settings_connection (self),
-						    nm_device_get_applied_connection (self),
-						    self,
-						    NULL,
-						    NULL,
-						    NULL);
+				                    nm_device_get_settings_connection (self),
+				                    nm_device_get_applied_connection (self),
+				                    self,
+				                    NULL,
+				                    NULL,
+				                    NULL);
 			} else {
 				/* still waiting for first dhcp6 lease. */
 				return;
 			}
 		}
 
-		/* Enter the IP_CHECK state if this is the first method to complete */
-		priv->ip6_state = IP_DONE;
-
 		nm_device_remove_pending_action (self, PENDING_ACTION_DHCP6, FALSE);
 		nm_device_remove_pending_action (self, PENDING_ACTION_AUTOCONF6, FALSE);
 
-		if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG)
-			nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE);
+		/* Enter the IP_CHECK state if this is the first method to complete */
+		priv->ip6_state = IP_DONE;
+		check_ip_done (self);
 	} else {
 		_LOGW (LOGD_DEVICE | LOGD_IP6, "Activation: Stage 5 of 5 (IPv6 Commit) failed");
 		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
@@ -6760,7 +6919,7 @@ clear_act_request (NMDevice *self)
 	nm_clear_g_signal_handler (priv->act_request, &priv->master_ready_id);
 
 	g_clear_object (&priv->act_request);
-	g_object_notify (G_OBJECT (self), NM_DEVICE_ACTIVE_CONNECTION);
+	_notify (self, PROP_ACTIVE_CONNECTION);
 }
 
 static void
@@ -6792,7 +6951,7 @@ _update_ip4_address (NMDevice *self)
 		addr = nm_ip4_config_get_address (priv->ip4_config, 0)->address;
 		if (addr != priv->ip4_address) {
 			priv->ip4_address = addr;
-			g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_ADDRESS);
+			_notify (self, PROP_IP4_ADDRESS);
 		}
 	}
 }
@@ -6911,25 +7070,23 @@ _cleanup_ip6_pre (NMDevice *self, CleanupType cleanup_type)
 	addrconf6_cleanup (self);
 }
 
-G_GNUC_NULL_TERMINATED
 static gboolean
-_hash_check_invalid_keys (GHashTable *hash, const char *setting_name, GError **error, ...)
+_hash_check_invalid_keys_impl (GHashTable *hash, const char *setting_name, GError **error, const char **argv)
 {
-	va_list ap;
-	const char *key;
 	guint found_keys = 0;
+	guint i;
+
+	nm_assert (argv && argv[0]);
 
 #if NM_MORE_ASSERTS > 10
 	/* Assert that the keys are unique. */
 	{
 		gs_unref_hashtable GHashTable *check_dups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
 
-		va_start (ap, error);
-		while ((key = va_arg (ap, const char *))) {
-			if (!g_hash_table_add (check_dups, (char *) key))
+		for (i = 0; argv[i]; i++) {
+			if (!g_hash_table_add (check_dups, (char *) argv[i]))
 				nm_assert (FALSE);
 		}
-		va_end (ap);
 		nm_assert (g_hash_table_size (check_dups) > 0);
 	}
 #endif
@@ -6937,12 +7094,10 @@ _hash_check_invalid_keys (GHashTable *hash, const char *setting_name, GError **e
 	if (!hash || g_hash_table_size (hash) == 0)
 		return TRUE;
 
-	va_start (ap, error);
-	while ((key = va_arg (ap, const char *))) {
-		if (g_hash_table_contains (hash, key))
+	for (i = 0; argv[i]; i++) {
+		if (g_hash_table_contains (hash, argv[i]))
 			found_keys++;
 	}
-	va_end (ap);
 
 	if (found_keys != g_hash_table_size (hash)) {
 		GHashTableIter iter;
@@ -6954,14 +7109,12 @@ _hash_check_invalid_keys (GHashTable *hash, const char *setting_name, GError **e
 
 		g_hash_table_iter_init (&iter, hash);
 		while (g_hash_table_iter_next (&iter, (gpointer *) &k, NULL)) {
-			va_start (ap, error);
-			while ((key = va_arg (ap, const char *))) {
-				if (!strcmp (key, k)) {
+			for (i = 0; argv[i]; i++) {
+				if (!strcmp (argv[i], k)) {
 					first_invalid_key = k;
 					break;
 				}
 			}
-			va_end (ap);
 			if (first_invalid_key)
 				break;
 		}
@@ -6978,6 +7131,7 @@ _hash_check_invalid_keys (GHashTable *hash, const char *setting_name, GError **e
 
 	return TRUE;
 }
+#define _hash_check_invalid_keys(hash, setting_name, error, ...) _hash_check_invalid_keys_impl (hash, setting_name, error, ((const char *[]) { __VA_ARGS__, NULL }))
 
 void
 nm_device_reactivate_ip4_config (NMDevice *self,
@@ -7002,8 +7156,10 @@ nm_device_reactivate_ip4_config (NMDevice *self,
 			priv->ip4_state = IP_WAIT;
 			if (!nm_device_activate_stage3_ip4_start (self))
 				_LOGW (LOGD_IP4, "Failed to apply IPv4 configuration");
-		} else
-			ip4_config_merge_and_apply (self, NULL, TRUE, NULL);
+		} else {
+			if (!ip4_config_merge_and_apply (self, NULL, TRUE, NULL))
+				_LOGW (LOGD_IP4, "Failed to reapply IPv4 configuration");
+		}
 	}
 }
 
@@ -7030,8 +7186,10 @@ nm_device_reactivate_ip6_config (NMDevice *self,
 			priv->ip6_state = IP_WAIT;
 			if (!nm_device_activate_stage3_ip6_start (self))
 				_LOGW (LOGD_IP6, "Failed to apply IPv6 configuration");
-		} else
-			ip6_config_merge_and_apply (self, TRUE, NULL);
+		} else {
+			if (!ip6_config_merge_and_apply (self, TRUE, NULL))
+				_LOGW (LOGD_IP4, "Failed to reapply IPv6 configuration");
+		}
 	}
 }
 
@@ -7039,6 +7197,8 @@ nm_device_reactivate_ip6_config (NMDevice *self,
 /* reapply_connection:
  * @connection: the new connection settings to be applied or %NULL to reapply
  *   the current settings connection
+ * @version_id: either zero, or the current version id for the applied
+ *   connection.
  * @error: the error if %FALSE is returned
  *
  * Change configuration of an already configured device if possible.
@@ -7049,6 +7209,7 @@ nm_device_reactivate_ip6_config (NMDevice *self,
 static gboolean
 reapply_connection (NMDevice *self,
                     NMConnection *connection,
+                    guint64 version_id,
                     GError **error)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
@@ -7079,24 +7240,36 @@ reapply_connection (NMDevice *self,
 	if (!_hash_check_invalid_keys (diffs, NULL, error,
 	                               NM_SETTING_IP4_CONFIG_SETTING_NAME,
 	                               NM_SETTING_IP6_CONFIG_SETTING_NAME,
-	                               NM_SETTING_CONNECTION_SETTING_NAME,
-	                               NULL))
+	                               NM_SETTING_CONNECTION_SETTING_NAME))
 		return FALSE;
 
 	if (!_hash_check_invalid_keys (diffs ? g_hash_table_lookup (diffs, NM_SETTING_CONNECTION_SETTING_NAME) : NULL,
 	                               NM_SETTING_CONNECTION_SETTING_NAME,
 	                               error,
 	                               NM_SETTING_CONNECTION_ZONE,
-	                               NM_SETTING_CONNECTION_METERED,
-	                               NULL))
+	                               NM_SETTING_CONNECTION_METERED))
 		return FALSE;
 
-	_LOGD (LOGD_DEVICE, "reapply");
+	if (   version_id != 0
+	    && version_id != nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request)) {
+		g_set_error_literal (error,
+		                     NM_DEVICE_ERROR,
+		                     NM_DEVICE_ERROR_VERSION_ID_MISMATCH,
+		                     "Reapply failed because device changed in the meantime and the version-id mismatches");
+		return FALSE;
+	}
 
 	/**************************************************************************
 	 * Update applied connection
 	 *************************************************************************/
 
+	if (diffs)
+		nm_active_connection_version_id_bump ((NMActiveConnection *) priv->act_request);
+
+	_LOGD (LOGD_DEVICE, "reapply (version-id %llu%s)",
+	       (long long unsigned) nm_active_connection_version_id_get (((NMActiveConnection *) priv->act_request)),
+	       diffs ? "" : " (unmodified)");
+
 	if (diffs) {
 		con_old = applied_clone  = nm_simple_connection_new_clone (applied);
 		con_new = applied;
@@ -7122,6 +7295,11 @@ reapply_connection (NMDevice *self,
 	return TRUE;
 }
 
+typedef struct {
+	NMConnection *connection;
+	guint64 version_id;
+} ReapplyData;
+
 static void
 reapply_cb (NMDevice *self,
             GDBusMethodInvocation *context,
@@ -7129,9 +7307,17 @@ reapply_cb (NMDevice *self,
             GError *error,
             gpointer user_data)
 {
-	gs_unref_object NMConnection *connection = NM_CONNECTION (user_data);
+	ReapplyData *reapply_data = user_data;
+	guint64 version_id = 0;
+	gs_unref_object NMConnection *connection = NULL;
 	GError *local = NULL;
 
+	if (reapply_data) {
+		connection = reapply_data->connection;
+		version_id = reapply_data->version_id;
+		g_slice_free (ReapplyData, reapply_data);
+	}
+
 	if (error) {
 		nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, subject, error->message);
 		g_dbus_method_invocation_return_gerror (context, error);
@@ -7140,6 +7326,7 @@ reapply_cb (NMDevice *self,
 
 	if (!reapply_connection (self,
 	                         connection ? : (NMConnection *) nm_device_get_settings_connection (self),
+	                         version_id,
 	                         &local)) {
 		nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, subject, local->message);
 		g_dbus_method_invocation_take_error (context, local);
@@ -7154,17 +7341,19 @@ static void
 impl_device_reapply (NMDevice *self,
                      GDBusMethodInvocation *context,
                      GVariant *settings,
-                     guint flags)
+                     guint64 version_id,
+                     guint32 flags)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMSettingsConnection *settings_connection;
 	NMConnection *connection = NULL;
 	GError *error = NULL;
+	ReapplyData *reapply_data;
 
 	/* No flags supported as of now. */
 	if (flags != 0) {
 		error = g_error_new_literal (NM_DEVICE_ERROR,
-		                             NM_DEVICE_ERROR_NOT_ACTIVE,
+		                             NM_DEVICE_ERROR_FAILED,
 		                             "Invalid flags specified");
 		nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message);
 		g_dbus_method_invocation_take_error (context, error);
@@ -7195,6 +7384,13 @@ impl_device_reapply (NMDevice *self,
 		nm_connection_clear_secrets (connection);
 	}
 
+	if (connection || version_id) {
+		reapply_data = g_slice_new (ReapplyData);
+		reapply_data->connection = connection;
+		reapply_data->version_id = version_id;
+	} else
+		reapply_data = NULL;
+
 	/* Ask the manager to authenticate this request for us */
 	g_signal_emit (self, signals[AUTH_REQUEST], 0,
 	               context,
@@ -7202,10 +7398,104 @@ impl_device_reapply (NMDevice *self,
 	               NM_AUTH_PERMISSION_NETWORK_CONTROL,
 	               TRUE,
 	               reapply_cb,
-	               connection);
+	               reapply_data);
+}
+
+/*****************************************************************************/
+
+static void
+get_applied_connection_cb (NMDevice *self,
+                           GDBusMethodInvocation *context,
+                           NMAuthSubject *subject,
+                           GError *error,
+                           gpointer user_data /* possibly dangling pointer */)
+{
+	NMDevicePrivate *priv;
+	NMConnection *applied_connection;
+	GVariant *settings;
+
+	g_return_if_fail (NM_IS_DEVICE (self));
+
+	if (error) {
+		g_dbus_method_invocation_return_gerror (context, error);
+		return;
+	}
+
+	priv = NM_DEVICE_GET_PRIVATE (self);
+
+	applied_connection = nm_device_get_applied_connection (self);
+
+	if (!applied_connection) {
+		error = g_error_new_literal (NM_DEVICE_ERROR,
+		                             NM_DEVICE_ERROR_NOT_ACTIVE,
+		                             "Device is not activated");
+		g_dbus_method_invocation_take_error (context, error);
+		return;
+	}
+
+	if (applied_connection != user_data) {
+		/* The applied connection changed due to a race. Reauthenticate. */
+		g_signal_emit (self, signals[AUTH_REQUEST], 0,
+		               context,
+		               applied_connection,
+		               NM_AUTH_PERMISSION_NETWORK_CONTROL,
+		               TRUE,
+		               get_applied_connection_cb,
+		               applied_connection /* no need take a ref. We will not dereference this pointer. */);
+		return;
+	}
+
+	settings = nm_connection_to_dbus (applied_connection, NM_CONNECTION_SERIALIZE_NO_SECRETS);
+	if (!settings)
+		settings = g_variant_new_array (G_VARIANT_TYPE ("{sa{sv}}"), NULL, 0);
+
+	g_dbus_method_invocation_return_value (context,
+	                                       g_variant_new ("(@a{sa{sv}}t)",
+	                                                      settings,
+	                                                      nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request)));
 }
 
 static void
+impl_device_get_applied_connection (NMDevice *self,
+                                    GDBusMethodInvocation *context,
+                                    guint32 flags)
+{
+	NMConnection *applied_connection;
+	GError *error = NULL;
+
+	g_return_if_fail (NM_IS_DEVICE (self));
+
+	/* No flags supported as of now. */
+	if (flags != 0) {
+		error = g_error_new_literal (NM_DEVICE_ERROR,
+		                             NM_DEVICE_ERROR_FAILED,
+		                             "Invalid flags specified");
+		g_dbus_method_invocation_take_error (context, error);
+		return;
+	}
+
+	applied_connection = nm_device_get_applied_connection (self);
+	if (!applied_connection) {
+		error = g_error_new_literal (NM_DEVICE_ERROR,
+		                             NM_DEVICE_ERROR_NOT_ACTIVE,
+		                             "Device is not activated");
+		g_dbus_method_invocation_take_error (context, error);
+		return;
+	}
+
+	/* Ask the manager to authenticate this request for us */
+	g_signal_emit (self, signals[AUTH_REQUEST], 0,
+	               context,
+	               applied_connection,
+	               NM_AUTH_PERMISSION_NETWORK_CONTROL,
+	               TRUE,
+	               get_applied_connection_cb,
+	               applied_connection /* no need take a ref. We will not dereference this pointer. */);
+}
+
+/*****************************************************************************/
+
+static void
 disconnect_cb (NMDevice *self,
                GDBusMethodInvocation *context,
                NMAuthSubject *subject,
@@ -7329,6 +7619,7 @@ _device_activate (NMDevice *self, NMActRequest *req)
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
 	g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE);
+	g_return_val_if_fail (nm_device_get_managed (self, FALSE), FALSE);
 
 	/* Ensure the activation request is still valid; the master may have
 	 * already failed in which case activation of this device should not proceed.
@@ -7347,13 +7638,6 @@ _device_activate (NMDevice *self, NMActRequest *req)
 
 	delete_on_deactivate_unschedule (self);
 
-	/* Move default unmanaged devices to DISCONNECTED state here */
-	if (nm_device_get_default_unmanaged (self) && priv->state == NM_DEVICE_STATE_UNMANAGED) {
-		nm_device_state_changed (self,
-		                         NM_DEVICE_STATE_DISCONNECTED,
-		                         NM_DEVICE_STATE_REASON_NOW_MANAGED);
-	}
-
 	/* note: don't notify D-Bus of the new AC here, but do it later when
 	 * changing state to PREPARE so that the two properties change together.
 	 */
@@ -7602,7 +7886,7 @@ nm_device_set_ip4_config (NMDevice *self,
 		_update_ip4_address (self);
 
 		if (old_config != priv->ip4_config)
-			g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_CONFIG);
+			_notify (self, PROP_IP4_CONFIG);
 		g_signal_emit (self, signals[IP4_CONFIG_CHANGED], 0, priv->ip4_config, old_config);
 
 		if (old_config != priv->ip4_config)
@@ -7769,7 +8053,7 @@ nm_device_set_ip6_config (NMDevice *self,
 
 	if (has_changes) {
 		if (old_config != priv->ip6_config)
-			g_object_notify (G_OBJECT (self), NM_DEVICE_IP6_CONFIG);
+			_notify (self, PROP_IP6_CONFIG);
 		g_signal_emit (self, signals[IP6_CONFIG_CHANGED], 0, priv->ip6_config, old_config);
 
 		if (old_config != priv->ip6_config)
@@ -8275,7 +8559,7 @@ nm_device_set_firmware_missing (NMDevice *self, gboolean new_missing)
 	priv = NM_DEVICE_GET_PRIVATE (self);
 	if (priv->firmware_missing != new_missing) {
 		priv->firmware_missing = new_missing;
-		g_object_notify (G_OBJECT (self), NM_DEVICE_FIRMWARE_MISSING);
+		_notify (self, PROP_FIRMWARE_MISSING);
 	}
 }
 
@@ -8295,7 +8579,7 @@ nm_device_set_nm_plugin_missing (NMDevice *self, gboolean new_missing)
 	priv = NM_DEVICE_GET_PRIVATE (self);
 	if (priv->nm_plugin_missing != new_missing) {
 		priv->nm_plugin_missing = new_missing;
-		g_object_notify (G_OBJECT (self), NM_DEVICE_NM_PLUGIN_MISSING);
+		_notify (self, PROP_NM_PLUGIN_MISSING);
 	}
 }
 
@@ -8507,7 +8791,6 @@ update_ip6_config (NMDevice *self, gboolean initial)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	int ifindex;
-	gboolean linklocal6_just_completed = FALSE;
 	gboolean capture_resolv_conf;
 	NMDnsManagerResolvConfMode resolv_conf_mode;
 
@@ -8520,12 +8803,11 @@ update_ip6_config (NMDevice *self, gboolean initial)
 
 	/* IPv6 */
 	g_clear_object (&priv->ext_ip6_config);
-	priv->ext_ip6_config = nm_ip6_config_capture (ifindex, capture_resolv_conf, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
-	if (priv->ext_ip6_config) {
+	g_clear_object (&priv->ext_ip6_config_captured);
+	priv->ext_ip6_config_captured = nm_ip6_config_capture (ifindex, capture_resolv_conf, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
+	if (priv->ext_ip6_config_captured) {
 
-		/* Check this before modifying ext_ip6_config */
-		linklocal6_just_completed = priv->linklocal6_timeout_id &&
-		                            have_ip6_address (priv->ext_ip6_config, TRUE);
+		priv->ext_ip6_config = nm_ip6_config_new_cloned (priv->ext_ip6_config_captured);
 
 		/* This function was called upon external changes. Remove the configuration
 		 * (addresses,routes) that is no longer present externally from the internal
@@ -8557,7 +8839,9 @@ update_ip6_config (NMDevice *self, gboolean initial)
 		ip6_config_merge_and_apply (self, FALSE, NULL);
 	}
 
-	if (linklocal6_just_completed) {
+	if (   priv->linklocal6_timeout_id
+	    && priv->ext_ip6_config_captured
+	    && nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE)) {
 		/* linklocal6 is ready now, do the state transition... we are also
 		 * invoked as g_idle_add, so no problems with reentrance doing it now.
 		 */
@@ -8673,8 +8957,8 @@ device_ipx_changed (NMPlatform *platform,
 
 		if (   priv->state > NM_DEVICE_STATE_DISCONNECTED
 		    && priv->state < NM_DEVICE_STATE_DEACTIVATING
-                    && (   (change_type == NM_PLATFORM_SIGNAL_CHANGED && addr->flags & IFA_F_DADFAILED)
-		        || (change_type == NM_PLATFORM_SIGNAL_REMOVED && addr->flags & IFA_F_TENTATIVE))) {
+		    && (   (change_type == NM_PLATFORM_SIGNAL_CHANGED && addr->n_ifa_flags & IFA_F_DADFAILED)
+		        || (change_type == NM_PLATFORM_SIGNAL_REMOVED && addr->n_ifa_flags & IFA_F_TENTATIVE))) {
 			priv->dad6_failed_addrs = g_slist_append (priv->dad6_failed_addrs,
 			                                          g_memdup (addr, sizeof (NMPlatformIP6Address)));
 		}
@@ -8690,119 +8974,319 @@ device_ipx_changed (NMPlatform *platform,
 	}
 }
 
+/*****************************************************************************/
+
+NM_UTILS_FLAGS2STR_DEFINE (nm_unmanaged_flags2str, NMUnmanagedFlags,
+	NM_UTILS_FLAGS2STR (NM_UNMANAGED_SLEEPING, "sleeping"),
+	NM_UTILS_FLAGS2STR (NM_UNMANAGED_QUITTING, "quitting"),
+	NM_UTILS_FLAGS2STR (NM_UNMANAGED_PARENT, "parent"),
+	NM_UTILS_FLAGS2STR (NM_UNMANAGED_LOOPBACK, "loopback"),
+	NM_UTILS_FLAGS2STR (NM_UNMANAGED_PLATFORM_INIT, "platform-init"),
+	NM_UTILS_FLAGS2STR (NM_UNMANAGED_USER_EXPLICIT, "user-explicit"),
+	NM_UTILS_FLAGS2STR (NM_UNMANAGED_BY_DEFAULT, "by-default"),
+	NM_UTILS_FLAGS2STR (NM_UNMANAGED_USER_SETTINGS, "user-settings"),
+	NM_UTILS_FLAGS2STR (NM_UNMANAGED_USER_UDEV, "user-udev"),
+	NM_UTILS_FLAGS2STR (NM_UNMANAGED_EXTERNAL_DOWN, "external-down"),
+	NM_UTILS_FLAGS2STR (NM_UNMANAGED_IS_SLAVE, "is-slave"),
+);
+
+static const char *
+_unmanaged_flags2str (NMUnmanagedFlags flags, NMUnmanagedFlags mask, char *buf, gsize len)
+{
+	char buf2[512];
+	char *b;
+	char *tmp, *tmp2;
+	gsize l;
+
+	nm_utils_to_string_buffer_init (&buf, &len);
+	if (!len)
+		return buf;
+
+	b = buf;
+
+	mask |= flags;
+
+	nm_unmanaged_flags2str (flags, b, len);
+	l = strlen (b);
+	b += l;
+	len -= l;
+
+	nm_unmanaged_flags2str (mask & ~flags, buf2, sizeof (buf2));
+	if (buf2[0]) {
+		gboolean add_separator = l > 0;
+
+		tmp = buf2;
+		while (TRUE) {
+			if (add_separator)
+				nm_utils_strbuf_append_c (&b, &len, ',');
+			add_separator = TRUE;
+
+			tmp2 = strchr (tmp, ',');
+			if (tmp2)
+				tmp2[0] = '\0';
+
+			nm_utils_strbuf_append_c (&b, &len, '!');
+			nm_utils_strbuf_append_str (&b, &len, tmp);
+			if (!tmp2)
+				break;
+
+			tmp = &tmp2[1];
+		}
+	}
+
+	return buf;
+}
+
+static gboolean
+_get_managed_by_flags(NMUnmanagedFlags flags, NMUnmanagedFlags mask, gboolean for_user_request)
+{
+	/* Evaluate the managed state based on the unmanaged flags.
+	 *
+	 * Some flags are authoritative, meaning they always cause
+	 * the device to be unmanaged (e.g. @NM_UNMANAGED_PLATFORM_INIT).
+	 *
+	 * OTOH, some flags can be overwritten. For example NM_UNMANAGED_USER_SETTINGS
+	 * is ignored once NM_UNMANAGED_USER_EXPLICIT is set. The idea is that
+	 * the flag from the configuration has no effect once the user explicitly
+	 * touches the unmanaged flags. */
+
+	if (for_user_request) {
+
+		/* @for_user_request can make the result only ~more~ managed.
+		 * If the flags already indicate a managed state for a non-user-request,
+		 * then it is also managed for an explict user-request.
+		 *
+		 * Effectively, this check is redundant, as the code below already
+		 * already ensures that. Still, express this invariant explictly here. */
+		if (_get_managed_by_flags (flags, mask, FALSE))
+			return TRUE;
+
+		/* A for-user-request, is effectively the same as pretending
+		 * that user-dbus flag is cleared. */
+		mask |= NM_UNMANAGED_USER_EXPLICIT;
+		flags &= ~NM_UNMANAGED_USER_EXPLICIT;
+	}
+
+	if (   NM_FLAGS_ANY (mask, NM_UNMANAGED_USER_SETTINGS)
+	    && !NM_FLAGS_ANY (flags, NM_UNMANAGED_USER_SETTINGS)) {
+		/* NM_UNMANAGED_USER_SETTINGS can only explicitly unmanage a device. It cannot
+		 * *manage* it. Having NM_UNMANAGED_USER_SETTINGS explicitly not set, is the
+		 * same as having it not set at all. */
+		mask &= ~NM_UNMANAGED_USER_SETTINGS;
+	}
+
+	if (NM_FLAGS_ANY (mask, NM_UNMANAGED_USER_UDEV)) {
+		/* configuration from udev or nm-config overwrites the by-default flag
+		 * which is based on the device type. */
+		flags &= ~NM_UNMANAGED_BY_DEFAULT;
+	}
+
+	if (   NM_FLAGS_HAS (mask, NM_UNMANAGED_IS_SLAVE)
+	    && !NM_FLAGS_HAS (flags, NM_UNMANAGED_IS_SLAVE)) {
+		/* for an enslaved device, by-default doesn't matter */
+		flags &= ~NM_UNMANAGED_BY_DEFAULT;
+	}
+
+	if (NM_FLAGS_HAS (mask, NM_UNMANAGED_USER_EXPLICIT)) {
+		/* if the device is managed by user-decision, certain other flags
+		 * are ignored. */
+
+		flags &= ~(  NM_UNMANAGED_BY_DEFAULT
+		           | NM_UNMANAGED_USER_UDEV
+		           | NM_UNMANAGED_EXTERNAL_DOWN);
+	}
+
+	return flags == NM_UNMANAGED_NONE;
+}
+
 /**
- * nm_device_get_managed():
+ * nm_device_get_managed:
  * @self: the #NMDevice
+ * @for_user_request: whether to check the flags for an explict user-request
+ *
+ * Whether the device is unmanaged according to the unmanaged flags.
  *
- * Returns: %TRUE if the device is managed
+ * Returns: %TRUE if the device is unmanaged because of the flags.
  */
 gboolean
-nm_device_get_managed (NMDevice *self)
+nm_device_get_managed (NMDevice *self, gboolean for_user_request)
 {
 	NMDevicePrivate *priv;
-	gboolean managed;
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
 
-	priv = NM_DEVICE_GET_PRIVATE (self);
+	if (!nm_device_is_real (self)) {
+		/* a unrealized device is always considered unmanaged. */
+		return FALSE;
+	}
 
-	/* Return the composite of all managed flags.  However, if the device
-	 * is a default-unmanaged device, and would be managed except for the
-	 * default-unmanaged flag (eg, only NM_UNMANAGED_DEFAULT is set) then
-	 * the device is managed whenever it's not in the UNMANAGED state.
-	 */
-	managed = !NM_FLAGS_ANY (priv->unmanaged_flags, ~NM_UNMANAGED_DEFAULT);
-	if (managed && NM_FLAGS_HAS (priv->unmanaged_flags, NM_UNMANAGED_DEFAULT))
-		managed = (priv->state > NM_DEVICE_STATE_UNMANAGED);
+	priv = NM_DEVICE_GET_PRIVATE (self);
 
-	return managed;
+	return _get_managed_by_flags (priv->unmanaged_flags, priv->unmanaged_mask, for_user_request);
 }
 
 /**
- * nm_device_get_unmanaged_flags():
+ * nm_device_get_unmanaged_flags:
  * @self: the #NMDevice
- * @flag: return only the selected flags
+ * @flag: the unmanaged flags to check.
+ *
+ * Return the unmanaged flags of the device.
  *
- * Returns: the unmanage flags of the device (filtered with @flag)
+ * Returns: the flags of the device ( & @flag)
  */
 NMUnmanagedFlags
 nm_device_get_unmanaged_flags (NMDevice *self, NMUnmanagedFlags flag)
 {
+	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
+	g_return_val_if_fail (flag != NM_UNMANAGED_NONE, FALSE);
+
 	return NM_DEVICE_GET_PRIVATE (self)->unmanaged_flags & flag;
 }
 
 /**
- * nm_device_get_default_unmanaged():
- * @self: the #NMDevice
+ * _set_unmanaged_flags:
+ * @self: the #NMDevice instance
+ * @flags: which #NMUnmanagedFlags to set.
+ * @set_op: whether to set/clear/forget the flags. You can also pass
+ *   boolean values %TRUE and %FALSE, which mean %NM_UNMAN_FLAG_OP_SET_UNMANAGED
+ *   and %NM_UNMAN_FLAG_OP_SET_MANAGED, respectively.
+ * @allow_state_transition: if %FALSE, setting flags never triggers a device
+ *   state change. If %TRUE, the device can change state, if it is real and
+ *   switches from managed to unmanaged (or vice versa).
+ * @reason: the device state reason passed to nm_device_state_changed() if
+ *   the device becomes managed/unmanaged. This is only relevant if the
+ *   device switches state and if @allow_state_transition is %TRUE.
  *
- * Returns: %TRUE if the device is by default unmanaged
- */
-static gboolean
-nm_device_get_default_unmanaged (NMDevice *self)
-{
-	return !!nm_device_get_unmanaged_flags (self, NM_UNMANAGED_DEFAULT);
-}
-
+ * Set the unmanaged flags of the device.
+ **/
 static void
 _set_unmanaged_flags (NMDevice *self,
                       NMUnmanagedFlags flags,
-                      gboolean unmanaged)
-{
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-
-	if (unmanaged) {
-		if (!NM_FLAGS_ALL (priv->unmanaged_flags, flags)) {
-			_LOGD (LOGD_DEVICE, "unmanaged: flags set to 0x%0llx (was 0x%0llx, %s 0x%0llx)",
-			       (long long unsigned) (priv->unmanaged_flags | flags),
-			       (long long unsigned) priv->unmanaged_flags,
-			       "set",
-			       (long long unsigned) flags);
-			priv->unmanaged_flags |= flags;
-		}
-	} else {
-		if (NM_FLAGS_ANY (priv->unmanaged_flags, flags)) {
-			_LOGD (LOGD_DEVICE, "unmanaged: flags set to 0x%0llx (was 0x%0llx, %s 0x%0llx)",
-			       (long long unsigned) (priv->unmanaged_flags & (~flags)),
-			       (long long unsigned) priv->unmanaged_flags,
-			       "clear",
-			       (long long unsigned) flags);
-			priv->unmanaged_flags &= ~flags;
-		}
-	}
-}
-
-void
-nm_device_set_unmanaged_flags (NMDevice *self,
-                               NMUnmanagedFlags flag,
-                               gboolean unmanaged,
-                               NMDeviceStateReason reason)
+                      NMUnmanFlagOp set_op,
+                      gboolean allow_state_transition,
+                      NMDeviceStateReason reason)
 {
 	NMDevicePrivate *priv;
-	gboolean was_managed, now_managed;
+	gboolean was_managed, transition_state;
+	NMUnmanagedFlags old_flags, old_mask;
+	const char *operation = NULL;
+	char str1[512];
+	char str2[512];
 
 	g_return_if_fail (NM_IS_DEVICE (self));
-	g_return_if_fail (flag <= NM_UNMANAGED_LAST);
+	g_return_if_fail (flags);
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
 
-	was_managed = nm_device_get_managed (self);
-	_set_unmanaged_flags (self, flag, unmanaged);
-	now_managed = nm_device_get_managed (self);
+	if (!priv->real)
+		allow_state_transition = FALSE;
+	was_managed = allow_state_transition && nm_device_get_managed (self, FALSE);
+
+	old_flags = priv->unmanaged_flags;
+	old_mask = priv->unmanaged_mask;
 
-	if (was_managed != now_managed) {
-		_LOGD (LOGD_DEVICE, "now %s", unmanaged ? "unmanaged" : "managed");
+	switch (set_op) {
+	case NM_UNMAN_FLAG_OP_FORGET:
+		priv->unmanaged_mask &= ~flags;
+		priv->unmanaged_flags &= ~flags;
+		operation = "forget";
+		break;
+	case NM_UNMAN_FLAG_OP_SET_UNMANAGED:
+		priv->unmanaged_mask |= flags;
+		priv->unmanaged_flags |= flags;
+		operation = "set-unmanaged";
+		break;
+	case NM_UNMAN_FLAG_OP_SET_MANAGED:
+		priv->unmanaged_mask |= flags;
+		priv->unmanaged_flags &= ~flags;
+		operation = "set-managed";
+		break;
+	default:
+		g_return_if_reached ();
+	}
 
-		g_object_notify (G_OBJECT (self), NM_DEVICE_MANAGED);
+	if (   old_flags == priv->unmanaged_flags
+	    && old_mask == priv->unmanaged_mask)
+		return;
 
-		if (unmanaged)
+	transition_state =    allow_state_transition
+	                   && was_managed != nm_device_get_managed (self, FALSE)
+	                   && (   was_managed
+	                       || (   !was_managed
+	                           && nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED));
+
+#define _FMTX "[%s%s0x%0x/0x%x/%s"
+#define _FMT(flags, mask, str) \
+	_unmanaged_flags2str ((flags), (mask), str, sizeof (str)), \
+	((flags) | (mask)) ? "=" : "", \
+	(flags), \
+	(mask), \
+	(_get_managed_by_flags (flags, mask, FALSE) \
+	     ? "managed" \
+	     : (_get_managed_by_flags (flags, mask, TRUE) \
+	            ? "manageable" \
+	            : "unmanaged"))
+	_LOGD (LOGD_DEVICE, "unmanaged: flags set to "_FMTX"%s, %s [%s=0x%0x]%s%s%s)",
+	       _FMT (priv->unmanaged_flags, priv->unmanaged_mask, str1),
+	       priv->real ? "" : "/unrealized",
+	       operation,
+	       nm_unmanaged_flags2str (flags, str2, sizeof (str2)),
+	       flags,
+	       NM_PRINT_FMT_QUOTED (allow_state_transition,
+	                            ", reason ",
+	                            reason_to_string (reason),
+	                            transition_state ? ", transition-state" : "",
+	                            ""));
+#undef _FMT
+
+	if (transition_state) {
+		if (was_managed)
 			nm_device_state_changed (self, NM_DEVICE_STATE_UNMANAGED, reason);
-		else if (nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED)
+		else
 			nm_device_state_changed (self, NM_DEVICE_STATE_UNAVAILABLE, reason);
 	}
 }
 
+/**
+ * @self: the #NMDevice instance
+ * @flags: which #NMUnmanagedFlags to set.
+ * @set_op: whether to set/clear/forget the flags. You can also pass
+ *   boolean values %TRUE and %FALSE, which mean %NM_UNMAN_FLAG_OP_SET_UNMANAGED
+ *   and %NM_UNMAN_FLAG_OP_SET_MANAGED, respectively.
+ *
+ * Set the unmanaged flags of the device (does not trigger a state change).
+ **/
+void
+nm_device_set_unmanaged_flags (NMDevice *self,
+                               NMUnmanagedFlags flags,
+                               NMUnmanFlagOp set_op)
+{
+	_set_unmanaged_flags (self, flags, set_op, FALSE, NM_DEVICE_STATE_REASON_NONE);
+}
+
+/**
+ * nm_device_set_unmanaged_by_flags:
+ * @self: the #NMDevice instance
+ * @flags: which #NMUnmanagedFlags to set.
+ * @set_op: whether to set/clear/forget the flags. You can also pass
+ *   boolean values %TRUE and %FALSE, which mean %NM_UNMAN_FLAG_OP_SET_UNMANAGED
+ *   and %NM_UNMAN_FLAG_OP_SET_MANAGED, respectively.
+ * @reason: the device state reason passed to nm_device_state_changed() if
+ *   the device becomes managed/unmanaged.
+ *
+ * Set the unmanaged flags of the device and possibly trigger a state change.
+ **/
+void
+nm_device_set_unmanaged_by_flags (NMDevice *self,
+                                  NMUnmanagedFlags flags,
+                                  NMUnmanFlagOp set_op,
+                                  NMDeviceStateReason reason)
+{
+	_set_unmanaged_flags (self, flags, set_op, TRUE, reason);
+}
+
 void
-nm_device_set_unmanaged_flags_by_device_spec (NMDevice *self, const GSList *unmanaged_specs)
+nm_device_set_unmanaged_by_user_config (NMDevice *self, const GSList *unmanaged_specs)
 {
 	NMDevicePrivate *priv;
 	gboolean unmanaged;
@@ -8811,46 +9295,36 @@ nm_device_set_unmanaged_flags_by_device_spec (NMDevice *self, const GSList *unma
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
 
-	if (priv->managed_touched_by_user)
-		return;
-
 	unmanaged = nm_device_spec_match_list (self, unmanaged_specs);
-	nm_device_set_unmanaged_flags (self,
-	                               NM_UNMANAGED_USER,
-	                               unmanaged,
-	                               unmanaged
-	                                   ? NM_DEVICE_STATE_REASON_NOW_UNMANAGED
-	                                   : NM_DEVICE_STATE_REASON_NOW_MANAGED);
+
+	nm_device_set_unmanaged_by_flags (self,
+	                                  NM_UNMANAGED_USER_SETTINGS,
+	                                  unmanaged,
+	                                  unmanaged
+	                                      ? NM_DEVICE_STATE_REASON_NOW_UNMANAGED
+	                                      : NM_DEVICE_STATE_REASON_NOW_MANAGED);
 }
 
-/**
- * nm_device_set_unmanaged_flags_initial():
- * @self: the #NMDevice
- * @flag: an #NMUnmanagedFlag
- * @unmanaged: %TRUE or %FALSE to set or clear @flag
- *
- * Like nm_device_set_unmanaged_flags(), but must be set before the device is
- * initialized by nm_device_finish_init(), and does not trigger state changes.
- * Should only be used when initializing a device.
- */
 void
-nm_device_set_unmanaged_flags_initial (NMDevice *self,
-                                       NMUnmanagedFlags flag,
-                                       gboolean unmanaged)
+nm_device_set_unmanaged_by_user_udev (NMDevice *self)
 {
-	NMDevicePrivate *priv;
+	int ifindex;
+	gboolean platform_unmanaged = FALSE;
 
-	g_return_if_fail (NM_IS_DEVICE (self));
-	g_return_if_fail (flag <= NM_UNMANAGED_LAST);
+	ifindex = self->priv->ifindex;
 
-	priv = NM_DEVICE_GET_PRIVATE (self);
-	g_return_if_fail (priv->initialized == FALSE);
+	if (   ifindex <= 0
+	    || !nm_platform_link_get_unmanaged (NM_PLATFORM_GET, ifindex, &platform_unmanaged))
+		return;
 
-	_set_unmanaged_flags (self, flag, unmanaged);
+	nm_device_set_unmanaged_by_flags (self,
+	                                  NM_UNMANAGED_USER_UDEV,
+	                                  platform_unmanaged,
+	                                  NM_DEVICE_STATE_REASON_USER_REQUESTED);
 }
 
 void
-nm_device_set_unmanaged_quitting (NMDevice *self)
+nm_device_set_unmanaged_by_quitting (NMDevice *self)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	gboolean need_deactivate = nm_device_is_activating (self) ||
@@ -8860,11 +9334,11 @@ nm_device_set_unmanaged_quitting (NMDevice *self)
 	if (need_deactivate)
 		_set_state_full (self, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_NOW_UNMANAGED, TRUE);
 
-	nm_device_set_unmanaged_flags (self,
-	                               NM_UNMANAGED_INTERNAL,
-	                               TRUE,
-	                               need_deactivate ? NM_DEVICE_STATE_REASON_REMOVED
-	                                               : NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
+	nm_device_set_unmanaged_by_flags (self,
+	                                  NM_UNMANAGED_QUITTING,
+	                                  TRUE,
+	                                  need_deactivate ? NM_DEVICE_STATE_REASON_REMOVED
+	                                                  : NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
 }
 
 /*****************************************************************************/
@@ -8901,6 +9375,7 @@ nm_device_reapply_settings_immediately (NMDevice *self)
 	NMSettingConnection *s_con_applied;
 	const char *zone;
 	NMMetered metered;
+	guint64 version_id;
 
 	g_return_if_fail (NM_IS_DEVICE (self));
 
@@ -8923,7 +9398,8 @@ nm_device_reapply_settings_immediately (NMDevice *self)
 	if (g_strcmp0 ((zone = nm_setting_connection_get_zone (s_con_settings)),
 	               nm_setting_connection_get_zone (s_con_applied)) != 0) {
 
-		_LOGD (LOGD_DEVICE, "reapply setting: zone = %s%s%s", NM_PRINT_FMT_QUOTE_STRING (zone));
+		version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->priv->act_request);
+		_LOGD (LOGD_DEVICE, "reapply setting: zone = %s%s%s (version-id %llu)", NM_PRINT_FMT_QUOTE_STRING (zone), (long long unsigned) version_id);
 
 		g_object_set (G_OBJECT (s_con_applied),
 		              NM_SETTING_CONNECTION_ZONE, zone,
@@ -8934,7 +9410,8 @@ nm_device_reapply_settings_immediately (NMDevice *self)
 
 	if ((metered = nm_setting_connection_get_metered (s_con_settings)) != nm_setting_connection_get_metered (s_con_applied)) {
 
-		_LOGD (LOGD_DEVICE, "reapply setting: metered = %d", (int) metered);
+		version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->priv->act_request);
+		_LOGD (LOGD_DEVICE, "reapply setting: metered = %d (version-id %llu)", (int) metered, (long long unsigned) version_id);
 
 		g_object_set (G_OBJECT (s_con_applied),
 		              NM_SETTING_CONNECTION_METERED, metered,
@@ -9017,7 +9494,7 @@ nm_device_update_metered (NMDevice *self)
 	if (value != priv->metered) {
 		_LOGD (LOGD_DEVICE, "set metered value %d", value);
 		priv->metered = value;
-		g_object_notify (G_OBJECT (self), NM_DEVICE_METERED);
+		_notify (self, PROP_METERED);
 	}
 }
 
@@ -9029,11 +9506,21 @@ _nm_device_check_connection_available (NMDevice *self,
 {
 	NMDeviceState state;
 
+	/* an unrealized software device is always available, hardware devices never. */
+	if (!nm_device_is_real (self)) {
+		if (nm_device_is_software (self))
+			return nm_device_check_connection_compatible (self, connection);
+		return FALSE;
+	}
+
 	state = nm_device_get_state (self);
 	if (state < NM_DEVICE_STATE_UNMANAGED)
 		return FALSE;
 	if (   state < NM_DEVICE_STATE_UNAVAILABLE
-	    && nm_device_get_unmanaged_flags (self, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT))
+	    && (   (   !NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST)
+	            && !nm_device_get_managed (self, FALSE))
+	        || (    NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST)
+	            && !nm_device_get_managed (self, TRUE))))
 		return FALSE;
 	if (   state < NM_DEVICE_STATE_DISCONNECTED
 	    && !nm_device_is_software (self)
@@ -9100,34 +9587,30 @@ nm_device_check_connection_available (NMDevice *self,
 }
 
 static void
-_signal_available_connections_changed (NMDevice *self)
+available_connections_notify (NMDevice *self)
 {
-	g_object_notify (G_OBJECT (self), NM_DEVICE_AVAILABLE_CONNECTIONS);
+	_notify (self, PROP_AVAILABLE_CONNECTIONS);
 }
 
-static void
-_clear_available_connections (NMDevice *self, gboolean do_signal)
+static gboolean
+available_connections_del_all (NMDevice *self)
 {
-	g_hash_table_remove_all (NM_DEVICE_GET_PRIVATE (self)->available_connections);
-	if (do_signal == TRUE)
-		_signal_available_connections_changed (self);
+	if (g_hash_table_size (self->priv->available_connections) == 0)
+		return FALSE;
+	g_hash_table_remove_all (self->priv->available_connections);
+	return TRUE;
 }
 
 static gboolean
-_try_add_available_connection (NMDevice *self, NMConnection *connection)
+available_connections_add (NMDevice *self, NMConnection *connection)
 {
-	if (nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL)) {
-		g_hash_table_add (NM_DEVICE_GET_PRIVATE (self)->available_connections,
-		                  g_object_ref (connection));
-		return TRUE;
-	}
-	return FALSE;
+	return nm_g_hash_table_add (self->priv->available_connections, g_object_ref (connection));
 }
 
 static gboolean
-_del_available_connection (NMDevice *self, NMConnection *connection)
+available_connections_del (NMDevice *self, NMConnection *connection)
 {
-	return g_hash_table_remove (NM_DEVICE_GET_PRIVATE (self)->available_connections, connection);
+	return g_hash_table_remove (self->priv->available_connections, connection);
 }
 
 static gboolean
@@ -9162,22 +9645,55 @@ nm_device_recheck_available_connections (NMDevice *self)
 {
 	NMDevicePrivate *priv;
 	const GSList *connections, *iter;
+	gboolean changed = FALSE;
+	GHashTableIter h_iter;
+	NMConnection *connection;
 
 	g_return_if_fail (NM_IS_DEVICE (self));
 
 	priv = NM_DEVICE_GET_PRIVATE(self);
 
 	if (priv->con_provider) {
-		_clear_available_connections (self, FALSE);
+		gs_unref_hashtable GHashTable *prune_list = NULL;
+
+		if (g_hash_table_size (priv->available_connections) > 0) {
+			prune_list = g_hash_table_new (g_direct_hash, g_direct_equal);
+			g_hash_table_iter_init (&h_iter, priv->available_connections);
+			while (g_hash_table_iter_next (&h_iter, (gpointer *) &connection, NULL))
+				g_hash_table_add (prune_list, connection);
+		}
 
 		connections = nm_connection_provider_get_connections (priv->con_provider);
-		for (iter = connections; iter; iter = g_slist_next (iter))
-			_try_add_available_connection (self, NM_CONNECTION (iter->data));
+		for (iter = connections; iter; iter = g_slist_next (iter)) {
+			connection = NM_CONNECTION (iter->data);
+
+			if (nm_device_check_connection_available (self,
+				                                  connection,
+				                                  NM_DEVICE_CHECK_CON_AVAILABLE_NONE,
+				                                  NULL)) {
+				if (available_connections_add (self, connection))
+					changed = TRUE;
+			} else {
+				if (prune_list && g_hash_table_remove (prune_list, connection))
+					changed = TRUE;
+			}
+		}
 
-		_signal_available_connections_changed (self);
+		if (prune_list) {
+			g_hash_table_iter_init (&h_iter, prune_list);
+			while (g_hash_table_iter_next (&h_iter, (gpointer *) &connection, NULL)) {
+				if (available_connections_del (self, connection))
+					changed = TRUE;
+			}
+		}
+	} else {
+		if (available_connections_del_all (self))
+			changed = TRUE;
 	}
 
-	available_connection_check_delete_unrealized (self);
+	if (changed)
+		available_connections_notify (self);
+	available_connections_check_delete_unrealized (self);
 }
 
 /**
@@ -9209,7 +9725,7 @@ nm_device_get_available_connections (NMDevice *self, const char *specific_object
 			 * compatible with it.
 			 */
 			if (   !specific_object /* << Optimization: we know that the connection is available without @specific_object.  */
-			    || nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, specific_object))
+			    || nm_device_check_connection_available (self, connection, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, specific_object))
 				g_ptr_array_add (array, connection);
 		}
 	}
@@ -9217,45 +9733,38 @@ nm_device_get_available_connections (NMDevice *self, const char *specific_object
 }
 
 static void
-cp_connection_added (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data)
+cp_connection_added_or_updated (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data)
 {
+	gboolean changed;
 	NMDevice *self = user_data;
 
 	g_return_if_fail (NM_IS_DEVICE (self));
+	g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection));
 
-	if (_try_add_available_connection (self, connection))
-		_signal_available_connections_changed (self);
-}
-
-static void
-cp_connection_removed (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data)
-{
-	NMDevice *self = user_data;
-
-	g_return_if_fail (NM_IS_DEVICE (self));
+	if (nm_device_check_connection_available (self,
+	                                          connection,
+	                                          _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST,
+	                                          NULL))
+		changed = available_connections_add (self, connection);
+	else
+		changed = available_connections_del (self, connection);
 
-	if (_del_available_connection (self, connection)) {
-		_signal_available_connections_changed (self);
-		available_connection_check_delete_unrealized (self);
+	if (changed) {
+		available_connections_notify (self);
+		available_connections_check_delete_unrealized (self);
 	}
 }
 
 static void
-cp_connection_updated (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data)
+cp_connection_removed (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data)
 {
 	NMDevice *self = user_data;
-	gboolean added, deleted;
 
 	g_return_if_fail (NM_IS_DEVICE (self));
 
-	/* FIXME: don't remove it from the hash if it's just going to get re-added */
-	deleted = _del_available_connection (self, connection);
-	added = _try_add_available_connection (self, connection);
-
-	/* Only signal if the connection was removed OR added, but not both */
-	if (added != deleted) {
-		_signal_available_connections_changed (self);
-		available_connection_check_delete_unrealized (self);
+	if (available_connections_del (self, connection)) {
+		available_connections_notify (self);
+		available_connections_check_delete_unrealized (self);
 	}
 }
 
@@ -9309,7 +9818,7 @@ nm_device_add_pending_action (NMDevice *self, const char *action, gboolean asser
 	_LOGD (LOGD_DEVICE, "add_pending_action (%d): '%s'", count, action);
 
 	if (count == 1)
-		g_object_notify (G_OBJECT (self), NM_DEVICE_HAS_PENDING_ACTION);
+		_notify (self, PROP_HAS_PENDING_ACTION);
 
 	return TRUE;
 }
@@ -9344,7 +9853,7 @@ nm_device_remove_pending_action (NMDevice *self, const char *action, gboolean as
 			g_free (iter->data);
 			priv->pending_actions = g_slist_delete_link (priv->pending_actions, iter);
 			if (priv->pending_actions == NULL)
-				g_object_notify (G_OBJECT (self), NM_DEVICE_HAS_PENDING_ACTION);
+				_notify (self, PROP_HAS_PENDING_ACTION);
 			return TRUE;
 		}
 		count++;
@@ -9453,6 +9962,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
 	g_clear_object (&priv->con_ip6_config);
 	g_clear_object (&priv->ac_ip6_config);
 	g_clear_object (&priv->ext_ip6_config);
+	g_clear_object (&priv->ext_ip6_config_captured);
 	g_clear_object (&priv->wwan_ip6_config);
 	g_clear_object (&priv->ip6_config);
 
@@ -9466,7 +9976,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
 	/* Clear legacy IPv4 address property */
 	if (priv->ip4_address) {
 		priv->ip4_address = 0;
-		g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_ADDRESS);
+		_notify (self, PROP_IP4_ADDRESS);
 	}
 
 	if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) {
@@ -9733,11 +10243,11 @@ ip_config_valid (NMDeviceState state)
 static void
 notify_ip_properties (NMDevice *self)
 {
-	g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE);
-	g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_CONFIG);
-	g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP4_CONFIG);
-	g_object_notify (G_OBJECT (self), NM_DEVICE_IP6_CONFIG);
-	g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP6_CONFIG);
+	_notify (self, PROP_IP_IFACE);
+	_notify (self, PROP_IP4_CONFIG);
+	_notify (self, PROP_DHCP4_CONFIG);
+	_notify (self, PROP_IP6_CONFIG);
+	_notify (self, PROP_DHCP6_CONFIG);
 }
 
 static void
@@ -9840,14 +10350,16 @@ _set_state_full (NMDevice *self,
 	 * can retry device initialization.
 	 */
 	if (   (priv->state == state)
-	    && !(state == NM_DEVICE_STATE_UNAVAILABLE && priv->firmware_missing)) {
-		_LOGD (LOGD_DEVICE, "device state change: %s -> %s (reason '%s') [%d %d %d] (skip due to missing firmware)",
+	    && (   state != NM_DEVICE_STATE_UNAVAILABLE
+	        || !priv->firmware_missing)) {
+		_LOGD (LOGD_DEVICE, "device state change: %s -> %s (reason '%s') [%d %d %d]%s",
 		       state_to_string (old_state),
 		       state_to_string (state),
 		       reason_to_string (reason),
 		       old_state,
 		       state,
-		       reason);
+		       reason,
+		       priv->firmware_missing ? " (missing firmware)" : "");
 		return;
 	}
 
@@ -9875,13 +10387,13 @@ _set_state_full (NMDevice *self,
 	req = priv->act_request ? g_object_ref (priv->act_request) : NULL;
 
 	if (state <= NM_DEVICE_STATE_UNAVAILABLE) {
-		_clear_available_connections (self, TRUE);
+		if (available_connections_del_all (self))
+			available_connections_notify (self);
 		_clear_queued_act_request (priv);
 	}
 
 	/* Update the available connections list when a device first becomes available */
-	if (   (state >= NM_DEVICE_STATE_DISCONNECTED && old_state < NM_DEVICE_STATE_DISCONNECTED)
-	    || nm_device_get_default_unmanaged (self))
+	if (state >= NM_DEVICE_STATE_DISCONNECTED && old_state < NM_DEVICE_STATE_DISCONNECTED)
 		nm_device_recheck_available_connections (self);
 
 	/* Handle the new state here; but anything that could trigger
@@ -9963,8 +10475,8 @@ _set_state_full (NMDevice *self,
 	    && state <= NM_DEVICE_STATE_ACTIVATED)
 		nm_device_set_autoconnect (self, TRUE);
 
-	g_object_notify (G_OBJECT (self), NM_DEVICE_STATE);
-	g_object_notify (G_OBJECT (self), NM_DEVICE_STATE_REASON);
+	_notify (self, PROP_STATE);
+	_notify (self, PROP_STATE_REASON);
 	g_signal_emit_by_name (self, NM_DEVICE_STATE_CHANGED, state, old_state, reason);
 
 	/* Post-process the event after internal notification */
@@ -9982,11 +10494,7 @@ _set_state_full (NMDevice *self,
 			                                   NM_DEVICE_STATE_REASON_NONE,
 			                                   NM_DEVICE_STATE_REASON_NONE);
 		} else {
-			if (old_state == NM_DEVICE_STATE_UNMANAGED)
-				_LOGD (LOGD_DEVICE, "device not yet available for transition to DISCONNECTED");
-			else if (   old_state > NM_DEVICE_STATE_UNAVAILABLE
-			         && nm_device_get_default_unmanaged (self))
-				nm_device_queue_state (self, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NONE);
+			_LOGD (LOGD_DEVICE, "device not yet available for transition to DISCONNECTED");
 		}
 		break;
 	case NM_DEVICE_STATE_DEACTIVATING:
@@ -10032,9 +10540,6 @@ _set_state_full (NMDevice *self,
 				break;
 			/* fall through */
 		}
-		if (   old_state > NM_DEVICE_STATE_DISCONNECTED
-		    && nm_device_get_default_unmanaged (self))
-			nm_device_queue_state (self, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NONE);
 		break;
 	case NM_DEVICE_STATE_ACTIVATED:
 		_LOGI (LOGD_DEVICE, "Activation: successful, device activated.");
@@ -10149,6 +10654,9 @@ _set_state_full (NMDevice *self,
 		g_object_unref (req);
 
 	priv->in_state_changed = FALSE;
+
+	if ((old_state > NM_DEVICE_STATE_UNMANAGED) != (state > NM_DEVICE_STATE_UNMANAGED))
+		_notify (self, PROP_MANAGED);
 }
 
 void
@@ -10297,7 +10805,7 @@ nm_device_update_hw_address (NMDevice *self)
 			priv->hw_addr = nm_utils_hwaddr_ntoa (hwaddr, hwaddrlen);
 
 			_LOGD (LOGD_HW | LOGD_DEVICE, "hardware address now %s", priv->hw_addr);
-			g_object_notify (G_OBJECT (self), NM_DEVICE_HW_ADDRESS);
+			_notify (self, PROP_HW_ADDRESS);
 		}
 	} else {
 		/* Invalid or no hardware address */
@@ -10306,7 +10814,7 @@ nm_device_update_hw_address (NMDevice *self)
 			priv->hw_addr_len = 0;
 			_LOGD (LOGD_HW | LOGD_DEVICE,
 			       "previous hardware address is no longer valid");
-			g_object_notify (G_OBJECT (self), NM_DEVICE_HW_ADDRESS);
+			_notify (self, PROP_HW_ADDRESS);
 		}
 	}
 }
@@ -10347,7 +10855,11 @@ nm_device_set_hw_addr (NMDevice *self, const char *addr,
 	const char *cur_addr = nm_device_get_hw_address (self);
 	guint8 addr_bytes[NM_UTILS_HWADDR_LEN_MAX];
 
-	g_return_val_if_fail (addr != NULL, FALSE);
+	/* Fall back to the permanent address */
+	if (!addr)
+		addr = priv->perm_hw_addr;
+	if (!addr)
+		return FALSE;
 
 	/* Do nothing if current MAC is same */
 	if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) {
@@ -10498,7 +11010,8 @@ nm_device_init (NMDevice *self)
 	priv->dhcp_timeout = 0;
 	priv->rfkill_type = RFKILL_TYPE_UNKNOWN;
 	priv->autoconnect = DEFAULT_AUTOCONNECT;
-	priv->unmanaged_flags = NM_UNMANAGED_INTERNAL;
+	priv->unmanaged_flags = NM_UNMANAGED_PLATFORM_INIT;
+	priv->unmanaged_mask = priv->unmanaged_flags;
 	priv->available_connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
 	priv->ip6_saved_properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
 
@@ -10533,7 +11046,7 @@ constructor (GType type,
 
 		if (pllink && link_type_compatible (self, pllink->type, NULL, NULL)) {
 			priv->ifindex = pllink->ifindex;
-			priv->up = NM_FLAGS_HAS (pllink->flags, IFF_UP);
+			priv->up = NM_FLAGS_HAS (pllink->n_ifi_flags, IFF_UP);
 		}
 	}
 
@@ -10563,7 +11076,7 @@ constructed (GObject *object)
 	g_assert (priv->con_provider);
 	g_signal_connect (priv->con_provider,
 	                  NM_CP_SIGNAL_CONNECTION_ADDED,
-	                  G_CALLBACK (cp_connection_added),
+	                  G_CALLBACK (cp_connection_added_or_updated),
 	                  self);
 
 	g_signal_connect (priv->con_provider,
@@ -10573,18 +11086,9 @@ constructed (GObject *object)
 
 	g_signal_connect (priv->con_provider,
 	                  NM_CP_SIGNAL_CONNECTION_UPDATED,
-	                  G_CALLBACK (cp_connection_updated),
+	                  G_CALLBACK (cp_connection_added_or_updated),
 	                  self);
 
-	/* Update default-unmanaged device available connections immediately,
-	 * since they don't transition from UNMANAGED (and thus the state handler
-	 * doesn't run and update them) until something external happens.
-	 */
-	if (nm_device_get_default_unmanaged (self)) {
-		nm_device_set_autoconnect (self, FALSE);
-		nm_device_recheck_available_connections (self);
-	}
-
 	G_OBJECT_CLASS (nm_device_parent_class)->constructed (object);
 
 	_LOGD (LOGD_DEVICE, "constructed (%s)", G_OBJECT_TYPE_NAME (self));
@@ -10599,6 +11103,11 @@ dispose (GObject *object)
 
 	_LOGD (LOGD_DEVICE, "disposing");
 
+	g_slist_free_full (priv->arping.dad_list, (GDestroyNotify) nm_arping_manager_destroy);
+	priv->arping.dad_list = NULL;
+
+	arp_cleanup (self);
+
 	g_signal_handlers_disconnect_by_func (nm_config_get (), config_changed_update_ignore_carrier, self);
 
 	dispatcher_cleanup (self);
@@ -10623,13 +11132,12 @@ dispose (GObject *object)
 	link_disconnect_action_cancel (self);
 
 	if (priv->con_provider) {
-		g_signal_handlers_disconnect_by_func (priv->con_provider, cp_connection_added, self);
+		g_signal_handlers_disconnect_by_func (priv->con_provider, cp_connection_added_or_updated, self);
 		g_signal_handlers_disconnect_by_func (priv->con_provider, cp_connection_removed, self);
-		g_signal_handlers_disconnect_by_func (priv->con_provider, cp_connection_updated, self);
 		priv->con_provider = NULL;
 	}
 
-	g_hash_table_remove_all (priv->available_connections);
+	available_connections_del_all (self);
 
 	nm_clear_g_source (&priv->carrier_wait_id);
 
@@ -10698,7 +11206,6 @@ set_property (GObject *object, guint prop_id,
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	const char *hw_addr, *p;
 	guint count;
-	gboolean val_bool;
 
 	switch (prop_id) {
 	case PROP_UDI:
@@ -10732,18 +11239,26 @@ set_property (GObject *object, guint prop_id,
 	case PROP_IP4_ADDRESS:
 		priv->ip4_address = g_value_get_uint (value);
 		break;
-	case PROP_MANAGED:
-		val_bool = g_value_get_boolean (value);
-		priv->managed_touched_by_user = TRUE;
-		nm_device_set_unmanaged_flags (self,
-		                               NM_UNMANAGED_USER | (val_bool ? NM_UNMANAGED_DEFAULT : NM_UNMANAGED_NONE),
-		                               !val_bool,
-		                               NM_DEVICE_STATE_REASON_USER_REQUESTED);
+	case PROP_MANAGED: {
+		gboolean managed;
+		NMDeviceStateReason reason;
+
+		managed = g_value_get_boolean (value);
+		if (managed)
+			reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED;
+		else
+			reason = NM_DEVICE_STATE_REASON_REMOVED;
+		nm_device_set_unmanaged_by_flags (self,
+		                                  NM_UNMANAGED_USER_EXPLICIT,
+		                                  !managed,
+		                                  reason);
 		break;
+	}
 	case PROP_AUTOCONNECT:
 		nm_device_set_autoconnect (self, g_value_get_boolean (value));
 		break;
 	case PROP_FIRMWARE_MISSING:
+		/* construct only */
 		priv->firmware_missing = g_value_get_boolean (value);
 		break;
 	case PROP_NM_PLUGIN_MISSING:
@@ -10878,7 +11393,8 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_uint (value, priv->link_type);
 		break;
 	case PROP_MANAGED:
-		g_value_set_boolean (value, nm_device_get_managed (self));
+		/* The managed state exposed on D-Bus only depends on the current device state alone. */
+		g_value_set_boolean (value, nm_device_get_state (self) > NM_DEVICE_STATE_UNMANAGED);
 		break;
 	case PROP_AUTOCONNECT:
 		g_value_set_boolean (value, priv->autoconnect);
@@ -11002,232 +11518,169 @@ nm_device_class_init (NMDeviceClass *klass)
 	klass->get_ip_iface_identifier = get_ip_iface_identifier;
 
 	/* Properties */
-	g_object_class_install_property
-		(object_class, PROP_UDI,
-		 g_param_spec_string (NM_DEVICE_UDI, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_IFACE,
-		 g_param_spec_string (NM_DEVICE_IFACE, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_IP_IFACE,
-		 g_param_spec_string (NM_DEVICE_IP_IFACE, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_DRIVER,
-		 g_param_spec_string (NM_DEVICE_DRIVER, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_DRIVER_VERSION,
-		 g_param_spec_string (NM_DEVICE_DRIVER_VERSION, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_FIRMWARE_VERSION,
-		 g_param_spec_string (NM_DEVICE_FIRMWARE_VERSION, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_CAPABILITIES,
-		 g_param_spec_uint (NM_DEVICE_CAPABILITIES, "", "",
-		                    0, G_MAXUINT32, NM_DEVICE_CAP_NONE,
-		                    G_PARAM_READABLE |
-		                    G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_CARRIER,
-		 g_param_spec_boolean (NM_DEVICE_CARRIER, "", "",
-		                       FALSE,
-		                       G_PARAM_READABLE |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_MTU,
-		 g_param_spec_uint (NM_DEVICE_MTU, "", "",
-		                    0, G_MAXUINT32, 1500,
-		                    G_PARAM_READABLE |
-		                    G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_IP4_ADDRESS,
-		 g_param_spec_uint (NM_DEVICE_IP4_ADDRESS, "", "",
-		                    0, G_MAXUINT32, 0, /* FIXME */
-		                    G_PARAM_READWRITE |
-		                    G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_IP4_CONFIG,
-		 g_param_spec_string (NM_DEVICE_IP4_CONFIG, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_DHCP4_CONFIG,
-		 g_param_spec_string (NM_DEVICE_DHCP4_CONFIG, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_IP6_CONFIG,
-		 g_param_spec_string (NM_DEVICE_IP6_CONFIG, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_DHCP6_CONFIG,
-		 g_param_spec_string (NM_DEVICE_DHCP6_CONFIG, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_STATE,
-		 g_param_spec_uint (NM_DEVICE_STATE, "", "",
-		                    0, G_MAXUINT32, NM_DEVICE_STATE_UNKNOWN,
-		                    G_PARAM_READABLE |
-		                    G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_STATE_REASON,
-		 g_param_spec_variant (NM_DEVICE_STATE_REASON, "", "",
-		                       G_VARIANT_TYPE ("(uu)"),
-		                       NULL,
-		                       G_PARAM_READABLE |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_ACTIVE_CONNECTION,
-		 g_param_spec_string (NM_DEVICE_ACTIVE_CONNECTION, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_DEVICE_TYPE,
-		 g_param_spec_uint (NM_DEVICE_DEVICE_TYPE, "", "",
-		                    0, G_MAXUINT32, NM_DEVICE_TYPE_UNKNOWN,
-		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                    G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_LINK_TYPE,
-		 g_param_spec_uint (NM_DEVICE_LINK_TYPE, "", "",
-		                    0, G_MAXUINT32, NM_LINK_TYPE_NONE,
-		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                    G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_MANAGED,
-		 g_param_spec_boolean (NM_DEVICE_MANAGED, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_AUTOCONNECT,
-		 g_param_spec_boolean (NM_DEVICE_AUTOCONNECT, "", "",
-		                       DEFAULT_AUTOCONNECT,
-		                       G_PARAM_READWRITE |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_FIRMWARE_MISSING,
-		 g_param_spec_boolean (NM_DEVICE_FIRMWARE_MISSING, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_NM_PLUGIN_MISSING,
-		 g_param_spec_boolean (NM_DEVICE_NM_PLUGIN_MISSING, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_TYPE_DESC,
-		 g_param_spec_string (NM_DEVICE_TYPE_DESC, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_RFKILL_TYPE,
-		 g_param_spec_uint (NM_DEVICE_RFKILL_TYPE, "", "",
-		                    RFKILL_TYPE_WLAN,
-		                    RFKILL_TYPE_MAX,
-		                    RFKILL_TYPE_UNKNOWN,
-		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                    G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_IFINDEX,
-		 g_param_spec_int (NM_DEVICE_IFINDEX, "", "",
-		                   0, G_MAXINT, 0,
-		                   G_PARAM_READABLE |
-		                   G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_AVAILABLE_CONNECTIONS,
-		 g_param_spec_boxed (NM_DEVICE_AVAILABLE_CONNECTIONS, "", "",
-		                     G_TYPE_STRV,
-		                     G_PARAM_READABLE |
-		                     G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_PHYSICAL_PORT_ID,
-		 g_param_spec_string (NM_DEVICE_PHYSICAL_PORT_ID, "", "",
-		                      NULL,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_IS_MASTER,
-		 g_param_spec_boolean (NM_DEVICE_IS_MASTER, "", "",
-		                       FALSE,
-		                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_MASTER,
-		 g_param_spec_object (NM_DEVICE_MASTER, "", "",
-		                      NM_TYPE_DEVICE,
-		                      G_PARAM_READABLE |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_HW_ADDRESS,
-		 g_param_spec_string (NM_DEVICE_HW_ADDRESS, "", "",
-		                      NULL,
-		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                      G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_HAS_PENDING_ACTION,
-		 g_param_spec_boolean (NM_DEVICE_HAS_PENDING_ACTION, "", "",
-		                       FALSE,
-		                       G_PARAM_READABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_UDI] =
+	    g_param_spec_string (NM_DEVICE_UDI, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_IFACE] =
+	    g_param_spec_string (NM_DEVICE_IFACE, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_IP_IFACE] =
+	    g_param_spec_string (NM_DEVICE_IP_IFACE, "", "",
+	                         NULL,
+	                         G_PARAM_READABLE |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_DRIVER] =
+	    g_param_spec_string (NM_DEVICE_DRIVER, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_DRIVER_VERSION] =
+	    g_param_spec_string (NM_DEVICE_DRIVER_VERSION, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_FIRMWARE_VERSION] =
+	    g_param_spec_string (NM_DEVICE_FIRMWARE_VERSION, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_CAPABILITIES] =
+	    g_param_spec_uint (NM_DEVICE_CAPABILITIES, "", "",
+	                       0, G_MAXUINT32, NM_DEVICE_CAP_NONE,
+	                       G_PARAM_READABLE |
+	                       G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_CARRIER] =
+	    g_param_spec_boolean (NM_DEVICE_CARRIER, "", "",
+	                          FALSE,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_MTU] =
+	    g_param_spec_uint (NM_DEVICE_MTU, "", "",
+	                       0, G_MAXUINT32, 1500,
+	                       G_PARAM_READABLE |
+	                       G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_IP4_ADDRESS] =
+	    g_param_spec_uint (NM_DEVICE_IP4_ADDRESS, "", "",
+	                       0, G_MAXUINT32, 0, /* FIXME */
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_IP4_CONFIG] =
+	    g_param_spec_string (NM_DEVICE_IP4_CONFIG, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_DHCP4_CONFIG] =
+	    g_param_spec_string (NM_DEVICE_DHCP4_CONFIG, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_IP6_CONFIG] =
+	    g_param_spec_string (NM_DEVICE_IP6_CONFIG, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_DHCP6_CONFIG] =
+	    g_param_spec_string (NM_DEVICE_DHCP6_CONFIG, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_STATE] =
+	    g_param_spec_uint (NM_DEVICE_STATE, "", "",
+	                       0, G_MAXUINT32, NM_DEVICE_STATE_UNKNOWN,
+	                       G_PARAM_READABLE |
+	                       G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_STATE_REASON] =
+	    g_param_spec_variant (NM_DEVICE_STATE_REASON, "", "",
+	                          G_VARIANT_TYPE ("(uu)"),
+	                          NULL,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_ACTIVE_CONNECTION] =
+	    g_param_spec_string (NM_DEVICE_ACTIVE_CONNECTION, "", "",
+	                         NULL,
+	                         G_PARAM_READABLE |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_DEVICE_TYPE] =
+	    g_param_spec_uint (NM_DEVICE_DEVICE_TYPE, "", "",
+	                       0, G_MAXUINT32, NM_DEVICE_TYPE_UNKNOWN,
+	                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                       G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_LINK_TYPE] =
+	    g_param_spec_uint (NM_DEVICE_LINK_TYPE, "", "",
+	                       0, G_MAXUINT32, NM_LINK_TYPE_NONE,
+	                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                       G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_MANAGED] =
+	    g_param_spec_boolean (NM_DEVICE_MANAGED, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_AUTOCONNECT] =
+	    g_param_spec_boolean (NM_DEVICE_AUTOCONNECT, "", "",
+	                          DEFAULT_AUTOCONNECT,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_FIRMWARE_MISSING] =
+	    g_param_spec_boolean (NM_DEVICE_FIRMWARE_MISSING, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                          G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_NM_PLUGIN_MISSING] =
+	    g_param_spec_boolean (NM_DEVICE_NM_PLUGIN_MISSING, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                          G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_TYPE_DESC] =
+	    g_param_spec_string (NM_DEVICE_TYPE_DESC, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_RFKILL_TYPE] =
+	    g_param_spec_uint (NM_DEVICE_RFKILL_TYPE, "", "",
+	                       RFKILL_TYPE_WLAN,
+	                       RFKILL_TYPE_MAX,
+	                       RFKILL_TYPE_UNKNOWN,
+	                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                       G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_IFINDEX] =
+	    g_param_spec_int (NM_DEVICE_IFINDEX, "", "",
+	                      0, G_MAXINT, 0,
+	                      G_PARAM_READABLE |
+	                      G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_AVAILABLE_CONNECTIONS] =
+	    g_param_spec_boxed (NM_DEVICE_AVAILABLE_CONNECTIONS, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READABLE |
+	                        G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_PHYSICAL_PORT_ID] =
+	    g_param_spec_string (NM_DEVICE_PHYSICAL_PORT_ID, "", "",
+	                         NULL,
+	                         G_PARAM_READABLE |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_IS_MASTER] =
+	    g_param_spec_boolean (NM_DEVICE_IS_MASTER, "", "",
+	                          FALSE,
+	                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                          G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_MASTER] =
+	    g_param_spec_object (NM_DEVICE_MASTER, "", "",
+	                         NM_TYPE_DEVICE,
+	                         G_PARAM_READABLE |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_HW_ADDRESS] =
+	    g_param_spec_string (NM_DEVICE_HW_ADDRESS, "", "",
+	                         NULL,
+	                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+	                         G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_HAS_PENDING_ACTION] =
+	    g_param_spec_boolean (NM_DEVICE_HAS_PENDING_ACTION, "", "",
+	                          FALSE,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
 
 	/**
 	 * NMDevice:metered:
@@ -11236,99 +11689,95 @@ nm_device_class_init (NMDeviceClass *klass)
 	 *
 	 * Since: 1.2
 	 **/
-	g_object_class_install_property
-		(object_class, PROP_METERED,
-		 g_param_spec_uint (NM_DEVICE_METERED, "", "",
-		                    0, G_MAXUINT32, NM_METERED_UNKNOWN,
-		                    G_PARAM_READABLE |
-		                    G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_LLDP_NEIGHBORS,
-		 g_param_spec_variant (NM_DEVICE_LLDP_NEIGHBORS, "", "",
-		                       G_VARIANT_TYPE ("aa{sv}"),
-		                       NULL,
-		                       G_PARAM_READABLE |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-		(object_class, PROP_REAL,
-		 g_param_spec_boolean (NM_DEVICE_REAL, "", "",
-		                       FALSE,
-		                       G_PARAM_READABLE |
-		                       G_PARAM_STATIC_STRINGS));
-
-	g_object_class_install_property
-	    (object_class, PROP_SLAVES,
-	     g_param_spec_boxed (NM_DEVICE_SLAVES, "", "",
-	                         G_TYPE_STRV,
-	                         G_PARAM_READABLE |
-	                         G_PARAM_STATIC_STRINGS));
+	obj_properties[PROP_METERED] =
+	    g_param_spec_uint (NM_DEVICE_METERED, "", "",
+	                       0, G_MAXUINT32, NM_METERED_UNKNOWN,
+	                       G_PARAM_READABLE |
+	                       G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_LLDP_NEIGHBORS] =
+	    g_param_spec_variant (NM_DEVICE_LLDP_NEIGHBORS, "", "",
+	                          G_VARIANT_TYPE ("aa{sv}"),
+	                          NULL,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_REAL] =
+	    g_param_spec_boolean (NM_DEVICE_REAL, "", "",
+	                          FALSE,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_SLAVES] =
+	    g_param_spec_boxed (NM_DEVICE_SLAVES, "", "",
+	                        G_TYPE_STRV,
+	                        G_PARAM_READABLE |
+	                        G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
 	/* Signals */
 	signals[STATE_CHANGED] =
-		g_signal_new (NM_DEVICE_STATE_CHANGED,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_LAST,
-		              G_STRUCT_OFFSET (NMDeviceClass, state_changed),
-		              NULL, NULL, NULL,
-		              G_TYPE_NONE, 3,
-		              G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
+	    g_signal_new (NM_DEVICE_STATE_CHANGED,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_LAST,
+	                  G_STRUCT_OFFSET (NMDeviceClass, state_changed),
+	                  NULL, NULL, NULL,
+	                  G_TYPE_NONE, 3,
+	                  G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
 
 	signals[AUTOCONNECT_ALLOWED] =
-		g_signal_new ("autoconnect-allowed",
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_LAST,
-		              0,
-		              autoconnect_allowed_accumulator, NULL, NULL,
-		              G_TYPE_BOOLEAN, 0);
+	    g_signal_new ("autoconnect-allowed",
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_LAST,
+	                  0,
+	                  autoconnect_allowed_accumulator, NULL, NULL,
+	                  G_TYPE_BOOLEAN, 0);
 
 	signals[AUTH_REQUEST] =
-		g_signal_new (NM_DEVICE_AUTH_REQUEST,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_FIRST,
-		              0, NULL, NULL, NULL,
-		              /* context, connection, permission, allow_interaction, callback, user_data */
-		              G_TYPE_NONE, 6, G_TYPE_DBUS_METHOD_INVOCATION, NM_TYPE_CONNECTION, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER, G_TYPE_POINTER);
+	    g_signal_new (NM_DEVICE_AUTH_REQUEST,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0, NULL, NULL, NULL,
+	                  /* context, connection, permission, allow_interaction, callback, user_data */
+	                  G_TYPE_NONE, 6, G_TYPE_DBUS_METHOD_INVOCATION, NM_TYPE_CONNECTION, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER, G_TYPE_POINTER);
 
 	signals[IP4_CONFIG_CHANGED] =
-		g_signal_new (NM_DEVICE_IP4_CONFIG_CHANGED,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_FIRST,
-		              0, NULL, NULL, NULL,
-		              G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT);
+	    g_signal_new (NM_DEVICE_IP4_CONFIG_CHANGED,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0, NULL, NULL, NULL,
+	                  G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT);
 
 	signals[IP6_CONFIG_CHANGED] =
-		g_signal_new (NM_DEVICE_IP6_CONFIG_CHANGED,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_FIRST,
-		              0, NULL, NULL, NULL,
-		              G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT);
+	    g_signal_new (NM_DEVICE_IP6_CONFIG_CHANGED,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0, NULL, NULL, NULL,
+	                  G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT);
 
 	signals[REMOVED] =
-		g_signal_new (NM_DEVICE_REMOVED,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_FIRST,
-		              0, NULL, NULL, NULL,
-		              G_TYPE_NONE, 0);
+	    g_signal_new (NM_DEVICE_REMOVED,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0, NULL, NULL, NULL,
+	                  G_TYPE_NONE, 0);
 
 	signals[RECHECK_AUTO_ACTIVATE] =
-		g_signal_new (NM_DEVICE_RECHECK_AUTO_ACTIVATE,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_FIRST,
-		              0, NULL, NULL, NULL,
-		              G_TYPE_NONE, 0);
+	    g_signal_new (NM_DEVICE_RECHECK_AUTO_ACTIVATE,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0, NULL, NULL, NULL,
+	                  G_TYPE_NONE, 0);
 
 	signals[RECHECK_ASSUME] =
-		g_signal_new (NM_DEVICE_RECHECK_ASSUME,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_FIRST,
-		              0, NULL, NULL, NULL,
-		              G_TYPE_NONE, 0);
+	    g_signal_new (NM_DEVICE_RECHECK_ASSUME,
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST,
+	                  0, NULL, NULL, NULL,
+	                  G_TYPE_NONE, 0);
 
 	nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
 	                                        NMDBUS_TYPE_DEVICE_SKELETON,
 	                                        "Reapply", impl_device_reapply,
+	                                        "GetAppliedConnection", impl_device_get_applied_connection,
 	                                        "Disconnect", impl_device_disconnect,
 	                                        "Delete", impl_device_delete,
 	                                        NULL);
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index e173b2db..9b9edda4 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -103,12 +103,14 @@ typedef enum NMActStageReturn NMActStageReturn;
 typedef enum { /*< skip >*/
 	NM_DEVICE_CHECK_CON_AVAILABLE_NONE                                  = 0,
 
-	_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER     = (1L << 0),
-	_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP           = (1L << 1),
-	NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST                      = _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER
+	_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST                     = (1L << 0),
+	_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER     = (1L << 1),
+	_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP           = (1L << 2),
+	NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST                      = _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST
+	                                                                    | _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER
 	                                                                    | _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP,
 
-	NM_DEVICE_CHECK_CON_AVAILABLE_ALL                                   = (1L << 2) - 1,
+	NM_DEVICE_CHECK_CON_AVAILABLE_ALL                                   = (1L << 3) - 1,
 } NMDeviceCheckConAvailableFlags;
 
 struct _NMDevicePrivate;
@@ -324,8 +326,6 @@ typedef void (*NMDeviceAuthRequestFunc) (NMDevice *device,
 
 GType nm_device_get_type (void);
 
-void            nm_device_finish_init   (NMDevice *device);
-
 const char *	nm_device_get_udi		(NMDevice *dev);
 const char *	nm_device_get_iface		(NMDevice *dev);
 int             nm_device_get_ifindex	(NMDevice *dev);
@@ -375,6 +375,7 @@ NMSettingsConnection *  nm_device_get_settings_connection       (NMDevice *dev);
 NMConnection *          nm_device_get_applied_connection        (NMDevice *dev);
 gboolean                nm_device_has_unmodified_applied_connection (NMDevice *self,
                                                                      NMSettingCompareFlags compare_flags);
+NMSetting *             nm_device_get_applied_setting           (NMDevice *dev, GType setting_type);
 
 void            nm_device_removed        (NMDevice *dev);
 
@@ -421,45 +422,67 @@ RfKillType nm_device_get_rfkill_type (NMDevice *device);
 /**
  * NMUnmanagedFlags:
  * @NM_UNMANAGED_NONE: placeholder value
- * @NM_UNMANAGED_INTERNAL: %TRUE when unmanaged by internal decision (ie,
- *   because NM is sleeping or not managed for some other reason)
+ * @NM_UNMANAGED_SLEEPING: %TRUE when unmanaged because NM is sleeping.
+ * @NM_UNMANAGED_QUITTING: %TRUE when unmanaged because NM is shutting down.
  * @NM_UNMANAGED_PARENT: %TRUE when unmanaged due to parent device being unmanaged
  * @NM_UNMANAGED_LOOPBACK: %TRUE for unmanaging loopback device
  * @NM_UNMANAGED_PLATFORM_INIT: %TRUE when unmanaged because platform link not
- *   yet initialized
- * @NM_UNMANAGED_USER: %TRUE when unmanaged by user decision (via unmanaged-specs)
- * @NM_UNMANAGED_DEFAULT: %TRUE when unmanaged by default (ie, Generic devices)
+ *   yet initialized. Unrealized device are also unmanaged for this reason.
+ * @NM_UNMANAGED_USER_EXPLICIT: %TRUE when unmanaged by explicit user decision
+ *   (e.g. via a D-Bus command)
+ * @NM_UNMANAGED_USER_SETTINGS: %TRUE when unmanaged by user decision via
+ *   the settings plugin (for example keyfile.unmanaged-devices or ifcfg-rh's
+ *   NM_CONTROLLED=no)
+ * @NM_UNMANAGED_BY_DEFAULT: %TRUE for certain device types where we unmanage
+ *   them by default
+ * @NM_UNMANAGED_USER_UDEV: %TRUE when unmanaged by user decision (via UDev rule)
  * @NM_UNMANAGED_EXTERNAL_DOWN: %TRUE when unmanaged because !IFF_UP and not created by NM
+ * @NM_UNMANAGED_IS_SLAVE: indicates that the device is enslaved. Note that
+ *   setting the NM_UNMANAGED_IS_SLAVE to %TRUE makes no sense, this flag has only
+ *   meaning to set a slave device as managed if the parent is managed too.
  */
 typedef enum { /*< skip >*/
 	NM_UNMANAGED_NONE          = 0,
 
-	NM_UNMANAGED_INTERNAL      = (1LL <<  0),
-	NM_UNMANAGED_PARENT        = (1LL <<  1),
-	NM_UNMANAGED_LOOPBACK      = (1LL <<  2),
-	NM_UNMANAGED_PLATFORM_INIT = (1LL <<  3),
-	NM_UNMANAGED_USER          = (1LL <<  4),
-
-	NM_UNMANAGED_DEFAULT       = (1LL <<  8),
+	/* these flags are authorative. If one of them is set,
+	 * the device cannot be managed. */
+	NM_UNMANAGED_SLEEPING      = (1LL <<  0),
+	NM_UNMANAGED_QUITTING      = (1LL <<  1),
+	NM_UNMANAGED_PARENT        = (1LL <<  2),
+	NM_UNMANAGED_LOOPBACK      = (1LL <<  3),
+	NM_UNMANAGED_PLATFORM_INIT = (1LL <<  4),
+	NM_UNMANAGED_USER_EXPLICIT = (1LL <<  5),
+	NM_UNMANAGED_USER_SETTINGS = (1LL <<  6),
+
+	/* These flags can be non-effective and be overwritten
+	 * by other flags. */
+	NM_UNMANAGED_BY_DEFAULT    = (1LL <<  8),
+	NM_UNMANAGED_USER_UDEV     = (1LL << 10),
 	NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 11),
+	NM_UNMANAGED_IS_SLAVE      = (1LL << 12),
 
-	/* Boundary value */
-	__NM_UNMANAGED_LAST,
-	NM_UNMANAGED_LAST          = __NM_UNMANAGED_LAST - 1,
-	NM_UNMANAGED_ALL           = ((NM_UNMANAGED_LAST << 1) - 1),
 } NMUnmanagedFlags;
 
-gboolean nm_device_get_managed (NMDevice *device);
+typedef enum {
+	NM_UNMAN_FLAG_OP_SET_MANAGED        = FALSE,
+	NM_UNMAN_FLAG_OP_SET_UNMANAGED      = TRUE,
+	NM_UNMAN_FLAG_OP_FORGET             = 2,
+} NMUnmanFlagOp;
+
+const char *nm_unmanaged_flags2str (NMUnmanagedFlags flags, char *buf, gsize len);
+
+gboolean nm_device_get_managed (NMDevice *device, gboolean for_user_request);
 NMUnmanagedFlags nm_device_get_unmanaged_flags (NMDevice *device, NMUnmanagedFlags flag);
 void nm_device_set_unmanaged_flags (NMDevice *device,
-                                    NMUnmanagedFlags flag,
-                                    gboolean unmanaged,
-                                    NMDeviceStateReason reason);
-void nm_device_set_unmanaged_flags_by_device_spec (NMDevice *self, const GSList *unmanaged_specs);
-void nm_device_set_unmanaged_flags_initial (NMDevice *device,
-                                            NMUnmanagedFlags flag,
-                                            gboolean unmanaged);
-void nm_device_set_unmanaged_quitting (NMDevice *device);
+                                    NMUnmanagedFlags flags,
+                                    NMUnmanFlagOp set_op);
+void nm_device_set_unmanaged_by_flags (NMDevice *device,
+                                       NMUnmanagedFlags flags,
+                                       NMUnmanFlagOp set_op,
+                                       NMDeviceStateReason reason);
+void nm_device_set_unmanaged_by_user_config (NMDevice *self, const GSList *unmanaged_specs);
+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);
 
@@ -481,6 +504,7 @@ gboolean nm_device_unrealize          (NMDevice *device,
 
 gboolean nm_device_get_autoconnect (NMDevice *device);
 void nm_device_set_autoconnect (NMDevice *device, gboolean autoconnect);
+void nm_device_emit_recheck_auto_activate (NMDevice *device);
 
 void nm_device_state_changed (NMDevice *device,
                               NMDeviceState state,
diff --git a/src/devices/nm-lldp-listener.c b/src/devices/nm-lldp-listener.c
index 91181292..81827817 100644
--- a/src/devices/nm-lldp-listener.c
+++ b/src/devices/nm-lldp-listener.c
@@ -18,7 +18,7 @@
  * Copyright (C) 2015 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <net/ethernet.h>
 
@@ -65,6 +65,32 @@ typedef struct {
 
 static void process_lldp_neighbors (NMLldpListener *self);
 
+/*****************************************************************************/
+
+#define _NMLOG_PREFIX_NAME                "lldp"
+#define _NMLOG_DOMAIN                     LOGD_DEVICE
+#define _NMLOG(level, ...) \
+    G_STMT_START { \
+        const NMLogLevel _level = (level); \
+        \
+        if (nm_logging_enabled (_level, _NMLOG_DOMAIN)) { \
+            char _sbuf[64]; \
+            int _ifindex = (self) ? NM_LLDP_LISTENER_GET_PRIVATE (self)->ifindex : 0; \
+            \
+            _nm_log (_level, _NMLOG_DOMAIN, 0, \
+                     "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+                     _NMLOG_PREFIX_NAME, \
+                     ((_ifindex > 0) \
+                        ? nm_sprintf_buf (_sbuf, "[%p,%d]", (self), _ifindex) \
+                        : ((self) \
+                            ? nm_sprintf_buf (_sbuf, "[%p]", (self)) \
+                            : "")) \
+                     _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
+        } \
+    } G_STMT_END \
+
+/*****************************************************************************/
+
 static void
 gvalue_destroy (gpointer data)
 {
@@ -100,11 +126,13 @@ static guint
 lldp_neighbor_id_hash (gconstpointer ptr)
 {
 	const LLDPNeighbor *neigh = ptr;
+	guint hash;
 
-	return g_str_hash (neigh->chassis_id) ^
-	       g_str_hash (neigh->port_id) ^
-	       neigh->chassis_id_type ^
-	       (neigh->port_id_type * 33);
+	hash =   23423423u  + ((guint) (neigh->chassis_id ? g_str_hash (neigh->chassis_id) : 12321u));
+	hash = (hash * 33u) + ((guint) (neigh->port_id ? g_str_hash (neigh->port_id) : 34342343u));
+	hash = (hash * 33u) + ((guint) neigh->chassis_id_type);
+	hash = (hash * 33u) + ((guint) neigh->port_id_type);
+	return hash;
 }
 
 static gboolean
@@ -119,18 +147,22 @@ lldp_neighbor_id_equal (gconstpointer a, gconstpointer b)
 }
 
 static void
-lldp_neighbor_free (gpointer data)
+lldp_neighbor_free (LLDPNeighbor *neighbor)
 {
-	LLDPNeighbor *neighbor = data;
-
 	if (neighbor) {
 		g_free (neighbor->chassis_id);
 		g_free (neighbor->port_id);
 		g_hash_table_unref (neighbor->tlvs);
-		g_free (neighbor);
+		g_slice_free (LLDPNeighbor, neighbor);
 	}
 }
 
+static void
+lldp_neighbor_freep (LLDPNeighbor **ptr)
+{
+	lldp_neighbor_free (*ptr);
+}
+
 static gboolean
 lldp_neighbor_equal (LLDPNeighbor *a, LLDPNeighbor *b)
 {
@@ -207,8 +239,12 @@ lldp_hash_table_equal (GHashTable *a, GHashTable *b)
 static gboolean
 lldp_timeout (gpointer user_data)
 {
-	NMLldpListener *self = NM_LLDP_LISTENER (user_data);
-	NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE (self);
+	NMLldpListener *self = user_data;
+	NMLldpListenerPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_LLDP_LISTENER (self), G_SOURCE_REMOVE);
+
+	priv = NM_LLDP_LISTENER_GET_PRIVATE (self);
 
 	priv->timer = 0;
 
@@ -222,24 +258,26 @@ static void
 process_lldp_neighbors (NMLldpListener *self)
 {
 	NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE (self);
-	sd_lldp_packet **packets = NULL;
+	nm_auto_free sd_lldp_packet **packets = NULL;
 	GHashTable *hash;
 	int num, i;
 
+	g_return_if_fail (priv->lldp_handle);
+
 	num = sd_lldp_get_packets (priv->lldp_handle, &packets);
 	if (num < 0) {
-		nm_log_dbg (LOGD_DEVICE, "LLDP: error %d retrieving neighbor packets for %s",
-		            num, priv->iface);
+		_LOGD ("process: error %d retrieving neighbor packets for %s",
+		        num, priv->iface);
 		return;
 	}
 
 	hash = g_hash_table_new_full (lldp_neighbor_id_hash, lldp_neighbor_id_equal,
-	                              lldp_neighbor_free, NULL);
+	                              (GDestroyNotify) lldp_neighbor_free, NULL);
 
 	for (i = 0; packets && i < num; i++) {
+		nm_auto (lldp_neighbor_freep) LLDPNeighbor *neigh = NULL;
 		uint8_t chassis_id_type, port_id_type, *chassis_id, *port_id, data8;
 		uint16_t chassis_id_len, port_id_len, len, data16;
-		LLDPNeighbor *neigh;
 		GValue *value;
 		char *str;
 		int r;
@@ -257,37 +295,32 @@ process_lldp_neighbors (NMLldpListener *self)
 		if (r < 0)
 			goto next_packet;
 
-		neigh = g_malloc0 (sizeof (LLDPNeighbor));
+		neigh = g_slice_new0 (LLDPNeighbor);
 		neigh->tlvs = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gvalue_destroy);
 		neigh->chassis_id_type = chassis_id_type;
 		neigh->port_id_type = port_id_type;
 		sd_lldp_packet_get_destination_type (packets[i], &neigh->dest);
 
-		if (chassis_id_len < 1) {
-			lldp_neighbor_free (neigh);
+		if (chassis_id_len < 1)
 			goto next_packet;
-		}
 
 		switch (chassis_id_type) {
 		case LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS:
 		case LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME:
 		case LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED:
 		case LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT:
-			neigh->chassis_id = strndup ((char *) chassis_id, chassis_id_len);
+			neigh->chassis_id = g_strndup ((const char *) chassis_id, chassis_id_len);
 			break;
 		case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
 			neigh->chassis_id = nm_utils_hwaddr_ntoa (chassis_id, chassis_id_len);
 			break;
 		default:
-			nm_log_dbg (LOGD_DEVICE, "LLDP: unsupported chassis ID type %d", chassis_id_type);
-			lldp_neighbor_free (neigh);
+			_LOGD ("process: unsupported chassis ID type %d", chassis_id_type);
 			goto next_packet;
 		}
 
-		if (port_id_len < 1) {
-			lldp_neighbor_free (neigh);
+		if (port_id_len < 1)
 			goto next_packet;
-		}
 
 		switch (port_id_type) {
 		case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
@@ -300,8 +333,7 @@ process_lldp_neighbors (NMLldpListener *self)
 			neigh->port_id = nm_utils_hwaddr_ntoa (port_id, port_id_len);
 			break;
 		default:
-			nm_log_dbg (LOGD_DEVICE, "LLDP: unsupported port ID type %d", port_id_type);
-			lldp_neighbor_free (neigh);
+			_LOGD ("process: unsupported port ID type %d", port_id_type);
 			goto next_packet;
 		}
 
@@ -346,16 +378,15 @@ process_lldp_neighbors (NMLldpListener *self)
 			g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME, value);
 		}
 
-		nm_log_dbg (LOGD_DEVICE, "LLDP: new neigh: CHASSIS='%s' PORT='%s'",
-		            neigh->chassis_id, neigh->port_id);
+		_LOGD ("process: new neigh: CHASSIS='%s' PORT='%s'",
+		        neigh->chassis_id, neigh->port_id);
 
 		g_hash_table_add (hash, neigh);
+		neigh = NULL;
 next_packet:
 		sd_lldp_packet_unref (packets[i]);
 	}
 
-	g_free (packets);
-
 	if (lldp_hash_table_equal (priv->lldp_neighbors, hash)) {
 		g_hash_table_destroy (hash);
 	} else {
@@ -380,6 +411,7 @@ lldp_event_handler (sd_lldp *lldp, int event, void *userdata)
 	NMLldpListenerPrivate *priv;
 
 	g_return_if_fail (NM_IS_LLDP_LISTENER (self));
+
 	priv = NM_LLDP_LISTENER_GET_PRIVATE (self);
 
 	if (priv->timer > 0) {
@@ -446,6 +478,7 @@ nm_lldp_listener_start (NMLldpListener *self, int ifindex, const char *iface,
 
 	priv->ifindex = ifindex;
 	priv->iface = strdup (iface);
+	_LOGD ("start");
 	return TRUE;
 
 err:
@@ -466,6 +499,7 @@ nm_lldp_listener_stop (NMLldpListener *self)
 	priv = NM_LLDP_LISTENER_GET_PRIVATE (self);
 
 	if (priv->lldp_handle) {
+		_LOGD ("stop");
 		sd_lldp_stop (priv->lldp_handle);
 		sd_lldp_detach_event (priv->lldp_handle);
 		sd_lldp_unref (priv->lldp_handle);
@@ -481,6 +515,7 @@ nm_lldp_listener_stop (NMLldpListener *self)
 	}
 
 	nm_clear_g_source (&priv->timer);
+	priv->ifindex = 0;
 }
 
 gboolean
@@ -595,7 +630,9 @@ nm_lldp_listener_init (NMLldpListener *self)
 
 	priv->lldp_neighbors = g_hash_table_new_full (lldp_neighbor_id_hash,
 	                                              lldp_neighbor_id_equal,
-	                                              lldp_neighbor_free, NULL);
+	                                              (GDestroyNotify) lldp_neighbor_free, NULL);
+
+	_LOGT ("lldp listener created");
 }
 
 NMLldpListener *
@@ -623,6 +660,8 @@ finalize (GObject *object)
 
 	nm_clear_g_variant (&priv->variant);
 
+	_LOGT ("lldp listener destroyed");
+
 	G_OBJECT_CLASS (nm_lldp_listener_parent_class)->finalize (object);
 }
 
diff --git a/src/devices/nm-lldp-listener.h b/src/devices/nm-lldp-listener.h
index 492752c1..10c43e7c 100644
--- a/src/devices/nm-lldp-listener.h
+++ b/src/devices/nm-lldp-listener.h
@@ -21,9 +21,6 @@
 #ifndef __NM_LLDP_LISTENER__
 #define __NM_LLDP_LISTENER__
 
-#include "nm-glib.h"
-#include "nm-types.h"
-
 G_BEGIN_DECLS
 
 #define NM_TYPE_LLDP_LISTENER            (nm_lldp_listener_get_type ())
diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c
index c0b83b84..c3d48b41 100644
--- a/src/devices/team/nm-device-team.c
+++ b/src/devices/team/nm-device-team.c
@@ -18,7 +18,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <sys/types.h>
 #include <unistd.h>
@@ -27,7 +27,6 @@
 #include <teamdctl.h>
 #include <stdlib.h>
 
-#include "nm-default.h"
 #include "nm-device-team.h"
 #include "NetworkManagerUtils.h"
 #include "nm-device-private.h"
@@ -85,7 +84,6 @@ check_connection_available (NMDevice *device,
 static gboolean
 check_connection_compatible (NMDevice *device, NMConnection *connection)
 {
-	const char *iface;
 	NMSettingTeam *s_team;
 
 	if (!NM_DEVICE_CLASS (nm_device_team_parent_class)->check_connection_compatible (device, connection))
@@ -95,11 +93,6 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 	if (!s_team || !nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME))
 		return FALSE;
 
-	/* Team connections must specify the virtual interface name */
-	iface = nm_connection_get_interface_name (connection);
-	if (!iface || strcmp (nm_device_get_iface (device), iface))
-		return FALSE;
-
 	/* FIXME: match team properties like mode, etc? */
 
 	return TRUE;
@@ -218,6 +211,7 @@ master_update_slave_connection (NMDevice *self,
 
 	err = teamdctl_port_config_get_raw_direct (tdc, iface_slave, (char **)&team_port_config);
 	port_config = g_strdup (team_port_config);
+	teamdctl_disconnect (tdc);
 	teamdctl_free (tdc);
 	if (err) {
 		g_set_error (error,
@@ -501,7 +495,6 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
 	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self);
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
 	gs_free_error GError *error = NULL;
-	NMConnection *connection;
 	NMSettingTeam *s_team;
 	const char *cfg;
 
@@ -511,9 +504,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
 	if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
 		return ret;
 
-	connection = nm_device_get_applied_connection (device);
-	g_assert (connection);
-	s_team = nm_connection_get_setting_team (connection);
+	s_team = (NMSettingTeam *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_TEAM);
 	g_assert (s_team);
 
 	if (priv->tdc) {
@@ -673,7 +664,7 @@ create_and_realize (NMDevice *device,
 	NMPlatformError plerr;
 
 	plerr = nm_platform_link_team_add (NM_PLATFORM_GET, iface, out_plink);
-	if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+	if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 		             "Failed to create team master interface '%s' for '%s': %s",
 		             iface,
diff --git a/src/devices/team/nm-team-factory.c b/src/devices/team/nm-team-factory.c
index 5f9e142a..971efe87 100644
--- a/src/devices/team/nm-team-factory.c
+++ b/src/devices/team/nm-team-factory.c
@@ -18,7 +18,7 @@
  * Copyright (C) 2014 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 #include <gmodule.h>
@@ -26,7 +26,6 @@
 #include "nm-device-factory.h"
 #include "nm-team-factory.h"
 #include "nm-device-team.h"
-#include "nm-default.h"
 #include "nm-platform.h"
 #include "nm-core-internal.h"
 
diff --git a/src/devices/tests/Makefile.am b/src/devices/tests/Makefile.am
index 330377b0..e4f4d3fe 100644
--- a/src/devices/tests/Makefile.am
+++ b/src/devices/tests/Makefile.am
@@ -23,7 +23,8 @@ DEVICES_LDADD = \
 @GNOME_CODE_COVERAGE_RULES@
 
 noinst_PROGRAMS = \
-	test-lldp
+	test-lldp \
+	test-arping
 
 test_lldp_SOURCES = \
 	test-lldp.c \
@@ -37,6 +38,19 @@ test_lldp_CPPFLAGS = \
 
 test_lldp_LDADD = $(DEVICES_LDADD)
 
+test_arping_SOURCES = \
+	test-arping.c \
+	../nm-arping-manager.c \
+	$(top_srcdir)/src/platform/tests/test-common.c
+
+test_arping_CPPFLAGS = \
+	$(AM_CPPFLAGS) \
+	-I$(top_srcdir)/src/platform/tests \
+	-DSETUP=nm_linux_platform_setup
+
+test_arping_LDADD = $(DEVICES_LDADD)
+
 @VALGRIND_RULES@
 TESTS = \
-	test-lldp
+	test-lldp \
+	test-arping
diff --git a/src/devices/tests/Makefile.in b/src/devices/tests/Makefile.in
index 1cfe46b6..1cb73d28 100644
--- a/src/devices/tests/Makefile.in
+++ b/src/devices/tests/Makefile.in
@@ -88,8 +88,8 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-noinst_PROGRAMS = test-lldp$(EXEEXT)
-TESTS = test-lldp$(EXEEXT)
+noinst_PROGRAMS = test-lldp$(EXEEXT) test-arping$(EXEEXT)
+TESTS = test-lldp$(EXEEXT) test-arping$(EXEEXT)
 subdir = src/devices/tests
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
@@ -113,15 +113,20 @@ CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 PROGRAMS = $(noinst_PROGRAMS)
+am_test_arping_OBJECTS = test_arping-test-arping.$(OBJEXT) \
+	test_arping-nm-arping-manager.$(OBJEXT) \
+	test_arping-test-common.$(OBJEXT)
+test_arping_OBJECTS = $(am_test_arping_OBJECTS)
+test_arping_DEPENDENCIES = $(DEVICES_LDADD)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
 am_test_lldp_OBJECTS = test_lldp-test-lldp.$(OBJEXT) \
 	test_lldp-nm-lldp-listener.$(OBJEXT) \
 	test_lldp-test-common.$(OBJEXT)
 test_lldp_OBJECTS = $(am_test_lldp_OBJECTS)
 test_lldp_DEPENDENCIES = $(DEVICES_LDADD)
-AM_V_lt = $(am__v_lt_@AM_V@)
-am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
-am__v_lt_0 = --silent
-am__v_lt_1 = 
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -156,8 +161,8 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = $(test_lldp_SOURCES)
-DIST_SOURCES = $(test_lldp_SOURCES)
+SOURCES = $(test_arping_SOURCES) $(test_lldp_SOURCES)
+DIST_SOURCES = $(test_arping_SOURCES) $(test_lldp_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -685,6 +690,17 @@ test_lldp_CPPFLAGS = \
 	-DSETUP=nm_linux_platform_setup
 
 test_lldp_LDADD = $(DEVICES_LDADD)
+test_arping_SOURCES = \
+	test-arping.c \
+	../nm-arping-manager.c \
+	$(top_srcdir)/src/platform/tests/test-common.c
+
+test_arping_CPPFLAGS = \
+	$(AM_CPPFLAGS) \
+	-I$(top_srcdir)/src/platform/tests \
+	-DSETUP=nm_linux_platform_setup
+
+test_arping_LDADD = $(DEVICES_LDADD)
 all: all-am
 
 .SUFFIXES:
@@ -728,6 +744,10 @@ clean-noinstPROGRAMS:
 	echo " rm -f" $$list; \
 	rm -f $$list
 
+test-arping$(EXEEXT): $(test_arping_OBJECTS) $(test_arping_DEPENDENCIES) $(EXTRA_test_arping_DEPENDENCIES) 
+	@rm -f test-arping$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(test_arping_OBJECTS) $(test_arping_LDADD) $(LIBS)
+
 test-lldp$(EXEEXT): $(test_lldp_OBJECTS) $(test_lldp_DEPENDENCIES) $(EXTRA_test_lldp_DEPENDENCIES) 
 	@rm -f test-lldp$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(test_lldp_OBJECTS) $(test_lldp_LDADD) $(LIBS)
@@ -738,6 +758,9 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_arping-nm-arping-manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_arping-test-arping.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_arping-test-common.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lldp-nm-lldp-listener.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lldp-test-common.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lldp-test-lldp.Po@am__quote@
@@ -763,6 +786,48 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
+test_arping-test-arping.o: test-arping.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_arping_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_arping-test-arping.o -MD -MP -MF $(DEPDIR)/test_arping-test-arping.Tpo -c -o test_arping-test-arping.o `test -f 'test-arping.c' || echo '$(srcdir)/'`test-arping.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/test_arping-test-arping.Tpo $(DEPDIR)/test_arping-test-arping.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='test-arping.c' object='test_arping-test-arping.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_arping_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_arping-test-arping.o `test -f 'test-arping.c' || echo '$(srcdir)/'`test-arping.c
+
+test_arping-test-arping.obj: test-arping.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_arping_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_arping-test-arping.obj -MD -MP -MF $(DEPDIR)/test_arping-test-arping.Tpo -c -o test_arping-test-arping.obj `if test -f 'test-arping.c'; then $(CYGPATH_W) 'test-arping.c'; else $(CYGPATH_W) '$(srcdir)/test-arping.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/test_arping-test-arping.Tpo $(DEPDIR)/test_arping-test-arping.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='test-arping.c' object='test_arping-test-arping.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_arping_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_arping-test-arping.obj `if test -f 'test-arping.c'; then $(CYGPATH_W) 'test-arping.c'; else $(CYGPATH_W) '$(srcdir)/test-arping.c'; fi`
+
+test_arping-nm-arping-manager.o: ../nm-arping-manager.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_arping_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_arping-nm-arping-manager.o -MD -MP -MF $(DEPDIR)/test_arping-nm-arping-manager.Tpo -c -o test_arping-nm-arping-manager.o `test -f '../nm-arping-manager.c' || echo '$(srcdir)/'`../nm-arping-manager.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/test_arping-nm-arping-manager.Tpo $(DEPDIR)/test_arping-nm-arping-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../nm-arping-manager.c' object='test_arping-nm-arping-manager.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_arping_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_arping-nm-arping-manager.o `test -f '../nm-arping-manager.c' || echo '$(srcdir)/'`../nm-arping-manager.c
+
+test_arping-nm-arping-manager.obj: ../nm-arping-manager.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_arping_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_arping-nm-arping-manager.obj -MD -MP -MF $(DEPDIR)/test_arping-nm-arping-manager.Tpo -c -o test_arping-nm-arping-manager.obj `if test -f '../nm-arping-manager.c'; then $(CYGPATH_W) '../nm-arping-manager.c'; else $(CYGPATH_W) '$(srcdir)/../nm-arping-manager.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/test_arping-nm-arping-manager.Tpo $(DEPDIR)/test_arping-nm-arping-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='../nm-arping-manager.c' object='test_arping-nm-arping-manager.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_arping_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_arping-nm-arping-manager.obj `if test -f '../nm-arping-manager.c'; then $(CYGPATH_W) '../nm-arping-manager.c'; else $(CYGPATH_W) '$(srcdir)/../nm-arping-manager.c'; fi`
+
+test_arping-test-common.o: $(top_srcdir)/src/platform/tests/test-common.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_arping_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_arping-test-common.o -MD -MP -MF $(DEPDIR)/test_arping-test-common.Tpo -c -o test_arping-test-common.o `test -f '$(top_srcdir)/src/platform/tests/test-common.c' || echo '$(srcdir)/'`$(top_srcdir)/src/platform/tests/test-common.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/test_arping-test-common.Tpo $(DEPDIR)/test_arping-test-common.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$(top_srcdir)/src/platform/tests/test-common.c' object='test_arping-test-common.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_arping_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_arping-test-common.o `test -f '$(top_srcdir)/src/platform/tests/test-common.c' || echo '$(srcdir)/'`$(top_srcdir)/src/platform/tests/test-common.c
+
+test_arping-test-common.obj: $(top_srcdir)/src/platform/tests/test-common.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_arping_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_arping-test-common.obj -MD -MP -MF $(DEPDIR)/test_arping-test-common.Tpo -c -o test_arping-test-common.obj `if test -f '$(top_srcdir)/src/platform/tests/test-common.c'; then $(CYGPATH_W) '$(top_srcdir)/src/platform/tests/test-common.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/src/platform/tests/test-common.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/test_arping-test-common.Tpo $(DEPDIR)/test_arping-test-common.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$(top_srcdir)/src/platform/tests/test-common.c' object='test_arping-test-common.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_arping_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_arping-test-common.obj `if test -f '$(top_srcdir)/src/platform/tests/test-common.c'; then $(CYGPATH_W) '$(top_srcdir)/src/platform/tests/test-common.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/src/platform/tests/test-common.c'; fi`
+
 test_lldp-test-lldp.o: test-lldp.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lldp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lldp-test-lldp.o -MD -MP -MF $(DEPDIR)/test_lldp-test-lldp.Tpo -c -o test_lldp-test-lldp.o `test -f 'test-lldp.c' || echo '$(srcdir)/'`test-lldp.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/test_lldp-test-lldp.Tpo $(DEPDIR)/test_lldp-test-lldp.Po
@@ -1011,6 +1076,13 @@ test-lldp.log: test-lldp$(EXEEXT)
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+test-arping.log: test-arping$(EXEEXT)
+	@p='test-arping$(EXEEXT)'; \
+	b='test-arping'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 .test.log:
 	@p='$<'; \
 	$(am__set_b); \
diff --git a/src/devices/tests/test-arping.c b/src/devices/tests/test-arping.c
new file mode 100644
index 00000000..36e17631
--- /dev/null
+++ b/src/devices/tests/test-arping.c
@@ -0,0 +1,139 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* nm-platform.c - Handle runtime kernel networking configuration
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-arping-manager.h"
+#include "test-common.h"
+
+#define IFACE_VETH0 "nm-test-veth0"
+#define IFACE_VETH1 "nm-test-veth1"
+
+#define ADDR1 0x01010101
+#define ADDR2 0x02020202
+#define ADDR3 0x03030303
+#define ADDR4 0x04040404
+
+typedef struct {
+	int ifindex0;
+	int ifindex1;
+} test_fixture;
+
+static void
+fixture_setup (test_fixture *fixture, gconstpointer user_data)
+{
+	/* create veth pair. */
+	nmtstp_run_command_check ("ip link add dev %s type veth peer name %s", IFACE_VETH0, IFACE_VETH1);
+	fixture->ifindex0 = nmtstp_assert_wait_for_link (IFACE_VETH0, NM_LINK_TYPE_VETH, 100)->ifindex;
+	fixture->ifindex1 = nmtstp_assert_wait_for_link (IFACE_VETH1, NM_LINK_TYPE_VETH, 100)->ifindex;
+
+	g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex0, NULL));
+	g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex1, NULL));
+}
+
+typedef struct {
+	in_addr_t addresses[8];
+	in_addr_t peer_addresses[8];
+	gboolean expected_result[8];
+} TestInfo;
+
+static void
+arping_manager_probe_terminated (NMArpingManager *arping_manager, GMainLoop *loop)
+{
+	g_main_loop_quit (loop);
+}
+
+static void
+test_arping_common (test_fixture *fixture, TestInfo *info)
+{
+	gs_unref_object NMArpingManager *manager = NULL;
+	GMainLoop *loop;
+	int i;
+
+	if (!nm_utils_find_helper ("arping", NULL, NULL)) {
+		g_test_skip ("arping binary is missing");
+		return;
+	}
+
+	manager = nm_arping_manager_new (fixture->ifindex0);
+	g_assert (manager != NULL);
+
+	for (i = 0; info->addresses[i]; i++)
+		g_assert (nm_arping_manager_add_address (manager, info->addresses[i]));
+
+	for (i = 0; info->peer_addresses[i]; i++) {
+		nmtstp_ip4_address_add (FALSE, fixture->ifindex1, info->peer_addresses[i],
+		                        24, 0, 3600, 1800, NULL);
+	}
+
+	loop = g_main_loop_new (NULL, FALSE);
+	g_signal_connect (manager, NM_ARPING_MANAGER_PROBE_TERMINATED,
+	                  G_CALLBACK (arping_manager_probe_terminated), loop);
+	g_assert (nm_arping_manager_start_probe (manager, 100, NULL));
+	g_assert (nmtst_main_loop_run (loop, 1000));
+
+	for (i = 0; info->addresses[i]; i++) {
+		g_assert_cmpint (nm_arping_manager_check_address (manager, info->addresses[i]),
+		                 ==,
+		                 info->expected_result[i]);
+	}
+
+	g_main_loop_unref (loop);
+}
+
+static void
+test_arping_1 (test_fixture *fixture, gconstpointer user_data)
+{
+	TestInfo info = { .addresses       = { ADDR1, ADDR2, ADDR3 },
+	                  .peer_addresses  = { ADDR4 },
+	                  .expected_result = { TRUE, TRUE, TRUE } };
+
+	test_arping_common (fixture, &info);
+}
+
+static void
+test_arping_2 (test_fixture *fixture, gconstpointer user_data)
+{
+	TestInfo info = { .addresses       = { ADDR1, ADDR2, ADDR3, ADDR4 },
+	                  .peer_addresses  = { ADDR3, ADDR2 },
+	                  .expected_result = { TRUE, FALSE, FALSE, TRUE } };
+
+	test_arping_common (fixture, &info);
+}
+
+static void
+fixture_teardown (test_fixture *fixture, gconstpointer user_data)
+{
+	nm_platform_link_delete (NM_PLATFORM_GET, fixture->ifindex0);
+	nm_platform_link_delete (NM_PLATFORM_GET, fixture->ifindex1);
+}
+
+void
+init_tests (int *argc, char ***argv)
+{
+	nmtst_init_with_logging (argc, argv, NULL, "ALL");
+}
+
+void
+setup_tests (void)
+{
+	g_test_add ("/arping/1", test_fixture, NULL, fixture_setup, test_arping_1, fixture_teardown);
+	g_test_add ("/arping/2", test_fixture, NULL, fixture_setup, test_arping_2, fixture_teardown);
+}
diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c
index c339d9ca..dfae58b1 100644
--- a/src/devices/tests/test-lldp.c
+++ b/src/devices/tests/test-lldp.c
@@ -18,7 +18,7 @@
  * Copyright (C) 2015 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <fcntl.h>
 #include <linux/if_tun.h>
@@ -26,7 +26,6 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include "nm-default.h"
 #include "nm-lldp-listener.h"
 #include "test-common.h"
 
@@ -95,7 +94,6 @@ get_lldp_neighbor_attribute (GVariant *neighbors,
 	GVariantIter iter, attrs_iter;
 	GVariant *variant, *attr_variant;
 	const char *attr_name;
-	GVariant *chassis_v, *port_v, *attr_v;
 
 	g_return_val_if_fail (g_variant_is_of_type (neighbors,
 	                                            G_VARIANT_TYPE ("aa{sv}")),
@@ -103,31 +101,34 @@ get_lldp_neighbor_attribute (GVariant *neighbors,
 	g_variant_iter_init (&iter, neighbors);
 
 	while (g_variant_iter_next (&iter, "@a{sv}", &variant)) {
-		g_variant_iter_init (&attrs_iter, variant);
-		chassis_v = NULL;
-		port_v = NULL;
-		attr_v = NULL;
+		gs_unref_variant GVariant *chassis_v = NULL;
+		gs_unref_variant GVariant *port_v = NULL;
+		gs_unref_variant GVariant *attr_v = NULL;
 
+		g_variant_iter_init (&attrs_iter, variant);
 		while (g_variant_iter_next (&attrs_iter, "{&sv}", &attr_name, &attr_variant)) {
-			if (!g_strcmp0 (attr_name, NM_LLDP_ATTR_CHASSIS_ID))
+			if (!g_strcmp0 (attr_name, NM_LLDP_ATTR_CHASSIS_ID)) {
+				g_assert (!chassis_v);
 				chassis_v = attr_variant;
-			else if (!g_strcmp0 (attr_name, NM_LLDP_ATTR_PORT_ID))
+			} else if (!g_strcmp0 (attr_name, NM_LLDP_ATTR_PORT_ID)) {
+				g_assert (!port_v);
 				port_v = attr_variant;
-			else if (!g_strcmp0 (attr_name, name))
+			} else if (!g_strcmp0 (attr_name, name)) {
+				g_assert (!attr_v);
 				attr_v = attr_variant;
+			} else
+				g_variant_unref (attr_variant);
 		}
 
-		if (   g_variant_is_of_type (chassis_v, G_VARIANT_TYPE_STRING)
+		g_variant_unref (variant);
+
+		if (   chassis_v
+		    && port_v
+		    && g_variant_is_of_type (chassis_v, G_VARIANT_TYPE_STRING)
 		    && g_variant_is_of_type (port_v, G_VARIANT_TYPE_STRING)
 		    && !g_strcmp0 (chassis, g_variant_get_string (chassis_v, NULL))
-		    && !g_strcmp0 (port, g_variant_get_string (port_v, NULL))) {
-
-			g_variant_ref (attr_v);
-			g_variant_unref (variant);
-
-			return attr_v;
-		}
-		g_variant_unref (variant);
+		    && !g_strcmp0 (port, g_variant_get_string (port_v, NULL)))
+			return g_variant_ref (attr_v);
 	}
 
 	/* neighbor not found */
@@ -137,7 +138,7 @@ get_lldp_neighbor_attribute (GVariant *neighbors,
 static void
 test_receive_frame (test_fixture *fixture, gconstpointer user_data)
 {
-	NMLldpListener *listener;
+	gs_unref_object NMLldpListener *listener = NULL;
 	GMainLoop *loop;
 	TestInfo info = { };
 	GVariant *neighbors, *attr;
@@ -182,6 +183,7 @@ test_receive_frame (test_fixture *fixture, gconstpointer user_data)
 	g_assert (attr != NULL);
 	g_assert (g_variant_is_of_type (attr, G_VARIANT_TYPE_STRING));
 	g_assert_cmpstr (g_variant_get_string (attr, NULL), ==, "Port");
+	nm_clear_g_variant (&attr);
 
 	/* Check system name */
 	attr = get_lldp_neighbor_attribute (neighbors, "00:01:02:03:04:05", "1/3",
@@ -189,6 +191,7 @@ test_receive_frame (test_fixture *fixture, gconstpointer user_data)
 	g_assert (attr != NULL);
 	g_assert (g_variant_is_of_type (attr, G_VARIANT_TYPE_STRING));
 	g_assert_cmpstr (g_variant_get_string (attr, NULL), ==, "SYS");
+	nm_clear_g_variant (&attr);
 
 	/* Check destination */
 	attr = get_lldp_neighbor_attribute (neighbors, "00:01:02:03:04:05", "1/3",
@@ -197,6 +200,7 @@ test_receive_frame (test_fixture *fixture, gconstpointer user_data)
 	g_assert (g_variant_is_of_type (attr, G_VARIANT_TYPE_STRING));
 	g_assert_cmpstr (g_variant_get_string (attr, NULL), ==,
 	                 NM_LLDP_DEST_NEAREST_NON_TPMR_BRIDGE);
+	nm_clear_g_variant (&attr);
 
 	g_clear_pointer (&loop, g_main_loop_unref);
 }
diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c
index 23ebd9c8..11da011e 100644
--- a/src/devices/wifi/nm-device-olpc-mesh.c
+++ b/src/devices/wifi/nm-device-olpc-mesh.c
@@ -24,7 +24,7 @@
  * (C) Copyright 2009 One Laptop per Child
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <netinet/in.h>
 #include <string.h>
@@ -35,7 +35,6 @@
 #include <sys/ioctl.h>
 #include <errno.h>
 
-#include "nm-default.h"
 #include "nm-device.h"
 #include "nm-device-wifi.h"
 #include "nm-device-olpc-mesh.h"
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index 64da03e1..da2a0f4a 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -19,14 +19,13 @@
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <netinet/in.h>
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
 
-#include "nm-default.h"
 #include "nm-device.h"
 #include "nm-device-wifi.h"
 #include "nm-device-private.h"
@@ -125,8 +124,6 @@ static gboolean check_scanning_allowed (NMDeviceWifi *self);
 
 static void schedule_scan (NMDeviceWifi *self, gboolean backoff);
 
-static void cancel_pending_scan (NMDeviceWifi *self);
-
 static void cleanup_association_attempt (NMDeviceWifi * self,
                                          gboolean disconnect);
 
@@ -194,13 +191,12 @@ supplicant_interface_acquire (NMDeviceWifi *self)
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 
 	g_return_val_if_fail (self != NULL, FALSE);
-	/* interface already acquired? */
-	g_return_val_if_fail (priv->sup_iface == NULL, TRUE);
+	g_return_val_if_fail (!priv->sup_iface, TRUE);
 
-	priv->sup_iface = nm_supplicant_manager_iface_get (priv->sup_mgr,
-	                                                   nm_device_get_iface (NM_DEVICE (self)),
-	                                                   TRUE);
-	if (priv->sup_iface == NULL) {
+	priv->sup_iface = nm_supplicant_manager_create_interface (priv->sup_mgr,
+	                                                          nm_device_get_iface (NM_DEVICE (self)),
+	                                                          TRUE);
+	if (!priv->sup_iface) {
 		_LOGE (LOGD_WIFI, "Couldn't initialize supplicant interface");
 		return FALSE;
 	}
@@ -249,7 +245,7 @@ supplicant_interface_release (NMDeviceWifi *self)
 
 	priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 
-	cancel_pending_scan (self);
+	nm_clear_g_source (&priv->pending_scan_id);
 
 	/* Reset the scan interval to be pretty frequent when disconnected */
 	priv->scan_interval = SCAN_INTERVAL_MIN + SCAN_INTERVAL_STEP;
@@ -259,16 +255,13 @@ supplicant_interface_release (NMDeviceWifi *self)
 	nm_clear_g_source (&priv->ap_dump_id);
 
 	if (priv->sup_iface) {
-		remove_supplicant_interface_error_handler (self);
-
 		/* Clear supplicant interface signal handlers */
 		g_signal_handlers_disconnect_by_data (priv->sup_iface, self);
 
 		/* Tell the supplicant to disconnect from the current AP */
 		nm_supplicant_interface_disconnect (priv->sup_iface);
 
-		nm_supplicant_manager_iface_release (priv->sup_mgr, priv->sup_iface);
-		priv->sup_iface = NULL;
+		g_clear_object (&priv->sup_iface);
 	}
 }
 
@@ -495,8 +488,6 @@ deactivate (NMDevice *device)
 	if (nm_device_get_initial_hw_address (device))
 		nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_WIFI);
 
-	nm_platform_wifi_set_powersave (NM_PLATFORM_GET, ifindex, 0);
-
 	/* Ensure we're in infrastructure mode after deactivation; some devices
 	 * (usually older ones) don't scan well in adhoc mode.
 	 */
@@ -513,7 +504,7 @@ deactivate (NMDevice *device)
 
 	/* Ensure we trigger a scan after deactivating a Hotspot */
 	if (old_mode == NM_802_11_MODE_AP) {
-		cancel_pending_scan (self);
+		nm_clear_g_source (&priv->pending_scan_id);
 		request_wireless_scan (self, NULL);
 	}
 }
@@ -926,13 +917,26 @@ can_auto_connect (NMDevice *device,
                   char **specific_object)
 {
 	NMDeviceWifi *self = NM_DEVICE_WIFI (device);
+	NMSettingWireless *s_wifi;
 	NMAccessPoint *ap;
-	const char *method = NULL;
+	const char *method, *mode;
 	guint64 timestamp = 0;
 
 	if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->can_auto_connect (device, connection, specific_object))
 		return FALSE;
 
+	s_wifi = nm_connection_get_setting_wireless (connection);
+	g_return_val_if_fail (s_wifi, FALSE);
+
+	/* Always allow autoconnect for AP and non-autoconf Ad-Hoc */
+	method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
+	mode = nm_setting_wireless_get_mode (s_wifi);
+	if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_AP) == 0)
+		return TRUE;
+	else if (   g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC) == 0
+	         && g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) != 0)
+		return TRUE;
+
 	/* Don't autoconnect to networks that have been tried at least once
 	 * but haven't been successful, since these are often accidental choices
 	 * from the menu and the user may not know the password.
@@ -942,11 +946,6 @@ can_auto_connect (NMDevice *device,
 			return FALSE;
 	}
 
-	/* Use the connection if it's a shared connection */
-	method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
-	if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED))
-		return TRUE;
-
 	ap = find_first_compatible_ap (self, connection, FALSE);
 	if (ap) {
 		/* All good; connection is usable */
@@ -1027,6 +1026,7 @@ request_scan_cb (NMDevice *device,
                  gpointer user_data)
 {
 	NMDeviceWifi *self = NM_DEVICE_WIFI (device);
+	NMDeviceWifiPrivate *priv;
 	gs_unref_variant GVariant *new_scan_options = user_data;
 
 	if (error) {
@@ -1042,7 +1042,9 @@ request_scan_cb (NMDevice *device,
 		return;
 	}
 
-	cancel_pending_scan (self);
+	priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+
+	nm_clear_g_source (&priv->pending_scan_id);
 	request_wireless_scan (self, new_scan_options);
 	g_dbus_method_invocation_return_value (context, NULL);
 }
@@ -1366,7 +1368,7 @@ schedule_scan (NMDeviceWifi *self, gboolean backoff)
 	/* Cancel the pending scan if it would happen later than (now + the scan_interval) */
 	if (priv->pending_scan_id) {
 		if (now + priv->scan_interval < priv->scheduled_scan_time)
-			cancel_pending_scan (self);
+			nm_clear_g_source (&priv->pending_scan_id);
 	}
 
 	if (!priv->pending_scan_id) {
@@ -1399,15 +1401,6 @@ schedule_scan (NMDeviceWifi *self, gboolean backoff)
 	}
 }
 
-
-static void
-cancel_pending_scan (NMDeviceWifi *self)
-{
-	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
-
-	nm_clear_g_source (&priv->pending_scan_id);
-}
-
 static void
 supplicant_iface_scan_done_cb (NMSupplicantInterface *iface,
                                gboolean success,
@@ -2205,7 +2198,7 @@ build_supplicant_config (NMDeviceWifi *self,
 	NMSettingMacRandomization mac_randomization_fallback;
 	gs_free char *svalue = NULL;
 
-	g_return_val_if_fail (self != NULL, NULL);
+	g_return_val_if_fail (priv->sup_iface, NULL);
 
 	s_wireless = nm_connection_get_setting_wireless (connection);
 	g_return_val_if_fail (s_wireless != NULL, NULL);
@@ -2323,8 +2316,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
 
 	/* Set spoof MAC to the interface */
 	cloned_mac = nm_setting_wireless_get_cloned_mac_address (s_wireless);
-	if (cloned_mac)
-		nm_device_set_hw_addr (device, cloned_mac, "set", LOGD_WIFI);
+	nm_device_set_hw_addr (device, cloned_mac, "set", LOGD_WIFI);
 
 	/* AP mode never uses a specific object or existing scanned AP */
 	if (priv->mode != NM_802_11_MODE_AP) {
@@ -2393,6 +2385,38 @@ ensure_hotspot_frequency (NMDeviceWifi *self,
 	nm_ap_set_freq (ap, freq);
 }
 
+static void
+set_powersave (NMDevice *device)
+{
+	NMDeviceWifi *self = NM_DEVICE_WIFI (device);
+	NMSettingWireless *s_wireless;
+	NMSettingWirelessPowersave powersave;
+	gs_free char *value = NULL;
+
+	s_wireless = (NMSettingWireless *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRELESS);
+	g_return_if_fail (s_wireless);
+
+	powersave = nm_setting_wireless_get_powersave (s_wireless);
+	if (powersave == NM_SETTING_WIRELESS_POWERSAVE_DEFAULT) {
+		value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
+		                                               "wifi.powersave",
+		                                               device);
+		powersave = _nm_utils_ascii_str_to_int64 (value, 10,
+		                                          NM_SETTING_WIRELESS_POWERSAVE_IGNORE,
+		                                          NM_SETTING_WIRELESS_POWERSAVE_ENABLE,
+		                                          NM_SETTING_WIRELESS_POWERSAVE_IGNORE);
+	}
+
+	_LOGT (LOGD_WIFI, "powersave is set to %u", (unsigned int) powersave);
+
+	if (powersave == NM_SETTING_WIRELESS_POWERSAVE_IGNORE)
+		return;
+
+	nm_platform_wifi_set_powersave (NM_PLATFORM_GET,
+	                                nm_device_get_ifindex (device),
+	                                powersave == NM_SETTING_WIRELESS_POWERSAVE_ENABLE);
+}
+
 static NMActStageReturn
 act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 {
@@ -2459,11 +2483,8 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 	if ((nm_ap_get_mode (ap) == NM_802_11_MODE_ADHOC) || nm_ap_is_hotspot (ap))
 		ensure_hotspot_frequency (self, s_wireless, ap);
 
-	if (nm_ap_get_mode (ap) == NM_802_11_MODE_INFRA) {
-		nm_platform_wifi_set_powersave (NM_PLATFORM_GET,
-		                                nm_device_get_ifindex (device),
-		                                nm_setting_wireless_get_powersave (s_wireless));
-	}
+	if (nm_ap_get_mode (ap) == NM_802_11_MODE_INFRA)
+		set_powersave (device);
 
 	/* Build up the supplicant configuration */
 	config = build_supplicant_config (self, connection, nm_ap_get_freq (ap), &error);
@@ -2817,7 +2838,7 @@ device_state_changed (NMDevice *device,
 	case NM_DEVICE_STATE_DISCONNECTED:
 		/* Kick off a scan to get latest results */
 		priv->scan_interval = SCAN_INTERVAL_MIN;
-		cancel_pending_scan (self);
+		nm_clear_g_source (&priv->pending_scan_id);
 		request_wireless_scan (self, NULL);
 		break;
 	default:
diff --git a/src/devices/wifi/nm-wifi-ap-utils.c b/src/devices/wifi/nm-wifi-ap-utils.c
index d7916aa0..bcf439da 100644
--- a/src/devices/wifi/nm-wifi-ap-utils.c
+++ b/src/devices/wifi/nm-wifi-ap-utils.c
@@ -18,12 +18,11 @@
  * (C) Copyright 2011 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 #include <stdlib.h>
 
-#include "nm-default.h"
 #include "nm-wifi-ap-utils.h"
 #include "nm-utils.h"
 
@@ -162,7 +161,7 @@ verify_no_wpa (NMSettingWirelessSecurity *s_wsec,
 		g_set_error (error,
 		             NM_CONNECTION_ERROR,
 		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
-		             _("a connection using '%s' authentication cannot specific WPA protocols"),
+		             _("a connection using '%s' authentication cannot specify WPA protocols"),
 		             tag);
 		g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
 		                NM_SETTING_WIRELESS_SECURITY_PROTO);
@@ -178,7 +177,7 @@ verify_no_wpa (NMSettingWirelessSecurity *s_wsec,
 			g_set_error (error,
 			             NM_CONNECTION_ERROR,
 			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
-			             _("a connection using '%s' authentication cannot specific WPA ciphers"),
+			             _("a connection using '%s' authentication cannot specify WPA ciphers"),
 			             tag);
 			g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
 			                NM_SETTING_WIRELESS_SECURITY_PAIRWISE);
@@ -195,7 +194,7 @@ verify_no_wpa (NMSettingWirelessSecurity *s_wsec,
 			g_set_error (error,
 			             NM_CONNECTION_ERROR,
 			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
-			             _("a connection using '%s' authentication cannot specific WPA ciphers"),
+			             _("a connection using '%s' authentication cannot specify WPA ciphers"),
 			             tag);
 			g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
 			                NM_SETTING_WIRELESS_SECURITY_GROUP);
@@ -207,7 +206,7 @@ verify_no_wpa (NMSettingWirelessSecurity *s_wsec,
 		g_set_error (error,
 		             NM_CONNECTION_ERROR,
 		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
-		             _("a connection using '%s' authentication cannot specific a WPA password"),
+		             _("a connection using '%s' authentication cannot specify a WPA password"),
 		             tag);
 		g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
 		                NM_SETTING_WIRELESS_SECURITY_PSK);
diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c
index 771d6704..307825c6 100644
--- a/src/devices/wifi/nm-wifi-ap.c
+++ b/src/devices/wifi/nm-wifi-ap.c
@@ -19,12 +19,11 @@
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 #include <stdlib.h>
 
-#include "nm-default.h"
 #include "nm-wifi-ap.h"
 #include "nm-wifi-ap-utils.h"
 #include "NetworkManagerUtils.h"
diff --git a/src/devices/wifi/nm-wifi-factory.c b/src/devices/wifi/nm-wifi-factory.c
index 7f56dc74..2d5f8faf 100644
--- a/src/devices/wifi/nm-wifi-factory.c
+++ b/src/devices/wifi/nm-wifi-factory.c
@@ -18,7 +18,7 @@
  * Copyright (C) 2011 - 2014 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <gmodule.h>
 
@@ -66,6 +66,7 @@ create_device (NMDeviceFactory *factory,
                gboolean *out_ignore)
 {
 	NMDeviceWifiCapabilities capabilities;
+	NM80211Mode mode;
 
 	g_return_val_if_fail (iface != NULL, NULL);
 	g_return_val_if_fail (plink != NULL, NULL);
@@ -79,6 +80,16 @@ create_device (NMDeviceFactory *factory,
 		return NULL;
 	}
 
+	/* Ignore monitor-mode and other unhandled interface types.
+	 * FIXME: keep TYPE_MONITOR devices in UNAVAILABLE state and manage
+	 * them if/when they change to a handled type.
+	 */
+	mode = nm_platform_wifi_get_mode (NM_PLATFORM_GET, plink->ifindex);
+	if (mode == NM_802_11_MODE_UNKNOWN) {
+		*out_ignore = TRUE;
+		return NULL;
+	}
+
 	if (plink->type == NM_LINK_TYPE_WIFI)
 		return nm_device_wifi_new (iface, capabilities);
 	else
diff --git a/src/devices/wifi/tests/test-wifi-ap-utils.c b/src/devices/wifi/tests/test-wifi-ap-utils.c
index b5642fe2..01990bee 100644
--- a/src/devices/wifi/tests/test-wifi-ap-utils.c
+++ b/src/devices/wifi/tests/test-wifi-ap-utils.c
@@ -18,11 +18,10 @@
  *
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 
-#include "nm-default.h"
 #include "nm-wifi-ap-utils.h"
 
 #include "nm-core-internal.h"
@@ -594,7 +593,7 @@ wpa_flags_for_idx (guint32 idx)
 		return NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_KEY_MGMT_PSK;
 	else if (idx == IDX_WPA_RSN_PSK_PTKIP_PCCMP_GTKIP)
 		return NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_PAIR_CCMP | NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_KEY_MGMT_PSK;
-	else if (IDX_WPA_RSN_PSK_PCCMP_GCCMP)
+	else if (NM_IN_SET (idx, IDX_WPA_PSK_PTKIP_PCCMP_GTKIP, IDX_WPA_RSN_PSK_PCCMP_GCCMP))
 		return NM_802_11_AP_SEC_PAIR_CCMP | NM_802_11_AP_SEC_GROUP_CCMP | NM_802_11_AP_SEC_KEY_MGMT_PSK;
 	else if (idx == IDX_WPA_8021X)
 		return NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_KEY_MGMT_802_1X;
diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c
index edecd24d..e9c4f02e 100644
--- a/src/devices/wwan/nm-device-modem.c
+++ b/src/devices/wwan/nm-device-modem.c
@@ -18,11 +18,10 @@
  * Copyright (C) 2009 - 2011 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 
-#include "nm-default.h"
 #include "nm-device-modem.h"
 #include "nm-modem.h"
 #include "nm-device-private.h"
diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c
index 427f3ed6..6343416c 100644
--- a/src/devices/wwan/nm-modem-broadband.c
+++ b/src/devices/wwan/nm-modem-broadband.c
@@ -18,7 +18,7 @@
  * Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 #include <arpa/inet.h>
@@ -26,7 +26,6 @@
 
 #include "nm-modem-broadband.h"
 #include "nm-core-internal.h"
-#include "nm-default.h"
 #include "NetworkManagerUtils.h"
 #include "nm-device-private.h"
 #include "nm-platform.h"
@@ -52,6 +51,7 @@ typedef struct {
 	MMSimpleConnectProperties *connect_properties;
 	GArray *ip_types;
 	guint ip_types_i;
+	guint ip_type_tries;
 	GError *first_error;
 } ConnectContext;
 
@@ -331,11 +331,17 @@ connect_ready (MMModemSimple *simple_iface,
 		} else
 			g_error_free (error);
 
-		/* If the modem/provider lies and the IP type we tried isn't supported,
-		 * retry with the next one, if any.
-		 */
-		ctx->ip_types_i++;
-		connect_context_clear (self);
+		if (ctx->ip_type_tries == 0 && g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY)) {
+			/* Try one more time */
+			ctx->ip_type_tries++;
+		} else {
+			/* If the modem/provider lies and the IP type we tried isn't supported,
+			 * retry with the next one, if any.
+			 */
+			ctx->ip_types_i++;
+			ctx->ip_type_tries = 0;
+		}
+		connect_context_step (self);
 		return;
 	}
 
@@ -485,9 +491,10 @@ connect_context_step (NMModemBroadband *self)
 			else
 				g_assert_not_reached ();
 
-			nm_log_dbg (LOGD_MB, "(%s): launching connection with ip type '%s'",
+			nm_log_dbg (LOGD_MB, "(%s): launching connection with ip type '%s' (try %d)",
 			            nm_modem_get_uid (NM_MODEM (self)),
-			            nm_modem_ip_type_to_string (current));
+			            nm_modem_ip_type_to_string (current),
+			            ctx->ip_type_tries + 1);
 
 			mm_modem_simple_connect (self->priv->simple_iface,
 			                         ctx->connect_properties,
diff --git a/src/devices/wwan/nm-modem-manager.c b/src/devices/wwan/nm-modem-manager.c
index c28d86ad..79082c41 100644
--- a/src/devices/wwan/nm-modem-manager.c
+++ b/src/devices/wwan/nm-modem-manager.c
@@ -20,14 +20,13 @@
  * Copyright (C) 2009 Canonical Ltd.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 
 #include <libmm-glib.h>
 
 #include "nm-modem-manager.h"
-#include "nm-default.h"
 #include "nm-dbus-compat.h"
 #include "nm-modem.h"
 #include "nm-modem-broadband.h"
diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c
index 15104307..c1736ecf 100644
--- a/src/devices/wwan/nm-modem.c
+++ b/src/devices/wwan/nm-modem.c
@@ -19,20 +19,19 @@
  * Copyright (C) 2009 Novell, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
+
+#include "nm-modem.h"
 
 #include <string.h>
 
-#include "nm-modem.h"
 #include "nm-core-internal.h"
 #include "nm-platform.h"
 #include "nm-setting-connection.h"
-#include "nm-default.h"
 #include "NetworkManagerUtils.h"
 #include "nm-device-private.h"
 #include "nm-modem-enum-types.h"
 #include "nm-route-manager.h"
-#include "gsystem-local-alloc.h"
 
 G_DEFINE_TYPE (NMModem, nm_modem, G_TYPE_OBJECT)
 
diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c
index 2fd9e0bd..805aea69 100644
--- a/src/devices/wwan/nm-wwan-factory.c
+++ b/src/devices/wwan/nm-wwan-factory.c
@@ -18,7 +18,7 @@
  * Copyright (C) 2014 Red Hat, Inc.
  */
 
-#include "config.h"
+#include "nm-default.h"
 
 #include <string.h>
 #include <gmodule.h>
@@ -29,7 +29,6 @@
 #include "nm-setting-cdma.h"
 #include "nm-modem-manager.h"
 #include "nm-device-modem.h"
-#include "nm-default.h"
 #include "nm-platform.h"
 
 static GType nm_wwan_factory_get_type (void);