diff --git a/SOURCES/0023-udev-initialized-race-rh1388286.patch b/SOURCES/0023-udev-initialized-race-rh1388286.patch
new file mode 100644
index 0000000..323d720
--- /dev/null
+++ b/SOURCES/0023-udev-initialized-race-rh1388286.patch
@@ -0,0 +1,2972 @@
+From 443691e1017a66509dffdc81cff15d86d5e4d0b4 Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Thu, 6 Oct 2016 21:28:40 +0200
+Subject: [PATCH 01/15] logging: remove LOGD_HW alias for LOGD_PLATFORM
+
+Since commit 1495853e01299d1eb33d4eb10b91e37dcf855cc8, LOGD_HW is renamed to
+LOGD_PLATFORM. Remove the internal usage of the deprecated name.
+
+Backport this patch to nm-1-4 because it avoids follow-up conflicts with
+future backports. Also, it is a really trivial change, meaning, we only
+replace the obsolte LOGD_HW name.
+
+(cherry picked from commit 64951f07fb39e1c88448ba2ad72a5e710712c89d)
+
+Conflicts:
+    src/devices/nm-device.c
+    src/devices/wwan/nm-modem.c
+
+(cherry picked from commit a67eb9d8d00b9c69f52879e5edf087932bf4d07d)
+---
+ src/devices/adsl/nm-atm-manager.c      | 14 +++++++-------
+ src/devices/nm-device-bond.c           |  2 +-
+ src/devices/nm-device-ethernet.c       | 14 +++++++-------
+ src/devices/nm-device-factory.c        | 18 +++++++++---------
+ src/devices/nm-device-ip-tunnel.c      |  8 ++++----
+ src/devices/nm-device-macvlan.c        |  2 +-
+ src/devices/nm-device-tun.c            |  2 +-
+ src/devices/nm-device-veth.c           |  2 +-
+ src/devices/nm-device-vxlan.c          |  2 +-
+ src/devices/nm-device.c                | 30 +++++++++++++++---------------
+ src/devices/wifi/nm-device-wifi.c      |  2 +-
+ src/devices/wifi/nm-wifi-factory.c     |  2 +-
+ src/devices/wwan/nm-modem.c            |  4 ++--
+ src/nm-logging.h                       |  1 -
+ src/nm-manager.c                       |  6 +++---
+ src/nm-rfkill-manager.c                |  2 +-
+ src/platform/wifi/wifi-utils-nl80211.c | 16 ++++++++--------
+ src/platform/wifi/wifi-utils-wext.c    | 32 ++++++++++++++++----------------
+ 18 files changed, 79 insertions(+), 80 deletions(-)
+
+diff --git a/src/devices/adsl/nm-atm-manager.c b/src/devices/adsl/nm-atm-manager.c
+index 6708575..40c782f 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/nm-device-bond.c b/src/devices/nm-device-bond.c
+index 3f17849..75b2e31 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 b213a0c..2f0b68a 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;
+ 	}
+@@ -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);
+ 		}
+@@ -1529,7 +1529,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 7873756..a72c0bb 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-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c
+index 785010e..72a1389 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 2bfc65c..0a43646 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;
+ 	}
+ 
+diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c
+index 1f42d06..f818cd7 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 5692331..c16df6d 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-vxlan.c b/src/devices/nm-device-vxlan.c
+index 674c2a7..2453543 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 aabbd53..96d6a7c 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -757,7 +757,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 +900,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;
+@@ -2299,7 +2299,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)" : "");
+@@ -9033,7 +9033,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))
+@@ -9059,9 +9059,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;
+ 	}
+ 
+@@ -9125,7 +9125,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))
+@@ -9147,9 +9147,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");
+ 	}
+ }
+ 
+@@ -9162,7 +9162,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;
+ }
+ 
+@@ -11150,7 +11150,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);
+ 			}
+ 
+@@ -11533,7 +11533,7 @@ nm_device_update_hw_address (NMDevice *self)
+ 			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);
++			_LOGD (LOGD_PLATFORM | LOGD_DEVICE, "hw-addr: hardware address now %s", priv->hw_addr);
+ 			_notify (self, PROP_HW_ADDRESS);
+ 
+ 			if (   !priv->hw_addr_initial
+@@ -11550,11 +11550,11 @@ nm_device_update_hw_address (NMDevice *self)
+ 	} else {
+ 		/* Invalid or no hardware address */
+ 		if (priv->hw_addr_len != 0) {
+-			_LOGD (LOGD_HW | LOGD_DEVICE,
++			_LOGD (LOGD_PLATFORM | LOGD_DEVICE,
+ 			       "hw-addr: failed reading current MAC address (stay with %s)",
+ 			       priv->hw_addr);
+ 		} else {
+-			_LOGD (LOGD_HW | LOGD_DEVICE,
++			_LOGD (LOGD_PLATFORM | LOGD_DEVICE,
+ 			       "hw-addr: failed reading current MAC address");
+ 		}
+ 	}
+@@ -11614,7 +11614,7 @@ nm_device_update_permanent_hw_address (NMDevice *self)
+ 		 *
+ 		 * 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)",
++		_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",
+diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
+index f97e668..f467c81 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 ());
+diff --git a/src/devices/wifi/nm-wifi-factory.c b/src/devices/wifi/nm-wifi-factory.c
+index 2d5f8fa..cf8cf03 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-modem.c b/src/devices/wwan/nm-modem.c
+index 2e3d63b..df6f7cf 100644
+--- a/src/devices/wwan/nm-modem.c
++++ b/src/devices/wwan/nm-modem.c
+@@ -1327,12 +1327,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/nm-logging.h b/src/nm-logging.h
+index 9e2b010..72eb3db 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 9ad6517..932dafd 100644
+--- a/src/nm-manager.c
++++ b/src/nm-manager.c
+@@ -2125,10 +2125,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;
+@@ -2142,7 +2142,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 */
+diff --git a/src/nm-rfkill-manager.c b/src/nm-rfkill-manager.c
+index 453a3b9..e4e738c 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/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c
+index 79f217a..2e222eb 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 af285b4..66c1376 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);
+ 	}
+@@ -583,13 +583,13 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
+ 
+ 	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);
+ 
+-- 
+2.9.3
+
+
+From 1f57d7676330b61b8af72d87195d3ddd4da76228 Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Thu, 22 Sep 2016 11:31:19 +0200
+Subject: [PATCH 02/15] device: fix NULL pointer dereference in dhcp6_start()
+
+Don't crash when nm_device_dhcp6_renew() calls dhcp6_start() with NULL
+@reason.
+
+Fixes: d1295b12e9f802867edef57ee02c87495df1683e
+(cherry picked from commit dbf0b343ec54ee8d34a003609a19fb74082d4afc)
+(cherry picked from commit 6c4a6f2b755c6b9de1617830e2708cd1687b4dfa)
+---
+ src/devices/nm-device.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
+index 96d6a7c..b182536 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -5904,7 +5904,7 @@ dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason)
+ 	}
+ 
+ 	if (!dhcp6_start_with_link_ready (self, connection)) {
+-		*reason = NM_DEVICE_STATE_REASON_DHCP_START_FAILED;
++		NM_SET_OUT (reason, NM_DEVICE_STATE_REASON_DHCP_START_FAILED);
+ 		return FALSE;
+ 	}
+ 
+-- 
+2.9.3
+
+
+From 61b6a9984a0f010a22270f7b14bb2dbc34dc7a50 Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Tue, 13 Sep 2016 11:16:11 +0200
+Subject: [PATCH 03/15] device: cleanup _hw_addr_set()
+
+No change in behavior, just reorganize.
+
+Fixes: 32f7c1d4b9aba597a99128631f07c2985149f303
+(cherry picked from commit e7a1008b4b405a83c78f7e44fe86cc3db8f2015e)
+(cherry picked from commit 66c665808f7794350036c57f7d44cadd087d8d11)
+---
+ src/devices/nm-device.c | 39 +++++++++++++++------------------------
+ 1 file changed, 15 insertions(+), 24 deletions(-)
+
+diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
+index b182536..7a47f74 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -11734,7 +11734,6 @@ _hw_addr_set (NMDevice *self,
+ {
+ 	NMDevicePrivate *priv;
+ 	gboolean success = FALSE;
+-	gboolean needs_refresh = FALSE;
+ 	NMPlatformError plerr;
+ 	guint8 addr_bytes[NM_UTILS_HWADDR_LEN_MAX];
+ 	guint hw_addr_len;
+@@ -11776,24 +11775,11 @@ _hw_addr_set (NMDevice *self,
+ 			_LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
+ 			       operation, addr, detail);
+ 		} else {
++			gint64 poll_end, now;
++
+ 			_LOGD (LOGD_DEVICE,
+ 			       "set-hw-addr: new MAC address %s not successfully %s (%s) (refresh link)",
+ 			       addr, operation, detail);
+-			needs_refresh = TRUE;
+-		}
+-	} else {
+-		_NMLOG (plerr == NM_PLATFORM_ERROR_NOT_FOUND ? LOGL_DEBUG : LOGL_WARN,
+-		        LOGD_DEVICE, "set-hw-addr: failed to %s MAC address to %s (%s) (%s)",
+-		        operation, addr, detail,
+-		        nm_platform_error_to_string (plerr));
+-	}
+-
+-	if (needs_refresh) {
+-		success = TRUE;
+-		if (_hw_addr_matches (self, addr)) {
+-			/* the MAC address already changed during nm_device_bring_up() above. */
+-		} else {
+-			gint64 poll_end, now;
+ 
+ 			/* The platform call indicated success, however the address is not
+ 			 * as expected. That is either due to a driver issue (brcmfmac, bgo#770456,
+@@ -11829,16 +11815,21 @@ handle_fail:
+ 				success = FALSE;
+ 				break;
+ 			}
+-		}
+ 
+-		if (success) {
+-			_LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
+-			       operation, addr, detail);
+-		} else {
+-			_LOGW (LOGD_DEVICE,
+-			       "set-hw-addr: new MAC address %s not successfully %s (%s)",
+-			       addr, operation, detail);
++			if (success) {
++				_LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
++				       operation, addr, detail);
++			} else {
++				_LOGW (LOGD_DEVICE,
++				       "set-hw-addr: new MAC address %s not successfully %s (%s)",
++				       addr, operation, detail);
++			}
+ 		}
++	} else {
++		_NMLOG (plerr == NM_PLATFORM_ERROR_NOT_FOUND ? LOGL_DEBUG : LOGL_WARN,
++		        LOGD_DEVICE, "set-hw-addr: failed to %s MAC address to %s (%s) (%s)",
++		        operation, addr, detail,
++		        nm_platform_error_to_string (plerr));
+ 	}
+ 
+ 	if (was_up) {
+-- 
+2.9.3
+
+
+From 56b845b359d83b3c685539d11389256088c1ce1e Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Sat, 15 Oct 2016 15:22:01 +0200
+Subject: [PATCH 04/15] tools: fix starting tests with D-Bus session with
+ NMTST_NO_VALGRIND=1
+
+When running
+
+  NMTST_NO_VALGRIND=1 make check -j
+
+we would not start separate D-Bus sessions, thus running tests with
+valgrind enabled failed.
+
+(cherry picked from commit c94dac0b5d9d77ef7d60d18eb835a0dd7bba4f42)
+(cherry picked from commit 7927d451fc7b6cfbd9cd3bf1078fa3cb4140789a)
+---
+ tools/run-test-valgrind.sh | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/tools/run-test-valgrind.sh b/tools/run-test-valgrind.sh
+index d3dd915..634ca2c 100755
+--- a/tools/run-test-valgrind.sh
++++ b/tools/run-test-valgrind.sh
+@@ -91,6 +91,7 @@ if [ "$NMTST_LAUNCH_DBUS" == "yes" ]; then
+ fi
+ 
+ if [ "$NMTST_NO_VALGRIND" != "" ]; then
++	"${NMTST_DBUS_RUN_SESSION[@]}" \
+ 	"$TEST" "$@"
+ 	exit $?
+ fi
+-- 
+2.9.3
+
+
+From 6d654721a1997c464deb99cd61aabb3c7b930517 Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Wed, 28 Sep 2016 15:34:52 +0200
+Subject: [PATCH 05/15] shared: add nm_clear_g_free()
+
+(cherry picked from commit b4e66c4818cf6ff14e8b5181ec9d71fa5c9f5452)
+(cherry picked from commit beeb676735d6242dd4c12de27bbc1b8fd3afaeee)
+---
+ libnm-core/tests/test-general.c      |  2 +-
+ shared/nm-utils/nm-macros-internal.h | 21 +++++++++++++++++++++
+ 2 files changed, 22 insertions(+), 1 deletion(-)
+
+diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
+index 6aee252..6b54dc3 100644
+--- a/libnm-core/tests/test-general.c
++++ b/libnm-core/tests/test-general.c
+@@ -2527,7 +2527,7 @@ test_setting_compare_wireless_cloned_mac_address (void)
+ 	g_assert_cmpstr ("stable-bia", ==, nm_setting_wireless_get_cloned_mac_address ((NMSettingWireless *) new));
+ 	g_object_get (new, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, &str1, NULL);
+ 	g_assert_cmpstr ("stable-bia", ==, str1);
+-	g_clear_pointer (&str1, g_free);
++	nm_clear_g_free (&str1);
+ 
+ 	success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT);
+ 	g_assert (!success);
+diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h
+index 91970c3..9f96a4c 100644
+--- a/shared/nm-utils/nm-macros-internal.h
++++ b/shared/nm-utils/nm-macros-internal.h
+@@ -410,6 +410,27 @@ nm_g_object_unref (gpointer obj)
+ 		g_object_unref (obj);
+ }
+ 
++/* basically, replaces
++ *   g_clear_pointer (&location, g_free)
++ * with
++ *   nm_clear_g_free (&location)
++ *
++ * Another advantage is that by using a macro and typeof(), it is more
++ * typesafe and gives you for example a compiler warning when pp is a const
++ * pointer or points to a const-pointer.
++ */
++#define nm_clear_g_free(pp) \
++	({  \
++		typeof (*(pp)) *_pp = (pp); \
++		typeof (**_pp) *_p = *_pp; \
++		\
++		if (_p) { \
++			*_pp = NULL; \
++			g_free (_p); \
++		} \
++		!!_p; \
++	})
++
+ static inline gboolean
+ nm_clear_g_source (guint *id)
+ {
+-- 
+2.9.3
+
+
+From e935a4cf7340cbcde24370e752e35aad736da886 Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Wed, 26 Oct 2016 14:44:02 +0200
+Subject: [PATCH 06/15] shared: add nm_assert_se() macro
+
+We usually don't build NM with g_assert() disabled (G_DISABLE_ASSERT).
+But even if we would, there is no assertion macro that always evaluates
+the condition for possible side effects.
+
+I think that is a useful thing to have.
+
+(cherry picked from commit ba950cedee5c4a92d9fb7e00f58b9f97a151b9e8)
+(cherry picked from commit d242fdc3193948cce078a55adec540f3489ee94a)
+---
+ shared/nm-utils/nm-macros-internal.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h
+index 9f96a4c..2e05b2a 100644
+--- a/shared/nm-utils/nm-macros-internal.h
++++ b/shared/nm-utils/nm-macros-internal.h
+@@ -344,9 +344,11 @@ nm_strdup_not_empty (const char *str)
+ 
+ #if NM_MORE_ASSERTS
+ #define nm_assert(cond) G_STMT_START { g_assert (cond); } G_STMT_END
++#define nm_assert_se(cond) G_STMT_START { if (G_LIKELY (cond)) { ; } else { g_assert (FALSE && (cond)); } } G_STMT_END
+ #define nm_assert_not_reached() G_STMT_START { g_assert_not_reached (); } G_STMT_END
+ #else
+ #define nm_assert(cond) G_STMT_START { if (FALSE) { if (cond) { } } } G_STMT_END
++#define nm_assert_se(cond) G_STMT_START { if (G_LIKELY (cond)) { ; } } G_STMT_END
+ #define nm_assert_not_reached() G_STMT_START { ; } G_STMT_END
+ #endif
+ 
+-- 
+2.9.3
+
+
+From 59f0ed05eaf656c5f3846717003e22caed41e376 Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Thu, 13 Oct 2016 17:51:07 +0200
+Subject: [PATCH 07/15] libnm-core/utils: update hwaddr utilities
+
+_nm_utils_hwaddr_length() did a validation of the string
+and returned the length of the address. In all cases where
+we were interested in that, we also either want to validate
+the address, get the address in binary form, or canonicalize
+the address.
+
+We can avoid these duplicate checks, by using _nm_utils_hwaddr_aton()
+which both does the parsing and returning the length.
+
+(cherry picked from commit e5fe5a4c033875679adbea3cae50108daef43eb3)
+(cherry picked from commit 977fbf70895f3a9dce3e178b5e4c03ecf4ee8fa3)
+---
+ libnm-core/nm-core-internal.h |   5 +-
+ libnm-core/nm-utils.c         | 307 ++++++++++++++++++++++++------------------
+ src/devices/nm-device.c       |  46 ++++---
+ src/nm-core-utils.c           |   7 +-
+ 4 files changed, 205 insertions(+), 160 deletions(-)
+
+diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
+index e491bce..5d3c190 100644
+--- a/libnm-core/nm-core-internal.h
++++ b/libnm-core/nm-core-internal.h
+@@ -123,7 +123,10 @@ guint32 _nm_setting_get_setting_priority (NMSetting *setting);
+ 
+ gboolean _nm_setting_get_property (NMSetting *setting, const char *name, GValue *value);
+ 
+-guint _nm_utils_hwaddr_length (const char *asc);
++#define NM_UTILS_HWADDR_LEN_MAX_STR (NM_UTILS_HWADDR_LEN_MAX * 3)
++
++guint8 *_nm_utils_hwaddr_aton (const char *asc, gpointer buffer, gsize buffer_length, gsize *out_length);
++const char *nm_utils_hwaddr_ntoa_buf (gconstpointer addr, gsize addr_len, gboolean upper_case, char *buf, gsize buf_len);
+ 
+ char *_nm_utils_bin2str (gconstpointer addr, gsize length, gboolean upper_case);
+ 
+diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
+index df75d56..fe8a371 100644
+--- a/libnm-core/nm-utils.c
++++ b/libnm-core/nm-utils.c
+@@ -2965,17 +2965,64 @@ nm_utils_wifi_strength_bars (guint8 strength)
+ gsize
+ nm_utils_hwaddr_len (int type)
+ {
+-	g_return_val_if_fail (type == ARPHRD_ETHER || type == ARPHRD_INFINIBAND, 0);
+-
+ 	if (type == ARPHRD_ETHER)
+ 		return ETH_ALEN;
+ 	else if (type == ARPHRD_INFINIBAND)
+ 		return INFINIBAND_ALEN;
+ 
+-	g_assert_not_reached ();
++	g_return_val_if_reached (0);
+ }
+ 
+-#define HEXVAL(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
++static guint8 *
++hwaddr_aton (const char *asc, guint8 *buffer, gsize buffer_length, gsize *out_len)
++{
++	const char *in = asc;
++	guint8 *out = buffer;
++	guint8 delimiter = '\0';
++
++	nm_assert (asc);
++	nm_assert (buffer);
++	nm_assert (buffer_length);
++	nm_assert (out_len);
++
++	while (TRUE) {
++		const guint8 d1 = in[0];
++		guint8 d2;
++
++		if (!g_ascii_isxdigit (d1))
++			return NULL;
++
++#define HEXVAL(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - ('A' - 10))
++
++		/* If there's no leading zero (ie "aa:b:cc") then fake it */
++		d2 = in[1];
++		if (d2 && g_ascii_isxdigit (d2)) {
++			*out++ = (HEXVAL (d1) << 4) + HEXVAL (d2);
++			d2 = in[2];
++			in += 3;
++		} else {
++			/* Fake leading zero */
++			*out++ = HEXVAL (d1);
++			in += 2;
++		}
++
++		if (!d2)
++			break;
++		if (--buffer_length == 0)
++			return NULL;
++
++		if (d2 != delimiter) {
++			if (   delimiter == '\0'
++			    && (d2 == ':' || d2 == '-'))
++				delimiter = d2;
++			else
++				return NULL;
++		}
++	}
++
++	*out_len = out - buffer;
++	return buffer;
++}
+ 
+ /**
+  * nm_utils_hwaddr_atoba:
+@@ -2992,18 +3039,52 @@ GByteArray *
+ nm_utils_hwaddr_atoba (const char *asc, gsize length)
+ {
+ 	GByteArray *ba;
++	gsize l;
+ 
+-	g_return_val_if_fail (asc != NULL, NULL);
++	g_return_val_if_fail (asc, NULL);
+ 	g_return_val_if_fail (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX, NULL);
+ 
+ 	ba = g_byte_array_sized_new (length);
+ 	g_byte_array_set_size (ba, length);
+-	if (!nm_utils_hwaddr_aton (asc, ba->data, length)) {
+-		g_byte_array_unref (ba);
+-		return NULL;
+-	}
++	if (!hwaddr_aton (asc, ba->data, length, &l))
++		goto fail;
++	if (length != l)
++		goto fail;
+ 
+ 	return ba;
++fail:
++	g_byte_array_unref (ba);
++	return NULL;
++}
++
++/**
++ * _nm_utils_hwaddr_aton:
++ * @asc: the ASCII representation of a hardware address
++ * @buffer: buffer to store the result into. Must have
++ *   at least a size of @buffer_length.
++ * @buffer_length: the length of the input buffer @buffer.
++ *   The result must fit into that buffer, otherwise
++ *   the function fails and returns %NULL.
++ * @out_length: the output length in case of success.
++ *
++ * Parses @asc and converts it to binary form in @buffer.
++ * Bytes in @asc can be sepatared by colons (:), or hyphens (-), but not mixed.
++ *
++ * It is like nm_utils_hwaddr_aton(), but contrary to that it
++ * can parse addresses of any length. That is, you don't need
++ * to know the length before-hand.
++ *
++ * Return value: @buffer, or %NULL if @asc couldn't be parsed.
++ */
++guint8 *
++_nm_utils_hwaddr_aton (const char *asc, gpointer buffer, gsize buffer_length, gsize *out_length)
++{
++	g_return_val_if_fail (asc, NULL);
++	g_return_val_if_fail (buffer, NULL);
++	g_return_val_if_fail (buffer_length > 0, NULL);
++	g_return_val_if_fail (out_length, NULL);
++
++	return hwaddr_aton (asc, buffer, buffer_length, out_length);
+ }
+ 
+ /**
+@@ -3022,72 +3103,55 @@ nm_utils_hwaddr_atoba (const char *asc, gsize length)
+ guint8 *
+ nm_utils_hwaddr_aton (const char *asc, gpointer buffer, gsize length)
+ {
+-	const char *in = asc;
+-	guint8 *out = (guint8 *)buffer;
+-	char delimiter = '\0';
++	gsize l;
+ 
+-	g_return_val_if_fail (asc != NULL, NULL);
+-	g_return_val_if_fail (buffer != NULL, NULL);
++	g_return_val_if_fail (asc, NULL);
++	g_return_val_if_fail (buffer, NULL);
+ 	g_return_val_if_fail (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX, NULL);
+ 
+-	while (length && *in) {
+-		guint8 d1 = in[0], d2 = in[1];
+-
+-		if (!g_ascii_isxdigit (d1))
+-			return NULL;
+-
+-		/* If there's no leading zero (ie "aa:b:cc") then fake it */
+-		if (d2 && g_ascii_isxdigit (d2)) {
+-			*out++ = (HEXVAL (d1) << 4) + HEXVAL (d2);
+-			in += 2;
+-		} else {
+-			/* Fake leading zero */
+-			*out++ = (HEXVAL ('0') << 4) + HEXVAL (d1);
+-			in += 1;
+-		}
+-
+-		length--;
+-		if (*in) {
+-			if (delimiter == '\0') {
+-				if (*in == ':' || *in == '-')
+-					delimiter = *in;
+-				else
+-					return NULL;
+-			} else {
+-				if (*in != delimiter)
+-					return NULL;
+-			}
+-			in++;
+-		}
+-	}
+-
+-	if (length == 0 && !*in)
+-		return buffer;
+-	else
++	if (!hwaddr_aton (asc, buffer, length, &l))
++		return NULL;
++	if (length != l)
+ 		return NULL;
++	return buffer;
+ }
+ 
+-static char *
+-_bin2str (gconstpointer addr, gsize length, gboolean upper_case)
++static void
++_bin2str_buf (gconstpointer addr, gsize length, gboolean upper_case, char *out)
+ {
+ 	const guint8 *in = addr;
+-	char *out, *result;
+ 	const char *LOOKUP = upper_case ? "0123456789ABCDEF" : "0123456789abcdef";
+ 
+-	g_return_val_if_fail (addr != NULL, g_strdup (""));
+-	g_return_val_if_fail (length > 0, g_strdup (""));
++	nm_assert (addr);
++	nm_assert (out);
++	nm_assert (length > 0);
+ 
+-	result = out = g_malloc (length * 3);
+-	while (length--) {
+-		guint8 v = *in++;
++	/* @out must contain at least @length*3 bytes */
++
++	for (;;) {
++		const guint8 v = *in++;
+ 
+ 		*out++ = LOOKUP[v >> 4];
+ 		*out++ = LOOKUP[v & 0x0F];
+-		if (length)
+-			*out++ = ':';
++		length--;
++		if (!length)
++			break;
++		*out++ = ':';
+ 	}
+ 
+ 	*out = 0;
++}
++
++static char *
++_bin2str (gconstpointer addr, gsize length, gboolean upper_case)
++{
++	char *result;
++
++	nm_assert (addr);
++	nm_assert (length > 0);
++
++	result = g_malloc (length * 3);
++	_bin2str_buf (addr, length, upper_case, result);
+ 	return result;
+ }
+ 
+@@ -3103,9 +3167,25 @@ _bin2str (gconstpointer addr, gsize length, gboolean upper_case)
+ char *
+ nm_utils_hwaddr_ntoa (gconstpointer addr, gsize length)
+ {
++	g_return_val_if_fail (addr, g_strdup (""));
++	g_return_val_if_fail (length > 0, g_strdup (""));
++
+ 	return _bin2str (addr, length, TRUE);
+ }
+ 
++const char *
++nm_utils_hwaddr_ntoa_buf (gconstpointer addr, gsize addr_len, gboolean upper_case, char *buf, gsize buf_len)
++{
++	g_return_val_if_fail (addr, NULL);
++	g_return_val_if_fail (addr_len > 0, NULL);
++	g_return_val_if_fail (buf, NULL);
++	if (buf_len < addr_len * 3)
++		g_return_val_if_reached (NULL);
++
++	_bin2str_buf (addr, addr_len, TRUE, buf);
++	return buf;
++}
++
+ /**
+  * _nm_utils_bin2str:
+  * @addr: (type guint8) (array length=length): a binary hardware address
+@@ -3119,49 +3199,10 @@ nm_utils_hwaddr_ntoa (gconstpointer addr, gsize length)
+ char *
+ _nm_utils_bin2str (gconstpointer addr, gsize length, gboolean upper_case)
+ {
+-	return _bin2str (addr, length, upper_case);
+-}
+-
+-static int
+-hwaddr_binary_len (const char *asc)
+-{
+-	int octets = 1;
+-
+-	if (!*asc)
+-		return 0;
+-
+-	for (; *asc; asc++) {
+-		if (*asc == ':' || *asc == '-')
+-			octets++;
+-	}
+-	return octets;
+-}
+-
+-/**
+- * _nm_utils_hwaddr_length:
+- * @asc: the ASCII representation of the hardware address
+- *
+- * Validates that @asc is a valid representation of a hardware
+- * address up to (including) %NM_UTILS_HWADDR_LEN_MAX bytes.
+- *
+- * Returns: binary length of the hardware address @asc or
+- *   0 on error.
+- */
+-guint
+-_nm_utils_hwaddr_length (const char *asc)
+-{
+-	int l;
+-
+-	if (!asc)
+-		return 0;
+-
+-	l = hwaddr_binary_len (asc);
+-	if (l <= 0 || l > NM_UTILS_HWADDR_LEN_MAX)
+-		return 0;
++	g_return_val_if_fail (addr, g_strdup (""));
++	g_return_val_if_fail (length > 0, g_strdup (""));
+ 
+-	if (!nm_utils_hwaddr_valid (asc, l))
+-		return 0;
+-	return l;
++	return _bin2str (addr, length, upper_case);
+ }
+ 
+ /**
+@@ -3180,17 +3221,18 @@ gboolean
+ nm_utils_hwaddr_valid (const char *asc, gssize length)
+ {
+ 	guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
++	gsize l;
+ 
+ 	g_return_val_if_fail (asc != NULL, FALSE);
+-	g_return_val_if_fail (length == -1 || (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX), FALSE);
+ 
+-	if (length == -1) {
+-		length = hwaddr_binary_len (asc);
+-		if (length == 0 || length > NM_UTILS_HWADDR_LEN_MAX)
++	if (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX) {
++		if (!hwaddr_aton (asc, buf, length, &l))
+ 			return FALSE;
+-	}
+-
+-	return nm_utils_hwaddr_aton (asc, buf, length) != NULL;
++		return length == l;
++	} else if (length == -1) {
++		return !!hwaddr_aton (asc, buf, sizeof (buf), &l);
++	} else
++		g_return_val_if_reached (FALSE);
+ }
+ 
+ /**
+@@ -3210,20 +3252,23 @@ char *
+ nm_utils_hwaddr_canonical (const char *asc, gssize length)
+ {
+ 	guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
++	gsize l;
+ 
+-	g_return_val_if_fail (asc != NULL, NULL);
++	g_return_val_if_fail (asc, NULL);
+ 	g_return_val_if_fail (length == -1 || (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX), NULL);
+ 
+-	if (length == -1) {
+-		length = hwaddr_binary_len (asc);
+-		if (length == 0 || length > NM_UTILS_HWADDR_LEN_MAX)
++	if (length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX) {
++		if (!hwaddr_aton (asc, buf, length, &l))
+ 			return NULL;
+-	}
+-
+-	if (nm_utils_hwaddr_aton (asc, buf, length) == NULL)
+-		return NULL;
++		if (l != length)
++			return NULL;
++	} else if (length == -1) {
++		if (!hwaddr_aton (asc, buf, NM_UTILS_HWADDR_LEN_MAX, &l))
++			return NULL;
++	} else
++		g_return_val_if_reached (NULL);
+ 
+-	return nm_utils_hwaddr_ntoa (buf, length);
++	return nm_utils_hwaddr_ntoa (buf, l);
+ }
+ 
+ /* This is used to possibly canonicalize values passed to MAC address property
+@@ -3287,17 +3332,17 @@ nm_utils_hwaddr_matches (gconstpointer hwaddr1,
+                          gssize        hwaddr2_len)
+ {
+ 	guint8 buf1[NM_UTILS_HWADDR_LEN_MAX], buf2[NM_UTILS_HWADDR_LEN_MAX];
++	gsize l;
+ 
+ 	if (hwaddr1_len == -1) {
+ 		g_return_val_if_fail (hwaddr1 != NULL, FALSE);
+ 
+-		hwaddr1_len = hwaddr_binary_len (hwaddr1);
+-		if (hwaddr1_len == 0 || hwaddr1_len > NM_UTILS_HWADDR_LEN_MAX)
+-			return FALSE;
+-		if (!nm_utils_hwaddr_aton (hwaddr1, buf1, hwaddr1_len))
++		if (!hwaddr_aton (hwaddr1, buf1, sizeof (buf1), &l)) {
++			g_return_val_if_fail ((hwaddr2_len == -1 && hwaddr2) || (hwaddr2_len > 0 && hwaddr2_len <= NM_UTILS_HWADDR_LEN_MAX), FALSE);
+ 			return FALSE;
+-
++		}
+ 		hwaddr1 = buf1;
++		hwaddr1_len = l;
+ 	} else {
+ 		g_return_val_if_fail (hwaddr1_len > 0 && hwaddr1_len <= NM_UTILS_HWADDR_LEN_MAX, FALSE);
+ 
+@@ -3310,23 +3355,24 @@ nm_utils_hwaddr_matches (gconstpointer hwaddr1,
+ 	if (hwaddr2_len == -1) {
+ 		g_return_val_if_fail (hwaddr2 != NULL, FALSE);
+ 
+-		if (!nm_utils_hwaddr_aton (hwaddr2, buf2, hwaddr1_len))
++		if (!hwaddr_aton (hwaddr2, buf2, sizeof (buf2), &l))
++			return FALSE;
++		if (l != hwaddr1_len)
+ 			return FALSE;
+-
+ 		hwaddr2 = buf2;
+ 		hwaddr2_len = hwaddr1_len;
+ 	} else {
+ 		g_return_val_if_fail (hwaddr2_len > 0 && hwaddr2_len <= NM_UTILS_HWADDR_LEN_MAX, FALSE);
+ 
++		if (hwaddr2_len != hwaddr1_len)
++			return FALSE;
++
+ 		if (!hwaddr2) {
+ 			memset (buf2, 0, hwaddr2_len);
+ 			hwaddr2 = buf2;
+ 		}
+ 	}
+ 
+-	if (hwaddr1_len != hwaddr2_len)
+-		return FALSE;
+-
+ 	if (hwaddr1_len == INFINIBAND_ALEN) {
+ 		hwaddr1 = (guint8 *)hwaddr1 + INFINIBAND_ALEN - 8;
+ 		hwaddr2 = (guint8 *)hwaddr2 + INFINIBAND_ALEN - 8;
+@@ -3342,16 +3388,11 @@ static GVariant *
+ _nm_utils_hwaddr_to_dbus_impl (const char *str)
+ {
+ 	guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
+-	int len;
++	gsize len;
+ 
+ 	if (!str)
+ 		return NULL;
+-
+-	len = _nm_utils_hwaddr_length (str);
+-	if (len == 0)
+-		return NULL;
+-
+-	if (!nm_utils_hwaddr_aton (str, buf, len))
++	if (!hwaddr_aton (str, buf, sizeof (buf), &len))
+ 		return NULL;
+ 
+ 	return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, buf, len, 1);
+diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
+index 7a47f74..4be572c 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -11718,25 +11718,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));
+@@ -11745,18 +11745,20 @@ _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))
+-		g_return_val_if_reached (FALSE);
++	if (priv->hw_addr_len != addr_len) {
++		if (priv->hw_addr_len)
++			g_return_val_if_reached (FALSE);
++		priv->hw_addr_len = addr_len;
++	}
+ 
+ 	_LOGT (LOGD_DEVICE, "set-hw-addr: setting MAC address to '%s' (%s, %s)...", addr, operation, detail);
+ 
+@@ -11766,12 +11768,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 {
+@@ -11801,7 +11803,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;
+@@ -11928,9 +11930,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;
+ 	}
+ 
+@@ -12127,13 +12128,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);
+ 	}
+ 
+diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
+index 6dfbb4c..6988a12 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)) {
+-- 
+2.9.3
+
+
+From 8b6c03327ab5038e71f79020782e552a8192ef59 Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Thu, 13 Oct 2016 15:56:13 +0200
+Subject: [PATCH 08/15] core: add nm_device_get_permanent_hw_address_full()
+ function
+
+This is a partial cherry-pick from commit 5912b2f9a170893002b789fe37a7784eefac4e34.
+
+(cherry picked from commit b071c91eef15d6dbbf365d2db5aaca1b4eadcce0)
+---
+ src/devices/nm-device.c | 32 ++++++++++++++++++++++++--------
+ src/devices/nm-device.h |  2 ++
+ 2 files changed, 26 insertions(+), 8 deletions(-)
+
+diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
+index 4be572c..5001fce 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -11609,8 +11609,10 @@ nm_device_update_permanent_hw_address (NMDevice *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.
++		priv->hw_addr_perm_fake = TRUE;
++
++		/* we failed to read a permanent MAC address, thus we use a fake address,
++		 * that is the current MAC address of the device.
+ 		 *
+ 		 * In some cases it might be necessary to know whether this is a "real" or
+ 		 * a temporary address (fake). */
+@@ -11619,14 +11621,16 @@ nm_device_update_permanent_hw_address (NMDevice *self)
+ 		           ? "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 {
+-		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 out;
+ 	}
++
++	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);
++
++out:
+ 	_notify (self, PROP_PERM_HW_ADDRESS);
+ }
+ 
+@@ -11963,6 +11967,18 @@ nm_device_hw_addr_reset (NMDevice *self, const char *detail)
+ }
+ 
+ const char *
++nm_device_get_permanent_hw_address_full (NMDevice *self, gboolean *out_is_fake)
++{
++	NMDevicePrivate *priv;
++
++	g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
++
++	priv = NM_DEVICE_GET_PRIVATE (self);
++	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, gboolean fallback_fake)
+ {
+ 	NMDevicePrivate *priv;
+diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
+index a757a37..010c9b9 100644
+--- a/src/devices/nm-device.h
++++ b/src/devices/nm-device.h
+@@ -366,6 +366,8 @@ 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_full (NMDevice *self,
++                                                         gboolean *out_is_fake);
+ const char *    nm_device_get_initial_hw_address (NMDevice *dev);
+ 
+ NMDhcp4Config * nm_device_get_dhcp4_config      (NMDevice *dev);
+-- 
+2.9.3
+
+
+From c6bd879444816dbf7f2bc86b10b2b0589b4c94bf Mon Sep 17 00:00:00 2001
+From: Lubomir Rintel <lkundrak@v3.sk>
+Date: Tue, 11 Oct 2016 07:47:25 +0000
+Subject: [PATCH 09/15] config: allow fallback to fake permanent address for
+ default wired connections
+
+The default wired connection is already generated allowing the use of a fake
+address, but for the state file and the device matching specs only non-fake
+addresses are used. Let's allow fake addresses consistently, so that default
+wired connections work properly in containers (where the veth address is
+considered fake) as well.
+
+Also, it would really be a better idea to use ifnames everywhere instead, but
+that would change the format of the state file.
+
+(cherry picked from commit bcb685c4cb2b126f4a8593083fed043aed74ed17)
+(cherry picked from commit bb5ee41dc440709c3f2e0a3e498ab70fde4cea1a)
+---
+ src/devices/nm-device.c | 2 +-
+ src/nm-config.c         | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
+index 5001fce..a3af85a 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -12048,7 +12048,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, TRUE);
+ 	if (hw_addr_perm) {
+ 		m = nm_match_spec_hwaddr (specs, hw_addr_perm);
+ 		matched = MAX (matched, m);
+diff --git a/src/nm-config.c b/src/nm-config.c
+index 4bc4f48..3823e34 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, TRUE);
+ 	if (!hw_address)
+ 		return;
+ 
+-- 
+2.9.3
+
+
+From 5e1e3c0e79922ac4ff9a83ce406b9ff3b559832c Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Thu, 13 Oct 2016 18:52:12 +0200
+Subject: [PATCH 10/15] device: treat fake permanent MAC address mostly like a
+ real one
+
+Now that we persist the fake permanent address across
+restart of NetworkManager, we want to consider fake
+addresses as good enough in most cases.
+
+(cherry picked from commit 416164aa29c45d8071c8767fed866e06ee0e9169)
+(cherry picked from commit 7bb7b17408de2a1001c3ed77e06d2b23c1125b72)
+---
+ src/devices/nm-device-ethernet.c   | 15 +++++++++------
+ src/devices/nm-device-infiniband.c |  6 +++---
+ src/devices/nm-device-macvlan.c    |  2 +-
+ src/devices/nm-device-vlan.c       |  2 +-
+ src/devices/nm-device.c            | 25 +++++++++++--------------
+ src/devices/nm-device.h            |  3 +--
+ src/devices/wifi/nm-device-wifi.c  |  4 ++--
+ src/nm-config.c                    |  2 +-
+ src/nm-manager.c                   |  2 +-
+ src/settings/nm-settings.c         |  2 +-
+ 10 files changed, 31 insertions(+), 32 deletions(-)
+
+diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
+index 2f0b68a..004a4bd 100644
+--- a/src/devices/nm-device-ethernet.c
++++ b/src/devices/nm-device-ethernet.c
+@@ -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))
+@@ -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, &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, &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;
+diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c
+index 17f50ba..e2a67de 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-macvlan.c b/src/devices/nm-device-macvlan.c
+index 0a43646..c53abb6 100644
+--- a/src/devices/nm-device-macvlan.c
++++ b/src/devices/nm-device-macvlan.c
+@@ -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-vlan.c b/src/devices/nm-device-vlan.c
+index 16edc0d..461bae6 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.c b/src/devices/nm-device.c
+index a3af85a..8efd61f 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -11890,7 +11890,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;
+@@ -11979,19 +11979,11 @@ nm_device_get_permanent_hw_address_full (NMDevice *self, gboolean *out_is_fake)
+ }
+ 
+ const char *
+-nm_device_get_permanent_hw_address (NMDevice *self, gboolean fallback_fake)
++nm_device_get_permanent_hw_address (NMDevice *self)
+ {
+-	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;
+-	return priv->hw_addr_perm;
++	return NM_DEVICE_GET_PRIVATE (self)->hw_addr_perm;
+ }
+ 
+ const char *
+@@ -12048,7 +12040,7 @@ spec_match_list (NMDevice *self, const GSList *specs)
+ 		}
+ 	}
+ 
+-	hw_addr_perm = nm_device_get_permanent_hw_address (self, TRUE);
++	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);
+@@ -12521,10 +12513,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, &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 010c9b9..476a42b 100644
+--- a/src/devices/nm-device.h
++++ b/src/devices/nm-device.h
+@@ -364,8 +364,7 @@ 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 *out_is_fake);
+ const char *    nm_device_get_initial_hw_address (NMDevice *dev);
+diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
+index f467c81..f65b0cc 100644
+--- a/src/devices/wifi/nm-device-wifi.c
++++ b/src/devices/wifi/nm-device-wifi.c
+@@ -615,7 +615,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 +907,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/nm-config.c b/src/nm-config.c
+index 3823e34..f0f0c52 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, TRUE);
++	hw_address = nm_device_get_permanent_hw_address (device);
+ 	if (!hw_address)
+ 		return;
+ 
+diff --git a/src/nm-manager.c b/src/nm-manager.c
+index 932dafd..aadc572 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);
+ 		}
+diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
+index 1f691c0..cd54e52 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);
+-- 
+2.9.3
+
+
+From 1d2c444c6fc819c33a91dadd6535c117854cfd65 Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Wed, 26 Oct 2016 12:20:12 +0200
+Subject: [PATCH 11/15] device: don't allow mutating the device's hardware
+ address length
+
+We repeatedly call nm_device_update_hw_address() to reset the cached
+MAC address of the device. However, we don't allow changing the address
+length once it is set.
+
+Multiple entities (initial, current and permanent MAC address) are all
+checked to have the same address length. Changing the length would be a
+very strange thing (and probably indicate a bug somewhere else).
+
+Just don't allow that.
+
+(cherry picked from commit cbea1f9f23fac42626134b38cf94dd4ebca4091d)
+(cherry picked from commit e41284b3fca21123a6808cb1d5c262f678472d3f)
+---
+ src/devices/nm-device.c | 53 ++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 37 insertions(+), 16 deletions(-)
+
+diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
+index 8efd61f..c126728 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -227,7 +227,10 @@ 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;
+@@ -2475,11 +2478,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 +2486,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;
+@@ -11499,11 +11500,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;
+ }
+@@ -11528,9 +11535,25 @@ nm_device_update_hw_address (NMDevice *self)
+ 		hwaddrlen = 0;
+ 
+ 	if (hwaddrlen) {
+-		priv->hw_addr_len = hwaddrlen;
++		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;
++		}
++
+ 		if (!priv->hw_addr || !nm_utils_hwaddr_matches (priv->hw_addr, -1, hwaddr, hwaddrlen)) {
+ 			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);
+@@ -11758,11 +11781,9 @@ _hw_addr_set (NMDevice *self,
+ 		return TRUE;
+ 	}
+ 
+-	if (priv->hw_addr_len != addr_len) {
+-		if (priv->hw_addr_len)
+-			g_return_val_if_reached (FALSE);
+-		priv->hw_addr_len = 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);
+ 
+@@ -12144,7 +12165,7 @@ constructor (GType type,
+ 			g_return_val_if_reached (object);
+ 		}
+ 
+-		priv->hw_addr_len = l;
++		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);
+ 	}
+-- 
+2.9.3
+
+
+From f7af2a0a65f293809aac04faa17e469ecde5bc98 Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Mon, 24 Oct 2016 12:50:17 +0200
+Subject: [PATCH 12/15] device: delay capturing permanent MAC address until
+ UDEV is settled
+
+The permanent MAC address of an NMDevice shall not change as
+long as the device is realized. That is, we read it only once
+and don't change it afterwards.
+
+There are two issues that this commit tries to mitigate:
+
+(1) users are advised to use UDEV to rename interfaces. As we lookup
+  the permenent MAC address using ethtool (which uses the interface
+  name), there is a race where we could read the permanent MAC
+  address using the wrong interface name. We should wait until
+  UDEV finished initializing the device and until the interface
+  name is stable (see rh#1388286).
+  This commit still cannot avoid the race of ethtool entirely. It only
+  tries to avoid ethtool until UDEV has done its work. That is, until we
+  expect the interface name no longer to change.
+
+(2) some device types, don't have a permanent MAC address so we fall
+  back to use the currently set address (fake). Again, users are advised
+  to use UDEV to configure the MAC addresses on such software devices.
+  Thus, we should not get the fake MAC address until UDEV initialized
+  the device.
+
+This patch actually doesn't solve the problem at all yet.
+The reason is that a regular caller of nm_device_get_permanent_hw_address() can
+not afford to wait until UDEV settled. Thus, any user who requests the
+permanent MAC address before the link is initialized, runs into the
+problems above.
+
+In a next step, we shall revisit such calls to nm_device_get_permanent_hw_address()
+and delay them until the link is initialized.
+
+(cherry picked from commit 7b7c653c4f812f0ede676e8e0a08aa750e9e30b5)
+
+Conflicts:
+        src/devices/nm-device.c
+        src/nm-manager.c
+
+(cherry picked from commit 38b6f36edcc1d908863f66fd20dd79f1ef084f91)
+---
+ src/devices/nm-device-ethernet.c |   4 +-
+ src/devices/nm-device.c          | 100 +++++++++++++++++++++++++--------------
+ src/devices/nm-device.h          |   3 +-
+ 3 files changed, 69 insertions(+), 38 deletions(-)
+
+diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
+index 004a4bd..75802cf 100644
+--- a/src/devices/nm-device-ethernet.c
++++ b/src/devices/nm-device-ethernet.c
+@@ -1374,7 +1374,7 @@ complete_connection (NMDevice *device,
+ 		nm_connection_add_setting (connection, NM_SETTING (s_wired));
+ 	}
+ 
+-	perm_hw_addr = nm_device_get_permanent_hw_address_full (device, &perm_hw_addr_is_fake);
++	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) {
+@@ -1491,7 +1491,7 @@ 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.
+ 	 */
+-	perm_hw_addr = nm_device_get_permanent_hw_address_full (device, &perm_hw_addr_is_fake);
++	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);
+ 
+diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
+index c126728..638c37d 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -1822,7 +1822,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'",
+@@ -2288,7 +2288,7 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
+ 
+ 	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 ();
+@@ -11605,12 +11605,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
+@@ -11621,39 +11623,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;
+-	}
+-
+-	success_read = nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len);
+-	if (!success_read || len != priv->hw_addr_len) {
+-		priv->hw_addr_perm_fake = TRUE;
++		}
++		/* 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);
+ 
+-		/* we failed to read a permanent MAC address, thus we use a fake address,
+-		 * that is the current MAC address of the device.
++	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_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);
+-		goto out;
+-	}
+-
+-	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);
++		 * Abort if there is no current MAC address. */
++		return;
++	}
+ 
+-out:
++	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);
+ }
+ 
+@@ -11988,13 +12011,22 @@ nm_device_hw_addr_reset (NMDevice *self, const char *detail)
+ }
+ 
+ const char *
+-nm_device_get_permanent_hw_address_full (NMDevice *self, gboolean *out_is_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
++	    && 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;
+ }
+@@ -12002,9 +12034,7 @@ nm_device_get_permanent_hw_address_full (NMDevice *self, gboolean *out_is_fake)
+ const char *
+ nm_device_get_permanent_hw_address (NMDevice *self)
+ {
+-	g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
+-
+-	return NM_DEVICE_GET_PRIVATE (self)->hw_addr_perm;
++	return nm_device_get_permanent_hw_address_full (self, TRUE, NULL);
+ }
+ 
+ const char *
+@@ -12538,7 +12568,7 @@ get_property (GObject *object, guint prop_id,
+ 		const char *perm_hw_addr;
+ 		gboolean perm_hw_addr_is_fake;
+ 
+-		perm_hw_addr = nm_device_get_permanent_hw_address_full (self, &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, perm_hw_addr && !perm_hw_addr_is_fake ? perm_hw_addr : NULL);
+ 		break;
+diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
+index 476a42b..9044374 100644
+--- a/src/devices/nm-device.h
++++ b/src/devices/nm-device.h
+@@ -366,6 +366,7 @@ 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 *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);
+ 
+@@ -591,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__ */
+-- 
+2.9.3
+
+
+From 03b1d4dbdbb5914613d6d28f0fb8ee9d206bbf27 Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Tue, 25 Oct 2016 15:27:57 +0200
+Subject: [PATCH 13/15] device: delay evaluating unmanaged-by-user-settings
+ flags until link initialized
+
+Before the link is initialized, that is before UDEV completed
+initializing the device, we should not evaluate the user-settings
+unmanaged flags.
+
+The reason is, that evaluating it likely involves looking at the
+permanent MAC address, which might use the wrong fake MAC address
+(before UDEV set the right one). Also, it might use the wrong ifname
+to lookup the permanent MAC address via ethtool.
+
+(cherry picked from commit c0d249b733325046ca192d112d468b86aac54ba4)
+(cherry picked from commit 9f51a93d973e673ff5a6ee286cef1b7347f09767)
+---
+ src/devices/nm-device.c | 39 ++++++++++++++++++++++++++++++++-------
+ src/devices/nm-device.h |  2 +-
+ src/nm-manager.c        | 15 +++++++--------
+ 3 files changed, 40 insertions(+), 16 deletions(-)
+
+diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
+index 638c37d..aa3bf1e 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -1834,7 +1834,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;
+ 
+@@ -1913,7 +1913,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
+@@ -9868,6 +9868,21 @@ _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);
++		}
++	}
++
+ 	old_flags = priv->unmanaged_flags;
+ 	old_mask = priv->unmanaged_mask;
+ 
+@@ -9982,20 +9997,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);
+diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
+index 9044374..f90444c 100644
+--- a/src/devices/nm-device.h
++++ b/src/devices/nm-device.h
+@@ -509,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);
+ 
+diff --git a/src/nm-manager.c b/src/nm-manager.c
+index aadc572..4680f68 100644
+--- a/src/nm-manager.c
++++ b/src/nm-manager.c
+@@ -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
+@@ -1991,7 +1990,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,
+@@ -2810,15 +2809,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);
+ 	}
+ }
+ 
+-- 
+2.9.3
+
+
+From c464623f4049278fd3eff5551198d1fad280b519 Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Wed, 26 Oct 2016 13:43:49 +0200
+Subject: [PATCH 14/15] device: don't evaluate IP config changes until device
+ is initialized
+
+The unmanaged flags PLATFORM_INIT indicates whether UDEV is done
+initializing the device. We should not handle IP config changes
+before that pointer.
+
+This avoids codepaths that require the permanent MAC address of the
+device. We should not freeze the permanent MAC address before
+UDEV initialized the device, for two reasons:
+
+- getting the permanent MAC address using ethtool is racy as
+  UDEV might still rename the interface.
+- freezing a fake permanent MAC address should only happen after
+  UDEV is done configuring the MAC address of software devices.
+
+    #0  0x000055555568bc7a in nm_device_update_permanent_hw_address (self=self@entry=0x555555f0fb70 [NMDeviceVeth], force_freeze=force_freeze@entry=1) at src/devices/nm-device.c:11817
+    #1  0x000055555568c443 in nm_device_get_permanent_hw_address_full (self=self@entry=0x555555f0fb70 [NMDeviceVeth], force_freeze=force_freeze@entry=1, out_is_fake=out_is_fake@entry=0x0)
+        at src/devices/nm-device.c:12227
+    #2  0x000055555568cb06 in nm_device_get_permanent_hw_address (self=self@entry=0x555555f0fb70 [NMDeviceVeth]) at src/devices/nm-device.c:12237
+    #3  0x000055555568cb50 in spec_match_list (self=0x555555f0fb70 [NMDeviceVeth], specs=0x555555a5c000 = {...}) at src/devices/nm-device.c:12294
+    #4  0x00005555556a4ee6 in spec_match_list (device=0x555555f0fb70 [NMDeviceVeth], specs=0x555555a5c000 = {...}) at src/devices/nm-device-ethernet.c:1461
+    #5  0x00005555556978db in nm_device_spec_match_list (self=self@entry=0x555555f0fb70 [NMDeviceVeth], specs=0x555555a5c000 = {...}) at src/devices/nm-device.c:12277
+    #6  0x000055555558e187 in _match_section_infos_lookup (match_section_infos=0x555555a5d500, keyfile=0x555555a46f80, property=property@entry=0x555555793123 "ipv4.route-metric", device=device@entry=0x555555f0fb70 [NMDeviceVeth], out_value=out_value@entry=0x7fffffffe018) at src/nm-config-data.c:1169
+    #7  0x00005555555922ca in nm_config_data_get_connection_default (self=0x555555a548c0 [NMConfigData], property=property@entry=0x555555793123 "ipv4.route-metric", device=device@entry=0x555555f0fb70 [NMDeviceVeth]) at src/nm-config-data.c:1234
+    #8  0x00005555556790cd in _get_ipx_route_metric (self=self@entry=0x555555f0fb70 [NMDeviceVeth], is_v4=is_v4@entry=1) at src/devices/nm-device.c:1142
+    #9  0x000055555567912e in nm_device_get_ip4_route_metric (self=self@entry=0x555555f0fb70 [NMDeviceVeth]) at src/devices/nm-device.c:1161
+    #10 0x000055555567da6c in ip4_config_merge_and_apply (self=self@entry=0x555555f0fb70 [NMDeviceVeth], config=config@entry=0x0, commit=commit@entry=0, out_reason=out_reason@entry=0x0)
+        at src/devices/nm-device.c:4787
+    #11 0x000055555567e0fb in update_ip4_config (self=self@entry=0x555555f0fb70 [NMDeviceVeth], initial=initial@entry=0) at src/devices/nm-device.c:9532
+    #12 0x0000555555693acd in queued_ip4_config_change (user_data=0x555555f0fb70) at src/devices/nm-device.c:9651
+    #13 0x00007ffff4c966ba in g_main_context_dispatch (context=0x555555a46af0) at gmain.c:3154
+    #14 0x00007ffff4c966ba in g_main_context_dispatch (context=context@entry=0x555555a46af0) at gmain.c:3769
+    #15 0x00007ffff4c96a70 in g_main_context_iterate (context=0x555555a46af0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3840
+    #16 0x00007ffff4c96d92 in g_main_loop_run (loop=0x555555a47400) at gmain.c:4034
+    #17 0x000055555558372a in main (argc=<optimized out>, argv=<optimized out>) at src/main.c:411
+
+(cherry picked from commit 31ca7962f8f7d1993f0a363b9677c7cee89e7ee3)
+(cherry picked from commit cc0a590d57d860582396a5d03b1a316c364fd9a7)
+---
+ src/devices/nm-device.c | 44 ++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 38 insertions(+), 6 deletions(-)
+
+diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
+index aa3bf1e..119806c 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -233,7 +233,12 @@ typedef struct _NMDevicePrivate {
+ 	};
+ 	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;
+@@ -2282,9 +2287,8 @@ 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);
+@@ -7626,6 +7630,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);
+@@ -7642,6 +7647,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);
+@@ -9341,6 +9347,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;
+@@ -9431,6 +9438,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;
+@@ -9508,6 +9516,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;
+@@ -9532,6 +9542,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;
+@@ -9609,7 +9621,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");
+ 		}
+@@ -9626,7 +9642,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");
+ 		}
+@@ -9881,6 +9901,18 @@ _set_unmanaged_flags (NMDevice *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;
+-- 
+2.9.3
+
+
+From afc74296f260bd1a590b9c54b54b1170dea2e9ee Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Fri, 28 Oct 2016 17:06:13 +0200
+Subject: [PATCH 15/15] device: suppress log message in
+ nm_device_update_hw_address() when no MAC address
+
+For example for tun devices we get a lot of
+
+  (tun7): hw-addr: failed reading current MAC address
+
+warnings. Just be silent about it. We log when something
+changes, we don't need to log when we fail to obtain
+a MAC address.
+
+Thereby, refactor nm_device_update_hw_address() to return early.
+
+(cherry picked from commit 0e0018c8016156b9a01028f1448e7baf76e14d4a)
+
+Conflicts:
+    src/devices/nm-device.c
+
+(cherry picked from commit 37266b483bcaa89ae169c8e11ea9fbb42ba50d12)
+---
+ src/devices/nm-device.c | 79 ++++++++++++++++++++++---------------------------
+ 1 file changed, 35 insertions(+), 44 deletions(-)
+
+diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
+index 119806c..380e663 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -11578,7 +11578,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)
+@@ -11591,54 +11590,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) {
+-		if (   priv->hw_addr_len
+-		    && priv->hw_addr_len != hwaddrlen) {
+-			char s_buf[NM_UTILS_HWADDR_LEN_MAX_STR];
++	if (!hwaddrlen)
++		return FALSE;
+ 
+-			/* 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;
+-		}
++	if (   priv->hw_addr_len
++	    && priv->hw_addr_len != hwaddrlen) {
++		char s_buf[NM_UTILS_HWADDR_LEN_MAX_STR];
+ 
+-		if (!priv->hw_addr || !nm_utils_hwaddr_matches (priv->hw_addr, -1, hwaddr, hwaddrlen)) {
+-			g_free (priv->hw_addr);
+-			priv->hw_addr_len_ = hwaddrlen;
+-			priv->hw_addr = nm_utils_hwaddr_ntoa (hwaddr, hwaddrlen);
++		/* 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;
++	}
+ 
+-			_LOGD (LOGD_PLATFORM | LOGD_DEVICE, "hw-addr: hardware address now %s", priv->hw_addr);
+-			_notify (self, PROP_HW_ADDRESS);
++	if (   priv->hw_addr
++	    && nm_utils_hwaddr_matches (priv->hw_addr, -1, hwaddr, hwaddrlen))
++		return FALSE;
+ 
+-			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_PLATFORM | LOGD_DEVICE,
+-			       "hw-addr: failed reading current MAC address (stay with %s)",
+-			       priv->hw_addr);
+-		} else {
+-			_LOGD (LOGD_PLATFORM | LOGD_DEVICE,
+-			       "hw-addr: failed reading current MAC address");
+-		}
++	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 changed;
++	return TRUE;
+ }
+ 
+ void
+-- 
+2.9.3
+
diff --git a/SPECS/NetworkManager.spec b/SPECS/NetworkManager.spec
index 118ef3d..c54302e 100644
--- a/SPECS/NetworkManager.spec
+++ b/SPECS/NetworkManager.spec
@@ -12,7 +12,7 @@
 
 %global rpm_version 1.4.0
 %global real_version 1.4.0
-%global release_version 13
+%global release_version 14
 %global epoch_version 1
 
 %global obsoletes_nmver 1:0.9.9.95-1
@@ -126,6 +126,7 @@ Patch19: 0019-cli-fix-autocompletion-rh1375933.patch
 Patch20: 0020-fix-assume-bond-and-infiniband-rh1375558.patch
 Patch21: 0021-assume-devices-with-slaves-rh1333983.patch
 Patch22: 0022-no-unmanage-on-quit-rh1371126.patch
+Patch23: 0023-udev-initialized-race-rh1388286.patch
 
 Requires(post): systemd
 Requires(preun): systemd
@@ -396,6 +397,7 @@ by nm-connection-editor and nm-applet in a non-graphical environment.
 %patch20 -p1
 %patch21 -p1
 %patch22 -p1
+%patch23 -p1
 
 %build
 %if %{with regen_docs}
@@ -701,6 +703,9 @@ fi
 %endif
 
 %changelog
+* Tue Dec 13 2016 Thomas Haller <thaller@redhat.com> - 1:1.4.0-14
+- core: avoid race reading permanent MAC address before udev initialized (rh#1388286)
+
 * Wed Nov  2 2016 Thomas Haller <thaller@redhat.com> - 1:1.4.0-13
 - core: don't unmanage devices on shutdown (rh#1371126)