NetworkManager r4105 - in trunk: . src



Author: dcbw
Date: Thu Sep 25 10:02:28 2008
New Revision: 4105
URL: http://svn.gnome.org/viewvc/NetworkManager?rev=4105&view=rev

Log:
2008-09-25  Dan Williams  <dcbw redhat com>

	Fix bgo #549401 (inspired by patch from Alexander Sack)

	* src/nm-device-ethernet.c
		- (finish_supplicant_task): clean up scheduled tasks and free memory
		- (remove_supplicant_interface_error_handler): remove the supplicant
			error idle callback too
		- (supplicant_interface_release): rename from supplicant_interface_clean
			to match nm-device-wifi.c; clean up supplicant interface-related
			state tasks when the supplicant interface is disposed of
		- (schedule_state_handler): add scheduled tasks to a list so they can
			be cleaned up later
		- (supplicant_mgr_state_cb_handler, supplicant_iface_state_cb_handler,
		   supplicant_iface_connection_state_cb_handler): use
			finish_supplicant_task() to clean up each completed task
		- (supplicant_iface_connection_error_cb_handler,
		   supplicant_connection_timeout_cb): clear source id when the task is
			complete
		- (supplicant_iface_connection_error_cb): save scheduled task id for
			later cleanup
		- (nm_device_ethernet_dispose): clean up any pending supplicant state
			tasks

	* src/nm-device-wifi.c
		- (finish_supplicant_task): clean up scheduled tasks and free memory
		- (remove_supplicant_interface_error_handler): remove the supplicant
			error idle callback too
		- (supplicant_interface_release): clean up supplicant interface-related
			state tasks when the supplicant interface is disposed of
		- (schedule_state_handler): add scheduled tasks to a list so they can
			be cleaned up later
		- (supplicant_mgr_state_cb_handler, supplicant_iface_state_cb_handler,
		   supplicant_iface_connection_state_cb_handler): use
			finish_supplicant_task() to clean up each completed task
		- (supplicant_iface_connection_error_cb_handler): clear source id when
			the task is complete
		- (supplicant_iface_connection_error_cb): save scheduled task id for
			later cleanup
		- (nm_device_wifi_dispose): clean up any pending supplicant state tasks



Modified:
   trunk/ChangeLog
   trunk/src/nm-device-ethernet.c
   trunk/src/nm-device-wifi.c

Modified: trunk/src/nm-device-ethernet.c
==============================================================================
--- trunk/src/nm-device-ethernet.c	(original)
+++ trunk/src/nm-device-ethernet.c	Thu Sep 25 10:02:28 2008
@@ -18,7 +18,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2005 Red Hat, Inc.
+ * (C) Copyright 2005 - 2008 Red Hat, Inc.
  */
 
 #include <glib.h>
@@ -73,17 +73,30 @@
 #define NM_ETHERNET_ERROR (nm_ethernet_error_quark ())
 #define NM_TYPE_ETHERNET_ERROR (nm_ethernet_error_get_type ()) 
 
+typedef struct SupplicantStateTask {
+	NMDeviceEthernet *self;
+	guint32 new_state;
+	guint32 old_state;
+	gboolean mgr_task;
+	guint source_id;
+} SupplicantStateTask;
+
 typedef struct Supplicant {
 	NMSupplicantManager *mgr;
 	NMSupplicantInterface *iface;
 
 	/* signal handler ids */
-	guint                   mgr_state_id;
-	guint                   iface_error_id;
-	guint                   iface_state_id;
-	guint                   iface_con_state_id;
+	guint mgr_state_id;
+	guint iface_error_id;
+	guint iface_state_id;
+	guint iface_con_state_id;
+
+	/* Timeouts and idles */
+	guint iface_con_error_cb_id;
+	guint con_timeout_id;
 
-	guint                   con_timeout_id;
+	GSList *iface_tasks;
+	GSList *mgr_tasks;
 } Supplicant;
 
 typedef struct {
@@ -664,7 +677,31 @@
 }
 
 static void
-remove_supplicant_interface_connection_error_handler (NMDeviceEthernet *self)
+finish_supplicant_task (SupplicantStateTask *task, gboolean remove_source)
+{
+	NMDeviceEthernet *self = task->self;
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+
+	/* idle/timeout handlers should pass FALSE for remove_source, since they
+	 * will tell glib to remove their source from the mainloop by returning
+	 * FALSE when they exit.  When called from this NMDevice's dispose handler,
+	 * remove_source should be TRUE to cancel all outstanding idle/timeout
+	 * handlers asynchronously.
+	 */
+	if (task->source_id && remove_source)
+		g_source_remove (task->source_id);
+
+	if (task->mgr_task)
+		priv->supplicant.mgr_tasks = g_slist_remove (priv->supplicant.mgr_tasks, task);
+	else
+		priv->supplicant.iface_tasks = g_slist_remove (priv->supplicant.iface_tasks, task);
+
+	memset (task, 0, sizeof (SupplicantStateTask));
+	g_slice_free (SupplicantStateTask, task);
+}
+
+static void
+remove_supplicant_interface_error_handler (NMDeviceEthernet *self)
 {
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
 
@@ -672,15 +709,24 @@
 		g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_error_id);
 		priv->supplicant.iface_error_id = 0;
 	}
+
+	if (priv->supplicant.iface_con_error_cb_id > 0) {
+		g_source_remove (priv->supplicant.iface_con_error_cb_id);
+		priv->supplicant.iface_con_error_cb_id = 0;
+	}
 }
 
 static void
-supplicant_interface_clean (NMDeviceEthernet *self)
+supplicant_interface_release (NMDeviceEthernet *self)
 {
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
 
 	remove_supplicant_timeouts (self);
-	remove_supplicant_interface_connection_error_handler (self);
+	remove_supplicant_interface_error_handler (self);
+
+	/* Clean up all pending supplicant interface state idle tasks */
+	while (priv->supplicant.iface_tasks)
+		finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.iface_tasks->data, TRUE);
 
 	if (priv->supplicant.iface_con_state_id) {
 		g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_con_state_id);
@@ -739,7 +785,7 @@
 
 	nm_info ("Activation (%s/wired): disconnected during authentication,"
 	         " asking for new key.", nm_device_get_iface (dev));
-	supplicant_interface_clean (self);
+	supplicant_interface_release (self);
 
 	nm_device_state_changed (dev, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
 	nm_act_request_request_connection_secrets (req, setting_name, TRUE,
@@ -754,42 +800,47 @@
 	return FALSE;
 }
 
-struct state_cb_data {
-	NMDeviceEthernet *self;
-	guint32 new_state;
-	guint32 old_state;
-};
-
 static gboolean
 schedule_state_handler (NMDeviceEthernet *self,
                         GSourceFunc handler,
                         guint32 new_state,
-                        guint32 old_state)
+                        guint32 old_state,
+                        gboolean mgr_task)
 {
-	struct state_cb_data * cb_data;
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+	SupplicantStateTask *task;
 
 	if (new_state == old_state)
 		return TRUE;
 
-	cb_data = g_slice_new0 (struct state_cb_data);
-	cb_data->self = self;
-	cb_data->new_state = new_state;
-	cb_data->old_state = old_state;
-
-	g_idle_add (handler, cb_data);
+	task = g_slice_new0 (SupplicantStateTask);
+	if (!task) {
+		nm_warning ("Not enough memory to process supplicant manager state change.");
+		return FALSE;
+	}
 
+	task->self = self;
+	task->new_state = new_state;
+	task->old_state = old_state;
+	task->mgr_task = mgr_task;
+
+	task->source_id = g_idle_add (handler, task);
+	if (mgr_task)
+		priv->supplicant.mgr_tasks = g_slist_append (priv->supplicant.mgr_tasks, task);
+	else
+		priv->supplicant.iface_tasks = g_slist_append (priv->supplicant.iface_tasks, task);
 	return TRUE;
 }
 
 static gboolean
 supplicant_mgr_state_cb_handler (gpointer user_data)
 {
-	struct state_cb_data *info = (struct state_cb_data *) user_data;
-	NMDevice *device = NM_DEVICE (info->self);
+	SupplicantStateTask *task = (SupplicantStateTask *) user_data;
+	NMDevice *device = NM_DEVICE (task->self);
 
 	/* If the supplicant went away, release the supplicant interface */
-	if (info->new_state == NM_SUPPLICANT_MANAGER_STATE_DOWN) {
-		supplicant_interface_clean (info->self);
+	if (task->new_state == NM_SUPPLICANT_MANAGER_STATE_DOWN) {
+		supplicant_interface_release (task->self);
 
 		if (nm_device_get_state (device) > NM_DEVICE_STATE_UNAVAILABLE) {
 			nm_device_state_changed (device, NM_DEVICE_STATE_UNAVAILABLE,
@@ -797,8 +848,7 @@
 		}
 	}
 
-	g_slice_free (struct state_cb_data, info);
-
+	finish_supplicant_task (task, FALSE);
 	return FALSE;
 }
 
@@ -814,8 +864,10 @@
 		    old_state);
 
 	schedule_state_handler (NM_DEVICE_ETHERNET (user_data),
-					    supplicant_mgr_state_cb_handler,
-					    new_state, old_state);
+	                        supplicant_mgr_state_cb_handler,
+	                        new_state,
+	                        old_state,
+	                        TRUE);
 }
 
 static NMSupplicantConfig *
@@ -848,17 +900,17 @@
 static gboolean
 supplicant_iface_state_cb_handler (gpointer user_data)
 {
-	struct state_cb_data *info = (struct state_cb_data *) user_data;
-	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (info->self);
-	NMDevice *device = NM_DEVICE (info->self);
+	SupplicantStateTask *task = (SupplicantStateTask *) user_data;
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (task->self);
+	NMDevice *device = NM_DEVICE (task->self);
 
-	if (info->new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) {
+	if (task->new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) {
 		NMSupplicantConfig *config;
 		const char *iface;
 		gboolean success = FALSE;
 
 		iface = nm_device_get_iface (device);
-		config = build_supplicant_config (info->self);
+		config = build_supplicant_config (task->self);
 		if (config) {
 			success = nm_supplicant_interface_set_config (priv->supplicant.iface, config);
 			g_object_unref (config);
@@ -871,17 +923,16 @@
 
 		if (!success)
 			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED);
-	} else if (info->new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
+	} else if (task->new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
 		NMDeviceState state = nm_device_get_state (device);
 
-		supplicant_interface_clean (info->self);
+		supplicant_interface_release (task->self);
 
 		if (nm_device_is_activating (device) || state == NM_DEVICE_STATE_ACTIVATED)
 			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
 	}
 
-	g_slice_free (struct state_cb_data, info);
-
+	finish_supplicant_task (task, FALSE);
 	return FALSE;
 }
 
@@ -900,18 +951,19 @@
 	schedule_state_handler (NM_DEVICE_ETHERNET (user_data),
 	                        supplicant_iface_state_cb_handler,
 	                        new_state,
-	                        old_state);
+	                        old_state,
+	                        FALSE);
 }
 
 static gboolean
 supplicant_iface_connection_state_cb_handler (gpointer user_data)
 {
-	struct state_cb_data *info = (struct state_cb_data *) user_data;
-	NMDevice *dev = NM_DEVICE (info->self);
+	SupplicantStateTask *task = (SupplicantStateTask *) user_data;
+	NMDevice *dev = NM_DEVICE (task->self);
 
-	if (info->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED) {
-		remove_supplicant_interface_connection_error_handler (info->self);
-		remove_supplicant_timeouts (info->self);
+	if (task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED) {
+		remove_supplicant_interface_error_handler (task->self);
+		remove_supplicant_timeouts (task->self);
 
 		/* If this is the initial association during device activation,
 		 * schedule the next activation stage.
@@ -921,9 +973,9 @@
 				    nm_device_get_iface (dev));
 			nm_device_activate_schedule_stage3_ip_config_start (dev);
 		}
-	} else if (info->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED) {
+	} else if (task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED) {
 		if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED || nm_device_is_activating (dev)) {
-			NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (info->self);
+			NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (task->self);
 
 			/* Start the link timeout so we allow some time for reauthentication */
 			if (!priv->link_timeout_id)
@@ -931,8 +983,7 @@
 		}
 	}
 
-	g_slice_free (struct state_cb_data, info);
-
+	finish_supplicant_task (task, FALSE);
 	return FALSE;
 }
 
@@ -948,17 +999,20 @@
 	schedule_state_handler (NM_DEVICE_ETHERNET (user_data),
 	                        supplicant_iface_connection_state_cb_handler,
 	                        new_state,
-	                        old_state);
+	                        old_state,
+	                        FALSE);
 }
 
 static gboolean
 supplicant_iface_connection_error_cb_handler (gpointer user_data)
 {
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
 
-	supplicant_interface_clean (self);
+	supplicant_interface_release (self);
 	nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED);
 
+	priv->supplicant.iface_con_error_cb_id = 0;
 	return FALSE;
 }
 
@@ -968,12 +1022,18 @@
                                       const char *message,
                                       gpointer user_data)
 {
-	NMDevice *device = NM_DEVICE (user_data);
+	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+	guint id;
 
 	nm_info ("Activation (%s/wired): association request to the supplicant failed: %s - %s",
-	         nm_device_get_iface (device), name, message);
+	         nm_device_get_iface (NM_DEVICE (self)), name, message);
+
+	if (priv->supplicant.iface_con_error_cb_id)
+		g_source_remove (priv->supplicant.iface_con_error_cb_id);
 
-	g_idle_add (supplicant_iface_connection_error_cb_handler, device);
+	id = g_idle_add (supplicant_iface_connection_error_cb_handler, self);
+	priv->supplicant.iface_con_error_cb_id = id;
 }
 
 static NMActStageReturn
@@ -1017,16 +1077,19 @@
 supplicant_connection_timeout_cb (gpointer user_data)
 {
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
 	NMDevice *device = NM_DEVICE (self);
 	NMActRequest *req;
 	const char *iface;
 
+	priv->supplicant.con_timeout_id = 0;
+
 	iface = nm_device_get_iface (device);
 
 	/* Authentication failed, encryption key is probably bad */
 	nm_info ("Activation (%s/wired): association took too long.", iface);
 
-	supplicant_interface_clean (self);
+	supplicant_interface_release (self);
 	req = nm_device_get_act_request (device);
 	g_assert (req);
 
@@ -1050,7 +1113,7 @@
 	priv->supplicant.iface = nm_supplicant_manager_get_iface (priv->supplicant.mgr, iface, FALSE);
 	if (!priv->supplicant.iface) {
 		nm_warning ("Couldn't initialize supplicant interface for %s.", iface);
-		supplicant_interface_clean (self);
+		supplicant_interface_release (self);
 
 		return FALSE;
 	}
@@ -1290,7 +1353,7 @@
 		priv->ppp_manager = NULL;
 	}
 
-	supplicant_interface_clean (NM_DEVICE_ETHERNET (device));
+	supplicant_interface_release (NM_DEVICE_ETHERNET (device));
 }
 
 static gboolean
@@ -1345,7 +1408,8 @@
 static void
 nm_device_ethernet_dispose (GObject *object)
 {
-	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (object);
+	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object);
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
 	NMNetlinkMonitor *monitor;
 
 	if (priv->dispose_has_run) {
@@ -1355,6 +1419,12 @@
 
 	priv->dispose_has_run = TRUE;
 
+	/* Clean up all pending supplicant tasks */
+	while (priv->supplicant.iface_tasks)
+		finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.iface_tasks->data, TRUE);
+	while (priv->supplicant.mgr_tasks)
+		finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.mgr_tasks->data, TRUE);
+
 	monitor = nm_netlink_monitor_get ();
 	if (priv->link_connected_id) {
 		g_signal_handler_disconnect (monitor, priv->link_connected_id);

Modified: trunk/src/nm-device-wifi.c
==============================================================================
--- trunk/src/nm-device-wifi.c	(original)
+++ trunk/src/nm-device-wifi.c	Thu Sep 25 10:02:28 2008
@@ -17,7 +17,8 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2005 Red Hat, Inc.
+ * (C) Copyright 2005 - 2008 Red Hat, Inc.
+ * (C) Copyright 2007 - 2008 Novell, Inc.
  */
 
 #include <glib.h>
@@ -106,20 +107,32 @@
 #define NM_WIFI_ERROR (nm_wifi_error_quark ())
 #define NM_TYPE_WIFI_ERROR (nm_wifi_error_get_type ()) 
 
+typedef struct SupplicantStateTask {
+	NMDeviceWifi *self;
+	guint32 new_state;
+	guint32 old_state;
+	gboolean mgr_task;
+	guint source_id;
+} SupplicantStateTask;
 
 typedef struct Supplicant {
 	NMSupplicantManager *   mgr;
 	NMSupplicantInterface * iface;
 
 	/* signal handler ids */
-	guint                   mgr_state_id;
-	guint                   iface_error_id;
-	guint                   iface_state_id;
-	guint                   iface_scanned_ap_id;
-	guint                   iface_scan_result_id;
-	guint                   iface_con_state_id;
+	guint mgr_state_id;
+	guint iface_error_id;
+	guint iface_state_id;
+	guint iface_scanned_ap_id;
+	guint iface_scan_result_id;
+	guint iface_con_state_id;
+
+	/* Timeouts and idles */
+	guint iface_con_error_cb_id;
+	guint con_timeout_id;
 
-	guint                   con_timeout_id;
+	GSList *mgr_tasks;
+	GSList *iface_tasks;
 } Supplicant;
 
 struct _NMDeviceWifiPrivate
@@ -147,11 +160,11 @@
 	guint8			scan_interval; /* seconds */
 	guint               pending_scan_id;
 
-	Supplicant          supplicant;
+	Supplicant      supplicant;
 
-	guint32             failed_link_count;
-	guint               periodic_source_id;
-	guint               link_timeout_id;
+	guint32         failed_link_count;
+	guint           periodic_source_id;
+	guint           link_timeout_id;
 
 	/* Static options from driver */
 	guint8			we_version;
@@ -405,7 +418,6 @@
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 
 	priv->dispose_has_run = FALSE;
-	priv->supplicant.iface_error_id = 0;
 	priv->scanning = FALSE;
 	priv->ap_list = NULL;
 	priv->we_version = 0;
@@ -590,6 +602,49 @@
 }
 
 static void
+finish_supplicant_task (SupplicantStateTask *task, gboolean remove_source)
+{
+	NMDeviceWifi *self = task->self;
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+
+	/* idle/timeout handlers should pass FALSE for remove_source, since they
+	 * will tell glib to remove their source from the mainloop by returning
+	 * FALSE when they exit.  When called from this NMDevice's dispose handler,
+	 * remove_source should be TRUE to cancel all outstanding idle/timeout
+	 * handlers asynchronously.
+	 */
+	if (task->source_id && remove_source)
+		g_source_remove (task->source_id);
+
+	if (task->mgr_task)
+		priv->supplicant.mgr_tasks = g_slist_remove (priv->supplicant.mgr_tasks, task);
+	else
+		priv->supplicant.iface_tasks = g_slist_remove (priv->supplicant.iface_tasks, task);
+
+	memset (task, 0, sizeof (SupplicantStateTask));
+	g_slice_free (SupplicantStateTask, task);
+}
+
+static void
+remove_supplicant_interface_error_handler (NMDeviceWifi *self)
+{
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+
+	if (!priv->supplicant.iface)
+		return;
+
+	if (priv->supplicant.iface_error_id > 0) {
+		g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_error_id);
+		priv->supplicant.iface_error_id = 0;
+	}
+
+	if (priv->supplicant.iface_con_error_cb_id > 0) {
+		g_source_remove (priv->supplicant.iface_con_error_cb_id);
+		priv->supplicant.iface_con_error_cb_id = 0;
+	}
+}
+
+static void
 supplicant_interface_release (NMDeviceWifi *self)
 {
 	NMDeviceWifiPrivate *priv;
@@ -603,10 +658,11 @@
 	/* Reset the scan interval to be pretty frequent when disconnected */
 	priv->scan_interval = SCAN_INTERVAL_MIN + SCAN_INTERVAL_STEP;
 
-	if (priv->supplicant.iface_error_id > 0) {
-		g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_error_id);
-		priv->supplicant.iface_error_id = 0;
-	}
+	remove_supplicant_interface_error_handler (self);
+
+	/* Clean up all pending supplicant interface state idle tasks */
+	while (priv->supplicant.iface_tasks)
+		finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.iface_tasks->data, TRUE);
 
 	if (priv->supplicant.iface_state_id > 0) {
 		g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_state_id);
@@ -1945,26 +2001,11 @@
 
 
 static void
-remove_supplicant_interface_connection_error_handler (NMDeviceWifi *self)
-{
-	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
-
-	if (!priv->supplicant.iface)
-		return;
-
-	if (priv->supplicant.iface_error_id != 0) {
-		g_signal_handler_disconnect (priv->supplicant.iface,
-		                             priv->supplicant.iface_error_id);
-		priv->supplicant.iface_error_id = 0;
-	}
-}
-
-static void
 cleanup_association_attempt (NMDeviceWifi *self, gboolean disconnect)
 {
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 
-	remove_supplicant_interface_connection_error_handler (self);
+	remove_supplicant_interface_error_handler (self);
 	remove_supplicant_timeouts (self);
 	if (disconnect && priv->supplicant.iface)
 		nm_supplicant_interface_disconnect (priv->supplicant.iface);
@@ -2074,20 +2115,15 @@
 	return FALSE;
 }
 
-
-struct state_cb_data {
-	NMDeviceWifi * self;
-	guint32 new_state;
-	guint32 old_state;
-};
-
 static gboolean
-schedule_state_handler (NMDeviceWifi * self,
+schedule_state_handler (NMDeviceWifi *self,
                         GSourceFunc handler,
                         guint32 new_state,
-                        guint32 old_state)
+                        guint32 old_state,
+                        gboolean mgr_task)
 {
-	struct state_cb_data * cb_data;
+	NMDeviceWifiPrivate *priv;
+	SupplicantStateTask *task;
 
 	g_return_val_if_fail (self != NULL, FALSE);
 	g_return_val_if_fail (handler != NULL, FALSE);
@@ -2095,18 +2131,24 @@
 	if (new_state == old_state)
 		return TRUE;
 
-	cb_data = g_slice_new0 (struct state_cb_data);
-	if (cb_data == NULL) {
-		nm_warning ("Not enough memory to process supplicant manager state"
-		            " change.");
+	priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+
+	task = g_slice_new0 (SupplicantStateTask);
+	if (!task) {
+		nm_warning ("Not enough memory to process supplicant manager state change.");
 		return FALSE;
 	}
 
-	cb_data->self = self;
-	cb_data->new_state = new_state;
-	cb_data->old_state = old_state;
-
-	g_idle_add (handler, cb_data);
+	task->self = self;
+	task->new_state = new_state;
+	task->old_state = old_state;
+	task->mgr_task = mgr_task;
+
+	task->source_id = g_idle_add (handler, task);
+	if (mgr_task)
+		priv->supplicant.mgr_tasks = g_slist_append (priv->supplicant.mgr_tasks, task);
+	else
+		priv->supplicant.iface_tasks = g_slist_append (priv->supplicant.iface_tasks, task);
 
 	return TRUE;
 }
@@ -2114,37 +2156,34 @@
 static gboolean
 supplicant_iface_state_cb_handler (gpointer user_data)
 {
-	struct state_cb_data *cb_data = (struct state_cb_data *) user_data;
+	SupplicantStateTask *task = (SupplicantStateTask *) user_data;
 	NMDeviceWifi *self;
 	NMDeviceWifiPrivate *priv;
-	guint32 new_state, old_state;
 
-	g_return_val_if_fail (cb_data != NULL, FALSE);
+	g_return_val_if_fail (task != NULL, FALSE);
 
-	self = cb_data->self;
+	self = task->self;
 	priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
- 	new_state = cb_data->new_state;
-	old_state = cb_data->old_state;
 
 	nm_info ("(%s): supplicant interface state change: %d -> %d.",
              nm_device_get_iface (NM_DEVICE (self)),
-             old_state,
-             new_state);
+             task->old_state,
+             task->new_state);
 
-	if (new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) {
+	if (task->new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) {
 		priv->scan_interval = SCAN_INTERVAL_MIN;
 
 		/* Request a scan to get latest results */
 		cancel_pending_scan (self);
 		request_wireless_scan (self);
-	} else if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
+	} else if (task->new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
 		cleanup_association_attempt (self, FALSE);
 		supplicant_interface_release (self);
 		nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE,
 		                         NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
 	}
-	
-	g_slice_free (struct state_cb_data, cb_data);
+
+	finish_supplicant_task (task, FALSE);
 	return FALSE;
 }
 
@@ -2160,19 +2199,18 @@
 	schedule_state_handler (self,
 	                        supplicant_iface_state_cb_handler,
 	                        new_state,
-	                        old_state);
+	                        old_state,
+	                        FALSE);
 }
 
 
 static gboolean
 supplicant_iface_connection_state_cb_handler (gpointer user_data)
 {
-	struct state_cb_data *cb_data = (struct state_cb_data *) user_data;
-	NMDeviceWifi *self = cb_data->self;
+	SupplicantStateTask *task = (SupplicantStateTask *) user_data;
+	NMDeviceWifi *self = task->self;
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 	NMDevice *dev = NM_DEVICE (self);
-	guint32 new_state = cb_data->new_state;
-	guint32 old_state = cb_data->old_state;
 
 	if (!nm_device_get_act_request (dev)) {
 		/* The device is not activating or already activated; do nothing. */
@@ -2180,12 +2218,12 @@
 	}
 
 	nm_info ("(%s): supplicant connection state change: %d -> %d",
-	         nm_device_get_iface (dev), old_state, new_state);
+	         nm_device_get_iface (dev), task->old_state, task->new_state);
 
-	priv->scanning = (new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING);
+	priv->scanning = (task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING);
 
-	if (new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED) {
-		remove_supplicant_interface_connection_error_handler (self);
+	if (task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED) {
+		remove_supplicant_interface_error_handler (self);
 		remove_supplicant_timeouts (self);
 
 		/* If this is the initial association during device activation,
@@ -2201,7 +2239,7 @@
 			         ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)");
 			nm_device_activate_schedule_stage3_ip_config_start (dev);
 		}
-	} else if (new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED) {
+	} else if (task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED) {
 		if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED || nm_device_is_activating (dev)) {
 			/* Start the link timeout so we allow some time for reauthentication,
 			 * use a longer timeout if we are scanning since some cards take a
@@ -2215,7 +2253,7 @@
 	}
 
 out:
-	g_slice_free (struct state_cb_data, cb_data);
+	finish_supplicant_task (task, FALSE);
 	return FALSE;
 }
 
@@ -2231,35 +2269,32 @@
 	schedule_state_handler (self,
 	                        supplicant_iface_connection_state_cb_handler,
 	                        new_state,
-	                        old_state);
+	                        old_state,
+	                        FALSE);
 }
 
 
 static gboolean
 supplicant_mgr_state_cb_handler (gpointer user_data)
 {
-	struct state_cb_data * cb_data = (struct state_cb_data *) user_data;
+	SupplicantStateTask *task = (SupplicantStateTask *) user_data;
 	NMDeviceWifi *self;
 	NMDeviceWifiPrivate *priv;
 	NMDevice *dev;
-	guint32 new_state, old_state;
 	NMDeviceState dev_state;
 
-	g_return_val_if_fail (cb_data != NULL, FALSE);
+	g_return_val_if_fail (task != NULL, FALSE);
 
-	self = cb_data->self;
+	self = task->self;
 	priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 	dev = NM_DEVICE (self);
-	new_state = cb_data->new_state;
-	old_state = cb_data->old_state;
 
 	nm_info ("(%s): supplicant manager is now in state %d (from %d).",
              nm_device_get_iface (NM_DEVICE (self)),
-             new_state,
-             old_state);
+             task->new_state, task->old_state);
 
 	/* If the supplicant went away, release the supplicant interface */
-	if (new_state == NM_SUPPLICANT_MANAGER_STATE_DOWN) {
+	if (task->new_state == NM_SUPPLICANT_MANAGER_STATE_DOWN) {
 		if (priv->supplicant.iface) {
 			cleanup_association_attempt (self, FALSE);
 			supplicant_interface_release (self);
@@ -2269,7 +2304,7 @@
 			nm_device_state_changed (dev, NM_DEVICE_STATE_UNAVAILABLE,
 			                         NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
 		}
-	} else if (new_state == NM_SUPPLICANT_MANAGER_STATE_IDLE) {
+	} else if (task->new_state == NM_SUPPLICANT_MANAGER_STATE_IDLE) {
 		dev_state = nm_device_get_state (dev);
 		if (    priv->enabled
 		    && !priv->supplicant.iface
@@ -2287,7 +2322,7 @@
 		}
 	}
 
-	g_slice_free (struct state_cb_data, cb_data);
+	finish_supplicant_task (task, FALSE);
 	return FALSE;
 }
 
@@ -2302,25 +2337,27 @@
 	schedule_state_handler (self,
 	                        supplicant_mgr_state_cb_handler,
 	                        new_state,
-	                        old_state);
+	                        old_state,
+	                        TRUE);
 }
 
 struct iface_con_error_cb_data {
-	NMDeviceWifi * self;
-	char * name;
-	char * message;
+	NMDeviceWifi *self;
+	char *name;
+	char *message;
 };
 
-
 static gboolean
 supplicant_iface_connection_error_cb_handler (gpointer user_data)
 {
+	NMDeviceWifi *self;
+	NMDeviceWifiPrivate *priv;
 	struct iface_con_error_cb_data * cb_data = (struct iface_con_error_cb_data *) user_data;
-	NMDeviceWifi *          self;
 
 	g_return_val_if_fail (cb_data != NULL, FALSE);
 
 	self = cb_data->self;
+	priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 
 	if (!nm_device_is_activating (NM_DEVICE (self)))
 		goto out;
@@ -2335,6 +2372,7 @@
 	nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
 
 out:
+	priv->supplicant.iface_con_error_cb_id = 0;
 	g_free (cb_data->name);
 	g_free (cb_data->message);
 	g_slice_free (struct iface_con_error_cb_data, cb_data);
@@ -2348,10 +2386,12 @@
                                       const char * message,
                                       NMDeviceWifi * self)
 {
-	struct iface_con_error_cb_data * cb_data;
-	guint                            id;
+	NMDeviceWifiPrivate *priv;
+	struct iface_con_error_cb_data *cb_data;
+	guint id;
 
 	g_return_if_fail (self != NULL);
+	priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 
 	cb_data = g_slice_new0 (struct iface_con_error_cb_data);
 	if (cb_data == NULL) {
@@ -2363,7 +2403,11 @@
 	cb_data->name = g_strdup (name);
 	cb_data->message = g_strdup (message);
 
+	if (priv->supplicant.iface_con_error_cb_id)
+		g_source_remove (priv->supplicant.iface_con_error_cb_id);
+
 	id = g_idle_add (supplicant_iface_connection_error_cb_handler, cb_data);
+	priv->supplicant.iface_con_error_cb_id = id;
 }
 
 static void
@@ -3095,6 +3139,12 @@
 		priv->periodic_source_id = 0;
 	}
 
+	/* Clean up all pending supplicant tasks */
+	while (priv->supplicant.iface_tasks)
+		finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.iface_tasks->data, TRUE);
+	while (priv->supplicant.mgr_tasks)
+		finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.mgr_tasks->data, TRUE);
+
 	cleanup_association_attempt (self, TRUE);
 	supplicant_interface_release (self);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]