Blame SOURCES/0013-wifi-set-mac-addr-workaround-v2-rh1371623.patch

a85faa
From 495d758092b703c57653454cfa3fb198a970f51b Mon Sep 17 00:00:00 2001
a85faa
From: Thomas Haller <thaller@redhat.com>
a85faa
Date: Wed, 7 Sep 2016 23:47:14 +0200
a85faa
Subject: [PATCH 1/1] device: workaround driver issue with delayed change of
a85faa
 MAC address
a85faa
a85faa
brcmfmac and possibly other drivers don't change the MAC address
a85faa
right away, but instead the result is delayed. That is problematic
a85faa
because we cannot continue activation before the MAC address is
a85faa
settled.
a85faa
a85faa
Add a hack to workaround the issue by waiting until the MAC address
a85faa
changed.
a85faa
a85faa
The previous attempt to workaround this was less intrusive: we would
a85faa
just refresh the link once and check the result. But that turns out
a85faa
not to be sufficent for all cases. Now, wait and poll.
a85faa
a85faa
https://bugzilla.gnome.org/show_bug.cgi?id=770456
a85faa
https://bugzilla.redhat.com/show_bug.cgi?id=1374023
a85faa
(cherry picked from commit 1a85103765d4eaa0acab6b03658a4f9cfe684a64)
a85faa
(cherry picked from commit 8d575403685208aad75f918484ae7adbc1a46085)
a85faa
---
a85faa
 src/devices/nm-device.c | 85 ++++++++++++++++++++++++++++++++++---------------
a85faa
 src/devices/nm-device.h |  2 +-
a85faa
 2 files changed, 61 insertions(+), 26 deletions(-)
a85faa
a85faa
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
a85faa
index 45a2830..84246b7 100644
a85faa
--- a/src/devices/nm-device.c
a85faa
+++ b/src/devices/nm-device.c
a85faa
@@ -11565,16 +11565,17 @@ nm_device_get_hw_address (NMDevice *self)
a85faa
 	return priv->hw_addr;
a85faa
 }
a85faa
 
a85faa
-void
a85faa
+gboolean
a85faa
 nm_device_update_hw_address (NMDevice *self)
a85faa
 {
a85faa
 	NMDevicePrivate *priv;
a85faa
 	const guint8 *hwaddr;
a85faa
 	gsize hwaddrlen = 0;
a85faa
+	gboolean changed = FALSE;
a85faa
 
a85faa
 	priv = NM_DEVICE_GET_PRIVATE (self);
a85faa
 	if (priv->ifindex <= 0)
a85faa
-		return;
a85faa
+		return FALSE;
a85faa
 
a85faa
 	hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, priv->ifindex, &hwaddrlen);
a85faa
 
a85faa
@@ -11601,6 +11602,7 @@ nm_device_update_hw_address (NMDevice *self)
a85faa
 				 * update our inital hw-address as well. */
a85faa
 				nm_device_update_initial_hw_address (self);
a85faa
 			}
a85faa
+			changed = TRUE;
a85faa
 		}
a85faa
 	} else {
a85faa
 		/* Invalid or no hardware address */
a85faa
@@ -11613,6 +11615,7 @@ nm_device_update_hw_address (NMDevice *self)
a85faa
 			       "hw-addr: failed reading current MAC address");
a85faa
 		}
a85faa
 	}
a85faa
+	return changed;
a85faa
 }
a85faa
 
a85faa
 void
a85faa
@@ -11772,6 +11775,15 @@ nm_device_hw_addr_is_explict (NMDevice *self)
a85faa
 }
a85faa
 
a85faa
 static gboolean
a85faa
+_hw_addr_matches (NMDevice *self, const char *addr)
a85faa
+{
a85faa
+	const char *cur_addr;
a85faa
+
a85faa
+	cur_addr = nm_device_get_hw_address (self);
a85faa
+	return cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1);
a85faa
+}
a85faa
+
a85faa
+static gboolean
a85faa
 _hw_addr_set (NMDevice *self,
a85faa
               const char *addr,
a85faa
               const char *operation,
a85faa
@@ -11781,7 +11793,6 @@ _hw_addr_set (NMDevice *self,
a85faa
 	gboolean success = FALSE;
a85faa
 	gboolean needs_refresh = FALSE;
a85faa
 	NMPlatformError plerr;
a85faa
-	const char *cur_addr;
a85faa
 	guint8 addr_bytes[NM_UTILS_HWADDR_LEN_MAX];
a85faa
 	guint hw_addr_len;
a85faa
 	gboolean was_up;
a85faa
@@ -11792,11 +11803,9 @@ _hw_addr_set (NMDevice *self,
a85faa
 
a85faa
 	priv = NM_DEVICE_GET_PRIVATE (self);
a85faa
 
a85faa
-	cur_addr = nm_device_get_hw_address (self);
a85faa
-
a85faa
 	/* Do nothing if current MAC is same */
a85faa
-	if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) {
a85faa
-		_LOGT (LOGD_DEVICE, "set-hw-addr: no MAC address change needed (%s)", cur_addr);
a85faa
+	if (_hw_addr_matches (self, addr)) {
a85faa
+		_LOGT (LOGD_DEVICE, "set-hw-addr: no MAC address change needed (%s)", addr);
a85faa
 		return TRUE;
a85faa
 	}
a85faa
 
a85faa
@@ -11820,8 +11829,7 @@ _hw_addr_set (NMDevice *self,
a85faa
 	if (success) {
a85faa
 		/* MAC address succesfully changed; update the current MAC to match */
a85faa
 		nm_device_update_hw_address (self);
a85faa
-		cur_addr = nm_device_get_hw_address (self);
a85faa
-		if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) {
a85faa
+		if (_hw_addr_matches (self, addr)) {
a85faa
 			_LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
a85faa
 			       operation, addr, detail);
a85faa
 		} else {
a85faa
@@ -11843,24 +11851,51 @@ _hw_addr_set (NMDevice *self,
a85faa
 	}
a85faa
 
a85faa
 	if (needs_refresh) {
a85faa
-		/* The platform call indicated success, however the address is not
a85faa
-		 * as expected. May be a kernel issue and the MAC address takes
a85faa
-		 * a moment to change (bgo#770456).
a85faa
-		 *
a85faa
-		 * Try to reload the link and check again. */
a85faa
-		nm_platform_link_refresh (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self));
a85faa
-
a85faa
-		nm_device_update_hw_address (self);
a85faa
-		cur_addr = nm_device_get_hw_address (self);
a85faa
-		if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) {
a85faa
-			_LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
a85faa
-			       operation, addr, detail);
a85faa
+		if (_hw_addr_matches (self, addr)) {
a85faa
+			/* the MAC address already changed during nm_device_bring_up() above. */
a85faa
 		} else {
a85faa
-			_LOGW (LOGD_DEVICE,
a85faa
-			       "set-hw-addr: new MAC address %s not successfully %s (%s)",
a85faa
-			       addr, operation, detail);
a85faa
-			return FALSE;
a85faa
+			gint64 poll_end, now;
a85faa
+
a85faa
+			/* The platform call indicated success, however the address is not
a85faa
+			 * as expected. That is either due to a driver issue (brcmfmac, bgo#770456,
a85faa
+			 * rh#1374023) or a race where externally the MAC address was reset.
a85faa
+			 * The race is rather unlikely.
a85faa
+			 *
a85faa
+			 * The alternative would be to postpone the activation in case the
a85faa
+			 * MAC address is not yet ready and poll without blocking. However,
a85faa
+			 * that is rather complicated and it is not expected that this case
a85faa
+			 * happens for regular drivers.
a85faa
+			 * Note that brcmfmac can block NetworkManager for 500 msec while
a85faa
+			 * taking down the device. Let's add annother 100 msec to that.
a85faa
+			 *
a85faa
+			 * wait/poll up to 100 msec until it changes. */
a85faa
+
a85faa
+			poll_end = nm_utils_get_monotonic_timestamp_us () + (100 * 1000);
a85faa
+			for (;;) {
a85faa
+				if (!nm_platform_link_refresh (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self)))
a85faa
+					goto handle_fail;
a85faa
+				if (!nm_device_update_hw_address (self))
a85faa
+					goto handle_wait;
a85faa
+				if (!_hw_addr_matches (self, addr))
a85faa
+					goto handle_fail;
a85faa
+
a85faa
+				break;
a85faa
+handle_wait:
a85faa
+				now = nm_utils_get_monotonic_timestamp_us ();
a85faa
+				if (now < poll_end) {
a85faa
+					g_usleep (MIN (poll_end - now, 500));
a85faa
+					continue;
a85faa
+				}
a85faa
+handle_fail:
a85faa
+				_LOGW (LOGD_DEVICE,
a85faa
+				       "set-hw-addr: new MAC address %s not successfully %s (%s)",
a85faa
+				       addr, operation, detail);
a85faa
+				return FALSE;
a85faa
+			}
a85faa
 		}
a85faa
+
a85faa
+		_LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
a85faa
+		       operation, addr, detail);
a85faa
 	}
a85faa
 
a85faa
 	return success;
a85faa
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
a85faa
index 34d31ca..0f91b21 100644
a85faa
--- a/src/devices/nm-device.h
a85faa
+++ b/src/devices/nm-device.h
a85faa
@@ -588,7 +588,7 @@ void nm_device_reactivate_ip6_config (NMDevice *device,
a85faa
                                       NMSettingIPConfig *s_ip6_old,
a85faa
                                       NMSettingIPConfig *s_ip6_new);
a85faa
 
a85faa
-void nm_device_update_hw_address (NMDevice *self);
a85faa
+gboolean nm_device_update_hw_address (NMDevice *self);
a85faa
 void nm_device_update_initial_hw_address (NMDevice *self);
a85faa
 void nm_device_update_permanent_hw_address (NMDevice *self);
a85faa
 void nm_device_update_dynamic_ip_setup (NMDevice *self);
a85faa
-- 
a85faa
2.7.4
a85faa