about summary refs log tree commit diff
path: root/src/devices/wifi/nm-device-wifi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/wifi/nm-device-wifi.c')
-rw-r--r--src/devices/wifi/nm-device-wifi.c40
1 files changed, 37 insertions, 3 deletions
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index 15d41206..1bf64bcc 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -136,6 +136,8 @@ struct _NMDeviceWifiPrivate {
 	guint32           failed_link_count;
 	guint             periodic_source_id;
 	guint             link_timeout_id;
+	guint32           failed_iface_count;
+	guint             reacquire_iface_id;
 
 	NMDeviceWifiCapabilities capabilities;
 };
@@ -217,8 +219,7 @@ constructor (GType type,
 		_LOGI (LOGD_HW | LOGD_WIFI, "driver supports Access Point (AP) mode");
 
 	/* Connect to the supplicant manager */
-	priv->sup_mgr = nm_supplicant_manager_get ();
-	g_assert (priv->sup_mgr);
+	priv->sup_mgr = g_object_ref (nm_supplicant_manager_get ());
 
 	return object;
 }
@@ -1959,6 +1960,15 @@ cleanup_association_attempt (NMDeviceWifi *self, gboolean disconnect)
 }
 
 static void
+cleanup_supplicant_failures (NMDeviceWifi *self)
+{
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+
+	nm_clear_g_source (&priv->reacquire_iface_id);
+	priv->failed_iface_count = 0;
+}
+
+static void
 wifi_secrets_cb (NMActRequest *req,
                  guint32 call_id,
                  NMConnection *connection,
@@ -2158,6 +2168,24 @@ handle_8021x_or_psk_auth_fail (NMDeviceWifi *self,
 	return handled;
 }
 
+static gboolean
+reacquire_interface_cb (gpointer user_data)
+{
+	NMDevice *device = NM_DEVICE (user_data);
+	NMDeviceWifi *self = NM_DEVICE_WIFI (device);
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+
+	priv->reacquire_iface_id = 0;
+	priv->failed_iface_count++;
+
+	_LOGW (LOGD_WIFI, "re-acquiring supplicant interface (#%d).", priv->failed_iface_count);
+
+	if (!priv->sup_iface)
+		supplicant_interface_acquire (self);
+
+	return G_SOURCE_REMOVE;
+}
+
 static void
 supplicant_iface_state_cb (NMSupplicantInterface *iface,
                            guint32 new_state,
@@ -2264,7 +2292,10 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
 		 * ready if the supplicant comes back.
 		 */
 		supplicant_interface_release (self);
-		supplicant_interface_acquire (self);
+		if (priv->failed_iface_count < 5)
+			priv->reacquire_iface_id = g_timeout_add_seconds (10, reacquire_interface_cb, self);
+		else
+			_LOGI (LOGD_DEVICE | LOGD_WIFI, "supplicant interface keeps failing, giving up");
 		break;
 	default:
 		break;
@@ -3061,6 +3092,7 @@ device_state_changed (NMDevice *device,
 		}
 
 		cleanup_association_attempt (self, TRUE);
+		cleanup_supplicant_failures (self);
 		remove_all_aps (self);
 	}
 
@@ -3147,6 +3179,7 @@ set_enabled (NMDevice *device, gboolean enabled)
 		}
 
 		/* Re-initialize the supplicant interface and wait for it to be ready */
+		cleanup_supplicant_failures (self);
 		if (priv->sup_iface)
 			supplicant_interface_release (self);
 		supplicant_interface_acquire (self);
@@ -3201,6 +3234,7 @@ dispose (GObject *object)
 
 	cleanup_association_attempt (self, TRUE);
 	supplicant_interface_release (self);
+	cleanup_supplicant_failures (self);
 
 	g_clear_object (&priv->sup_mgr);