summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/devices/adsl/nm-atm-manager.c14
-rw-r--r--src/devices/adsl/nm-device-adsl.c6
-rw-r--r--src/devices/bluetooth/nm-bluez5-dun.c4
-rw-r--r--src/devices/nm-device-bond.c2
-rw-r--r--src/devices/nm-device-ethernet.c31
-rw-r--r--src/devices/nm-device-factory.c18
-rw-r--r--src/devices/nm-device-infiniband.c6
-rw-r--r--src/devices/nm-device-ip-tunnel.c8
-rw-r--r--src/devices/nm-device-macvlan.c4
-rw-r--r--src/devices/nm-device-tun.c2
-rw-r--r--src/devices/nm-device-veth.c2
-rw-r--r--src/devices/nm-device-vlan.c2
-rw-r--r--src/devices/nm-device-vxlan.c2
-rw-r--r--src/devices/nm-device.c465
-rw-r--r--src/devices/nm-device.h10
-rw-r--r--src/devices/tests/test-lldp.c4
-rw-r--r--src/devices/wifi/nm-device-wifi.c9
-rw-r--r--src/devices/wifi/nm-wifi-factory.c2
-rw-r--r--src/devices/wwan/nm-device-modem.c4
-rw-r--r--src/devices/wwan/nm-modem.c34
-rw-r--r--src/dns-manager/nm-dns-manager.c4
-rw-r--r--src/main-utils.c2
-rw-r--r--src/nm-config.c2
-rw-r--r--src/nm-core-utils.c9
-rw-r--r--src/nm-ip4-config.c128
-rw-r--r--src/nm-ip4-config.h35
-rw-r--r--src/nm-ip6-config.c105
-rw-r--r--src/nm-ip6-config.h31
-rw-r--r--src/nm-logging.h1
-rw-r--r--src/nm-manager.c54
-rw-r--r--src/nm-rfkill-manager.c2
-rw-r--r--src/nm-session-monitor.c30
-rw-r--r--src/platform/nm-linux-platform.c63
-rw-r--r--src/platform/nm-platform-utils.c87
-rw-r--r--src/platform/nm-platform-utils.h4
-rw-r--r--src/platform/nm-platform.c3
-rw-r--r--src/platform/nmp-netns.c6
-rw-r--r--src/platform/nmp-object.c1
-rw-r--r--src/platform/nmp-object.h1
-rw-r--r--src/platform/tests/test-common.c12
-rw-r--r--src/platform/wifi/wifi-utils-nl80211.c16
-rw-r--r--src/platform/wifi/wifi-utils-wext.c36
-rw-r--r--src/platform/wifi/wifi-utils.c32
-rw-r--r--src/platform/wifi/wifi-utils.h2
-rw-r--r--src/ppp-manager/nm-ppp-manager.c12
-rw-r--r--src/ppp-manager/nm-ppp-manager.h1
-rw-r--r--src/settings/nm-inotify-helper.c2
-rw-r--r--src/settings/nm-settings.c2
-rw-r--r--src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c3
-rw-r--r--src/settings/plugins/ifcfg-rh/shvar.c6
-rw-r--r--src/settings/plugins/ifupdown/interface_parser.c2
-rw-r--r--src/supplicant-manager/nm-supplicant-interface.c11
-rw-r--r--src/tests/test-general-with-expect.c3
-rw-r--r--src/tests/test-ip6-config.c9
-rw-r--r--src/vpn-manager/nm-vpn-connection.c10
55 files changed, 813 insertions, 543 deletions
diff --git a/src/devices/adsl/nm-atm-manager.c b/src/devices/adsl/nm-atm-manager.c
index 67085752..40c782fd 100644
--- a/src/devices/adsl/nm-atm-manager.c
+++ b/src/devices/adsl/nm-atm-manager.c
@@ -68,7 +68,7 @@ dev_get_attrs (GUdevDevice *udev_device,
 
 	path = g_udev_device_get_sysfs_path (udev_device);
 	if (!path) {
-		nm_log_warn (LOGD_HW, "couldn't determine device path; ignoring...");
+		nm_log_warn (LOGD_PLATFORM, "couldn't determine device path; ignoring...");
 		return FALSE;
 	}
 
@@ -110,11 +110,11 @@ adsl_add (NMAtmManager *self, GUdevDevice *udev_device)
 
 	ifname = g_udev_device_get_name (udev_device);
 	if (!ifname) {
-		nm_log_warn (LOGD_HW, "failed to get device's interface name");
+		nm_log_warn (LOGD_PLATFORM, "failed to get device's interface name");
 		return;
 	}
 
-	nm_log_dbg (LOGD_HW, "(%s): found ATM device", ifname);
+	nm_log_dbg (LOGD_PLATFORM, "(%s): found ATM device", ifname);
 
 	atm_index_path = g_strdup_printf ("/sys/class/atm/%s/atmindex",
 	                                  NM_ASSERT_VALID_PATH_COMPONENT (ifname));
@@ -123,12 +123,12 @@ adsl_add (NMAtmManager *self, GUdevDevice *udev_device)
 	                                                      10, 0, G_MAXINT,
 	                                                      -1);
 	if (atm_index < 0) {
-		nm_log_warn (LOGD_HW, "(%s): failed to get ATM index", ifname);
+		nm_log_warn (LOGD_PLATFORM, "(%s): failed to get ATM index", ifname);
 		return;
 	}
 
 	if (!dev_get_attrs (udev_device, &sysfs_path, &driver)) {
-		nm_log_warn (LOGD_HW, "(%s): failed to get ATM attributes", ifname);
+		nm_log_warn (LOGD_PLATFORM, "(%s): failed to get ATM attributes", ifname);
 		return;
 	}
 
@@ -153,7 +153,7 @@ adsl_remove (NMAtmManager *self, GUdevDevice *udev_device)
 	const char *iface = g_udev_device_get_name (udev_device);
 	GSList *iter;
 
-	nm_log_dbg (LOGD_HW, "(%s): removing ATM device", iface);
+	nm_log_dbg (LOGD_PLATFORM, "(%s): removing ATM device", iface);
 
 	for (iter = priv->devices; iter; iter = iter->next) {
 		NMDevice *device = iter->data;
@@ -210,7 +210,7 @@ handle_uevent (GUdevClient *client,
 
 	ifindex = g_udev_device_get_property (device, "IFINDEX");
 	seqnum = g_udev_device_get_seqnum (device);
-	nm_log_dbg (LOGD_HW, "UDEV event: action '%s' subsys '%s' device '%s' (%s); seqnum=%" G_GUINT64_FORMAT,
+	nm_log_dbg (LOGD_PLATFORM, "UDEV event: action '%s' subsys '%s' device '%s' (%s); seqnum=%" G_GUINT64_FORMAT,
 	            action, subsys, g_udev_device_get_name (device), ifindex ? ifindex : "unknown", seqnum);
 
 	if (!strcmp (action, "add"))
diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c
index ebb7a319..77c6e119 100644
--- a/src/devices/adsl/nm-device-adsl.c
+++ b/src/devices/adsl/nm-device-adsl.c
@@ -154,7 +154,7 @@ br2684_assign_vcc (NMDeviceAdsl *self, NMSettingAdsl *s_adsl)
 	g_return_val_if_fail (priv->brfd == -1, FALSE);
 	g_return_val_if_fail (priv->nas_ifname != NULL, FALSE);
 
-	priv->brfd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5);
+	priv->brfd = socket (PF_ATMPVC, SOCK_DGRAM | SOCK_CLOEXEC, ATM_AAL5);
 	if (priv->brfd < 0) {
 		errsv = errno;
 		_LOGE (LOGD_ADSL, "failed to open ATM control socket (%d)", errsv);
@@ -338,7 +338,7 @@ br2684_create_iface (NMDeviceAdsl *self,
 		nm_clear_g_source (&priv->nas_update_id);
 	}
 
-	fd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5);
+	fd = socket (PF_ATMPVC, SOCK_DGRAM | SOCK_CLOEXEC, ATM_AAL5);
 	if (fd < 0) {
 		errsv = errno;
 		_LOGE (LOGD_ADSL, "failed to open ATM control socket (%d)", errsv);
@@ -472,7 +472,7 @@ act_stage3_ip4_config_start (NMDevice *device,
 	}
 
 	priv->ppp_manager = nm_ppp_manager_new (ppp_iface);
-	if (nm_ppp_manager_start (priv->ppp_manager, req, nm_setting_adsl_get_username (s_adsl), 30, &err)) {
+	if (nm_ppp_manager_start (priv->ppp_manager, req, nm_setting_adsl_get_username (s_adsl), 30, 0, &err)) {
 		g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_STATE_CHANGED,
 		                  G_CALLBACK (ppp_state_changed),
 		                  self);
diff --git a/src/devices/bluetooth/nm-bluez5-dun.c b/src/devices/bluetooth/nm-bluez5-dun.c
index 4c93feba..aba3a0dd 100644
--- a/src/devices/bluetooth/nm-bluez5-dun.c
+++ b/src/devices/bluetooth/nm-bluez5-dun.c
@@ -64,7 +64,7 @@ dun_connect (NMBluez5DunContext *context)
 		.channel = context->rfcomm_channel
 	};
 
-	context->rfcomm_fd = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+	context->rfcomm_fd = socket (AF_BLUETOOTH, SOCK_STREAM | SOCK_CLOEXEC, BTPROTO_RFCOMM);
 	if (context->rfcomm_fd < 0) {
 		int errsv = errno;
 		error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED,
@@ -112,7 +112,7 @@ dun_connect (NMBluez5DunContext *context)
 	context->rfcomm_id = devid;
 
 	snprintf (tty, ttylen, "/dev/rfcomm%d", devid);
-	while ((context->rfcomm_tty_fd = open (tty, O_RDONLY | O_NOCTTY)) < 0 && try--) {
+	while ((context->rfcomm_tty_fd = open (tty, O_RDONLY | O_NOCTTY | O_CLOEXEC)) < 0 && try--) {
 		if (try) {
 			g_usleep (100 * 1000);
 			continue;
diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c
index 3f17849b..75b2e315 100644
--- a/src/devices/nm-device-bond.c
+++ b/src/devices/nm-device-bond.c
@@ -129,7 +129,7 @@ set_bond_attr (NMDevice *device, NMBondMode mode, const char *attr, const char *
 
 	ret = nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, attr, value);
 	if (!ret)
-		_LOGW (LOGD_HW, "failed to set bonding attribute '%s' to '%s'", attr, value);
+		_LOGW (LOGD_PLATFORM, "failed to set bonding attribute '%s' to '%s'", attr, value);
 	return ret;
 }
 
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index b213a0cc..51515c09 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -188,7 +188,7 @@ _update_s390_subchannels (NMDeviceEthernet *self)
 	parent_path = g_udev_device_get_sysfs_path (parent);
 	dir = g_dir_open (parent_path, 0, &error);
 	if (!dir) {
-		_LOGW (LOGD_DEVICE | LOGD_HW, "update-s390: failed to open directory '%s': %s",
+		_LOGW (LOGD_DEVICE | LOGD_PLATFORM, "update-s390: failed to open directory '%s': %s",
 		       parent_path, error->message);
 		g_clear_error (&error);
 		return;
@@ -218,11 +218,11 @@ _update_s390_subchannels (NMDeviceEthernet *self)
 				g_hash_table_insert (priv->s390_options, g_strdup (item), value);
 				value = NULL;
 			} else
-				_LOGW (LOGD_DEVICE | LOGD_HW, "update-s390: error reading %s", path);
+				_LOGW (LOGD_DEVICE | LOGD_PLATFORM, "update-s390: error reading %s", path);
 		}
 
 		if (error) {
-			_LOGW (LOGD_DEVICE | LOGD_HW, "update-s390: failed reading sysfs for %s (%s)", item, error->message);
+			_LOGW (LOGD_DEVICE | LOGD_PLATFORM, "update-s390: failed reading sysfs for %s (%s)", item, error->message);
 			g_clear_error (&error);
 		}
 	}
@@ -247,7 +247,7 @@ _update_s390_subchannels (NMDeviceEthernet *self)
 	priv->subchannels_dbus[2] = g_strdup (priv->subchan3);
 	priv->subchannels_dbus[3] = NULL;
 
-	_LOGI (LOGD_DEVICE | LOGD_HW, "update-s390: found s390 '%s' subchannels [%s]",
+	_LOGI (LOGD_DEVICE | LOGD_PLATFORM, "update-s390: found s390 '%s' subchannels [%s]",
 	       nm_device_get_driver ((NMDevice *) self) ?: "(unknown driver)",
 	       priv->subchannels);
 
@@ -311,7 +311,7 @@ get_generic_capabilities (NMDevice *device)
 	if (nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, nm_device_get_ifindex (device)))
 	    return NM_DEVICE_CAP_CARRIER_DETECT;
 	else {
-		_LOGI (LOGD_HW, "driver '%s' does not support carrier detection.",
+		_LOGI (LOGD_PLATFORM, "driver '%s' does not support carrier detection.",
 		       nm_device_get_driver (device));
 		return NM_DEVICE_CAP_NONE;
 	}
@@ -396,7 +396,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 		if (!match_subchans (self, s_wired, &try_mac))
 			return FALSE;
 
-		perm_hw_addr = nm_device_get_permanent_hw_address (device, TRUE);
+		perm_hw_addr = nm_device_get_permanent_hw_address (device);
 		mac = nm_setting_wired_get_mac_address (s_wired);
 		if (perm_hw_addr) {
 			if (try_mac && mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1))
@@ -935,7 +935,7 @@ pppoe_stage3_ip4_config_start (NMDeviceEthernet *self, NMDeviceStateReason *reas
 	g_assert (s_pppoe);
 
 	priv->ppp_manager = nm_ppp_manager_new (nm_device_get_iface (NM_DEVICE (self)));
-	if (nm_ppp_manager_start (priv->ppp_manager, req, nm_setting_pppoe_get_username (s_pppoe), 30, &err)) {
+	if (nm_ppp_manager_start (priv->ppp_manager, req, nm_setting_pppoe_get_username (s_pppoe), 30, 0, &err)) {
 		g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_STATE_CHANGED,
 		                  G_CALLBACK (ppp_state_changed),
 		                  self);
@@ -1324,7 +1324,7 @@ deactivate (NMDevice *device)
 	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",
+			_LOGW (LOGD_DEVICE | LOGD_PLATFORM, "failed to disable DCB/FCoE: %s",
 			       error->message);
 			g_clear_error (&error);
 		}
@@ -1346,6 +1346,7 @@ complete_connection (NMDevice *device,
 	NMSettingPppoe *s_pppoe;
 	const char *setting_mac;
 	const char *perm_hw_addr;
+	gboolean perm_hw_addr_is_fake;
 
 	s_pppoe = nm_connection_get_setting_pppoe (connection);
 
@@ -1373,8 +1374,8 @@ complete_connection (NMDevice *device,
 		nm_connection_add_setting (connection, NM_SETTING (s_wired));
 	}
 
-	perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE);
-	if (perm_hw_addr) {
+	perm_hw_addr = nm_device_get_permanent_hw_address_full (device, TRUE, &perm_hw_addr_is_fake);
+	if (perm_hw_addr && !perm_hw_addr_is_fake) {
 		setting_mac = nm_setting_wired_get_mac_address (s_wired);
 		if (setting_mac) {
 			/* Make sure the setting MAC (if any) matches the device's permanent MAC */
@@ -1410,7 +1411,7 @@ new_default_connection (NMDevice *self)
 	if (nm_config_get_no_auto_default_for_device (nm_config_get (), self))
 		return NULL;
 
-	perm_hw_addr = nm_device_get_permanent_hw_address (self, TRUE);
+	perm_hw_addr = nm_device_get_permanent_hw_address (self);
 	if (!perm_hw_addr)
 		return NULL;
 
@@ -1470,7 +1471,8 @@ update_connection (NMDevice *device, NMConnection *connection)
 {
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE ((NMDeviceEthernet *) device);
 	NMSettingWired *s_wired = nm_connection_get_setting_wired (connection);
-	const char *perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE);
+	gboolean perm_hw_addr_is_fake;
+	const char *perm_hw_addr;
 	const char *mac = nm_device_get_hw_address (device);
 	const char *mac_prop = NM_SETTING_WIRED_MAC_ADDRESS;
 	GHashTableIter iter;
@@ -1489,7 +1491,8 @@ update_connection (NMDevice *device, NMConnection *connection)
 	/* If the device reports a permanent address, use that for the MAC address
 	 * and the current MAC, if different, is the cloned MAC.
 	 */
-	if (perm_hw_addr) {
+	perm_hw_addr = nm_device_get_permanent_hw_address_full (device, TRUE, &perm_hw_addr_is_fake);
+	if (perm_hw_addr && !perm_hw_addr_is_fake) {
 		g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, perm_hw_addr, NULL);
 
 		mac_prop = NULL;
@@ -1529,7 +1532,7 @@ get_link_speed (NMDevice *device)
 	priv->speed = speed;
 	_notify (self, PROP_SPEED);
 
-	_LOGD (LOGD_HW | LOGD_ETHER, "speed is now %d Mb/s", speed);
+	_LOGD (LOGD_PLATFORM | LOGD_ETHER, "speed is now %d Mb/s", speed);
 }
 
 static void
diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c
index 7873756f..a72c0bbb 100644
--- a/src/devices/nm-device-factory.c
+++ b/src/devices/nm-device-factory.c
@@ -369,7 +369,7 @@ read_device_factory_paths (void)
 
 	dir = g_dir_open (NMPLUGINDIR, 0, &error);
 	if (!dir) {
-		nm_log_warn (LOGD_HW, "device plugin: failed to open directory %s: %s",
+		nm_log_warn (LOGD_PLATFORM, "device plugin: failed to open directory %s: %s",
 		             NMPLUGINDIR,
 		             error->message);
 		g_clear_error (&error);
@@ -391,17 +391,17 @@ read_device_factory_paths (void)
 
 		if (stat (data.path, &data.st) != 0) {
 			errsv = errno;
-			nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (error during stat: %s)", data.path, strerror (errsv));
+			nm_log_warn (LOGD_PLATFORM, "device plugin: skip invalid file %s (error during stat: %s)", data.path, strerror (errsv));
 			goto NEXT;
 		}
 		if (!S_ISREG (data.st.st_mode))
 			goto NEXT;
 		if (data.st.st_uid != 0) {
-			nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (file must be owned by root)", data.path);
+			nm_log_warn (LOGD_PLATFORM, "device plugin: skip invalid file %s (file must be owned by root)", data.path);
 			goto NEXT;
 		}
 		if (data.st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) {
-			nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (invalid file permissions)", data.path);
+			nm_log_warn (LOGD_PLATFORM, "device plugin: skip invalid file %s (invalid file permissions)", data.path);
 			goto NEXT;
 		}
 
@@ -443,7 +443,7 @@ _add_factory (NMDeviceFactory *factory,
 	if (check_duplicates) {
 		found = find_factory (link_types, setting_types);
 		if (found) {
-			nm_log_warn (LOGD_HW, "Loading device plugin failed: multiple plugins "
+			nm_log_warn (LOGD_PLATFORM, "Loading device plugin failed: multiple plugins "
 			             "for same type (using '%s' instead of '%s')",
 			             (char *) g_object_get_data (G_OBJECT (found), PLUGIN_PATH_TAG),
 			             path);
@@ -459,7 +459,7 @@ _add_factory (NMDeviceFactory *factory,
 
 	callback (factory, user_data);
 
-	nm_log_info (LOGD_HW, "Loaded device plugin: %s (%s)", G_OBJECT_TYPE_NAME (factory), path);
+	nm_log_info (LOGD_PLATFORM, "Loaded device plugin: %s (%s)", G_OBJECT_TYPE_NAME (factory), path);
 	return TRUE;
 }
 
@@ -502,12 +502,12 @@ nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc call
 		plugin = g_module_open (*path, G_MODULE_BIND_LOCAL);
 
 		if (!plugin) {
-			nm_log_warn (LOGD_HW, "(%s): failed to load plugin: %s", item, g_module_error ());
+			nm_log_warn (LOGD_PLATFORM, "(%s): failed to load plugin: %s", item, g_module_error ());
 			continue;
 		}
 
 		if (!g_module_symbol (plugin, "nm_device_factory_create", (gpointer) &create_func)) {
-			nm_log_warn (LOGD_HW, "(%s): failed to find device factory creator: %s", item, g_module_error ());
+			nm_log_warn (LOGD_PLATFORM, "(%s): failed to find device factory creator: %s", item, g_module_error ());
 			g_module_close (plugin);
 			continue;
 		}
@@ -518,7 +518,7 @@ nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc call
 
 		factory = create_func (&error);
 		if (!factory) {
-			nm_log_warn (LOGD_HW, "(%s): failed to initialize device factory: %s",
+			nm_log_warn (LOGD_PLATFORM, "(%s): failed to initialize device factory: %s",
 			             item, NM_G_ERROR_MSG (error));
 			g_clear_error (&error);
 			continue;
diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c
index 17f50ba2..e2a67de4 100644
--- a/src/devices/nm-device-infiniband.c
+++ b/src/devices/nm-device-infiniband.c
@@ -151,7 +151,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 
 		mac = nm_setting_infiniband_get_mac_address (s_infiniband);
 		if (mac) {
-			hw_addr = nm_device_get_permanent_hw_address (device, TRUE);
+			hw_addr = nm_device_get_permanent_hw_address (device);
 			if (   !hw_addr
 			    || !nm_utils_hwaddr_matches (mac, -1, hw_addr, -1))
 				return FALSE;
@@ -188,7 +188,7 @@ complete_connection (NMDevice *device,
 	}
 
 	setting_mac = nm_setting_infiniband_get_mac_address (s_infiniband);
-	hw_address = nm_device_get_permanent_hw_address (device, TRUE);
+	hw_address = nm_device_get_permanent_hw_address (device);
 	if (setting_mac) {
 		/* Make sure the setting MAC (if any) matches the device's MAC */
 		if (!nm_utils_hwaddr_matches (setting_mac, -1, hw_address, -1)) {
@@ -214,7 +214,7 @@ static void
 update_connection (NMDevice *device, NMConnection *connection)
 {
 	NMSettingInfiniband *s_infiniband = nm_connection_get_setting_infiniband (connection);
-	const char *mac = nm_device_get_permanent_hw_address (device, TRUE);
+	const char *mac = nm_device_get_permanent_hw_address (device);
 	const char *transport_mode = "datagram";
 	int ifindex;
 
diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c
index 785010eb..72a13893 100644
--- a/src/devices/nm-device-ip-tunnel.c
+++ b/src/devices/nm-device-ip-tunnel.c
@@ -160,7 +160,7 @@ clear:
 
 		lnk = nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, ifindex, NULL);
 		if (!lnk) {
-			_LOGW (LOGD_HW, "could not read %s properties", "gre");
+			_LOGW (LOGD_PLATFORM, "could not read %s properties", "gre");
 			goto clear;
 		}
 
@@ -205,7 +205,7 @@ clear:
 
 		lnk = nm_platform_link_get_lnk_sit (NM_PLATFORM_GET, ifindex, NULL);
 		if (!lnk) {
-			_LOGW (LOGD_HW, "could not read %s properties", "sit");
+			_LOGW (LOGD_PLATFORM, "could not read %s properties", "sit");
 			goto clear;
 		}
 
@@ -220,7 +220,7 @@ clear:
 
 		lnk = nm_platform_link_get_lnk_ipip (NM_PLATFORM_GET, ifindex, NULL);
 		if (!lnk) {
-			_LOGW (LOGD_HW, "could not read %s properties", "ipip");
+			_LOGW (LOGD_PLATFORM, "could not read %s properties", "ipip");
 			goto clear;
 		}
 
@@ -236,7 +236,7 @@ clear:
 
 		lnk = nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL);
 		if (!lnk) {
-			_LOGW (LOGD_HW, "could not read %s properties", "ip6tnl");
+			_LOGW (LOGD_PLATFORM, "could not read %s properties", "ip6tnl");
 			goto clear;
 		}
 
diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c
index 2bfc65cb..c53abb68 100644
--- a/src/devices/nm-device-macvlan.c
+++ b/src/devices/nm-device-macvlan.c
@@ -180,7 +180,7 @@ update_properties (NMDevice *device)
 		props = nm_platform_link_get_lnk_macvlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink);
 
 	if (!props) {
-		_LOGW (LOGD_HW, "could not get %s properties", priv->props.tap ? "macvtap" : "macvlan");
+		_LOGW (LOGD_PLATFORM, "could not get %s properties", priv->props.tap ? "macvtap" : "macvlan");
 		return;
 	}
 
@@ -373,7 +373,7 @@ match_hwaddr (NMDevice *device, NMConnection *connection, gboolean fail_if_no_hw
 	if (!priv->parent)
 		return !fail_if_no_hwaddr;
 
-	parent_mac = nm_device_get_permanent_hw_address (priv->parent, FALSE);
+	parent_mac = nm_device_get_permanent_hw_address (priv->parent);
 	return parent_mac && nm_utils_hwaddr_matches (setting_mac, -1, parent_mac, -1);
 }
 
diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c
index 1f42d060..f818cd7c 100644
--- a/src/devices/nm-device-tun.c
+++ b/src/devices/nm-device-tun.c
@@ -171,7 +171,7 @@ update_connection (NMDevice *device, NMConnection *connection)
 	}
 
 	if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) {
-		_LOGW (LOGD_HW, "failed to get TUN interface info while updating connection.");
+		_LOGW (LOGD_PLATFORM, "failed to get TUN interface info while updating connection.");
 		return;
 	}
 
diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c
index 56923315..c16df6d8 100644
--- a/src/devices/nm-device-veth.c
+++ b/src/devices/nm-device-veth.c
@@ -91,7 +91,7 @@ get_peer (NMDeviceVeth *self)
 		return priv->peer;
 
 	if (!nm_platform_link_veth_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &peer_ifindex)) {
-		_LOGW (LOGD_HW, "could not read veth properties");
+		_LOGW (LOGD_PLATFORM, "could not read veth properties");
 		return NULL;
 	}
 
diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c
index 16edc0d2..461bae66 100644
--- a/src/devices/nm-device-vlan.c
+++ b/src/devices/nm-device-vlan.c
@@ -391,7 +391,7 @@ match_hwaddr (NMDevice *device, NMConnection *connection, gboolean fail_if_no_hw
 	if (!priv->parent)
 		return !fail_if_no_hwaddr;
 
-	parent_mac = nm_device_get_permanent_hw_address (priv->parent, FALSE);
+	parent_mac = nm_device_get_permanent_hw_address (priv->parent);
 	return parent_mac && nm_utils_hwaddr_matches (setting_mac, -1, parent_mac, -1);
 }
 
diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c
index 674c2a78..2453543d 100644
--- a/src/devices/nm-device-vxlan.c
+++ b/src/devices/nm-device-vxlan.c
@@ -84,7 +84,7 @@ update_properties (NMDevice *device)
 
 	props = nm_platform_link_get_lnk_vxlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL);
 	if (!props) {
-		_LOGW (LOGD_HW, "could not get vxlan properties");
+		_LOGW (LOGD_PLATFORM, "could not get vxlan properties");
 		return;
 	}
 
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 27d940c9..ac840ab9 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -33,7 +33,6 @@
 #include <sys/wait.h>
 #include <arpa/inet.h>
 #include <fcntl.h>
-#include <netlink/route/addr.h>
 #include <linux/if_addr.h>
 
 #include "nm-common-macros.h"
@@ -227,10 +226,18 @@ typedef struct _NMDevicePrivate {
 	char *        iface;   /* may change, could be renamed by user */
 	int           ifindex;
 
-	guint         hw_addr_len;
+	union {
+		const guint8 hw_addr_len; /* read-only */
+		guint8 hw_addr_len_;
+	};
 	guint8 /*HwAddrType*/ hw_addr_type;
 
-	bool          real;
+	bool          real:1;
+
+	/* there was a IP config change, but no idle action was scheduled because device
+	 * is still not platform-init */
+	bool queued_ip4_config_pending:1;
+	bool queued_ip6_config_pending:1;
 
 	char *        ip_iface;
 	int           ip_ifindex;
@@ -757,7 +764,7 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface)
 				nm_platform_link_set_up (NM_PLATFORM_GET, priv->ip_ifindex, NULL);
 		} else {
 			/* Device IP interface must always be a kernel network interface */
-			_LOGW (LOGD_HW, "failed to look up interface index");
+			_LOGW (LOGD_PLATFORM, "failed to look up interface index");
 		}
 	}
 
@@ -900,7 +907,7 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid)
 	                                                  priv->dev_id,
 	                                                  out_iid);
 	if (!success) {
-		_LOGW (LOGD_HW, "failed to generate interface identifier "
+		_LOGW (LOGD_PLATFORM, "failed to generate interface identifier "
 		       "for link type %u hwaddr_len %u", pllink->type, (unsigned) pllink->addr.len);
 	}
 	return success;
@@ -1819,7 +1826,7 @@ device_link_changed (NMDevice *self)
 	had_hw_addr = (priv->hw_addr != NULL);
 	nm_device_update_hw_address (self);
 	got_hw_addr = (!had_hw_addr && priv->hw_addr);
-	nm_device_update_permanent_hw_address (self);
+	nm_device_update_permanent_hw_address (self, FALSE);
 
 	if (info.name[0] && strcmp (priv->iface, info.name) != 0) {
 		_LOGI (LOGD_DEVICE, "interface index %d renamed iface from '%s' to '%s'",
@@ -1831,7 +1838,7 @@ device_link_changed (NMDevice *self)
 		ip_ifname_changed = !priv->ip_iface;
 
 		if (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT))
-			nm_device_set_unmanaged_by_user_settings (self, nm_settings_get_unmanaged_specs (priv->settings));
+			nm_device_set_unmanaged_by_user_settings (self);
 		else
 			update_unmanaged_specs = TRUE;
 
@@ -1910,7 +1917,7 @@ device_link_changed (NMDevice *self)
 	}
 
 	if (update_unmanaged_specs)
-		nm_device_set_unmanaged_by_user_settings (self, nm_settings_get_unmanaged_specs (priv->settings));
+		nm_device_set_unmanaged_by_user_settings (self);
 
 	if (   got_hw_addr
 	    && !priv->up
@@ -2279,13 +2286,12 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
 		_notify (self, PROP_UDI);
 	}
 
-	/* trigger initial ip config change to initialize ip-config */
-	priv->queued_ip4_config_id = g_idle_add (queued_ip4_config_change, self);
-	priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self);
+	priv->queued_ip4_config_pending = TRUE;
+	priv->queued_ip6_config_pending = TRUE;
 
 	nm_device_update_hw_address (self);
 	nm_device_update_initial_hw_address (self);
-	nm_device_update_permanent_hw_address (self);
+	nm_device_update_permanent_hw_address (self, FALSE);
 
 	/* Note: initial hardware address must be read before calling get_ignore_carrier() */
 	config = nm_config_get ();
@@ -2299,7 +2305,7 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
 
 	if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) {
 		check_carrier (self);
-		_LOGD (LOGD_HW,
+		_LOGD (LOGD_PLATFORM,
 		       "carrier is %s%s",
 		       priv->carrier ? "ON" : "OFF",
 		       priv->ignore_carrier ? " (but ignored)" : "");
@@ -2475,11 +2481,6 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
 		g_clear_pointer (&priv->udi, g_free);
 		_notify (self, PROP_UDI);
 	}
-	if (priv->hw_addr) {
-		priv->hw_addr_len = 0;
-		g_clear_pointer (&priv->hw_addr, g_free);
-		_notify (self, PROP_HW_ADDRESS);
-	}
 	if (priv->physical_port_id) {
 		g_clear_pointer (&priv->physical_port_id, g_free);
 		_notify (self, PROP_PHYSICAL_PORT_ID);
@@ -2488,9 +2489,12 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
 	nm_clear_g_source (&priv->stats.timeout_id);
 	_stats_update_counters (self, 0, 0);
 
+	priv->hw_addr_len_ = 0;
+	if (nm_clear_g_free (&priv->hw_addr))
+		_notify (self, PROP_HW_ADDRESS);
 	priv->hw_addr_type = HW_ADDR_TYPE_UNSET;
-	g_clear_pointer (&priv->hw_addr_perm, g_free);
-	_notify (self, PROP_PERM_HW_ADDRESS);
+	if (nm_clear_g_free (&priv->hw_addr_perm))
+		_notify (self, PROP_PERM_HW_ADDRESS);
 	g_clear_pointer (&priv->hw_addr_initial, g_free);
 
 	priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED;
@@ -3493,95 +3497,35 @@ nm_device_can_assume_connections (NMDevice *self)
 	return !!NM_DEVICE_GET_CLASS (self)->update_connection;
 }
 
-/**
- * nm_device_can_assume_active_connection:
- * @self: #NMDevice instance
- *
- * This is a convenience function to determine whether the device's active
- * connection can be assumed if NetworkManager restarts.  This method returns
- * %TRUE if and only if the device can assume connections, and the device has
- * an active connection, and that active connection can be assumed.
- *
- * Returns: %TRUE if the device's active connection can be assumed, or %FALSE
- * if there is no active connection or the active connection cannot be
- * assumed.
- */
 static gboolean
-nm_device_can_assume_active_connection (NMDevice *self)
+unmanaged_on_quit (NMDevice *self)
 {
-	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMConnection *connection;
-	const char *method;
-	const char *assumable_ip6_methods[] = {
-		NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
-		NM_SETTING_IP6_CONFIG_METHOD_AUTO,
-		NM_SETTING_IP6_CONFIG_METHOD_DHCP,
-		NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL,
-		NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
-		NULL
-	};
-	const char *assumable_ip4_methods[] = {
-		NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
-		NM_SETTING_IP6_CONFIG_METHOD_AUTO,
-		NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
-		NULL
-	};
 
+	/* NMDeviceWifi overwrites this function to always unmanage wifi devices.
+	 *
+	 * For all other types, if the device type can assume connections, we leave
+	 * it up on quit.
+	 *
+	 * Originally, we would only keep devices up that can be assumed afterwards.
+	 * However, that meant we unmanged layer-2 only devices. So, this was step
+	 * by step refined to unmanage less (commit 25aaaab3, rh#1311988, rh#1333983).
+	 * But there are more scenarios where we also want to keep the device up
+	 * (rh#1378418, rh#1371126). */
 	if (!nm_device_can_assume_connections (self))
-		return FALSE;
+		return TRUE;
 
+	/* the only exception are IPv4 shared connections. We unmanage them on quit. */
 	connection = nm_device_get_applied_connection (self);
-	if (!connection)
-		return FALSE;
-
-	/* Can't assume connections that aren't yet configured
-	 * FIXME: what about bridges/bonds waiting for slaves?
-	 */
-	if (priv->state < NM_DEVICE_STATE_IP_CONFIG)
-		return FALSE;
-	if (priv->ip4_state != IP_DONE && priv->ip6_state != IP_DONE)
-		return FALSE;
-
-	method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
-	if (!g_strv_contains (assumable_ip6_methods, method))
-		return FALSE;
-
-	method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
-	if (!g_strv_contains (assumable_ip4_methods, method))
-		return FALSE;
-
-	return TRUE;
-}
-
-static gboolean
-unmanaged_on_quit (NMDevice *self)
-{
-	/* Leave certain devices alone when quitting so their configuration
-	 * can be taken over when NM restarts.  This ensures connectivity while
-	 * NM is stopped.
-	 */
-	if (nm_device_uses_assumed_connection (self)) {
-		/* An assume connection must be left alone */
-		return FALSE;
-	}
-
-	if (!nm_device_get_act_request (self)) {
-		/* a device without any active connection is either UNAVAILABLE or DISCONNECTED
-		 * state. Since we don't know whether the device was upped by NetworkManager,
-		 * we must leave it up on exit.
-		 */
-		return FALSE;
-	}
-
-	if (!nm_platform_link_can_assume (NM_PLATFORM_GET, nm_device_get_ifindex (self))) {
-		/* The device has no layer 3 configuration. Leave it up. */
-		return FALSE;
+	if (connection) {
+		if (NM_IN_STRSET (nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG),
+		                  NM_SETTING_IP4_CONFIG_METHOD_SHARED)) {
+			/* shared connections are to be unmangaed. */
+			return TRUE;
+		}
 	}
 
-	if (nm_device_can_assume_active_connection (self))
-		return FALSE;
-
-	return TRUE;
+	return FALSE;
 }
 
 gboolean
@@ -3768,7 +3712,7 @@ activation_source_schedule (NMDevice *self, ActivationHandleFunc func, int famil
 
 	act_data = activation_source_get_by_family (self, family, &source_func);
 
-	if (act_data->id && act_data->func != func) {
+	if (act_data->id && act_data->func == func) {
 		/* Don't bother rescheduling the same function that's about to
 		 * run anyway.  Fixes issues with crappy wireless drivers sending
 		 * streams of associate events before NM has had a chance to process
@@ -4869,8 +4813,6 @@ 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)
@@ -5490,13 +5432,15 @@ ip6_config_merge_and_apply (NMDevice *self,
 
 	/* If no config was passed in, create a new one */
 	composite = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
+	nm_ip6_config_set_privacy (composite,
+	                           priv->rdisc ?
+	                           priv->rdisc_use_tempaddr :
+	                           NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
 	init_ip6_config_dns_priority (self, composite);
 
 	if (commit)
 		ensure_con_ip6_config (self);
 
-	g_assert (composite);
-
 	/* Merge all the IP configs into the composite config */
 	if (priv->ac_ip6_config) {
 		nm_ip6_config_merge (composite, priv->ac_ip6_config,
@@ -5623,9 +5567,6 @@ END_ADD_DEFAULT_ROUTE:
 		priv->default_route.v6_has = _device_get_default_route_from_platform (self, AF_INET6, (NMPlatformIPRoute *) &priv->default_route.v6);
 	}
 
-	nm_ip6_config_addresses_sort (composite,
-	    priv->rdisc ? priv->rdisc_use_tempaddr : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
-
 	/* Allow setting MTU etc */
 	if (commit) {
 		NMUtilsIPv6IfaceId iid;
@@ -7686,6 +7627,7 @@ _cleanup_ip4_pre (NMDevice *self, CleanupType cleanup_type)
 
 	if (nm_clear_g_source (&priv->queued_ip4_config_id))
 		_LOGD (LOGD_DEVICE, "clearing queued IP4 config change");
+	priv->queued_ip4_config_pending = FALSE;
 
 	dhcp4_cleanup (self, cleanup_type, FALSE);
 	arp_cleanup (self);
@@ -7702,6 +7644,7 @@ _cleanup_ip6_pre (NMDevice *self, CleanupType cleanup_type)
 
 	if (nm_clear_g_source (&priv->queued_ip6_config_id))
 		_LOGD (LOGD_DEVICE, "clearing queued IP6 config change");
+	priv->queued_ip6_config_pending = FALSE;
 
 	g_clear_object (&priv->dad6_ip6_config);
 	dhcp6_cleanup (self, cleanup_type, FALSE);
@@ -7911,6 +7854,7 @@ reapply_connection (NMDevice *self,
 	                               error,
 	                               NM_SETTING_CONNECTION_ID,
 	                               NM_SETTING_CONNECTION_UUID,
+	                               NM_SETTING_CONNECTION_AUTOCONNECT,
 	                               NM_SETTING_CONNECTION_ZONE,
 	                               NM_SETTING_CONNECTION_METERED))
 		return FALSE;
@@ -9094,7 +9038,7 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware)
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
 
-	_LOGD (LOGD_HW, "bringing up device");
+	_LOGD (LOGD_PLATFORM, "bringing up device");
 
 	if (NM_DEVICE_GET_CLASS (self)->bring_up) {
 		if (!NM_DEVICE_GET_CLASS (self)->bring_up (self, no_firmware))
@@ -9120,9 +9064,9 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware)
 
 	if (!device_is_up) {
 		if (block)
-			_LOGW (LOGD_HW, "device not up after timeout!");
+			_LOGW (LOGD_PLATFORM, "device not up after timeout!");
 		else
-			_LOGD (LOGD_HW, "device not up immediately");
+			_LOGD (LOGD_PLATFORM, "device not up immediately");
 		return FALSE;
 	}
 
@@ -9186,7 +9130,7 @@ nm_device_take_down (NMDevice *self, gboolean block)
 
 	g_return_if_fail (NM_IS_DEVICE (self));
 
-	_LOGD (LOGD_HW, "taking down device");
+	_LOGD (LOGD_PLATFORM, "taking down device");
 
 	if (NM_DEVICE_GET_CLASS (self)->take_down) {
 		if (!NM_DEVICE_GET_CLASS (self)->take_down (self))
@@ -9208,9 +9152,9 @@ nm_device_take_down (NMDevice *self, gboolean block)
 
 	if (device_is_up) {
 		if (block)
-			_LOGW (LOGD_HW, "device not down after timeout!");
+			_LOGW (LOGD_PLATFORM, "device not down after timeout!");
 		else
-			_LOGD (LOGD_HW, "device not down immediately");
+			_LOGD (LOGD_PLATFORM, "device not down immediately");
 	}
 }
 
@@ -9223,7 +9167,7 @@ take_down (NMDevice *self)
 		return nm_platform_link_set_down (NM_PLATFORM_GET, ifindex);
 
 	/* devices without ifindex are always up. */
-	_LOGD (LOGD_HW, "cannot take down device without ifindex");
+	_LOGD (LOGD_PLATFORM, "cannot take down device without ifindex");
 	return FALSE;
 }
 
@@ -9401,6 +9345,7 @@ update_ip4_config (NMDevice *self, gboolean initial)
 	    && activation_source_is_scheduled (self,
 	                                       activate_stage5_ip4_config_commit,
 	                                       AF_INET)) {
+		priv->queued_ip4_config_pending = FALSE;
 		priv->queued_ip4_config_id = g_idle_add (queued_ip4_config_change, self);
 		_LOGT (LOGD_DEVICE, "IP4 update was postponed");
 		return;
@@ -9491,6 +9436,7 @@ update_ip6_config (NMDevice *self, gboolean initial)
 	    && activation_source_is_scheduled (self,
 	                                       activate_stage5_ip6_config_commit,
 	                                       AF_INET6)) {
+		priv->queued_ip6_config_pending = FALSE;
 		priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self);
 		_LOGT (LOGD_DEVICE, "IP6 update was postponed");
 		return;
@@ -9568,6 +9514,8 @@ queued_ip4_config_change (gpointer user_data)
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
 
+	nm_assert (!priv->queued_ip4_config_pending);
+
 	/* Wait for any queued state changes */
 	if (priv->queued_state.id)
 		return TRUE;
@@ -9592,6 +9540,8 @@ queued_ip6_config_change (gpointer user_data)
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
 
+	nm_assert (!priv->queued_ip4_config_pending);
+
 	/* Wait for any queued state changes */
 	if (priv->queued_state.id)
 		return TRUE;
@@ -9669,7 +9619,11 @@ device_ipx_changed (NMPlatform *platform,
 	switch (obj_type) {
 	case NMP_OBJECT_TYPE_IP4_ADDRESS:
 	case NMP_OBJECT_TYPE_IP4_ROUTE:
-		if (!priv->queued_ip4_config_id) {
+		if (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) {
+			priv->queued_ip4_config_pending = TRUE;
+			nm_assert_se (!nm_clear_g_source (&priv->queued_ip4_config_id));
+		} else if (!priv->queued_ip4_config_id) {
+			priv->queued_ip4_config_pending = FALSE;
 			priv->queued_ip4_config_id = g_idle_add (queued_ip4_config_change, self);
 			_LOGD (LOGD_DEVICE, "queued IP4 config change");
 		}
@@ -9686,7 +9640,11 @@ device_ipx_changed (NMPlatform *platform,
 		}
 		/* fallthrough */
 	case NMP_OBJECT_TYPE_IP6_ROUTE:
-		if (!priv->queued_ip6_config_id) {
+		if (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) {
+			priv->queued_ip6_config_pending = TRUE;
+			nm_assert_se (!nm_clear_g_source (&priv->queued_ip6_config_id));
+		} else if (!priv->queued_ip6_config_id) {
+			priv->queued_ip6_config_pending = FALSE;
 			priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self);
 			_LOGD (LOGD_DEVICE, "queued IP6 config change");
 		}
@@ -9928,6 +9886,33 @@ _set_unmanaged_flags (NMDevice *self,
 		allow_state_transition = FALSE;
 	was_managed = allow_state_transition && nm_device_get_managed (self, FALSE);
 
+	if (   NM_FLAGS_HAS (priv->unmanaged_flags, NM_UNMANAGED_PLATFORM_INIT)
+	    && NM_FLAGS_HAS (flags, NM_UNMANAGED_PLATFORM_INIT)
+	    && NM_IN_SET (set_op, NM_UNMAN_FLAG_OP_SET_MANAGED)) {
+		/* we are clearing the platform-init flags. This triggers additional actions. */
+		if (!NM_FLAGS_HAS (flags, NM_UNMANAGED_USER_SETTINGS)) {
+			gboolean unmanaged;
+
+			unmanaged = nm_device_spec_match_list (self,
+			                                       nm_settings_get_unmanaged_specs (NM_DEVICE_GET_PRIVATE (self)->settings));
+			nm_device_set_unmanaged_flags (self,
+			                               NM_UNMANAGED_USER_SETTINGS,
+			                               !!unmanaged);
+		}
+
+		if (priv->queued_ip4_config_pending) {
+			priv->queued_ip4_config_pending = FALSE;
+			nm_assert_se (!nm_clear_g_source (&priv->queued_ip4_config_id));
+			priv->queued_ip4_config_id = g_idle_add (queued_ip4_config_change, self);
+		}
+
+		if (priv->queued_ip6_config_pending) {
+			priv->queued_ip6_config_pending = FALSE;
+			nm_assert_se (!nm_clear_g_source (&priv->queued_ip6_config_id));
+			priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self);
+		}
+	}
+
 	old_flags = priv->unmanaged_flags;
 	old_mask = priv->unmanaged_mask;
 
@@ -10042,20 +10027,30 @@ nm_device_set_unmanaged_by_flags_queue (NMDevice *self,
 }
 
 void
-nm_device_set_unmanaged_by_user_settings (NMDevice *self, const GSList *unmanaged_specs)
+nm_device_set_unmanaged_by_user_settings (NMDevice *self)
 {
-	NMDevicePrivate *priv;
 	gboolean unmanaged;
 
 	g_return_if_fail (NM_IS_DEVICE (self));
 
-	priv = NM_DEVICE_GET_PRIVATE (self);
+	if (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) {
+		/* the device is already unmanaged due to platform-init.
+		 *
+		 * We want to delay evaluating the device spec, because it will freeze
+		 * the permanent MAC address. That should not be done, before the platform
+		 * link is fully initialized (via UDEV).
+		 *
+		 * Note that when clearing NM_UNMANAGED_PLATFORM_INIT, we will re-evaluate
+		 * whether the device is unmanaged by user-settings. */
+		return;
+	}
 
-	unmanaged = nm_device_spec_match_list (self, unmanaged_specs);
+	unmanaged = nm_device_spec_match_list (self,
+	                                       nm_settings_get_unmanaged_specs (NM_DEVICE_GET_PRIVATE (self)->settings));
 
 	nm_device_set_unmanaged_by_flags (self,
 	                                  NM_UNMANAGED_USER_SETTINGS,
-	                                  unmanaged,
+	                                  !!unmanaged,
 	                                  unmanaged
 	                                      ? NM_DEVICE_STATE_REASON_NOW_UNMANAGED
 	                                      : NM_DEVICE_STATE_REASON_NOW_MANAGED);
@@ -11211,7 +11206,7 @@ _set_state_full (NMDevice *self,
 		if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) {
 			if (old_state == NM_DEVICE_STATE_UNMANAGED || priv->firmware_missing) {
 				if (!nm_device_bring_up (self, TRUE, &no_firmware) && no_firmware)
-					_LOGW (LOGD_HW, "firmware may be missing.");
+					_LOGW (LOGD_PLATFORM, "firmware may be missing.");
 				nm_device_set_firmware_missing (self, no_firmware ? TRUE : FALSE);
 			}
 
@@ -11560,11 +11555,17 @@ const char *
 nm_device_get_hw_address (NMDevice *self)
 {
 	NMDevicePrivate *priv;
+	char buf[NM_UTILS_HWADDR_LEN_MAX];
+	gsize l;
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
+
 	priv = NM_DEVICE_GET_PRIVATE (self);
 
-	nm_assert ((!priv->hw_addr) ^ (priv->hw_addr_len > 0));
+	nm_assert (   (!priv->hw_addr && priv->hw_addr_len == 0)
+	           || (   priv->hw_addr
+	               && _nm_utils_hwaddr_aton (priv->hw_addr, buf, sizeof (buf), &l)
+	               && l == priv->hw_addr_len));
 
 	return priv->hw_addr;
 }
@@ -11575,7 +11576,6 @@ nm_device_update_hw_address (NMDevice *self)
 	NMDevicePrivate *priv;
 	const guint8 *hwaddr;
 	gsize hwaddrlen = 0;
-	gboolean changed = FALSE;
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
 	if (priv->ifindex <= 0)
@@ -11588,38 +11588,46 @@ nm_device_update_hw_address (NMDevice *self)
 	    && nm_utils_hwaddr_matches (hwaddr, hwaddrlen, nm_ip_addr_zero.addr_eth, sizeof (nm_ip_addr_zero.addr_eth)))
 		hwaddrlen = 0;
 
-	if (hwaddrlen) {
-		priv->hw_addr_len = hwaddrlen;
-		if (!priv->hw_addr || !nm_utils_hwaddr_matches (priv->hw_addr, -1, hwaddr, hwaddrlen)) {
-			g_free (priv->hw_addr);
-			priv->hw_addr = nm_utils_hwaddr_ntoa (hwaddr, hwaddrlen);
-
-			_LOGD (LOGD_HW | LOGD_DEVICE, "hw-addr: hardware address now %s", priv->hw_addr);
-			_notify (self, PROP_HW_ADDRESS);
-
-			if (   !priv->hw_addr_initial
-			    || (   priv->hw_addr_type == HW_ADDR_TYPE_UNSET
-			        && priv->state < NM_DEVICE_STATE_PREPARE
-			        && !nm_device_is_activating (self))) {
-				/* when we get a hw_addr the first time or while the device
-				 * is not activated (with no explict hw address set), always
-				 * update our inital hw-address as well. */
-				nm_device_update_initial_hw_address (self);
-			}
-			changed = TRUE;
-		}
-	} else {
-		/* Invalid or no hardware address */
-		if (priv->hw_addr_len != 0) {
-			_LOGD (LOGD_HW | LOGD_DEVICE,
-			       "hw-addr: failed reading current MAC address (stay with %s)",
-			       priv->hw_addr);
-		} else {
-			_LOGD (LOGD_HW | LOGD_DEVICE,
-			       "hw-addr: failed reading current MAC address");
-		}
+	if (!hwaddrlen)
+		return FALSE;
+
+	if (   priv->hw_addr_len
+	    && priv->hw_addr_len != hwaddrlen) {
+		char s_buf[NM_UTILS_HWADDR_LEN_MAX_STR];
+
+		/* we cannot change the address length of a device once it is set (except
+		 * unrealizing the device).
+		 *
+		 * The reason is that the permanent and initial MAC addresses also must have the
+		 * same address length, so it's unclear what it would mean that the length changes. */
+		_LOGD (LOGD_PLATFORM | LOGD_DEVICE,
+		       "hw-addr: read a MAC address with differing length (%s vs. %s)",
+		       priv->hw_addr,
+		       nm_utils_hwaddr_ntoa_buf (hwaddr, hwaddrlen, TRUE, s_buf, sizeof (s_buf)));
+		return FALSE;
 	}
-	return changed;
+
+	if (   priv->hw_addr
+	    && nm_utils_hwaddr_matches (priv->hw_addr, -1, hwaddr, hwaddrlen))
+		return FALSE;
+
+	g_free (priv->hw_addr);
+	priv->hw_addr_len_ = hwaddrlen;
+	priv->hw_addr = nm_utils_hwaddr_ntoa (hwaddr, hwaddrlen);
+
+	_LOGD (LOGD_PLATFORM | LOGD_DEVICE, "hw-addr: hardware address now %s", priv->hw_addr);
+	_notify (self, PROP_HW_ADDRESS);
+
+	if (   !priv->hw_addr_initial
+	    || (   priv->hw_addr_type == HW_ADDR_TYPE_UNSET
+	        && priv->state < NM_DEVICE_STATE_PREPARE
+	        && !nm_device_is_activating (self))) {
+		/* when we get a hw_addr the first time or while the device
+		 * is not activated (with no explict hw address set), always
+		 * update our inital hw-address as well. */
+		nm_device_update_initial_hw_address (self);
+	}
+	return TRUE;
 }
 
 void
@@ -11643,12 +11651,14 @@ nm_device_update_initial_hw_address (NMDevice *self)
 }
 
 void
-nm_device_update_permanent_hw_address (NMDevice *self)
+nm_device_update_permanent_hw_address (NMDevice *self, gboolean force_freeze)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
 	size_t len = 0;
 	gboolean success_read;
+	int ifindex;
+	const NMPlatformLink *pllink;
 
 	if (priv->hw_addr_perm) {
 		/* the permanent hardware address is only read once and not
@@ -11659,35 +11669,60 @@ nm_device_update_permanent_hw_address (NMDevice *self)
 		return;
 	}
 
-	if (priv->ifindex <= 0)
+	ifindex = priv->ifindex;
+	if (ifindex <= 0)
 		return;
 
-	if (!priv->hw_addr_len) {
-		nm_device_update_hw_address (self);
-		if (!priv->hw_addr_len)
+	/* the user is advised to configure stable MAC addresses for software devices via
+	 * UDEV. Thus, check whether the link is fully initialized. */
+	pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex);
+	if (   !pllink
+	    || !pllink->initialized) {
+		if (!force_freeze) {
+			/* we can afford to wait. Back off and leave the permanent MAC address
+			 * undecided for now. */
 			return;
-	}
+		}
+		/* try to refresh the link just to give UDEV a bit more time... */
+		nm_platform_link_refresh (NM_PLATFORM_GET, ifindex);
+		/* maybe the MAC address changed... */
+		nm_device_update_hw_address (self);
+	} else if (!priv->hw_addr_len)
+		nm_device_update_hw_address (self);
 
-	success_read = nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len);
-	if (!success_read || len != priv->hw_addr_len) {
-		/* Fall back to current address. We use the fake address and keep it
-		 * until the device unrealizes.
+	if (!priv->hw_addr_len) {
+		/* we need the current MAC address because we require the permanent MAC address
+		 * to have the same length as the current address.
 		 *
-		 * In some cases it might be necessary to know whether this is a "real" or
-		 * a temporary address (fake). */
-		_LOGD (LOGD_HW | LOGD_ETHER, "hw-addr: %s (use current: %s)",
-		       success_read
-		           ? "read HW addr length of permanent MAC address differs"
-		           : "unable to read permanent MAC address",
-		       priv->hw_addr);
-		priv->hw_addr_perm_fake = TRUE;
-		priv->hw_addr_perm = g_strdup (priv->hw_addr);
-	} else {
+		 * Abort if there is no current MAC address. */
+		return;
+	}
+
+	success_read = nm_platform_link_get_permanent_address (NM_PLATFORM_GET, ifindex, buf, &len);
+	if (success_read && priv->hw_addr_len == len) {
 		priv->hw_addr_perm_fake = FALSE;
 		priv->hw_addr_perm = nm_utils_hwaddr_ntoa (buf, len);
 		_LOGD (LOGD_DEVICE, "hw-addr: read permanent MAC address '%s'",
 		       priv->hw_addr_perm);
+		goto notify_and_out;
 	}
+
+	/* we failed to read a permanent MAC address, thus we use a fake address,
+	 * that is the current MAC address of the device.
+	 *
+	 * Note that the permanet MAC address of a NMDevice instance does not change
+	 * after being set once. Thus, we use now a fake address and stick to that
+	 * (until we unrealize the device). */
+	priv->hw_addr_perm_fake = TRUE;
+
+	_LOGD (LOGD_PLATFORM | LOGD_ETHER, "hw-addr: %s (use current: %s)",
+	       success_read
+	           ? "read HW addr length of permanent MAC address differs"
+	           : "unable to read permanent MAC address",
+	       priv->hw_addr);
+	priv->hw_addr_perm = g_strdup (priv->hw_addr);
+
+notify_and_out:
 	_notify (self, PROP_PERM_HW_ADDRESS);
 }
 
@@ -11779,25 +11814,25 @@ nm_device_hw_addr_is_explict (NMDevice *self)
 }
 
 static gboolean
-_hw_addr_matches (NMDevice *self, const char *addr)
+_hw_addr_matches (NMDevice *self, const guint8 *addr, gsize addr_len)
 {
 	const char *cur_addr;
 
 	cur_addr = nm_device_get_hw_address (self);
-	return cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1);
+	return cur_addr && nm_utils_hwaddr_matches (addr, addr_len, cur_addr, -1);
 }
 
 static gboolean
 _hw_addr_set (NMDevice *self,
-              const char *addr,
-              const char *operation,
-              const char *detail)
+              const char *const addr,
+              const char *const operation,
+              const char *const detail)
 {
 	NMDevicePrivate *priv;
 	gboolean success = FALSE;
 	NMPlatformError plerr;
 	guint8 addr_bytes[NM_UTILS_HWADDR_LEN_MAX];
-	guint hw_addr_len;
+	gsize addr_len;
 	gboolean was_up;
 
 	nm_assert (NM_IS_DEVICE (self));
@@ -11806,17 +11841,17 @@ _hw_addr_set (NMDevice *self,
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
 
+	if (!_nm_utils_hwaddr_aton (addr, addr_bytes, sizeof (addr_bytes), &addr_len))
+		g_return_val_if_reached (FALSE);
+
 	/* Do nothing if current MAC is same */
-	if (_hw_addr_matches (self, addr)) {
+	if (_hw_addr_matches (self, addr_bytes, addr_len)) {
 		_LOGT (LOGD_DEVICE, "set-hw-addr: no MAC address change needed (%s)", addr);
 		return TRUE;
 	}
 
-	hw_addr_len = priv->hw_addr_len;
-	if (!hw_addr_len)
-		hw_addr_len = _nm_utils_hwaddr_length (addr);
-	if (   !hw_addr_len
-	    || !nm_utils_hwaddr_aton (addr, addr_bytes, hw_addr_len))
+	if (   priv->hw_addr_len
+	    && priv->hw_addr_len != addr_len)
 		g_return_val_if_reached (FALSE);
 
 	_LOGT (LOGD_DEVICE, "set-hw-addr: setting MAC address to '%s' (%s, %s)...", addr, operation, detail);
@@ -11827,12 +11862,12 @@ _hw_addr_set (NMDevice *self,
 		nm_device_take_down (self, FALSE);
 	}
 
-	plerr = nm_platform_link_set_address (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self), addr_bytes, hw_addr_len);
+	plerr = nm_platform_link_set_address (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self), addr_bytes, addr_len);
 	success = (plerr == NM_PLATFORM_ERROR_SUCCESS);
 	if (success) {
 		/* MAC address succesfully changed; update the current MAC to match */
 		nm_device_update_hw_address (self);
-		if (_hw_addr_matches (self, addr)) {
+		if (_hw_addr_matches (self, addr_bytes, addr_len)) {
 			_LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
 			       operation, addr, detail);
 		} else {
@@ -11862,7 +11897,7 @@ _hw_addr_set (NMDevice *self,
 					goto handle_fail;
 				if (!nm_device_update_hw_address (self))
 					goto handle_wait;
-				if (!_hw_addr_matches (self, addr))
+				if (!_hw_addr_matches (self, addr_bytes, addr_len))
 					goto handle_fail;
 
 				break;
@@ -11945,7 +11980,7 @@ nm_device_hw_addr_set_cloned (NMDevice *self, NMConnection *connection, gboolean
 	}
 
 	if (nm_streq (addr, NM_CLONED_MAC_PERMANENT)) {
-		addr = nm_device_get_permanent_hw_address (self, TRUE);
+		addr = nm_device_get_permanent_hw_address (self);
 		if (!addr)
 			return FALSE;
 		priv->hw_addr_type = HW_ADDR_TYPE_PERMANENT;
@@ -11989,9 +12024,8 @@ nm_device_hw_addr_set_cloned (NMDevice *self, NMConnection *connection, gboolean
 		addr = hw_addr_generated;
 	} else {
 		/* this must be a valid address. Otherwise, we shouldn't come here. */
-		if (_nm_utils_hwaddr_length (addr) <= 0) {
+		if (!nm_utils_hwaddr_valid (addr, -1))
 			g_return_val_if_reached (FALSE);
-		}
 		priv->hw_addr_type = HW_ADDR_TYPE_EXPLICIT;
 	}
 
@@ -12023,22 +12057,33 @@ nm_device_hw_addr_reset (NMDevice *self, const char *detail)
 }
 
 const char *
-nm_device_get_permanent_hw_address (NMDevice *self, gboolean fallback_fake)
+nm_device_get_permanent_hw_address_full (NMDevice *self, gboolean force_freeze, gboolean *out_is_fake)
 {
 	NMDevicePrivate *priv;
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
-	if (!priv->hw_addr_perm)
-		return NULL;
-	if (   priv->hw_addr_perm_fake
-	    && !fallback_fake)
-		return NULL;
+
+	if (   !priv->hw_addr_perm
+	    && force_freeze) {
+		/* somebody requests a permanent MAC address, but we don't have it set
+		 * yet. We cannot delay it any longer and try to get it without waiting
+		 * for UDEV. */
+		nm_device_update_permanent_hw_address (self, TRUE);
+	}
+
+	NM_SET_OUT (out_is_fake, priv->hw_addr_perm && priv->hw_addr_perm_fake);
 	return priv->hw_addr_perm;
 }
 
 const char *
+nm_device_get_permanent_hw_address (NMDevice *self)
+{
+	return nm_device_get_permanent_hw_address_full (self, TRUE, NULL);
+}
+
+const char *
 nm_device_get_initial_hw_address (NMDevice *self)
 {
 	g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
@@ -12092,7 +12137,7 @@ spec_match_list (NMDevice *self, const GSList *specs)
 		}
 	}
 
-	hw_addr_perm = nm_device_get_permanent_hw_address (self, FALSE);
+	hw_addr_perm = nm_device_get_permanent_hw_address (self);
 	if (hw_addr_perm) {
 		m = nm_match_spec_hwaddr (specs, hw_addr_perm);
 		matched = MAX (matched, m);
@@ -12188,13 +12233,16 @@ constructor (GType type,
 	}
 
 	if (priv->hw_addr_perm) {
-		priv->hw_addr_len = _nm_utils_hwaddr_length (priv->hw_addr_perm);
-		if (!priv->hw_addr_len) {
+		guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
+		gsize l;
+
+		if (!_nm_utils_hwaddr_aton (priv->hw_addr_perm, buf, sizeof (buf), &l)) {
 			g_clear_pointer (&priv->hw_addr_perm, g_free);
 			g_return_val_if_reached (object);
 		}
 
-		priv->hw_addr = g_strdup (priv->hw_addr_perm);
+		priv->hw_addr_len_ = l;
+		priv->hw_addr = nm_utils_hwaddr_ntoa (buf, l);
 		_LOGT (LOGD_DEVICE, "hw-addr: has permanent hw-address '%s'", priv->hw_addr_perm);
 	}
 
@@ -12563,10 +12611,15 @@ get_property (GObject *object, guint prop_id,
 	case PROP_HW_ADDRESS:
 		g_value_set_string (value, priv->hw_addr);
 		break;
-	case PROP_PERM_HW_ADDRESS:
+	case PROP_PERM_HW_ADDRESS: {
+		const char *perm_hw_addr;
+		gboolean perm_hw_addr_is_fake;
+
+		perm_hw_addr = nm_device_get_permanent_hw_address_full (self, FALSE, &perm_hw_addr_is_fake);
 		/* this property is exposed on D-Bus for NMDeviceEthernet and NMDeviceWifi. */
-		g_value_set_string (value, nm_device_get_permanent_hw_address (self, FALSE));
+		g_value_set_string (value, perm_hw_addr && !perm_hw_addr_is_fake ? perm_hw_addr : NULL);
 		break;
+	}
 	case PROP_HAS_PENDING_ACTION:
 		g_value_set_boolean (value, nm_device_has_pending_action (self));
 		break;
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index a757a37e..f90444cd 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -364,8 +364,10 @@ guint32         nm_device_get_ip4_route_metric  (NMDevice *dev);
 guint32         nm_device_get_ip6_route_metric  (NMDevice *dev);
 
 const char *    nm_device_get_hw_address        (NMDevice *dev);
-const char *    nm_device_get_permanent_hw_address (NMDevice *dev,
-                                                    gboolean fallback_fake);
+const char *    nm_device_get_permanent_hw_address (NMDevice *self);
+const char *    nm_device_get_permanent_hw_address_full (NMDevice *self,
+                                                         gboolean force_freeze,
+                                                         gboolean *out_is_fake);
 const char *    nm_device_get_initial_hw_address (NMDevice *dev);
 
 NMDhcp4Config * nm_device_get_dhcp4_config      (NMDevice *dev);
@@ -507,7 +509,7 @@ void nm_device_set_unmanaged_by_flags_queue (NMDevice *self,
                                              NMUnmanagedFlags flags,
                                              NMUnmanFlagOp set_op,
                                              NMDeviceStateReason reason);
-void nm_device_set_unmanaged_by_user_settings (NMDevice *self, const GSList *unmanaged_specs);
+void nm_device_set_unmanaged_by_user_settings (NMDevice *self);
 void nm_device_set_unmanaged_by_user_udev (NMDevice *self);
 void nm_device_set_unmanaged_by_quitting (NMDevice *device);
 
@@ -590,7 +592,7 @@ void nm_device_reactivate_ip6_config (NMDevice *device,
 
 gboolean nm_device_update_hw_address (NMDevice *self);
 void nm_device_update_initial_hw_address (NMDevice *self);
-void nm_device_update_permanent_hw_address (NMDevice *self);
+void nm_device_update_permanent_hw_address (NMDevice *self, gboolean force_freeze);
 void nm_device_update_dynamic_ip_setup (NMDevice *self);
 
 #endif /* __NETWORKMANAGER_DEVICE_H__ */
diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c
index ff6f42a9..f6b6af90 100644
--- a/src/devices/tests/test-lldp.c
+++ b/src/devices/tests/test-lldp.c
@@ -352,7 +352,7 @@ _test_recv_fixture_setup (TestRecvFixture *fixture, gconstpointer user_data)
 	struct ifreq ifr = { };
 	int fd, s;
 
-	fd = open ("/dev/net/tun", O_RDWR);
+	fd = open ("/dev/net/tun", O_RDWR | O_CLOEXEC);
 	g_assert (fd >= 0);
 
 	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
@@ -360,7 +360,7 @@ _test_recv_fixture_setup (TestRecvFixture *fixture, gconstpointer user_data)
 	g_assert (ioctl (fd, TUNSETIFF, &ifr) >= 0);
 
 	/* Bring the interface up */
-	s = socket (AF_INET, SOCK_DGRAM, 0);
+	s = socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 	g_assert (s >= 0);
 	ifr.ifr_flags |= IFF_UP;
 	g_assert (ioctl (s, SIOCSIFFLAGS, &ifr) >= 0);
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index f97e6689..c58b3fa8 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -203,7 +203,7 @@ constructed (GObject *object)
 	G_OBJECT_CLASS (nm_device_wifi_parent_class)->constructed (object);
 
 	if (priv->capabilities & NM_WIFI_DEVICE_CAP_AP)
-		_LOGI (LOGD_HW | LOGD_WIFI, "driver supports Access Point (AP) mode");
+		_LOGI (LOGD_PLATFORM | LOGD_WIFI, "driver supports Access Point (AP) mode");
 
 	/* Connect to the supplicant manager */
 	priv->sup_mgr = g_object_ref (nm_supplicant_manager_get ());
@@ -478,7 +478,6 @@ ap_add_remove (NMDeviceWifi *self,
 	}
 
 	g_signal_emit (self, signals[signum], 0, ap);
-	_notify (self, PROP_ACCESS_POINTS);
 
 	if (signum == ACCESS_POINT_REMOVED) {
 		g_hash_table_remove (priv->aps, nm_exported_object_get_path ((NMExportedObject *) ap));
@@ -486,6 +485,8 @@ ap_add_remove (NMDeviceWifi *self,
 		g_object_unref (ap);
 	}
 
+	_notify (self, PROP_ACCESS_POINTS);
+
 	nm_device_emit_recheck_auto_activate (NM_DEVICE (self));
 	if (recheck_available_connections)
 		nm_device_recheck_available_connections (NM_DEVICE (self));
@@ -615,7 +616,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 	if (!s_wireless)
 		return FALSE;
 
-	perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE);
+	perm_hw_addr = nm_device_get_permanent_hw_address (device);
 	mac = nm_setting_wireless_get_mac_address (s_wireless);
 	if (perm_hw_addr) {
 		if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1))
@@ -907,7 +908,7 @@ complete_connection (NMDevice *device,
 	if (hidden)
 		g_object_set (s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL);
 
-	perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE);
+	perm_hw_addr = nm_device_get_permanent_hw_address (device);
 	if (perm_hw_addr) {
 		setting_mac = nm_setting_wireless_get_mac_address (s_wifi);
 		if (setting_mac) {
diff --git a/src/devices/wifi/nm-wifi-factory.c b/src/devices/wifi/nm-wifi-factory.c
index 2d5f8faf..cf8cf03b 100644
--- a/src/devices/wifi/nm-wifi-factory.c
+++ b/src/devices/wifi/nm-wifi-factory.c
@@ -76,7 +76,7 @@ create_device (NMDeviceFactory *factory,
 	if (!nm_platform_wifi_get_capabilities (NM_PLATFORM_GET,
 	                                        plink->ifindex,
 	                                        &capabilities)) {
-		nm_log_warn (LOGD_HW | LOGD_WIFI, "(%s) failed to initialize Wi-Fi driver for ifindex %d", iface, plink->ifindex);
+		nm_log_warn (LOGD_PLATFORM | LOGD_WIFI, "(%s) failed to initialize Wi-Fi driver for ifindex %d", iface, plink->ifindex);
 		return NULL;
 	}
 
diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c
index 0f96dafb..b277b15b 100644
--- a/src/devices/wwan/nm-device-modem.c
+++ b/src/devices/wwan/nm-device-modem.c
@@ -351,7 +351,7 @@ device_state_changed (NMDevice *device,
 {
 	NMDeviceModem *self = NM_DEVICE_MODEM (device);
 	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device);
-	NMConnection *connection = nm_device_get_applied_connection (device);
+	NMSettingsConnection *connection = nm_device_get_settings_connection (device);
 
 	g_assert (priv->modem);
 
@@ -378,7 +378,7 @@ device_state_changed (NMDevice *device,
 		 * where a retry attempt would just fail again.
 		 */
 		if (connection)
-			nm_settings_connection_set_autoconnect_blocked_reason (NM_SETTINGS_CONNECTION (connection), reason);
+			nm_settings_connection_set_autoconnect_blocked_reason (connection, reason);
 		break;
 	default:
 		break;
diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c
index 2e3d63bb..459d212a 100644
--- a/src/devices/wwan/nm-modem.c
+++ b/src/devices/wwan/nm-modem.c
@@ -23,7 +23,9 @@
 
 #include "nm-modem.h"
 
+#include <fcntl.h>
 #include <string.h>
+#include <termios.h>
 
 #include "nm-core-internal.h"
 #include "nm-platform.h"
@@ -491,6 +493,23 @@ ppp_stats (NMPPPManager *ppp_manager,
 	}
 }
 
+static gboolean
+port_speed_is_zero (const char *port)
+{
+	struct termios options;
+	nm_auto_close int fd = -1;
+
+	fd = open (port, O_RDWR | O_NONBLOCK | O_NOCTTY | O_CLOEXEC);
+	if (fd < 0)
+		return FALSE;
+
+	memset (&options, 0, sizeof (struct termios));
+	if (tcgetattr (fd, &options) != 0)
+		return FALSE;
+
+	return cfgetospeed (&options) == B0;
+}
+
 static NMActStageReturn
 ppp_stage3_ip_config_start (NMModem *self,
                             NMActRequest *req,
@@ -501,6 +520,7 @@ ppp_stage3_ip_config_start (NMModem *self,
 	GError *error = NULL;
 	NMActStageReturn ret;
 	guint ip_timeout = 30;
+	guint baud_override = 0;
 
 	g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE);
 	g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE);
@@ -530,8 +550,16 @@ ppp_stage3_ip_config_start (NMModem *self,
 		ip_timeout = priv->mm_ip_timeout;
 	}
 
+	/* Some tty drivers and modems ignore port speed, but pppd requires the
+	 * port speed to be > 0 or it exits. If the port speed is 0 pass an
+	 * explicit speed to pppd to prevent the exit.
+	 * https://bugzilla.redhat.com/show_bug.cgi?id=1281731
+	 */
+	if (port_speed_is_zero (priv->data_port))
+		baud_override = 57600;
+
 	priv->ppp_manager = nm_ppp_manager_new (priv->data_port);
-	if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, ip_timeout, &error)) {
+	if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, ip_timeout, baud_override, &error)) {
 		g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_STATE_CHANGED,
 		                  G_CALLBACK (ppp_state_changed),
 		                  self);
@@ -1327,12 +1355,12 @@ constructor (GType type,
 	priv = NM_MODEM_GET_PRIVATE (object);
 
 	if (!priv->data_port && !priv->control_port) {
-		nm_log_err (LOGD_HW, "neither modem command nor data interface provided");
+		nm_log_err (LOGD_PLATFORM, "neither modem command nor data interface provided");
 		goto err;
 	}
 
 	if (!priv->path) {
-		nm_log_err (LOGD_HW, "D-Bus path not provided");
+		nm_log_err (LOGD_PLATFORM, "D-Bus path not provided");
 		goto err;
 	}
 
diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c
index ce8f4d93..5a758a9e 100644
--- a/src/dns-manager/nm-dns-manager.c
+++ b/src/dns-manager/nm-dns-manager.c
@@ -707,7 +707,7 @@ update_resolv_conf (NMDnsManager *self,
 		}
 	}
 
-	if ((f = fopen (MY_RESOLV_CONF_TMP, "w")) == NULL) {
+	if ((f = fopen (MY_RESOLV_CONF_TMP, "we")) == NULL) {
 		errsv = errno;
 		g_set_error (error,
 		             NM_MANAGER_ERROR,
@@ -1576,7 +1576,7 @@ _check_resconf_immutable (NMDnsManagerResolvConfManager rc_manager)
 			}
 		}
 
-		fd = open (_PATH_RESCONF, O_RDONLY);
+		fd = open (_PATH_RESCONF, O_RDONLY | O_CLOEXEC);
 		if (fd != -1) {
 			if (ioctl (fd, FS_IOC_GETFLAGS, &flags) != -1)
 				immutable = NM_FLAGS_HAS (flags, FS_IMMUTABLE_FL);
diff --git a/src/main-utils.c b/src/main-utils.c
index c2ed9d1c..6497ea25 100644
--- a/src/main-utils.c
+++ b/src/main-utils.c
@@ -94,7 +94,7 @@ nm_main_utils_write_pidfile (const char *pidfile)
 	int fd;
 	gboolean success = FALSE;
 
-	if ((fd = open (pidfile, O_CREAT|O_WRONLY|O_TRUNC, 00644)) < 0) {
+	if ((fd = open (pidfile, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 00644)) < 0) {
 		fprintf (stderr, _("Opening %s failed: %s\n"), pidfile, strerror (errno));
 		return FALSE;
 	}
diff --git a/src/nm-config.c b/src/nm-config.c
index 4bc4f483..f0f0c528 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -399,7 +399,7 @@ nm_config_set_no_auto_default_for_device (NMConfig *self, NMDevice *device)
 
 	priv = NM_CONFIG_GET_PRIVATE (self);
 
-	hw_address = nm_device_get_permanent_hw_address (device, FALSE);
+	hw_address = nm_device_get_permanent_hw_address (device);
 	if (!hw_address)
 		return;
 
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
index 6dfbb4ce..ed2a871e 100644
--- a/src/nm-core-utils.c
+++ b/src/nm-core-utils.c
@@ -1272,7 +1272,7 @@ nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr)
 {
 	const GSList *iter;
 	NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH;
-	guint hwaddr_len = 0;
+	gsize hwaddr_len = 0;
 	guint8 hwaddr_bin[NM_UTILS_HWADDR_LEN_MAX];
 
 	nm_assert (nm_utils_hwaddr_valid (hwaddr, -1));
@@ -1297,11 +1297,8 @@ nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr)
 			continue;
 
 		if (G_UNLIKELY (hwaddr_len == 0)) {
-			hwaddr_len = _nm_utils_hwaddr_length (hwaddr);
-			if (!hwaddr_len)
+			if (!_nm_utils_hwaddr_aton (hwaddr, hwaddr_bin, sizeof (hwaddr_bin), &hwaddr_len))
 				g_return_val_if_reached (NM_MATCH_SPEC_NO_MATCH);
-			if (!nm_utils_hwaddr_aton (hwaddr, hwaddr_bin, hwaddr_len))
-				nm_assert_not_reached ();
 		}
 
 		if (nm_utils_hwaddr_matches (spec_str, -1, hwaddr_bin, hwaddr_len)) {
@@ -2813,7 +2810,7 @@ nm_utils_read_urandom (void *p, size_t nbytes)
 	int r;
 
 again:
-	fd = open ("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+	fd = open ("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOCTTY);
 	if (fd < 0) {
 		r = errno;
 		if (r == EINTR)
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index a4d43612..7b422359 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -55,6 +55,8 @@ typedef struct {
 	gint64 route_metric;
 	gboolean metered;
 	gint dns_priority;
+	GVariant *address_data_variant;
+	GVariant *addresses_variant;
 } NMIP4ConfigPrivate;
 
 struct _NMIP4Config {
@@ -207,8 +209,9 @@ _addresses_sort_cmp_get_prio (in_addr_t addr)
 static gint
 _addresses_sort_cmp (gconstpointer a, gconstpointer b)
 {
-	gint p1, p2, c;
+	gint p1, p2;
 	const NMPlatformIP4Address *a1 = a, *a2 = b;
+	guint32 n1, n2;
 
 	/* Sort by address type. For example link local will
 	 * be sorted *after* a global address. */
@@ -224,43 +227,30 @@ _addresses_sort_cmp (gconstpointer a, gconstpointer b)
 	if ((a1->label[0] == '\0') != (a2->label[0] == '\0'))
 		return (a1->label[0] == '\0') ? -1 : 1;
 
-	/* finally sort addresses lexically */
-	c = memcmp (&a1->address, &a2->address, sizeof (a2->address));
-	return c != 0 ? c : memcmp (a1, a2, sizeof (*a1));
-}
-
-gboolean
-nm_ip4_config_addresses_sort (NMIP4Config *self)
-{
-	NMIP4ConfigPrivate *priv;
-	size_t data_len = 0;
-	char *data_pre = NULL;
-	gboolean changed;
-
-	g_return_val_if_fail (NM_IS_IP4_CONFIG (self), FALSE);
+	/* Finally, sort addresses lexically. We compare only the
+	 * network part so that the order of addresses in the same
+	 * subnet (and thus also the primary/secondary role) is
+	 * preserved.
+	 */
+	n1 = a1->address & nm_utils_ip4_prefix_to_netmask (a1->plen);
+	n2 = a2->address & nm_utils_ip4_prefix_to_netmask (a2->plen);
 
-	priv = NM_IP4_CONFIG_GET_PRIVATE (self);
-	if (priv->addresses->len > 1) {
-		data_len = priv->addresses->len * g_array_get_element_size (priv->addresses);
-		data_pre = g_new (char, data_len);
-		memcpy (data_pre, priv->addresses->data, data_len);
+	return memcmp (&n1, &n2, sizeof (guint32));
+}
 
-		g_array_sort (priv->addresses, _addresses_sort_cmp);
+/*****************************************************************************/
 
-		changed = memcmp (data_pre, priv->addresses->data, data_len) != 0;
-		g_free (data_pre);
+static void
+notify_addresses (NMIP4Config *self)
+{
+	NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
 
-		if (changed) {
-			_notify (self, PROP_ADDRESS_DATA);
-			_notify (self, PROP_ADDRESSES);
-			return TRUE;
-		}
-	}
-	return FALSE;
+	nm_clear_g_variant (&priv->address_data_variant);
+	nm_clear_g_variant (&priv->addresses_variant);
+	_notify (self, PROP_ADDRESS_DATA);
+	_notify (self, PROP_ADDRESSES);
 }
 
-/*****************************************************************************/
-
 NMIP4Config *
 nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf)
 {
@@ -347,7 +337,6 @@ gboolean
 nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_full_sync, gint64 default_route_metric)
 {
 	const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
-	int i;
 	gs_unref_ptrarray GPtrArray *added_addresses = NULL;
 
 	g_return_val_if_fail (ifindex > 0, FALSE);
@@ -359,7 +348,8 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_fu
 
 	/* Routes */
 	{
-		int count = nm_ip4_config_get_num_routes (config);
+		guint i;
+		guint count = nm_ip4_config_get_num_routes (config);
 		GArray *routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP4Route), count);
 		gboolean success;
 		gs_unref_array GArray *device_route_purge_list = NULL;
@@ -1366,7 +1356,7 @@ gboolean
 nm_ip4_config_destination_is_direct (const NMIP4Config *config, guint32 network, guint8 plen)
 {
 	guint naddresses = nm_ip4_config_get_num_addresses (config);
-	int i;
+	guint i;
 	in_addr_t peer_network;
 
 	for (i = 0; i < naddresses; i++) {
@@ -1473,8 +1463,7 @@ nm_ip4_config_reset_addresses (NMIP4Config *config)
 
 	if (priv->addresses->len != 0) {
 		g_array_set_size (priv->addresses, 0);
-		_notify (config, PROP_ADDRESS_DATA);
-		_notify (config, PROP_ADDRESSES);
+		notify_addresses (config);
 	}
 }
 
@@ -1531,8 +1520,7 @@ nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *new)
 
 	g_array_append_val (priv->addresses, *new);
 NOTIFY:
-	_notify (config, PROP_ADDRESS_DATA);
-	_notify (config, PROP_ADDRESSES);
+	notify_addresses (config);
 }
 
 void
@@ -1543,8 +1531,8 @@ nm_ip4_config_del_address (NMIP4Config *config, guint i)
 	g_return_if_fail (i < priv->addresses->len);
 
 	g_array_remove_index (priv->addresses, i);
-	_notify (config, PROP_ADDRESS_DATA);
-	_notify (config, PROP_ADDRESSES);
+
+	notify_addresses (config);
 }
 
 guint
@@ -1725,7 +1713,7 @@ nm_ip4_config_del_nameserver (NMIP4Config *config, guint i)
 	_notify (config, PROP_NAMESERVERS);
 }
 
-guint32
+guint
 nm_ip4_config_get_num_nameservers (const NMIP4Config *config)
 {
 	const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
@@ -1782,7 +1770,7 @@ nm_ip4_config_del_domain (NMIP4Config *config, guint i)
 	_notify (config, PROP_DOMAINS);
 }
 
-guint32
+guint
 nm_ip4_config_get_num_domains (const NMIP4Config *config)
 {
 	const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
@@ -1854,7 +1842,7 @@ nm_ip4_config_del_search (NMIP4Config *config, guint i)
 	_notify (config, PROP_SEARCHES);
 }
 
-guint32
+guint
 nm_ip4_config_get_num_searches (const NMIP4Config *config)
 {
 	const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
@@ -1911,7 +1899,7 @@ nm_ip4_config_del_dns_option(NMIP4Config *config, guint i)
 	_notify (config, PROP_DNS_OPTIONS);
 }
 
-guint32
+guint
 nm_ip4_config_get_num_dns_options (const NMIP4Config *config)
 {
 	const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
@@ -1999,7 +1987,7 @@ nm_ip4_config_del_nis_server (NMIP4Config *config, guint i)
 	g_array_remove_index (priv->nis, i);
 }
 
-guint32
+guint
 nm_ip4_config_get_num_nis_servers (const NMIP4Config *config)
 {
 	const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
@@ -2072,7 +2060,7 @@ nm_ip4_config_del_wins (NMIP4Config *config, guint i)
 	_notify (config, PROP_WINS_SERVERS);
 }
 
-guint32
+guint
 nm_ip4_config_get_num_wins (const NMIP4Config *config)
 {
 	const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
@@ -2147,7 +2135,7 @@ hash_u32 (GChecksum *sum, guint32 n)
 void
 nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only)
 {
-	guint32 i;
+	guint i;
 	const char *s;
 
 	g_return_if_fail (config);
@@ -2267,6 +2255,8 @@ finalize (GObject *object)
 	NMIP4Config *self = NM_IP4_CONFIG (object);
 	NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
 
+	nm_clear_g_variant (&priv->address_data_variant);
+	nm_clear_g_variant (&priv->addresses_variant);
 	g_array_unref (priv->addresses);
 	g_array_unref (priv->routes);
 	g_array_unref (priv->nameservers);
@@ -2292,14 +2282,26 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_int (value, priv->ifindex);
 		break;
 	case PROP_ADDRESS_DATA:
+	case PROP_ADDRESSES:
 		{
 			GVariantBuilder array_builder, addr_builder;
-			int naddr = nm_ip4_config_get_num_addresses (config);
-			int i;
+			gs_unref_array GArray *new = NULL;
+			guint naddr, i;
+
+			g_return_if_fail (!!priv->address_data_variant == !!priv->addresses_variant);
+
+			if (priv->address_data_variant)
+				goto return_cached;
 
+			naddr = nm_ip4_config_get_num_addresses (config);
+			new = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP4Address), naddr);
+			g_array_append_vals (new, priv->addresses->data, priv->addresses->len);
+			g_array_sort (new, _addresses_sort_cmp);
+
+			/* Build address data variant */
 			g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}"));
 			for (i = 0; i < naddr; i++) {
-				const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i);
+				const NMPlatformIP4Address *address = &g_array_index (new, NMPlatformIP4Address, i);
 
 				g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}"));
 				g_variant_builder_add (&addr_builder, "{sv}",
@@ -2322,19 +2324,12 @@ get_property (GObject *object, guint prop_id,
 
 				g_variant_builder_add (&array_builder, "a{sv}", &addr_builder);
 			}
+			priv->address_data_variant = g_variant_ref_sink (g_variant_builder_end (&array_builder));
 
-			g_value_take_variant (value, g_variant_builder_end (&array_builder));
-		}
-		break;
-	case PROP_ADDRESSES:
-		{
-			GVariantBuilder array_builder;
-			int naddr = nm_ip4_config_get_num_addresses (config);
-			int i;
-
+			/* Build addresses variant */
 			g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aau"));
 			for (i = 0; i < naddr; i++) {
-				const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i);
+				const NMPlatformIP4Address *address = &g_array_index (new, NMPlatformIP4Address, i);
 				guint32 dbus_addr[3];
 
 				dbus_addr[0] = address->address;
@@ -2345,15 +2340,20 @@ get_property (GObject *object, guint prop_id,
 				                       g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
 				                                                  dbus_addr, 3, sizeof (guint32)));
 			}
+			priv->addresses_variant = g_variant_ref_sink (g_variant_builder_end (&array_builder));
 
-			g_value_take_variant (value, g_variant_builder_end (&array_builder));
+return_cached:
+			g_value_set_variant (value,
+			                     prop_id == PROP_ADDRESS_DATA ?
+			                     priv->address_data_variant :
+			                     priv->addresses_variant);
 		}
 		break;
 	case PROP_ROUTE_DATA:
 		{
 			GVariantBuilder array_builder, route_builder;
 			guint nroutes = nm_ip4_config_get_num_routes (config);
-			int i;
+			guint i;
 
 			g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}"));
 			for (i = 0; i < nroutes; i++) {
@@ -2385,7 +2385,7 @@ get_property (GObject *object, guint prop_id,
 		{
 			GVariantBuilder array_builder;
 			guint nroutes = nm_ip4_config_get_num_routes (config);
-			int i;
+			guint i;
 
 			g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aau"));
 			for (i = 0; i < nroutes; i++) {
diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h
index f302630a..6fc45dc2 100644
--- a/src/nm-ip4-config.h
+++ b/src/nm-ip4-config.h
@@ -58,13 +58,13 @@ NMIP4Config * nm_ip4_config_new (int ifindex);
 
 int nm_ip4_config_get_ifindex (const NMIP4Config *config);
 
-/* Integration with nm-platform and nm-setting */
+
 NMIP4Config *nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf);
 gboolean nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_full_sync, gint64 default_route_metric);
 void nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, guint32 default_route_metric);
 NMSetting *nm_ip4_config_create_setting (const NMIP4Config *config);
 
-/* Utility functions */
+
 void nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFlags merge_flags);
 void nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src);
 void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src);
@@ -72,7 +72,7 @@ gboolean nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboole
 gboolean nm_ip4_config_destination_is_direct (const NMIP4Config *config, guint32 dest, guint8 plen);
 void nm_ip4_config_dump (const NMIP4Config *config, const char *detail);
 
-/* Gateways */
+
 void nm_ip4_config_set_never_default (NMIP4Config *config, gboolean never_default);
 gboolean nm_ip4_config_get_never_default (const NMIP4Config *config);
 void nm_ip4_config_set_gateway (NMIP4Config *config, guint32 gateway);
@@ -81,82 +81,69 @@ gboolean nm_ip4_config_has_gateway (const NMIP4Config *config);
 guint32 nm_ip4_config_get_gateway (const NMIP4Config *config);
 gint64 nm_ip4_config_get_route_metric (const NMIP4Config *config);
 
-/* Addresses */
 void nm_ip4_config_reset_addresses (NMIP4Config *config);
 void nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *address);
 void nm_ip4_config_del_address (NMIP4Config *config, guint i);
 guint nm_ip4_config_get_num_addresses (const NMIP4Config *config);
 const NMPlatformIP4Address *nm_ip4_config_get_address (const NMIP4Config *config, guint i);
 gboolean nm_ip4_config_address_exists (const NMIP4Config *config, const NMPlatformIP4Address *address);
-gboolean nm_ip4_config_addresses_sort (NMIP4Config *config);
 
-/* Routes */
 void nm_ip4_config_reset_routes (NMIP4Config *config);
 void nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *route);
 void nm_ip4_config_del_route (NMIP4Config *config, guint i);
-guint32 nm_ip4_config_get_num_routes (const NMIP4Config *config);
-const NMPlatformIP4Route *nm_ip4_config_get_route (const NMIP4Config *config, guint32 i);
+guint nm_ip4_config_get_num_routes (const NMIP4Config *config);
+const NMPlatformIP4Route *nm_ip4_config_get_route (const NMIP4Config *config, guint i);
 
 const NMPlatformIP4Route *nm_ip4_config_get_direct_route_for_host (const NMIP4Config *config, guint32 host);
 
-/* Nameservers */
 void nm_ip4_config_reset_nameservers (NMIP4Config *config);
 void nm_ip4_config_add_nameserver (NMIP4Config *config, guint32 nameserver);
 void nm_ip4_config_del_nameserver (NMIP4Config *config, guint i);
-guint32 nm_ip4_config_get_num_nameservers (const NMIP4Config *config);
+guint nm_ip4_config_get_num_nameservers (const NMIP4Config *config);
 guint32 nm_ip4_config_get_nameserver (const NMIP4Config *config, guint i);
 
-/* Domains */
 void nm_ip4_config_reset_domains (NMIP4Config *config);
 void nm_ip4_config_add_domain (NMIP4Config *config, const char *domain);
 void nm_ip4_config_del_domain (NMIP4Config *config, guint i);
-guint32 nm_ip4_config_get_num_domains (const NMIP4Config *config);
+guint nm_ip4_config_get_num_domains (const NMIP4Config *config);
 const char * nm_ip4_config_get_domain (const NMIP4Config *config, guint i);
 
-/* Search lists */
 void nm_ip4_config_reset_searches (NMIP4Config *config);
 void nm_ip4_config_add_search (NMIP4Config *config, const char *search);
 void nm_ip4_config_del_search (NMIP4Config *config, guint i);
-guint32 nm_ip4_config_get_num_searches (const NMIP4Config *config);
+guint nm_ip4_config_get_num_searches (const NMIP4Config *config);
 const char * nm_ip4_config_get_search (const NMIP4Config *config, guint i);
 
-/* DNS options */
 void nm_ip4_config_reset_dns_options (NMIP4Config *config);
 void nm_ip4_config_add_dns_option (NMIP4Config *config, const char *option);
 void nm_ip4_config_del_dns_option (NMIP4Config *config, guint i);
-guint32 nm_ip4_config_get_num_dns_options (const NMIP4Config *config);
+guint nm_ip4_config_get_num_dns_options (const NMIP4Config *config);
 const char * nm_ip4_config_get_dns_option (const NMIP4Config *config, guint i);
 
-/* DNS priority */
 void nm_ip4_config_set_dns_priority (NMIP4Config *config, gint priority);
 gint nm_ip4_config_get_dns_priority (const NMIP4Config *config);
 
-/* MSS */
 void nm_ip4_config_set_mss (NMIP4Config *config, guint32 mss);
 guint32 nm_ip4_config_get_mss (const NMIP4Config *config);
 
-/* NIS */
 void nm_ip4_config_reset_nis_servers (NMIP4Config *config);
 void nm_ip4_config_add_nis_server (NMIP4Config *config, guint32 nis);
 void nm_ip4_config_del_nis_server (NMIP4Config *config, guint i);
-guint32 nm_ip4_config_get_num_nis_servers (const NMIP4Config *config);
+guint nm_ip4_config_get_num_nis_servers (const NMIP4Config *config);
 guint32 nm_ip4_config_get_nis_server (const NMIP4Config *config, guint i);
 void nm_ip4_config_set_nis_domain (NMIP4Config *config, const char *domain);
 const char * nm_ip4_config_get_nis_domain (const NMIP4Config *config);
 
-/* WINS */
 void nm_ip4_config_reset_wins (NMIP4Config *config);
 void nm_ip4_config_add_wins (NMIP4Config *config, guint32 wins);
 void nm_ip4_config_del_wins (NMIP4Config *config, guint i);
-guint32 nm_ip4_config_get_num_wins (const NMIP4Config *config);
+guint nm_ip4_config_get_num_wins (const NMIP4Config *config);
 guint32 nm_ip4_config_get_wins (const NMIP4Config *config, guint i);
 
-/* MTU */
 void nm_ip4_config_set_mtu (NMIP4Config *config, guint32 mtu, NMIPConfigSource source);
 guint32 nm_ip4_config_get_mtu (const NMIP4Config *config);
 NMIPConfigSource nm_ip4_config_get_mtu_source (const NMIP4Config *config);
 
-/* Metered */
 void nm_ip4_config_set_metered (NMIP4Config *config, gboolean metered);
 gboolean nm_ip4_config_get_metered (const NMIP4Config *config);
 
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index 8002d61a..a0211246 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -48,6 +48,9 @@ typedef struct {
 	int ifindex;
 	gint64 route_metric;
 	gint dns_priority;
+	GVariant *address_data_variant;
+	GVariant *addresses_variant;
+	NMSettingIP6ConfigPrivacy privacy;
 } NMIP6ConfigPrivate;
 
 struct _NMIP6Config {
@@ -104,7 +107,26 @@ nm_ip6_config_get_ifindex (const NMIP6Config *config)
 	return NM_IP6_CONFIG_GET_PRIVATE (config)->ifindex;
 }
 
-/******************************************************************/
+void
+nm_ip6_config_set_privacy (NMIP6Config *config, NMSettingIP6ConfigPrivacy privacy)
+{
+	NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+
+	priv->privacy = privacy;
+}
+
+/*****************************************************************************/
+
+static void
+notify_addresses (NMIP6Config *self)
+{
+	NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
+
+	nm_clear_g_variant (&priv->address_data_variant);
+	nm_clear_g_variant (&priv->addresses_variant);
+	_notify (self, PROP_ADDRESS_DATA);
+	_notify (self, PROP_ADDRESSES);
+}
 
 /**
  * nm_ip6_config_capture_resolv_conf():
@@ -266,7 +288,7 @@ _addresses_sort_cmp (gconstpointer a, gconstpointer b, gpointer user_data)
 }
 
 gboolean
-nm_ip6_config_addresses_sort (NMIP6Config *self, NMSettingIP6ConfigPrivacy use_temporary)
+nm_ip6_config_addresses_sort (NMIP6Config *self)
 {
 	NMIP6ConfigPrivate *priv;
 	size_t data_len = 0;
@@ -281,14 +303,14 @@ nm_ip6_config_addresses_sort (NMIP6Config *self, NMSettingIP6ConfigPrivacy use_t
 		data_pre = g_new (char, data_len);
 		memcpy (data_pre, priv->addresses->data, data_len);
 
-		g_array_sort_with_data (priv->addresses, _addresses_sort_cmp, GINT_TO_POINTER (use_temporary));
+		g_array_sort_with_data (priv->addresses, _addresses_sort_cmp,
+		                        GINT_TO_POINTER (priv->privacy));
 
 		changed = memcmp (data_pre, priv->addresses->data, data_len) != 0;
 		g_free (data_pre);
 
 		if (changed) {
-			_notify (self, PROP_ADDRESS_DATA);
-			_notify (self, PROP_ADDRESSES);
+			notify_addresses (self);
 			return TRUE;
 		}
 	}
@@ -384,7 +406,6 @@ gboolean
 nm_ip6_config_commit (const NMIP6Config *config, int ifindex, gboolean routes_full_sync)
 {
 	const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
-	int i;
 	gboolean success;
 
 	g_return_val_if_fail (ifindex > 0, FALSE);
@@ -395,7 +416,8 @@ nm_ip6_config_commit (const NMIP6Config *config, int ifindex, gboolean routes_fu
 
 	/* Routes */
 	{
-		int count = nm_ip6_config_get_num_routes (config);
+		guint i;
+		guint count = nm_ip6_config_get_num_routes (config);
 		GArray *routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Route), count);
 		const NMPlatformIP6Route *route;
 
@@ -712,8 +734,8 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl
 gboolean
 nm_ip6_config_destination_is_direct (const NMIP6Config *config, const struct in6_addr *network, guint8 plen)
 {
-	int num = nm_ip6_config_get_num_addresses (config);
-	int i;
+	guint num = nm_ip6_config_get_num_addresses (config);
+	guint i;
 
 	nm_assert (network);
 	nm_assert (plen <= 128);
@@ -1156,6 +1178,11 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
 		has_minor_changes = TRUE;
 	}
 
+	if (src_priv->privacy != dst_priv->privacy) {
+		nm_ip6_config_set_privacy (dst, src_priv->privacy);
+		has_minor_changes = TRUE;
+	}
+
 #if NM_MORE_ASSERTS
 	/* config_equal does not compare *all* the fields, therefore, we might have has_minor_changes
 	 * regardless of config_equal. But config_equal must correspond to has_relevant_changes. */
@@ -1282,8 +1309,7 @@ nm_ip6_config_reset_addresses (NMIP6Config *config)
 
 	if (priv->addresses->len != 0) {
 		g_array_set_size (priv->addresses, 0);
-		_notify (config, PROP_ADDRESS_DATA);
-		_notify (config, PROP_ADDRESSES);
+		notify_addresses (config);
 	}
 }
 
@@ -1340,8 +1366,7 @@ nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new)
 
 	g_array_append_val (priv->addresses, *new);
 NOTIFY:
-	_notify (config, PROP_ADDRESS_DATA);
-	_notify (config, PROP_ADDRESSES);
+notify_addresses (config);
 }
 
 void
@@ -1352,8 +1377,8 @@ nm_ip6_config_del_address (NMIP6Config *config, guint i)
 	g_return_if_fail (i < priv->addresses->len);
 
 	g_array_remove_index (priv->addresses, i);
-	_notify (config, PROP_ADDRESS_DATA);
-	_notify (config, PROP_ADDRESSES);
+
+	notify_addresses (config);
 }
 
 guint
@@ -1626,7 +1651,7 @@ nm_ip6_config_del_nameserver (NMIP6Config *config, guint i)
 	_notify (config, PROP_NAMESERVERS);
 }
 
-guint32
+guint
 nm_ip6_config_get_num_nameservers (const NMIP6Config *config)
 {
 	const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
@@ -1683,7 +1708,7 @@ nm_ip6_config_del_domain (NMIP6Config *config, guint i)
 	_notify (config, PROP_DOMAINS);
 }
 
-guint32
+guint
 nm_ip6_config_get_num_domains (const NMIP6Config *config)
 {
 	const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
@@ -1755,7 +1780,7 @@ nm_ip6_config_del_search (NMIP6Config *config, guint i)
 	_notify (config, PROP_SEARCHES);
 }
 
-guint32
+guint
 nm_ip6_config_get_num_searches (const NMIP6Config *config)
 {
 	const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
@@ -1812,7 +1837,7 @@ nm_ip6_config_del_dns_option (NMIP6Config *config, guint i)
 	_notify (config, PROP_DNS_OPTIONS);
 }
 
-guint32
+guint
 nm_ip6_config_get_num_dns_options (const NMIP6Config *config)
 {
 	const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
@@ -2000,6 +2025,8 @@ finalize (GObject *object)
 	g_ptr_array_unref (priv->domains);
 	g_ptr_array_unref (priv->searches);
 	g_ptr_array_unref (priv->dns_options);
+	nm_clear_g_variant (&priv->address_data_variant);
+	nm_clear_g_variant (&priv->addresses_variant);
 
 	G_OBJECT_CLASS (nm_ip6_config_parent_class)->finalize (object);
 }
@@ -2036,14 +2063,28 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_int (value, priv->ifindex);
 		break;
 	case PROP_ADDRESS_DATA:
+	case PROP_ADDRESSES:
 		{
 			GVariantBuilder array_builder, addr_builder;
-			int naddr = nm_ip6_config_get_num_addresses (config);
-			int i;
+			gs_unref_array GArray *new = NULL;
+			const struct in6_addr *gateway;
+			guint naddr, i;
+
+			g_return_if_fail (!!priv->address_data_variant == !!priv->addresses_variant);
+
+			if (priv->address_data_variant)
+				goto return_cached;
+
+			naddr = nm_ip6_config_get_num_addresses (config);
+			gateway = nm_ip6_config_get_gateway (config);
+			new = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Address), naddr);
+			g_array_append_vals (new, priv->addresses->data, naddr);
+			g_array_sort_with_data (new, _addresses_sort_cmp,
+			                        GINT_TO_POINTER (priv->privacy));
 
 			g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}"));
 			for (i = 0; i < naddr; i++) {
-				const NMPlatformIP6Address *address = nm_ip6_config_get_address (config, i);
+				const NMPlatformIP6Address *address = &g_array_index (new, NMPlatformIP6Address, i);
 
 				g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}"));
 				g_variant_builder_add (&addr_builder, "{sv}",
@@ -2061,20 +2102,11 @@ get_property (GObject *object, guint prop_id,
 
 				g_variant_builder_add (&array_builder, "a{sv}", &addr_builder);
 			}
-
-			g_value_take_variant (value, g_variant_builder_end (&array_builder));
-		}
-		break;
-	case PROP_ADDRESSES:
-		{
-			GVariantBuilder array_builder;
-			const struct in6_addr *gateway = nm_ip6_config_get_gateway (config);
-			int naddr = nm_ip6_config_get_num_addresses (config);
-			int i;
+			priv->address_data_variant = g_variant_ref_sink (g_variant_builder_end (&array_builder));
 
 			g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a(ayuay)"));
 			for (i = 0; i < naddr; i++) {
-				const NMPlatformIP6Address *address = nm_ip6_config_get_address (config, i);
+				const NMPlatformIP6Address *address = &g_array_index (new, NMPlatformIP6Address, i);
 
 				g_variant_builder_add (&array_builder, "(@ayu@ay)",
 				                       g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
@@ -2085,7 +2117,12 @@ get_property (GObject *object, guint prop_id,
 				                                                  16, 1));
 			}
 
-			g_value_take_variant (value, g_variant_builder_end (&array_builder));
+			priv->addresses_variant = g_variant_ref_sink (g_variant_builder_end (&array_builder));
+return_cached:
+			g_value_set_variant (value,
+			                     prop_id == PROP_ADDRESS_DATA ?
+			                     priv->address_data_variant :
+			                     priv->addresses_variant);
 		}
 		break;
 	case PROP_ROUTE_DATA:
diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h
index c3f8d9f8..9454c0f7 100644
--- a/src/nm-ip6-config.h
+++ b/src/nm-ip6-config.h
@@ -60,13 +60,13 @@ NMIP6Config * nm_ip6_config_new_cloned (const NMIP6Config *src);
 
 int nm_ip6_config_get_ifindex (const NMIP6Config *config);
 
-/* Integration with nm-platform and nm-setting */
+
 NMIP6Config *nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary);
 gboolean nm_ip6_config_commit (const NMIP6Config *config, int ifindex, gboolean routes_full_sync);
 void nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, guint32 default_route_metric);
 NMSetting *nm_ip6_config_create_setting (const NMIP6Config *config);
 
-/* Utility functions */
+
 void nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFlags merge_flags);
 void nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src);
 void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src);
@@ -74,14 +74,13 @@ gboolean nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboole
 int nm_ip6_config_destination_is_direct (const NMIP6Config *config, const struct in6_addr *dest, guint8 plen);
 void nm_ip6_config_dump (const NMIP6Config *config, const char *detail);
 
-/* Gateways */
+
 void nm_ip6_config_set_never_default (NMIP6Config *config, gboolean never_default);
 gboolean nm_ip6_config_get_never_default (const NMIP6Config *config);
 void nm_ip6_config_set_gateway (NMIP6Config *config, const struct in6_addr *);
 const struct in6_addr *nm_ip6_config_get_gateway (const NMIP6Config *config);
 gint64 nm_ip6_config_get_route_metric (const NMIP6Config *config);
 
-/* Addresses */
 void nm_ip6_config_reset_addresses (NMIP6Config *config);
 void nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *address);
 void nm_ip6_config_del_address (NMIP6Config *config, guint i);
@@ -89,60 +88,54 @@ guint nm_ip6_config_get_num_addresses (const NMIP6Config *config);
 const NMPlatformIP6Address *nm_ip6_config_get_address (const NMIP6Config *config, guint i);
 const NMPlatformIP6Address *nm_ip6_config_get_address_first_nontentative (const NMIP6Config *config, gboolean linklocal);
 gboolean nm_ip6_config_address_exists (const NMIP6Config *config, const NMPlatformIP6Address *address);
-gboolean nm_ip6_config_addresses_sort (NMIP6Config *config, NMSettingIP6ConfigPrivacy use_temporary);
+gboolean nm_ip6_config_addresses_sort (NMIP6Config *config);
 gboolean nm_ip6_config_has_any_dad_pending (const NMIP6Config *self,
                                             const NMIP6Config *candidates);
 
-/* Routes */
 void nm_ip6_config_reset_routes (NMIP6Config *config);
 void nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *route);
 void nm_ip6_config_del_route (NMIP6Config *config, guint i);
-guint32 nm_ip6_config_get_num_routes (const NMIP6Config *config);
-const NMPlatformIP6Route *nm_ip6_config_get_route (const NMIP6Config *config, guint32 i);
+guint nm_ip6_config_get_num_routes (const NMIP6Config *config);
+const NMPlatformIP6Route *nm_ip6_config_get_route (const NMIP6Config *config, guint i);
 
 const NMPlatformIP6Route *nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct in6_addr *host);
 const NMPlatformIP6Address *nm_ip6_config_get_subnet_for_host (const NMIP6Config *config, const struct in6_addr *host);
 
-/* Nameservers */
 void nm_ip6_config_reset_nameservers (NMIP6Config *config);
 void nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *nameserver);
 void nm_ip6_config_del_nameserver (NMIP6Config *config, guint i);
-guint32 nm_ip6_config_get_num_nameservers (const NMIP6Config *config);
+guint nm_ip6_config_get_num_nameservers (const NMIP6Config *config);
 const struct in6_addr *nm_ip6_config_get_nameserver (const NMIP6Config *config, guint i);
 
-/* Domains */
 void nm_ip6_config_reset_domains (NMIP6Config *config);
 void nm_ip6_config_add_domain (NMIP6Config *config, const char *domain);
 void nm_ip6_config_del_domain (NMIP6Config *config, guint i);
-guint32 nm_ip6_config_get_num_domains (const NMIP6Config *config);
+guint nm_ip6_config_get_num_domains (const NMIP6Config *config);
 const char * nm_ip6_config_get_domain (const NMIP6Config *config, guint i);
 
-/* Search lists */
 void nm_ip6_config_reset_searches (NMIP6Config *config);
 void nm_ip6_config_add_search (NMIP6Config *config, const char *search);
 void nm_ip6_config_del_search (NMIP6Config *config, guint i);
-guint32 nm_ip6_config_get_num_searches (const NMIP6Config *config);
+guint nm_ip6_config_get_num_searches (const NMIP6Config *config);
 const char * nm_ip6_config_get_search (const NMIP6Config *config, guint i);
 
-/* DNS options */
 void nm_ip6_config_reset_dns_options (NMIP6Config *config);
 void nm_ip6_config_add_dns_option (NMIP6Config *config, const char *option);
 void nm_ip6_config_del_dns_option (NMIP6Config *config, guint i);
-guint32 nm_ip6_config_get_num_dns_options (const NMIP6Config *config);
+guint nm_ip6_config_get_num_dns_options (const NMIP6Config *config);
 const char * nm_ip6_config_get_dns_option (const NMIP6Config *config, guint i);
 
-/* DNS priority */
 void nm_ip6_config_set_dns_priority (NMIP6Config *config, gint priority);
 gint nm_ip6_config_get_dns_priority (const NMIP6Config *config);
 
-/* MSS */
 void nm_ip6_config_set_mss (NMIP6Config *config, guint32 mss);
 guint32 nm_ip6_config_get_mss (const NMIP6Config *config);
 
 void nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only);
 gboolean nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b);
 
-/******************************************************/
+void nm_ip6_config_set_privacy (NMIP6Config *config, NMSettingIP6ConfigPrivacy privacy);
+
 /* Testing-only functions */
 
 gboolean nm_ip6_config_capture_resolv_conf (GArray *nameservers,
diff --git a/src/nm-logging.h b/src/nm-logging.h
index 9e2b0108..72eb3db4 100644
--- a/src/nm-logging.h
+++ b/src/nm-logging.h
@@ -78,7 +78,6 @@ typedef enum  { /*< skip >*/
 	/* aliases: */
 	LOGD_DHCP       = LOGD_DHCP4 | LOGD_DHCP6,
 	LOGD_IP         = LOGD_IP4 | LOGD_IP6,
-	LOGD_HW         = LOGD_PLATFORM,
 } NMLogDomain;
 
 /* Log levels */
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 836ab768..c3d65cd1 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -610,7 +610,7 @@ find_device_by_permanent_hw_addr (NMManager *manager, const char *hwaddr)
 
 	if (nm_utils_hwaddr_valid (hwaddr, -1)) {
 		for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
-			device_addr = nm_device_get_permanent_hw_address (NM_DEVICE (iter->data), FALSE);
+			device_addr = nm_device_get_permanent_hw_address (NM_DEVICE (iter->data));
 			if (device_addr && nm_utils_hwaddr_matches (hwaddr, -1, device_addr, -1))
 				return NM_DEVICE (iter->data);
 		}
@@ -746,9 +746,7 @@ checked_connectivity (GObject *object, GAsyncResult *result, gpointer user_data)
 
 		if (connectivity == NM_CONNECTIVITY_FULL)
 			set_state (manager, NM_STATE_CONNECTED_GLOBAL);
-		else if (   connectivity == NM_CONNECTIVITY_PORTAL
-		         || connectivity == NM_CONNECTIVITY_LIMITED)
-			set_state (manager, NM_STATE_CONNECTED_SITE);
+
 		_notify (manager, PROP_CONNECTIVITY);
 	}
 
@@ -756,7 +754,7 @@ checked_connectivity (GObject *object, GAsyncResult *result, gpointer user_data)
 }
 
 static NMState
-find_best_device_state (NMManager *manager)
+find_best_device_state (NMManager *manager, gboolean *force_connectivity_check)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
 	NMState best_state = NM_STATE_DISCONNECTED;
@@ -774,6 +772,7 @@ find_best_device_state (NMManager *manager)
 					return NM_STATE_CONNECTED_GLOBAL;
 
 				best_state = NM_STATE_CONNECTED_SITE;
+				NM_SET_OUT (force_connectivity_check, TRUE);
 			} else {
 				if (best_state < NM_STATE_CONNECTING)
 					best_state = NM_STATE_CONNECTED_LOCAL;
@@ -827,6 +826,7 @@ nm_manager_update_state (NMManager *manager)
 {
 	NMManagerPrivate *priv;
 	NMState new_state = NM_STATE_DISCONNECTED;
+	gboolean force_connectivity_check = FALSE;
 
 	g_return_if_fail (NM_IS_MANAGER (manager));
 
@@ -835,11 +835,11 @@ nm_manager_update_state (NMManager *manager)
 	if (manager_sleeping (manager))
 		new_state = NM_STATE_ASLEEP;
 	else
-		new_state = find_best_device_state (manager);
+		new_state = find_best_device_state (manager, &force_connectivity_check);
 
 	nm_connectivity_set_online (priv->connectivity, new_state >= NM_STATE_CONNECTED_LOCAL);
 
-	if (new_state == NM_STATE_CONNECTED_SITE) {
+	if (new_state == NM_STATE_CONNECTED_SITE || force_connectivity_check) {
 		nm_connectivity_check_async (priv->connectivity,
 		                             checked_connectivity,
 		                             g_object_ref (manager));
@@ -1320,11 +1320,10 @@ system_unmanaged_devices_changed_cb (NMSettings *settings,
 {
 	NMManager *self = NM_MANAGER (user_data);
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	const GSList *unmanaged_specs, *iter;
+	const GSList *iter;
 
-	unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
 	for (iter = priv->devices; iter; iter = g_slist_next (iter))
-		nm_device_set_unmanaged_by_user_settings (NM_DEVICE (iter->data), unmanaged_specs);
+		nm_device_set_unmanaged_by_user_settings (NM_DEVICE (iter->data));
 }
 
 static void
@@ -1993,7 +1992,7 @@ add_device (NMManager *self, NMDevice *device, GError **error)
 	type_desc = nm_device_get_type_desc (device);
 	g_assert (type_desc);
 
-	nm_device_set_unmanaged_by_user_settings (device, nm_settings_get_unmanaged_specs (priv->settings));
+	nm_device_set_unmanaged_by_user_settings (device);
 
 	nm_device_set_unmanaged_flags (device,
 	                               NM_UNMANAGED_SLEEPING,
@@ -2127,10 +2126,10 @@ platform_link_added (NMManager *self,
 		device = nm_device_factory_create_device (factory, plink->name, plink, NULL, &ignore, &error);
 		if (!device) {
 			if (!ignore) {
-				_LOGW (LOGD_HW, "%s: factory failed to create device: %s",
+				_LOGW (LOGD_PLATFORM, "%s: factory failed to create device: %s",
 				       plink->name, error->message);
 			} else {
-				_LOGD (LOGD_HW, "%s: factory failed to create device: %s",
+				_LOGD (LOGD_PLATFORM, "%s: factory failed to create device: %s",
 				       plink->name, error->message);
 			}
 			return;
@@ -2144,7 +2143,7 @@ platform_link_added (NMManager *self,
 		case NM_LINK_TYPE_OLPC_MESH:
 		case NM_LINK_TYPE_TEAM:
 		case NM_LINK_TYPE_WIFI:
-			_LOGI (LOGD_HW, "(%s): '%s' plugin not available; creating generic device",
+			_LOGI (LOGD_PLATFORM, "(%s): '%s' plugin not available; creating generic device",
 			       plink->name, nm_link_type_to_string (plink->type));
 			nm_plugin_missing = TRUE;
 			/* fall through */
@@ -2812,15 +2811,15 @@ unmanaged_to_disconnected (NMDevice *device)
 
 	if (nm_device_get_state (device) == NM_DEVICE_STATE_UNMANAGED) {
 		nm_device_state_changed (device,
-					 NM_DEVICE_STATE_UNAVAILABLE,
-					 NM_DEVICE_STATE_REASON_USER_REQUESTED);
+		                         NM_DEVICE_STATE_UNAVAILABLE,
+		                         NM_DEVICE_STATE_REASON_USER_REQUESTED);
 	}
 
 	if (   nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_FOR_USER_REQUEST)
 	    && (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE)) {
 		nm_device_state_changed (device,
-					 NM_DEVICE_STATE_DISCONNECTED,
-					 NM_DEVICE_STATE_REASON_USER_REQUESTED);
+		                         NM_DEVICE_STATE_DISCONNECTED,
+		                         NM_DEVICE_STATE_REASON_USER_REQUESTED);
 	}
 }
 
@@ -4060,16 +4059,26 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
 
 		if (waking_from_suspend) {
 			sleep_devices_clear (self);
-			/* Belatedly take down Wake-on-LAN devices; ideally we wouldn't have to do this
-			 * but for now it's the only way to make sure we re-check their connectivity.
-			 */
 			for (iter = priv->devices; iter; iter = iter->next) {
 				NMDevice *device = iter->data;
 
 				if (nm_device_is_software (device))
 					continue;
+
+				/* Belatedly take down Wake-on-LAN devices; ideally we wouldn't have to do this
+				 * but for now it's the only way to make sure we re-check their connectivity.
+				 */
 				if (device_is_wake_on_lan (device))
 					nm_device_set_unmanaged_by_flags (device, NM_UNMANAGED_SLEEPING, TRUE, NM_DEVICE_STATE_REASON_SLEEPING);
+
+				/* Check if the device is unmanaged but the state transition is still pending.
+				 * If so, change state now so that later we re-manage the device forcing a
+				 * re-check of available connections.
+				 */
+				if (   !nm_device_get_managed (device, FALSE)
+				    && nm_device_get_state (device) != NM_DEVICE_STATE_UNMANAGED) {
+					nm_device_state_changed (device, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_SLEEPING);
+				}
 			}
 		}
 
@@ -5323,7 +5332,7 @@ rfkill_change (NMManager *self, const char *desc, RfKillType rtype, gboolean ena
 	g_return_if_fail (rtype == RFKILL_TYPE_WLAN || rtype == RFKILL_TYPE_WWAN);
 
 	errno = 0;
-	fd = open ("/dev/rfkill", O_RDWR);
+	fd = open ("/dev/rfkill", O_RDWR | O_CLOEXEC);
 	if (fd < 0) {
 		if (errno == EACCES)
 			_LOGW (LOGD_RFKILL, "(%s): failed to open killswitch device", desc);
@@ -5644,7 +5653,6 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_string (value, VERSION);
 		break;
 	case PROP_STATE:
-		nm_manager_update_state (self);
 		g_value_set_uint (value, priv->state);
 		break;
 	case PROP_STARTUP:
diff --git a/src/nm-rfkill-manager.c b/src/nm-rfkill-manager.c
index 453a3b9b..e4e738c9 100644
--- a/src/nm-rfkill-manager.c
+++ b/src/nm-rfkill-manager.c
@@ -347,7 +347,7 @@ handle_uevent (GUdevClient *client,
 	subsys = g_udev_device_get_subsystem (device);
 	g_return_if_fail (!g_strcmp0 (subsys, "rfkill"));
 
-	nm_log_dbg (LOGD_HW, "udev rfkill event: action '%s' device '%s'",
+	nm_log_dbg (LOGD_PLATFORM, "udev rfkill event: action '%s' device '%s'",
 	            action, g_udev_device_get_name (device));
 
 	if (!strcmp (action, "add"))
diff --git a/src/nm-session-monitor.c b/src/nm-session-monitor.c
index 279a8886..fb656c6b 100644
--- a/src/nm-session-monitor.c
+++ b/src/nm-session-monitor.c
@@ -78,6 +78,19 @@ static guint signals[LAST_SIGNAL] = { 0 };
 
 /********************************************************************/
 
+#define _NMLOG_PREFIX_NAME    "session-monitor"
+#define _NMLOG_DOMAIN         LOGD_CORE
+
+#define _NMLOG(level, ...) \
+	G_STMT_START { \
+		nm_log (level, _NMLOG_DOMAIN, \
+		        "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+		        _NMLOG_PREFIX_NAME \
+		        _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+	} G_STMT_END
+
+/*****************************************************************************/
+
 #ifdef SESSION_TRACKING_SYSTEMD
 static gboolean
 st_sd_session_exists (NMSessionMonitor *monitor, uid_t uid, gboolean active)
@@ -90,8 +103,7 @@ st_sd_session_exists (NMSessionMonitor *monitor, uid_t uid, gboolean active)
 	status = sd_uid_get_sessions (uid, active, NULL);
 
 	if (status < 0)
-		nm_log_err (LOGD_CORE, "Failed to get systemd sessions for uid %d: %d",
-		            uid, status);
+		_LOGE ("failed to get systemd sessions for uid %d: %d", uid, status);
 
 	return status > 0;
 }
@@ -118,7 +130,7 @@ st_sd_init (NMSessionMonitor *monitor)
 		return;
 
 	if ((status = sd_login_monitor_new (NULL, &monitor->sd.monitor)) < 0) {
-		nm_log_err (LOGD_CORE, "Failed to create systemd login monitor: %d", status);
+		_LOGE ("failed to create systemd login monitor: %d", status);
 		return;
 	}
 
@@ -156,7 +168,7 @@ ck_load_cache (GHashTable *cache)
 		goto out;
 
 	if (!(groups = g_key_file_get_groups (keyfile, &len))) {
-		nm_log_err (LOGD_CORE, "Could not load groups from " CKDB_PATH);
+		_LOGE ("could not load groups from " CKDB_PATH);
 		goto out;
 	}
 
@@ -166,7 +178,7 @@ ck_load_cache (GHashTable *cache)
 		guint uid = G_MAXUINT;
 		CkSession session = { .active = FALSE };
 
-		if (!g_str_has_prefix (groups[i], "CkSession "))
+		if (!g_str_has_prefix (groups[i], "Session "))
 			continue;
 
 		uid = g_key_file_get_integer (keyfile, groups[i], "uid", &error);
@@ -183,7 +195,7 @@ ck_load_cache (GHashTable *cache)
 	finished = TRUE;
 out:
 	if (error)
-		nm_log_err (LOGD_CORE, "ConsoleKit: Failed to load database: %s", error->message);
+		_LOGE ("failed to load ConsoleKit database: %s", error->message);
 	g_clear_error (&error);
 	g_clear_pointer (&groups, g_strfreev);
 	g_clear_pointer (&keyfile, g_key_file_free);
@@ -201,7 +213,7 @@ ck_update_cache (NMSessionMonitor *monitor)
 
 	/* Check the database file */
 	if (stat (CKDB_PATH, &statbuf) != 0) {
-		nm_log_err (LOGD_CORE, "Failed to check ConsoleKit timestamp: %s", strerror (errno));
+		_LOGE ("failed to check ConsoleKit timestamp: %s", strerror (errno));
 		return FALSE;
 	}
 	if (statbuf.st_mtime == monitor->ck.timestamp)
@@ -258,7 +270,7 @@ ck_init (NMSessionMonitor *monitor)
 							  G_CALLBACK (ck_changed),
 							  monitor);
 		} else {
-			nm_log_err (LOGD_CORE, "Error monitoring " CKDB_PATH ": %s", error->message);
+			_LOGE ("error monitoring " CKDB_PATH ": %s", error->message);
 			g_clear_error (&error);
 		}
 	}
@@ -363,10 +375,12 @@ nm_session_monitor_init (NMSessionMonitor *monitor)
 {
 #ifdef SESSION_TRACKING_SYSTEMD
 	st_sd_init (monitor);
+	_LOGD ("using systemd-logind session tracking");
 #endif
 
 #ifdef SESSION_TRACKING_CONSOLEKIT
 	ck_init (monitor);
+	_LOGD ("using ConsoleKit session tracking");
 #endif
 }
 
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 070a83ea..f9f4b088 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -36,12 +36,7 @@
 #include <linux/if_tun.h>
 #include <linux/if_tunnel.h>
 #include <netlink/netlink.h>
-#include <netlink/object.h>
-#include <netlink/cache.h>
-#include <netlink/route/link.h>
-#include <netlink/route/link/vlan.h>
-#include <netlink/route/addr.h>
-#include <netlink/route/route.h>
+#include <netlink/msg.h>
 #include <gudev/gudev.h>
 
 #include "nm-utils.h"
@@ -54,6 +49,7 @@
 #include "nm-platform-utils.h"
 #include "wifi/wifi-utils.h"
 #include "wifi/wifi-utils-wext.h"
+#include "nm-utils/unaligned.h"
 
 #define offset_plus_sizeof(t,m) (offsetof (t,m) + sizeof (((t *) NULL)->m))
 
@@ -61,6 +57,7 @@
 
 /* nm-internal error codes for libnl. Make sure they don't overlap. */
 #define _NLE_NM_NOBUFS 500
+#define _NLE_MSG_TRUNC 501
 
 /*********************************************************************************************/
 
@@ -724,7 +721,7 @@ _linktype_get_type (NMPlatform *platform,
 		}
 
 		/* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */
-		if (wifi_utils_is_wifi (ifname))
+		if (wifi_utils_is_wifi (ifindex, ifname))
 			return NM_LINK_TYPE_WIFI;
 
 		if (arptype == ARPHRD_ETHER) {
@@ -1477,12 +1474,18 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 	}
 
 	if (tb[IFLA_STATS64]) {
-		struct rtnl_link_stats64 *stats = nla_data (tb[IFLA_STATS64]);
+		/* tb[IFLA_STATS64] is only guaranteed to be 32bit-aligned,
+		 * so in general we can't access the rtnl_link_stats64 struct
+		 * members directly on 64bit architectures. */
+		char *stats = nla_data (tb[IFLA_STATS64]);
 
-		obj->link.rx_packets = stats->rx_packets;
-		obj->link.rx_bytes = stats->rx_bytes;
-		obj->link.tx_packets = stats->tx_packets;
-		obj->link.tx_bytes = stats->tx_bytes;
+#define READ_STAT64(member) \
+	unaligned_read_ne64 (stats + offsetof (struct rtnl_link_stats64, member))
+
+		obj->link.rx_packets = READ_STAT64 (rx_packets);
+		obj->link.rx_bytes   = READ_STAT64 (rx_bytes);
+		obj->link.tx_packets = READ_STAT64 (tx_packets);
+		obj->link.tx_bytes   = READ_STAT64 (tx_bytes);
 	}
 
 	obj->link.n_ifi_flags = ifi->ifi_flags;
@@ -5144,7 +5147,7 @@ tun_add (NMPlatform *platform, const char *name, gboolean tap,
 	_LOGD ("link: add %s '%s' owner %" G_GINT64_FORMAT " group %" G_GINT64_FORMAT,
 	       tap ? "tap" : "tun", name, owner, group);
 
-	fd = open ("/dev/net/tun", O_RDWR);
+	fd = open ("/dev/net/tun", O_RDWR | O_CLOEXEC);
 	if (fd < 0)
 		return FALSE;
 
@@ -5967,6 +5970,23 @@ continue_reading:
 			n = -NLE_AGAIN;
 		}
 		break;
+	case -NLE_MSG_TRUNC: {
+		int buf_size;
+
+		/* the message receive buffer was too small. We lost one message, which
+		 * is unfortunate. Try to double the buffer size for the next time. */
+		buf_size = nl_socket_get_msg_buf_size (sk);
+		if (buf_size < 512*1024) {
+			buf_size *= 2;
+			_LOGT ("netlink: recvmsg: increase message buffer size for recvmsg() to %d bytes", buf_size);
+			if (nl_socket_set_msg_buf_size (sk, buf_size) < 0)
+				nm_assert_not_reached ();
+			if (!handle_events)
+				goto continue_reading;
+		}
+		n = -_NLE_MSG_TRUNC;
+		break;
+	}
 	case -NLE_NOMEM:
 		if (errno == ENOBUFS) {
 			/* we are very much interested in a overrun of the receive buffer.
@@ -6155,8 +6175,17 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks)
 				case -NLE_DUMP_INTR:
 					_LOGD ("netlink: read: uncritical failure to retrieve incoming events: %s (%d)", nl_geterror (nle), nle);
 					break;
+				case -_NLE_MSG_TRUNC:
 				case -_NLE_NM_NOBUFS:
-					_LOGI ("netlink: read: too many netlink events. Need to resynchronize platform cache");
+					_LOGI ("netlink: read: %s. Need to resynchronize platform cache",
+					       ({
+					            const char *_reason = "unknown";
+					            switch (nle) {
+					            case -_NLE_MSG_TRUNC: _reason = "message truncated";       break;
+					            case -_NLE_NM_NOBUFS: _reason = "too many netlink events"; break;
+					            }
+					            _reason;
+					       }));
 					event_handler_recvmsgs (platform, FALSE);
 					delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC);
 					delayed_action_schedule (platform,
@@ -6413,6 +6442,12 @@ constructed (GObject *_object)
 	nle = nl_socket_set_buffer_size (priv->nlh, 8*1024*1024, 0);
 	g_assert (!nle);
 
+	/* explicitly set the msg buffer size and disable MSG_PEEK.
+	 * If we later encounter NLE_MSG_TRUNC, we will adjust the buffer size. */
+	nl_socket_disable_msg_peek (priv->nlh);
+	nle = nl_socket_set_msg_buf_size (priv->nlh, 32 * 1024);
+	g_assert (!nle);
+
 	nle = nl_socket_add_memberships (priv->nlh,
 	                                 RTNLGRP_LINK,
 	                                 RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR,
diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c
index 068801ee..b939e783 100644
--- a/src/platform/nm-platform-utils.c
+++ b/src/platform/nm-platform-utils.c
@@ -31,12 +31,15 @@
 #include <linux/mii.h>
 #include <linux/version.h>
 #include <linux/rtnetlink.h>
+#include <fcntl.h>
 
 #include "nm-utils.h"
 #include "nm-setting-wired.h"
 
 #include "nm-core-utils.h"
 
+extern char *if_indextoname (unsigned int __ifindex, char *__ifname);
+
 /******************************************************************
  * ethtool
  ******************************************************************/
@@ -60,7 +63,7 @@ ethtool_get (const char *name, gpointer edata)
 	nm_utils_ifname_cpy (ifr.ifr_name, name);
 	ifr.ifr_data = edata;
 
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
+	fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 	if (fd < 0) {
 		nm_log_err (LOGD_PLATFORM, "ethtool: Could not open socket.");
 		return FALSE;
@@ -342,7 +345,7 @@ nmp_utils_mii_supports_carrier_detect (const char *ifname)
 	if (!nmp_utils_device_exists (ifname))
 		return FALSE;
 
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
+	fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 	if (fd < 0) {
 		nm_log_err (LOGD_PLATFORM, "mii: couldn't open control socket (%s)", ifname);
 		return FALSE;
@@ -558,3 +561,83 @@ nmp_utils_ip_config_source_to_string (NMIPConfigSource source, char *buf, gsize
 	return buf;
 }
 
+/**
+ * nmp_utils_sysctl_open_netdir:
+ * @ifindex: the ifindex for which to open "/sys/class/net/%s"
+ * @ifname_guess: (allow-none): optional argument, if present used as initial
+ *   guess as the current name for @ifindex. If guessed right,
+ *   it saves an addtional if_indextoname() call.
+ * @out_ifname: (allow-none): if present, must be at least IFNAMSIZ
+ *   characters. On success, this will contain the actual ifname
+ *   found while opening the directory.
+ *
+ * Returns: a negative value on failure, on success returns the open fd
+ *   to the "/sys/class/net/%s" directory for @ifindex.
+ */
+int
+nmp_utils_sysctl_open_netdir (int ifindex,
+                              const char *ifname_guess,
+                              char *out_ifname)
+{
+	#define SYS_CLASS_NET "/sys/class/net/"
+	const char *ifname = ifname_guess;
+	char ifname_buf_last_try[IFNAMSIZ];
+	char ifname_buf[IFNAMSIZ];
+	guint try_count = 0;
+	char sysdir[NM_STRLEN (SYS_CLASS_NET) + IFNAMSIZ] = SYS_CLASS_NET;
+	char fd_buf[256];
+	ssize_t nn;
+
+	g_return_val_if_fail (ifindex >= 0, -1);
+
+	ifname_buf_last_try[0] = '\0';
+
+	for (try_count = 0; try_count < 10; try_count++, ifname = NULL) {
+		nm_auto_close int fd_dir = -1;
+		nm_auto_close int fd_ifindex = -1;
+		int fd;
+
+		if (!ifname) {
+			ifname = if_indextoname (ifindex, ifname_buf);
+			if (!ifname)
+				return -1;
+		}
+
+		nm_assert (nm_utils_iface_valid_name (ifname));
+
+		if (g_strlcpy (&sysdir[NM_STRLEN (SYS_CLASS_NET)], ifname, IFNAMSIZ) >= IFNAMSIZ)
+			g_return_val_if_reached (-1);
+
+		/* we only retry, if the name changed since previous attempt.
+		 * Hence, it is extremely unlikely that this loop runes until the
+		 * end of the @try_count. */
+		if (nm_streq (ifname, ifname_buf_last_try))
+			return -1;
+		strcpy (ifname_buf_last_try, ifname);
+
+		fd_dir = open (sysdir, O_DIRECTORY | O_CLOEXEC);
+		if (fd_dir < 0)
+			continue;
+
+		fd_ifindex = openat (fd_dir, "ifindex", O_CLOEXEC);
+		if (fd_ifindex < 0)
+			continue;
+
+		nn = nm_utils_fd_read_loop (fd_ifindex, fd_buf, sizeof (fd_buf) - 2, FALSE);
+		if (nn <= 0)
+			continue;
+		fd_buf[nn] = '\0';
+
+		if (ifindex != _nm_utils_ascii_str_to_int64 (fd_buf, 10, 1, G_MAXINT, -1))
+			continue;
+
+		if (out_ifname)
+			strcpy (out_ifname, ifname);
+
+		fd = fd_dir;
+		fd_dir = -1;
+		return fd;
+	}
+
+	return -1;
+}
diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h
index 456c0865..92a06fdf 100644
--- a/src/platform/nm-platform-utils.h
+++ b/src/platform/nm-platform-utils.h
@@ -60,4 +60,8 @@ NMIPConfigSource nmp_utils_ip_config_source_coerce_from_rtprot (NMIPConfigSource
 NMIPConfigSource nmp_utils_ip_config_source_round_trip_rtprot  (NMIPConfigSource source) _nm_const;
 const char *     nmp_utils_ip_config_source_to_string (NMIPConfigSource source, char *buf, gsize len);
 
+int nmp_utils_sysctl_open_netdir (int ifindex,
+                                  const char *ifname_guess,
+                                  char *out_ifname);
+
 #endif /* __NM_PLATFORM_UTILS_H__ */
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 9dace699..9274a31d 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -28,11 +28,10 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <string.h>
-#include <netlink/route/addr.h>
-#include <netlink/route/rtnl.h>
 #include <linux/ip.h>
 #include <linux/if_tun.h>
 #include <linux/if_tunnel.h>
+#include <linux/rtnetlink.h>
 
 #include "nm-utils.h"
 #include "nm-core-internal.h"
diff --git a/src/platform/nmp-netns.c b/src/platform/nmp-netns.c
index 26295855..07e134c1 100644
--- a/src/platform/nmp-netns.c
+++ b/src/platform/nmp-netns.c
@@ -277,7 +277,7 @@ _netns_new (GError **error)
 	int fd_net, fd_mnt;
 	int errsv;
 
-	fd_net = open (PROC_SELF_NS_NET, O_RDONLY);
+	fd_net = open (PROC_SELF_NS_NET, O_RDONLY | O_CLOEXEC);
 	if (fd_net == -1) {
 		errsv = errno;
 		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
@@ -286,7 +286,7 @@ _netns_new (GError **error)
 		return NULL;
 	}
 
-	fd_mnt = open (PROC_SELF_NS_MNT, O_RDONLY);
+	fd_mnt = open (PROC_SELF_NS_MNT, O_RDONLY | O_CLOEXEC);
 	if (fd_mnt == -1) {
 		errsv = errno;
 		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
@@ -623,7 +623,7 @@ nmp_netns_bind_to_path (NMPNetns *self, const char *filename, int *out_fd)
 	}
 
 	if (out_fd) {
-		if ((fd = open (filename, O_RDONLY)) == -1) {
+		if ((fd = open (filename, O_RDONLY | O_CLOEXEC)) == -1) {
 			errsv = errno;
 			_LOGE (self, "bind: failed to open %s: %s", filename, g_strerror (errsv));
 			umount2 (filename, MNT_DETACH);
diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c
index 30a52c25..993c23d6 100644
--- a/src/platform/nmp-object.c
+++ b/src/platform/nmp-object.c
@@ -23,6 +23,7 @@
 #include "nmp-object.h"
 
 #include <unistd.h>
+#include <linux/rtnetlink.h>
 
 #include "nm-utils.h"
 
diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h
index d295f7a0..b6d6709c 100644
--- a/src/platform/nmp-object.h
+++ b/src/platform/nmp-object.h
@@ -21,7 +21,6 @@
 #ifndef __NMP_OBJECT_H__
 #define __NMP_OBJECT_H__
 
-#include <netlink/netlink.h>
 #include <gudev/gudev.h>
 
 #include "nm-platform.h"
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index b1947a6d..d636ebeb 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -1398,7 +1398,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error)
 	int pipefd_p2c[2];
 	ssize_t r;
 
-	e = pipe (pipefd_c2p);
+	e = pipe2 (pipefd_c2p, O_CLOEXEC);
 	if (e != 0) {
 		errsv = errno;
 		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
@@ -1406,7 +1406,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error)
 		return FALSE;
 	}
 
-	e = pipe (pipefd_p2c);
+	e = pipe2 (pipefd_p2c, O_CLOEXEC);
 	if (e != 0) {
 		errsv = errno;
 		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
@@ -1540,7 +1540,7 @@ nmtstp_namespace_get_fd_for_process (pid_t pid, const char *ns_name)
 
 	nm_sprintf_buf (p, "/proc/%lu/ns/%s", (long unsigned) pid, ns_name);
 
-	return open(p, O_RDONLY);
+	return open(p, O_RDONLY | O_CLOEXEC);
 }
 
 /*****************************************************************************/
@@ -1564,21 +1564,21 @@ unshare_user (void)
 
 	/* Since Linux 3.19 we have to disable setgroups() in order to map users.
 	 * Just proceed if the file is not there. */
-	f = fopen ("/proc/self/setgroups", "w");
+	f = fopen ("/proc/self/setgroups", "we");
 	if (f) {
 		fprintf (f, "deny");
 		fclose (f);
 	}
 
 	/* Map current UID to root in NS to be created. */
-	f = fopen ("/proc/self/uid_map", "w");
+	f = fopen ("/proc/self/uid_map", "we");
 	if (!f)
 		return FALSE;
 	fprintf (f, "0 %d 1", uid);
 	fclose (f);
 
 	/* Map current GID to root in NS to be created. */
-	f = fopen ("/proc/self/gid_map", "w");
+	f = fopen ("/proc/self/gid_map", "we");
 	if (!f)
 		return FALSE;
 	fprintf (f, "0 %d 1", gid);
diff --git a/src/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c
index 79f217a8..2e222eb8 100644
--- a/src/platform/wifi/wifi-utils-nl80211.c
+++ b/src/platform/wifi/wifi-utils-nl80211.c
@@ -1003,7 +1003,7 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 			case WLAN_CIPHER_SUITE_SMS4:
 				break;
 			default:
-				nm_log_dbg (LOGD_HW | LOGD_WIFI, "Don't know the meaning of NL80211_ATTR_CIPHER_SUITE %#8.8x.", ciphers[i]);
+				nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI, "Don't know the meaning of NL80211_ATTR_CIPHER_SUITE %#8.8x.", ciphers[i]);
 				break;
 			}
 		}
@@ -1071,42 +1071,42 @@ wifi_nl80211_init (const char *iface, int ifindex)
 
 	if (nl80211_send_and_recv (nl80211, msg, nl80211_wiphy_info_handler,
 	                           &device_info) < 0) {
-		nm_log_dbg (LOGD_HW | LOGD_WIFI,
+		nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI,
 		            "(%s): NL80211_CMD_GET_WIPHY request failed",
 		            nl80211->parent.iface);
 		goto error;
 	}
 
 	if (!device_info.success) {
-		nm_log_dbg (LOGD_HW | LOGD_WIFI,
+		nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI,
 		            "(%s): NL80211_CMD_GET_WIPHY request indicated failure",
 		            nl80211->parent.iface);
 		goto error;
 	}
 
 	if (!device_info.supported) {
-		nm_log_dbg (LOGD_HW | LOGD_WIFI,
+		nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI,
 		            "(%s): driver does not fully support nl80211, falling back to WEXT",
 		            nl80211->parent.iface);
 		goto error;
 	}
 
 	if (!device_info.can_scan_ssid) {
-		nm_log_err (LOGD_HW | LOGD_WIFI,
+		nm_log_err (LOGD_PLATFORM | LOGD_WIFI,
 		            "(%s): driver does not support SSID scans",
 		            nl80211->parent.iface);
 		goto error;
 	}
 
 	if (device_info.num_freqs == 0 || device_info.freqs == NULL) {
-		nm_log_err (LOGD_HW | LOGD_WIFI,
+		nm_log_err (LOGD_PLATFORM | LOGD_WIFI,
 		            "(%s): driver reports no supported frequencies",
 		            nl80211->parent.iface);
 		goto error;
 	}
 
 	if (device_info.caps == 0) {
-		nm_log_err (LOGD_HW | LOGD_WIFI,
+		nm_log_err (LOGD_PLATFORM | LOGD_WIFI,
 		            "(%s): driver doesn't report support of any encryption",
 		            nl80211->parent.iface);
 		goto error;
@@ -1120,7 +1120,7 @@ wifi_nl80211_init (const char *iface, int ifindex)
 	if (device_info.can_wowlan)
 		nl80211->parent.get_wowlan = wifi_nl80211_get_wowlan;
 
-	nm_log_info (LOGD_HW | LOGD_WIFI,
+	nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
 	             "(%s): using nl80211 for WiFi device control",
 	             nl80211->parent.iface);
 
diff --git a/src/platform/wifi/wifi-utils-wext.c b/src/platform/wifi/wifi-utils-wext.c
index af285b45..d4ed86eb 100644
--- a/src/platform/wifi/wifi-utils-wext.c
+++ b/src/platform/wifi/wifi-utils-wext.c
@@ -105,7 +105,7 @@ wifi_wext_get_mode (WifiData *data)
 
 	if (ioctl (wext->fd, SIOCGIWMODE, &wrq) < 0) {
 		if (errno != ENODEV) {
-			nm_log_warn (LOGD_HW | LOGD_WIFI,
+			nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
 			             "(%s): error %d getting card mode",
 			             wext->parent.iface, errno);
 		}
@@ -154,7 +154,7 @@ wifi_wext_set_mode (WifiData *data, const NM80211Mode mode)
 	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
 	if (ioctl (wext->fd, SIOCSIWMODE, &wrq) < 0) {
 		if (errno != ENODEV) {
-			nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): error setting mode %d",
+			nm_log_err (LOGD_PLATFORM | LOGD_WIFI, "(%s): error setting mode %d",
 			            wext->parent.iface, mode);
 		}
 		return FALSE;
@@ -178,7 +178,7 @@ wifi_wext_set_powersave (WifiData *data, guint32 powersave)
 	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
 	if (ioctl (wext->fd, SIOCSIWPOWER, &wrq) < 0) {
 		if (errno != ENODEV) {
-			nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): error setting powersave %" G_GUINT32_FORMAT,
+			nm_log_err (LOGD_PLATFORM | LOGD_WIFI, "(%s): error setting powersave %" G_GUINT32_FORMAT,
 			            wext->parent.iface, powersave);
 		}
 		return FALSE;
@@ -196,7 +196,7 @@ wifi_wext_get_freq (WifiData *data)
 	memset (&wrq, 0, sizeof (struct iwreq));
 	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
 	if (ioctl (wext->fd, SIOCGIWFREQ, &wrq) < 0) {
-		nm_log_warn (LOGD_HW | LOGD_WIFI,
+		nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): error getting frequency: %s",
 		             wext->parent.iface, strerror (errno));
 		return 0;
@@ -230,7 +230,7 @@ wifi_wext_get_bssid (WifiData *data, guint8 *out_bssid)
 	memset (&wrq, 0, sizeof (wrq));
 	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
 	if (ioctl (wext->fd, SIOCGIWAP, &wrq) < 0) {
-		nm_log_warn (LOGD_HW | LOGD_WIFI,
+		nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): error getting associated BSSID: %s",
 		             wext->parent.iface, strerror (errno));
 		return FALSE;
@@ -360,7 +360,7 @@ wifi_wext_get_qual (WifiData *data)
 	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
 
 	if (ioctl (wext->fd, SIOCGIWSTATS, &wrq) < 0) {
-		nm_log_warn (LOGD_HW | LOGD_WIFI,
+		nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): error getting signal strength: %s",
 		             wext->parent.iface, strerror (errno));
 		return -1;
@@ -403,7 +403,7 @@ wifi_wext_set_mesh_channel (WifiData *data, guint32 channel)
 	}
 
 	if (ioctl (wext->fd, SIOCSIWFREQ, &wrq) < 0) {
-		nm_log_err (LOGD_HW | LOGD_WIFI | LOGD_OLPC,
+		nm_log_err (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC,
 		            "(%s): error setting channel to %d: %s",
 		            wext->parent.iface, channel, strerror (errno));
 		return FALSE;
@@ -431,7 +431,7 @@ wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len)
 		return TRUE;
 
 	if (errno != ENODEV) {
-		nm_log_err (LOGD_HW | LOGD_WIFI | LOGD_OLPC,
+		nm_log_err (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC,
 		            "(%s): error setting SSID to '%s': %s",
 		            wext->parent.iface,
 		            ssid ? nm_utils_escape_ssid (ssid, len) : "(null)",
@@ -482,7 +482,7 @@ wext_get_range (WifiDataWext *wext,
 			success = TRUE;
 			break;
 		} else if (errno != EAGAIN) {
-			nm_log_err (LOGD_HW | LOGD_WIFI,
+			nm_log_err (LOGD_PLATFORM | LOGD_WIFI,
 			            "(%s): couldn't get driver range information (%d).",
 			            wext->parent.iface, errno);
 			break;
@@ -492,7 +492,7 @@ wext_get_range (WifiDataWext *wext,
 	}
 
 	if (i <= 0) {
-		nm_log_warn (LOGD_HW | LOGD_WIFI,
+		nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): driver took too long to respond to IWRANGE query.",
 		             wext->parent.iface);
 	}
@@ -577,19 +577,19 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 	wext->parent.set_mesh_channel = wifi_wext_set_mesh_channel;
 	wext->parent.set_mesh_ssid = wifi_wext_set_mesh_ssid;
 
-	wext->fd = socket (PF_INET, SOCK_DGRAM, 0);
+	wext->fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 	if (wext->fd < 0)
 		goto error;
 
 	memset (&range, 0, sizeof (struct iw_range));
 	if (wext_get_range (wext, &range, &response_len) == FALSE) {
-		nm_log_info (LOGD_HW | LOGD_WIFI, "(%s): driver WEXT range request failed",
+		nm_log_info (LOGD_PLATFORM | LOGD_WIFI, "(%s): driver WEXT range request failed",
 		             wext->parent.iface);
 		goto error;
 	}
 
 	if ((response_len < 300) || (range.we_version_compiled < 21)) {
-		nm_log_info (LOGD_HW | LOGD_WIFI,
+		nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): driver WEXT version too old (got %d, expected >= 21)",
 		             wext->parent.iface,
 		             range.we_version_compiled);
@@ -613,7 +613,7 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 
 	/* Check for scanning capability; cards that can't scan are not supported */
 	if (check_scan && (wext_can_scan (wext) == FALSE)) {
-		nm_log_info (LOGD_HW | LOGD_WIFI,
+		nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): drivers that cannot scan are unsupported",
 		             wext->parent.iface);
 		goto error;
@@ -625,12 +625,12 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 	 */
 	scan_capa_range = (struct iw_range_with_scan_capa *) &range;
 	if (scan_capa_range->scan_capa & NM_IW_SCAN_CAPA_ESSID) {
-		nm_log_info (LOGD_HW | LOGD_WIFI,
+		nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): driver supports SSID scans (scan_capa 0x%02X).",
 		             wext->parent.iface,
 		             scan_capa_range->scan_capa);
 	} else {
-		nm_log_info (LOGD_HW | LOGD_WIFI,
+		nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): driver does not support SSID scans (scan_capa 0x%02X).",
 		             wext->parent.iface,
 		             scan_capa_range->scan_capa);
@@ -644,7 +644,7 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 	if (has_5ghz)
 		wext->parent.caps |= NM_WIFI_DEVICE_CAP_FREQ_5GHZ;
 
-	nm_log_info (LOGD_HW | LOGD_WIFI,
+	nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
 	             "(%s): using WEXT for WiFi device control",
 	             wext->parent.iface);
 
@@ -665,7 +665,7 @@ wifi_wext_is_wifi (const char *iface)
 	if (!nmp_utils_device_exists (iface))
 		return FALSE;
 
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
+	fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 	if (fd >= 0) {
 		nm_utils_ifname_cpy (iwr.ifr_ifrn.ifrn_name, iface);
 		if (ioctl (fd, SIOCGIWNAME, &iwr) == 0)
diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c
index b7fe86bb..2ce6eb77 100644
--- a/src/platform/wifi/wifi-utils.c
+++ b/src/platform/wifi/wifi-utils.c
@@ -26,6 +26,7 @@
 #include <sys/stat.h>
 #include <stdio.h>
 #include <string.h>
+#include <fcntl.h>
 
 #include "wifi-utils-private.h"
 #include "wifi-utils-nl80211.h"
@@ -34,6 +35,8 @@
 #endif
 #include "nm-core-utils.h"
 
+#include "platform/nm-platform-utils.h"
+
 gpointer
 wifi_data_new (const char *iface, int ifindex, gsize len)
 {
@@ -180,23 +183,32 @@ wifi_utils_deinit (WifiData *data)
 }
 
 gboolean
-wifi_utils_is_wifi (const char *iface)
+wifi_utils_is_wifi (int ifindex, const char *ifname)
 {
-	char phy80211_path[NM_STRLEN ("/sys/class/net/123456789012345/phy80211\0") + 100 /*safety*/];
-	struct stat s;
+	int fd_sysnet;
+	int fd_phy80211;
+	char ifname_verified[IFNAMSIZ];
+
+	g_return_val_if_fail (ifindex > 0, FALSE);
 
-	g_return_val_if_fail (iface != NULL, FALSE);
+	fd_sysnet = nmp_utils_sysctl_open_netdir (ifindex, ifname, ifname_verified);
+	if (fd_sysnet < 0)
+		return FALSE;
 
-	nm_sprintf_buf (phy80211_path,
-	                "/sys/class/net/%s/phy80211",
-	                NM_ASSERT_VALID_PATH_COMPONENT (iface));
-	nm_assert (strlen (phy80211_path) < sizeof (phy80211_path) - 1);
+	/* there might have been a race and ifname might be wrong. Below for checking
+	 * wext, use the possibly improved name that we just verified. */
+	ifname = ifname_verified;
 
-	if ((stat (phy80211_path, &s) == 0 && (s.st_mode & S_IFDIR)))
+	fd_phy80211 = openat (fd_sysnet, "phy80211", O_CLOEXEC);
+	close (fd_sysnet);
+
+	if (fd_phy80211 >= 0) {
+		close (fd_phy80211);
 		return TRUE;
+	}
 
 #if HAVE_WEXT
-	if (wifi_wext_is_wifi (iface))
+	if (wifi_wext_is_wifi (ifname))
 		return TRUE;
 #endif
 
diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h
index 8e2b93f1..3dca2ac1 100644
--- a/src/platform/wifi/wifi-utils.h
+++ b/src/platform/wifi/wifi-utils.h
@@ -28,7 +28,7 @@
 
 typedef struct WifiData WifiData;
 
-gboolean wifi_utils_is_wifi (const char *iface);
+gboolean wifi_utils_is_wifi (int ifindex, const char *ifname);
 
 WifiData *wifi_utils_init (const char *iface, int ifindex, gboolean check_scan);
 
diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c
index a51f7cfa..34c550fa 100644
--- a/src/ppp-manager/nm-ppp-manager.c
+++ b/src/ppp-manager/nm-ppp-manager.c
@@ -197,7 +197,7 @@ monitor_cb (gpointer user_data)
 		if (errno != ENODEV)
 			_LOGW ("could not read ppp stats: %s", strerror (errno));
 	} else {
-		g_signal_emit (manager, signals[STATS], 0, 
+		g_signal_emit (manager, signals[STATS], 0,
 		               stats.p.ppp_ibytes,
 		               stats.p.ppp_obytes);
 	}
@@ -214,7 +214,7 @@ monitor_stats (NMPPPManager *manager)
 	if (priv->monitor_fd >= 0)
 		return;
 
-	priv->monitor_fd = socket (AF_INET, SOCK_DGRAM, 0);
+	priv->monitor_fd = socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 	if (priv->monitor_fd >= 0) {
 		g_warn_if_fail (priv->monitor_id == 0);
 		if (priv->monitor_id)
@@ -595,7 +595,7 @@ nm_ppp_manager_class_init (NMPPPManagerClass *manager_class)
 
 	g_type_class_add_private (manager_class, sizeof (NMPPPManagerPrivate));
 
-	exported_object_class->export_path = NM_DBUS_PATH "/PPP";
+	exported_object_class->export_path = NM_DBUS_PATH "/PPP/%u";
 	exported_object_class->export_on_construction = TRUE;
 
 	object_class->dispose = dispose;
@@ -834,6 +834,7 @@ create_pppd_cmd_line (NMPPPManager *self,
                       NMSettingPppoe *pppoe,
                       NMSettingAdsl  *adsl,
                       const char *ppp_name,
+                      guint baud_override,
                       GError **err)
 {
 	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self);
@@ -925,6 +926,8 @@ create_pppd_cmd_line (NMPPPManager *self,
 
 	if (nm_setting_ppp_get_baud (setting))
 		nm_cmd_line_add_int (cmd, nm_setting_ppp_get_baud (setting));
+	else if (baud_override)
+		nm_cmd_line_add_int (cmd, (int) baud_override);
 
 	/* noauth by default, because we certainly don't have any information
 	 * with which to verify anything the peer gives us if we ask it to
@@ -1023,6 +1026,7 @@ nm_ppp_manager_start (NMPPPManager *manager,
                       NMActRequest *req,
                       const char *ppp_name,
                       guint32 timeout_secs,
+                      guint baud_override,
                       GError **err)
 {
 	NMPPPManagerPrivate *priv;
@@ -1076,7 +1080,7 @@ nm_ppp_manager_start (NMPPPManager *manager,
 
 	adsl_setting = (NMSettingAdsl *) nm_connection_get_setting (connection, NM_TYPE_SETTING_ADSL);
 
-	ppp_cmd = create_pppd_cmd_line (manager, s_ppp, pppoe_setting, adsl_setting, ppp_name, err);
+	ppp_cmd = create_pppd_cmd_line (manager, s_ppp, pppoe_setting, adsl_setting, ppp_name, baud_override, err);
 	if (!ppp_cmd)
 		goto out;
 
diff --git a/src/ppp-manager/nm-ppp-manager.h b/src/ppp-manager/nm-ppp-manager.h
index 188be84e..9a8b13dc 100644
--- a/src/ppp-manager/nm-ppp-manager.h
+++ b/src/ppp-manager/nm-ppp-manager.h
@@ -69,6 +69,7 @@ gboolean nm_ppp_manager_start (NMPPPManager *manager,
                                NMActRequest *req,
                                const char *ppp_name,
                                guint32 timeout_secs,
+                               guint baud_override,
                                GError **err);
 
 void     nm_ppp_manager_stop        (NMPPPManager *manager,
diff --git a/src/settings/nm-inotify-helper.c b/src/settings/nm-inotify-helper.c
index ce15246c..46112648 100644
--- a/src/settings/nm-inotify-helper.c
+++ b/src/settings/nm-inotify-helper.c
@@ -128,7 +128,7 @@ init_inotify (NMInotifyHelper *self)
 	GIOChannel *channel;
 	guint source_id;
 
-	priv->ifd = inotify_init ();
+	priv->ifd = inotify_init1 (IN_CLOEXEC);
 	if (priv->ifd == -1) {
 		int errsv = errno;
 
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 1f691c0b..cd54e52c 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -1874,7 +1874,7 @@ have_connection_for_device (NMSettings *self, NMDevice *device)
 
 	g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE);
 
-	perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE);
+	perm_hw_addr = nm_device_get_permanent_hw_address (device);
 
 	/* Find a wired connection locked to the given MAC address, if any */
 	g_hash_table_iter_init (&iter, priv->connections);
diff --git a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
index 184e95b2..a83bd35d 100644
--- a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
+++ b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
@@ -106,7 +106,7 @@ devtimeout_ready (gpointer user_data)
 }
 
 static void
-link_changed (NMPlatform *platform, NMPObjectType *obj_type, int ifindex, const NMPlatformLink *link,
+link_changed (NMPlatform *platform, NMPObjectType obj_type, int ifindex, const NMPlatformLink *link,
               NMPlatformSignalChangeType change_type,
               NMConnection *self)
 {
@@ -117,7 +117,6 @@ link_changed (NMPlatform *platform, NMPObjectType *obj_type, int ifindex, const
 	if (g_strcmp0 (link->name, ifname) != 0)
 		return;
 
-	/* Shouldn't happen, but... */
 	if (change_type == NM_PLATFORM_SIGNAL_REMOVED)
 		return;
 
diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c
index 75b19d53..a865c7df 100644
--- a/src/settings/plugins/ifcfg-rh/shvar.c
+++ b/src/settings/plugins/ifcfg-rh/shvar.c
@@ -53,11 +53,11 @@ svOpenFileInternal (const char *name, gboolean create, GError **error)
 
 	s->fd = -1;
 	if (create)
-		s->fd = open (name, O_RDWR); /* NOT O_CREAT */
+		s->fd = open (name, O_RDWR | O_CLOEXEC); /* NOT O_CREAT */
 
 	if (!create || s->fd == -1) {
 		/* try read-only */
-		s->fd = open (name, O_RDONLY); /* NOT O_CREAT */
+		s->fd = open (name, O_RDONLY | O_CLOEXEC); /* NOT O_CREAT */
 		if (s->fd == -1)
 			errsv = errno;
 		else
@@ -461,7 +461,7 @@ svWriteFile (shvarFile *s, int mode, GError **error)
 
 	if (s->modified) {
 		if (s->fd == -1)
-			s->fd = open (s->fileName, O_WRONLY | O_CREAT, mode);
+			s->fd = open (s->fileName, O_WRONLY | O_CREAT | O_CLOEXEC, mode);
 		if (s->fd == -1) {
 			int errsv = errno;
 
diff --git a/src/settings/plugins/ifupdown/interface_parser.c b/src/settings/plugins/ifupdown/interface_parser.c
index 764ba5c9..3386a6ba 100644
--- a/src/settings/plugins/ifupdown/interface_parser.c
+++ b/src/settings/plugins/ifupdown/interface_parser.c
@@ -117,7 +117,7 @@ _recursive_ifparser (const char *eni_file, int quiet)
 			nm_log_warn (LOGD_SETTINGS, "interfaces file %s doesn't exist\n", eni_file);
 		return;
 	}
-	inp = fopen (eni_file, "r");
+	inp = fopen (eni_file, "re");
 	if (inp == NULL) {
 		if (!quiet)
 			nm_log_warn (LOGD_SETTINGS, "Can't open %s\n", eni_file);
diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c
index 626472d0..05d9aa67 100644
--- a/src/supplicant-manager/nm-supplicant-interface.c
+++ b/src/supplicant-manager/nm-supplicant-interface.c
@@ -1288,6 +1288,7 @@ nm_supplicant_interface_set_config (NMSupplicantInterface *self,
 
 	g_clear_object (&priv->cfg);
 	if (cfg) {
+		priv->assoc_cancellable = g_cancellable_new ();
 		priv->cfg = g_object_ref (cfg);
 		g_dbus_proxy_call (priv->iface_proxy,
 		                   DBUS_INTERFACE_PROPERTIES ".Set",
@@ -1525,13 +1526,9 @@ dispose (GObject *object)
 		g_signal_handlers_disconnect_by_data (priv->iface_proxy, NM_SUPPLICANT_INTERFACE (object));
 	g_clear_object (&priv->iface_proxy);
 
-	if (priv->init_cancellable)
-		g_cancellable_cancel (priv->init_cancellable);
-	g_clear_object (&priv->init_cancellable);
-
-	if (priv->other_cancellable)
-		g_cancellable_cancel (priv->other_cancellable);
-	g_clear_object (&priv->other_cancellable);
+	nm_clear_g_cancellable (&priv->init_cancellable);
+	nm_clear_g_cancellable (&priv->other_cancellable);
+	nm_clear_g_cancellable (&priv->assoc_cancellable);
 
 	g_clear_object (&priv->wpas_proxy);
 	g_clear_pointer (&priv->bss_proxies, (GDestroyNotify) g_hash_table_destroy);
diff --git a/src/tests/test-general-with-expect.c b/src/tests/test-general-with-expect.c
index ab2b15b5..f04c147f 100644
--- a/src/tests/test-general-with-expect.c
+++ b/src/tests/test-general-with-expect.c
@@ -26,6 +26,7 @@
 #include <netinet/ether.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <fcntl.h>
 
 #include "NetworkManagerUtils.h"
 #include "nm-multi-index.h"
@@ -173,7 +174,7 @@ test_nm_utils_kill_child_create_and_join_pgroup (void)
 	int pipefd[2];
 	pid_t pgid;
 
-	err = pipe (pipefd);
+	err = pipe2 (pipefd, O_CLOEXEC);
 	g_assert (err == 0);
 
 	pgid = fork();
diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c
index 3eceec0c..de890141 100644
--- a/src/tests/test-ip6-config.c
+++ b/src/tests/test-ip6-config.c
@@ -238,10 +238,13 @@ test_nm_ip6_config_addresses_sort_check (NMIP6Config *config, NMSettingIP6Config
 {
 	int addr_count = nm_ip6_config_get_num_addresses (config);
 	int i, irepeat;
-	NMIP6Config *copy = nmtst_ip6_config_clone (config);
-	NMIP6Config *copy2 = nmtst_ip6_config_clone (config);
+	NMIP6Config *copy, *copy2;
 	int *idx = g_new (int, addr_count);
 
+	nm_ip6_config_set_privacy (config, use_tempaddr);
+	copy = nmtst_ip6_config_clone (config);
+	copy2 = nmtst_ip6_config_clone (config);
+
 	/* initialize the array of indeces, and keep shuffling them for every @repeat iteration. */
 	for (i = 0; i < addr_count; i++)
 		idx[i] = i;
@@ -257,7 +260,7 @@ test_nm_ip6_config_addresses_sort_check (NMIP6Config *config, NMSettingIP6Config
 		}
 
 		/* reorder them again */
-		nm_ip6_config_addresses_sort (copy, use_tempaddr);
+		nm_ip6_config_addresses_sort (copy);
 
 		/* check equality using nm_ip6_config_equal() */
 		if (!nm_ip6_config_equal (copy, config)) {
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index 69b45dcc..1441c3c6 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -1369,6 +1369,11 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
 	if (priv->vpn_state == STATE_CONNECT)
 		_set_vpn_state (self, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
 
+	if (priv->vpn_state > STATE_ACTIVATED) {
+		_LOGI ("VPN connection: (IP4 Config Get) ignoring, the connection is no longer active");
+		return;
+	}
+
 	if (priv->has_ip4) {
 		_LOGI ("VPN connection: (IP4 Config Get) reply received");
 
@@ -1538,6 +1543,11 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict)
 	if (priv->vpn_state == STATE_CONNECT)
 		_set_vpn_state (self, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
 
+	if (priv->vpn_state > STATE_ACTIVATED) {
+		_LOGI ("VPN connection: (IP6 Config Get) ignoring, the connection is no longer active");
+		return;
+	}
+
 	if (g_variant_n_children (dict) == 0) {
 		priv->has_ip6 = FALSE;
 		nm_vpn_connection_config_maybe_complete (self, TRUE);