about summary refs log tree commit diff
path: root/src/devices
diff options
context:
space:
mode:
authorAron Xu <aron@debian.org>2016-12-20 20:06:37 +0800
committerAron Xu <aron@debian.org>2016-12-20 20:06:37 +0800
commit45cb5bb3c0e6edb887cf69b417fcaf7053814a9b (patch)
tree795f8d6a3aa1145e4ba8fa1564f39425ea0c6ed9 /src/devices
parent270c4830551c9810ad4e83f9a1db2b1cb946208c (diff)
Imported Upstream version 1.4.4 upstream/1.4.4
Diffstat (limited to 'src/devices')
-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
20 files changed, 358 insertions, 271 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;
 	}