]> git.pld-linux.org Git - packages/NetworkManager.git/blob - 0003-wifi-set-mac-addr-workaround-rh1371478-v2.patch
2038b2f0fdca5aaddd443808da339c21d29c968b
[packages/NetworkManager.git] / 0003-wifi-set-mac-addr-workaround-rh1371478-v2.patch
1 From 3c701b60dc169a24cf52c0397560125ddce3d54c Mon Sep 17 00:00:00 2001
2 From: Thomas Haller <thaller@redhat.com>
3 Date: Wed, 7 Sep 2016 23:47:14 +0200
4 Subject: [PATCH 1/2] device: workaround driver issue with delayed change of
5  MAC address
6
7 brcmfmac and possibly other drivers don't change the MAC address
8 right away, but instead the result is delayed. That is problematic
9 because we cannot continue activation before the MAC address is
10 settled.
11
12 Add a hack to workaround the issue by waiting until the MAC address
13 changed.
14
15 The previous attempt to workaround this was less intrusive: we would
16 just refresh the link once and check the result. But that turns out
17 not to be sufficent for all cases. Now, wait and poll.
18
19 https://bugzilla.gnome.org/show_bug.cgi?id=770456
20 https://bugzilla.redhat.com/show_bug.cgi?id=1374023
21 (cherry picked from commit 1a85103765d4eaa0acab6b03658a4f9cfe684a64)
22 (cherry picked from commit 8d575403685208aad75f918484ae7adbc1a46085)
23 ---
24  src/devices/nm-device.c | 85 ++++++++++++++++++++++++++++++++++---------------
25  src/devices/nm-device.h |  2 +-
26  2 files changed, 61 insertions(+), 26 deletions(-)
27
28 diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
29 index 674563f..3e549c5 100644
30 --- a/src/devices/nm-device.c
31 +++ b/src/devices/nm-device.c
32 @@ -11549,16 +11549,17 @@ nm_device_get_hw_address (NMDevice *self)
33         return priv->hw_addr;
34  }
35  
36 -void
37 +gboolean
38  nm_device_update_hw_address (NMDevice *self)
39  {
40         NMDevicePrivate *priv;
41         const guint8 *hwaddr;
42         gsize hwaddrlen = 0;
43 +       gboolean changed = FALSE;
44  
45         priv = NM_DEVICE_GET_PRIVATE (self);
46         if (priv->ifindex <= 0)
47 -               return;
48 +               return FALSE;
49  
50         hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, priv->ifindex, &hwaddrlen);
51  
52 @@ -11585,6 +11586,7 @@ nm_device_update_hw_address (NMDevice *self)
53                                  * update our inital hw-address as well. */
54                                 nm_device_update_initial_hw_address (self);
55                         }
56 +                       changed = TRUE;
57                 }
58         } else {
59                 /* Invalid or no hardware address */
60 @@ -11597,6 +11599,7 @@ nm_device_update_hw_address (NMDevice *self)
61                                "hw-addr: failed reading current MAC address");
62                 }
63         }
64 +       return changed;
65  }
66  
67  void
68 @@ -11756,6 +11759,15 @@ nm_device_hw_addr_is_explict (NMDevice *self)
69  }
70  
71  static gboolean
72 +_hw_addr_matches (NMDevice *self, const char *addr)
73 +{
74 +       const char *cur_addr;
75 +
76 +       cur_addr = nm_device_get_hw_address (self);
77 +       return cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1);
78 +}
79 +
80 +static gboolean
81  _hw_addr_set (NMDevice *self,
82                const char *addr,
83                const char *operation,
84 @@ -11765,7 +11777,6 @@ _hw_addr_set (NMDevice *self,
85         gboolean success = FALSE;
86         gboolean needs_refresh = FALSE;
87         NMPlatformError plerr;
88 -       const char *cur_addr;
89         guint8 addr_bytes[NM_UTILS_HWADDR_LEN_MAX];
90         guint hw_addr_len;
91         gboolean was_up;
92 @@ -11776,11 +11787,9 @@ _hw_addr_set (NMDevice *self,
93  
94         priv = NM_DEVICE_GET_PRIVATE (self);
95  
96 -       cur_addr = nm_device_get_hw_address (self);
97 -
98         /* Do nothing if current MAC is same */
99 -       if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) {
100 -               _LOGT (LOGD_DEVICE, "set-hw-addr: no MAC address change needed (%s)", cur_addr);
101 +       if (_hw_addr_matches (self, addr)) {
102 +               _LOGT (LOGD_DEVICE, "set-hw-addr: no MAC address change needed (%s)", addr);
103                 return TRUE;
104         }
105  
106 @@ -11804,8 +11813,7 @@ _hw_addr_set (NMDevice *self,
107         if (success) {
108                 /* MAC address succesfully changed; update the current MAC to match */
109                 nm_device_update_hw_address (self);
110 -               cur_addr = nm_device_get_hw_address (self);
111 -               if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) {
112 +               if (_hw_addr_matches (self, addr)) {
113                         _LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
114                                operation, addr, detail);
115                 } else {
116 @@ -11827,24 +11835,51 @@ _hw_addr_set (NMDevice *self,
117         }
118  
119         if (needs_refresh) {
120 -               /* The platform call indicated success, however the address is not
121 -                * as expected. May be a kernel issue and the MAC address takes
122 -                * a moment to change (bgo#770456).
123 -                *
124 -                * Try to reload the link and check again. */
125 -               nm_platform_link_refresh (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self));
126 -
127 -               nm_device_update_hw_address (self);
128 -               cur_addr = nm_device_get_hw_address (self);
129 -               if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) {
130 -                       _LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
131 -                              operation, addr, detail);
132 +               if (_hw_addr_matches (self, addr)) {
133 +                       /* the MAC address already changed during nm_device_bring_up() above. */
134                 } else {
135 -                       _LOGW (LOGD_DEVICE,
136 -                              "set-hw-addr: new MAC address %s not successfully %s (%s)",
137 -                              addr, operation, detail);
138 -                       return FALSE;
139 +                       gint64 poll_end, now;
140 +
141 +                       /* The platform call indicated success, however the address is not
142 +                        * as expected. That is either due to a driver issue (brcmfmac, bgo#770456,
143 +                        * rh#1374023) or a race where externally the MAC address was reset.
144 +                        * The race is rather unlikely.
145 +                        *
146 +                        * The alternative would be to postpone the activation in case the
147 +                        * MAC address is not yet ready and poll without blocking. However,
148 +                        * that is rather complicated and it is not expected that this case
149 +                        * happens for regular drivers.
150 +                        * Note that brcmfmac can block NetworkManager for 500 msec while
151 +                        * taking down the device. Let's add annother 100 msec to that.
152 +                        *
153 +                        * wait/poll up to 100 msec until it changes. */
154 +
155 +                       poll_end = nm_utils_get_monotonic_timestamp_us () + (100 * 1000);
156 +                       for (;;) {
157 +                               if (!nm_platform_link_refresh (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self)))
158 +                                       goto handle_fail;
159 +                               if (!nm_device_update_hw_address (self))
160 +                                       goto handle_wait;
161 +                               if (!_hw_addr_matches (self, addr))
162 +                                       goto handle_fail;
163 +
164 +                               break;
165 +handle_wait:
166 +                               now = nm_utils_get_monotonic_timestamp_us ();
167 +                               if (now < poll_end) {
168 +                                       g_usleep (NM_MIN (poll_end - now, 500));
169 +                                       continue;
170 +                               }
171 +handle_fail:
172 +                               _LOGW (LOGD_DEVICE,
173 +                                      "set-hw-addr: new MAC address %s not successfully %s (%s)",
174 +                                      addr, operation, detail);
175 +                               return FALSE;
176 +                       }
177                 }
178 +
179 +               _LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
180 +                      operation, addr, detail);
181         }
182  
183         return success;
184 diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
185 index be12ce7..a757a37 100644
186 --- a/src/devices/nm-device.h
187 +++ b/src/devices/nm-device.h
188 @@ -588,7 +588,7 @@ void nm_device_reactivate_ip6_config (NMDevice *device,
189                                        NMSettingIPConfig *s_ip6_old,
190                                        NMSettingIPConfig *s_ip6_new);
191  
192 -void nm_device_update_hw_address (NMDevice *self);
193 +gboolean nm_device_update_hw_address (NMDevice *self);
194  void nm_device_update_initial_hw_address (NMDevice *self);
195  void nm_device_update_permanent_hw_address (NMDevice *self);
196  void nm_device_update_dynamic_ip_setup (NMDevice *self);
197 -- 
198 2.7.4
199
200
201 From d99c3b63e81347fb861e1306eb0b603cfa15223e Mon Sep 17 00:00:00 2001
202 From: Thomas Haller <thaller@redhat.com>
203 Date: Sun, 11 Sep 2016 09:48:56 +0200
204 Subject: [PATCH 2/2] device: wait for MAC address change to complete before
205  setting interface up
206
207 Some drivers (brcmfmac) don't change the MAC address right away.
208 NetworkManager works around that by waiting synchronously until
209 the address changes (commit 1a85103765d4eaa0acab6b03658a4f9cfe684a64).
210
211 wpa_supplicant on the other hand, only re-reads the MAC address
212 when changing state from DISABLED to ENABLED, which happens when
213 the interface comes up.
214
215 That is a bug in wpa_supplicant and the driver, but we can work-around by
216 waiting until the MAC address actually changed before setting the interface
217 IFF_UP. Also note, that there is still a race in wpa_supplicant which might
218 miss a change to DISABLED state altogether.
219
220 https://bugzilla.gnome.org/show_bug.cgi?id=770504
221 https://bugzilla.redhat.com/show_bug.cgi?id=1374023
222 (cherry picked from commit 32f7c1d4b9aba597a99128631f07c2985149f303)
223 (cherry picked from commit cd8f2ecc617a896d8007e6fe825c676a626a3b8d)
224 ---
225  src/devices/nm-device.c | 27 ++++++++++++++++-----------
226  1 file changed, 16 insertions(+), 11 deletions(-)
227
228 diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
229 index 3e549c5..47e858b 100644
230 --- a/src/devices/nm-device.c
231 +++ b/src/devices/nm-device.c
232 @@ -11829,12 +11829,8 @@ _hw_addr_set (NMDevice *self,
233                         nm_platform_error_to_string (plerr));
234         }
235  
236 -       if (was_up) {
237 -               if (!nm_device_bring_up (self, TRUE, NULL))
238 -                       return FALSE;
239 -       }
240 -
241         if (needs_refresh) {
242 +               success = TRUE;
243                 if (_hw_addr_matches (self, addr)) {
244                         /* the MAC address already changed during nm_device_bring_up() above. */
245                 } else {
246 @@ -11871,15 +11867,24 @@ handle_wait:
247                                         continue;
248                                 }
249  handle_fail:
250 -                               _LOGW (LOGD_DEVICE,
251 -                                      "set-hw-addr: new MAC address %s not successfully %s (%s)",
252 -                                      addr, operation, detail);
253 -                               return FALSE;
254 +                               success = FALSE;
255 +                               break;
256                         }
257                 }
258  
259 -               _LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
260 -                      operation, addr, detail);
261 +               if (success) {
262 +                       _LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
263 +                              operation, addr, detail);
264 +               } else {
265 +                       _LOGW (LOGD_DEVICE,
266 +                              "set-hw-addr: new MAC address %s not successfully %s (%s)",
267 +                              addr, operation, detail);
268 +               }
269 +       }
270 +
271 +       if (was_up) {
272 +               if (!nm_device_bring_up (self, TRUE, NULL))
273 +                       return FALSE;
274         }
275  
276         return success;
277 -- 
278 2.7.4
279
This page took 0.038734 seconds and 2 git commands to generate.