NetworkManager r3785 - in trunk: . src



Author: dcbw
Date: Mon Jun 30 17:34:56 2008
New Revision: 3785
URL: http://svn.gnome.org/viewvc/NetworkManager?rev=3785&view=rev

Log:
2008-06-30  Dan Williams  <dcbw redhat com>

	Attempt to fix various issues causing rh #448889.  Mainly, to qualify for
	the DISCONNECTED state, the device must not be rfkilled _and_ have a valid
	priv->supplicant.iface.  When either condition is false, the device should
	transition back to UNAVAILABLE because it cannot be used.

	* src/nm-device-wifi.c
		- (constructor): cleanup; connect to supplicant manager here since the
			supplicant manager is always around
		- (supplicant_interface_acquire): rename from init_supplicant_interface,
			ensure the supplicant manager is in the IDLE state
		- (supplicant_interface_release): rename from cleanup_supplicant_interface,
			cancel any pending scans too
		- (real_bring_up): don't set up the supplicnat interface here, because
			we need the supplicant interface at times when the device may not
			be "up"
		- (real_take_down): just remove the periodic source
		- (schedule_scan): ensure a state that would peg the CPU doesn't happen
		- (remove_supplicant_interface_connection_error_handler): cleanup; don't
			do anything if there's no supplicant interface
		- (cleanup_association_attempt): cleanup
		- (supplicant_iface_state_cb_handler): request an immediate scan when
			the interface enters the READY state; transition to UNAVAILABLE
			state when the interface goes down because the device can't be used
			without a supplicant interface
		- (supplicant_mgr_state_cb_handler): if the supplicant goes away, clean
			up and transition to UNAVAILABLE; if the supplicant becomes ready,
			acquire the supplicant interface and transition to DISCONNECTED
			if the radio isn't killed
		- (nm_device_wifi_dispose): move most of device_cleanup() here
		- (state_changed_cb): release any existing supplicant interface; if the
			radio is enabled then try to acquire a new supplicant interface;
			if the radio is enabled and a supplicant interface has been acquired,
			we can transition to DISCONNECTED
		- (nm_device_wifi_set_enabled): if bringing the hardware up failed,
			don't enable the radio, because HAL probably lied to us about the
			killswitch being off.  If bringing the hardware up worked, then
			try to grab a supplicant interface, and if that was successful,
			transition to DISCONNECTED



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

Modified: trunk/src/nm-device-wifi.c
==============================================================================
--- trunk/src/nm-device-wifi.c	(original)
+++ trunk/src/nm-device-wifi.c	Mon Jun 30 17:34:56 2008
@@ -54,15 +54,6 @@
                                                GPtrArray **aps,
                                                GError **err);
 
-static guint32 nm_device_wifi_get_frequency (NMDeviceWifi *self);
-
-static void nm_device_wifi_set_ssid (NMDeviceWifi *self,
-                                                const GByteArray * ssid);
-
-#if DEBUG
-static void nm_device_wifi_ap_list_print (NMDeviceWifi *self);
-#endif
-
 #include "nm-device-wifi-glue.h"
 
 
@@ -166,21 +157,30 @@
 	gboolean		has_scan_capa_ssid;
 };
 
+static guint32 nm_device_wifi_get_frequency (NMDeviceWifi *self);
+
+static void nm_device_wifi_set_ssid (NMDeviceWifi *self, const GByteArray * ssid);
+
+#if DEBUG
+static void nm_device_wifi_ap_list_print (NMDeviceWifi *self);
+#endif
+
+static gboolean request_wireless_scan (gpointer user_data);
 
 static void	schedule_scan (NMDeviceWifi *self, gboolean backoff);
 
 static void	cancel_pending_scan (NMDeviceWifi *self);
 
-static int	wireless_qual_to_percent (const struct iw_quality *qual,
-                                         const struct iw_quality *max_qual,
-                                         const struct iw_quality *avg_qual);
+static int wireless_qual_to_percent (const struct iw_quality *qual,
+                                     const struct iw_quality *max_qual,
+                                     const struct iw_quality *avg_qual);
 
 static void cleanup_association_attempt (NMDeviceWifi * self,
                                          gboolean disconnect);
 
-static void		remove_supplicant_timeouts (NMDeviceWifi *self);
+static void remove_supplicant_timeouts (NMDeviceWifi *self);
 
-static void		nm_device_wifi_disable_encryption (NMDeviceWifi *self);
+static void nm_device_wifi_disable_encryption (NMDeviceWifi *self);
 
 static void supplicant_iface_state_cb (NMSupplicantInterface * iface,
                                        guint32 new_state,
@@ -205,10 +205,6 @@
                                      guint32 old_state,
                                      NMDeviceWifi *self);
 
-static void cleanup_supplicant_interface (NMDeviceWifi * self);
-
-static void device_cleanup (NMDeviceWifi *self);
-
 static guint32 nm_device_wifi_get_bitrate (NMDeviceWifi *self);
 
 
@@ -463,11 +459,10 @@
 	NMDeviceWifi *self;
 	NMDeviceWifiPrivate *priv;
 	const char *iface;
-	int fd;
+	int fd, i, err;
 	struct iw_range range;
 	struct iw_range_with_scan_capa *scan_capa_range;
 	struct iwreq wrq;
-	int i;
 
 	klass = G_OBJECT_CLASS (nm_device_wifi_parent_class);
 	object = klass->constructor (type, n_construct_params, construct_params);
@@ -488,7 +483,9 @@
 	wrq.u.data.pointer = (caddr_t) &range;
 	wrq.u.data.length = sizeof (struct iw_range);
 
-	if (ioctl (fd, SIOCGIWRANGE, &wrq) < 0)
+	err = ioctl (fd, SIOCGIWRANGE, &wrq);
+	close (fd);
+	if (err < 0)
 		goto error;
 
 	priv->max_qual.qual = range.max_qual.qual;
@@ -526,55 +523,115 @@
 	/* 802.11 wireless-specific capabilities */
 	priv->capabilities = get_wireless_capabilities (self, &range, wrq.u.data.length);
 
-	close (fd);
+	/* Connect to the supplicant manager */
+	priv->supplicant.mgr = nm_supplicant_manager_get ();
+	priv->supplicant.mgr_state_id = g_signal_connect (priv->supplicant.mgr,
+	                                                  "state",
+	                                                  G_CALLBACK (supplicant_mgr_state_cb),
+	                                                  self);
+
 	return object;
 
 error:
-	if (fd >= 0)
-		close (fd);
 	g_object_unref (object);
 	return NULL;
 }
 
+static gboolean
+supplicant_interface_acquire (NMDeviceWifi *self)
+{
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+	guint id, mgr_state;
+
+	g_return_val_if_fail (self != NULL, FALSE);
+	g_return_val_if_fail (priv->supplicant.mgr != NULL, FALSE);
+	/* interface already acquired? */
+	g_return_val_if_fail (priv->supplicant.iface == NULL, TRUE);
+
+	mgr_state = nm_supplicant_manager_get_state (priv->supplicant.mgr);
+	g_return_val_if_fail (mgr_state == NM_SUPPLICANT_MANAGER_STATE_IDLE, FALSE);
+
+	priv->supplicant.iface = nm_supplicant_manager_get_iface (priv->supplicant.mgr,
+	                                                          nm_device_get_iface (NM_DEVICE (self)),
+	                                                          TRUE);
+	if (priv->supplicant.iface == NULL) {
+		nm_warning ("Couldn't initialize supplicant interface for %s.",
+		            nm_device_get_iface (NM_DEVICE (self)));
+		return FALSE;
+	}
+
+	id = g_signal_connect (priv->supplicant.iface,
+	                       "state",
+	                       G_CALLBACK (supplicant_iface_state_cb),
+	                       self);
+	priv->supplicant.iface_state_id = id;
+
+	id = g_signal_connect (priv->supplicant.iface,
+	                       "scanned-ap",
+	                       G_CALLBACK (supplicant_iface_scanned_ap_cb),
+	                       self);
+	priv->supplicant.iface_scanned_ap_id = id;
+
+	id = g_signal_connect (priv->supplicant.iface,
+	                       "scan-result",
+	                       G_CALLBACK (supplicant_iface_scan_result_cb),
+	                       self);
+	priv->supplicant.iface_scan_result_id = id;
+
+	id = g_signal_connect (priv->supplicant.iface,
+	                       "connection-state",
+	                       G_CALLBACK (supplicant_iface_connection_state_cb),
+	                       self);
+	priv->supplicant.iface_con_state_id = id;
+
+	return TRUE;
+}
+
 static void
-init_supplicant_interface (NMDeviceWifi * self)
+supplicant_interface_release (NMDeviceWifi *self)
 {
-	Supplicant * sup;
-	guint id;
+	NMDeviceWifiPrivate *priv;
 
 	g_return_if_fail (self != NULL);
-	sup = (Supplicant *) &self->priv->supplicant;
 
-	sup->iface = nm_supplicant_manager_get_iface (sup->mgr,
-												  nm_device_get_iface (NM_DEVICE (self)),
-												  TRUE);
-	if (sup->iface == NULL) {
-		nm_warning ("Couldn't initialize supplicant interface for %s.",
-		            nm_device_get_iface (NM_DEVICE (self)));
-	} else {
-		id = g_signal_connect (sup->iface,
-		                       "state",
-		                       G_CALLBACK (supplicant_iface_state_cb),
-		                       self);
-		sup->iface_state_id = id;
-
-		id = g_signal_connect (sup->iface,
-		                       "scanned-ap",
-		                       G_CALLBACK (supplicant_iface_scanned_ap_cb),
-		                       self);
-		sup->iface_scanned_ap_id = id;
-
-		id = g_signal_connect (sup->iface,
-		                       "scan-result",
-		                       G_CALLBACK (supplicant_iface_scan_result_cb),
-		                       self);
-		sup->iface_scan_result_id = id;
-
-		id = g_signal_connect (sup->iface,
-		                       "connection-state",
-		                       G_CALLBACK (supplicant_iface_connection_state_cb),
-		                       self);
-		sup->iface_con_state_id = id;
+	priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+
+	cancel_pending_scan (self);
+
+	/* 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;
+	}
+
+	if (priv->supplicant.iface_state_id > 0) {
+		g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_state_id);
+		priv->supplicant.iface_state_id = 0;
+	}
+
+	if (priv->supplicant.iface_scanned_ap_id > 0) {
+		g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_scanned_ap_id);
+		priv->supplicant.iface_scanned_ap_id = 0;
+	}
+
+	if (priv->supplicant.iface_scan_result_id > 0) {
+		g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_scan_result_id);
+		priv->supplicant.iface_scan_result_id = 0;
+	}
+
+	if (priv->supplicant.iface_con_state_id > 0) {
+		g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_con_state_id);
+		priv->supplicant.iface_con_state_id = 0;
+	}
+
+	if (priv->supplicant.iface) {
+		/* Tell the supplicant to disconnect from the current AP */
+		nm_supplicant_interface_disconnect (priv->supplicant.iface);
+
+		nm_supplicant_manager_release_iface (priv->supplicant.mgr, priv->supplicant.iface);
+		priv->supplicant.iface = NULL;
 	}
 }
 
@@ -763,19 +820,7 @@
 	NMDeviceWifi *self = NM_DEVICE_WIFI (dev);
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 
-	nm_device_wifi_set_mode (self, NM_802_11_MODE_INFRA);
-
-	priv->supplicant.mgr = nm_supplicant_manager_get ();
-	priv->supplicant.mgr_state_id = g_signal_connect (priv->supplicant.mgr,
-													  "state",
-													  G_CALLBACK (supplicant_mgr_state_cb),
-													  self);
-	if (nm_supplicant_manager_get_state (priv->supplicant.mgr) == NM_SUPPLICANT_MANAGER_STATE_IDLE)
-		init_supplicant_interface (self);
-
-	/* Peridoically update signal strength */
 	priv->periodic_source_id = g_timeout_add (6000, nm_device_wifi_periodic_update, self);
-
 	return TRUE;
 }
 
@@ -797,8 +842,9 @@
 }
 
 static void
-device_cleanup (NMDeviceWifi *self)
+real_take_down (NMDevice *dev)
 {
+	NMDeviceWifi *self = NM_DEVICE_WIFI (dev);
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 
 	if (priv->periodic_source_id) {
@@ -806,47 +852,12 @@
 		priv->periodic_source_id = 0;
 	}
 
-	cancel_pending_scan (self);
-	/* Reset the scan interval to be pretty frequent when disconnected */
-	priv->scan_interval = SCAN_INTERVAL_MIN + SCAN_INTERVAL_STEP;
-
 	cleanup_association_attempt (self, TRUE);
-
-	/* Tell the supplicant to disconnect from the current AP */
-	if (priv->supplicant.iface)
-		nm_supplicant_interface_disconnect (priv->supplicant.iface);
-
-	cleanup_supplicant_interface (self);
-
-	if (priv->supplicant.mgr_state_id) {
-		g_signal_handler_disconnect (priv->supplicant.mgr, priv->supplicant.mgr_state_id);
-		priv->supplicant.mgr_state_id = 0;
-	}
-
-	if (priv->supplicant.mgr) {
-		g_object_unref (priv->supplicant.mgr);
-		priv->supplicant.mgr = NULL;
-	}
-
-	if (priv->ssid) {
-		g_byte_array_free (priv->ssid, TRUE);
-		priv->ssid = NULL;
-	}
-
-
 	set_current_ap (self, NULL);
 	remove_all_aps (self);
 }
 
 static void
-real_take_down (NMDevice *dev)
-{
-	NMDeviceWifi *self = NM_DEVICE_WIFI (dev);
-
-	device_cleanup (self);
-}
-
-static void
 real_deactivate_quickly (NMDevice *dev)
 {
 	NMDeviceWifi *	self = NM_DEVICE_WIFI (dev);
@@ -1521,6 +1532,8 @@
 	NMDeviceState dev_state;
 	gboolean is_disconnected = FALSE;
 
+	g_return_val_if_fail (priv->supplicant.iface != NULL, FALSE);
+
 	sup_state = nm_supplicant_interface_get_connection_state (priv->supplicant.iface);
 	dev_state = nm_device_get_state (NM_DEVICE (self));
 
@@ -1608,6 +1621,11 @@
 				priv->scan_interval = MAX(priv->scan_interval, SCAN_INTERVAL_MIN + SCAN_INTERVAL_STEP);
 				/* ... or more than 120s */
 				priv->scan_interval = MIN(priv->scan_interval, SCAN_INTERVAL_MAX);
+		} else if (!backoff && (priv->scan_interval == 0)) {
+			/* Invalid combination; would cause continual rescheduling of
+			 * the scan and hog CPU.  Reset to something minimally sane.
+			 */
+			priv->scan_interval = 5;
 		}
 	}
 }
@@ -1896,26 +1914,29 @@
 
 
 static void
-remove_supplicant_interface_connection_error_handler (NMDeviceWifi * self)
+remove_supplicant_interface_connection_error_handler (NMDeviceWifi *self)
 {
-	g_return_if_fail (self != NULL);
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 
-	if (self->priv->supplicant.iface_error_id != 0) {
-		g_signal_handler_disconnect (self->priv->supplicant.iface,
-		                             self->priv->supplicant.iface_error_id);
-		self->priv->supplicant.iface_error_id = 0;
+	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)
+cleanup_association_attempt (NMDeviceWifi *self, gboolean disconnect)
 {
-	g_return_if_fail (self != NULL);
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
 
 	remove_supplicant_interface_connection_error_handler (self);
 	remove_supplicant_timeouts (self);
-	if (disconnect && self->priv->supplicant.iface)
-		nm_supplicant_interface_disconnect (self->priv->supplicant.iface);
+	if (disconnect && priv->supplicant.iface)
+		nm_supplicant_interface_disconnect (priv->supplicant.iface);
 }
 
 
@@ -2057,10 +2078,10 @@
 static gboolean
 supplicant_iface_state_cb_handler (gpointer user_data)
 {
-	struct state_cb_data *  cb_data = (struct state_cb_data *) user_data;
-	NMDeviceWifi * self;
+	struct state_cb_data *cb_data = (struct state_cb_data *) user_data;
+	NMDeviceWifi *self;
 	NMDeviceWifiPrivate *priv;
-	guint32                 new_state, old_state;
+	guint32 new_state, old_state;
 
 	g_return_val_if_fail (cb_data != NULL, FALSE);
 
@@ -2076,11 +2097,14 @@
 
 	if (new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) {
 		priv->scan_interval = SCAN_INTERVAL_MIN;
-		schedule_scan (self, TRUE);
-	} else if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
+
+		/* Request a scan to get latest results */
 		cancel_pending_scan (self);
+		request_wireless_scan (self);
+	} else if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
 		cleanup_association_attempt (self, FALSE);
-		cleanup_supplicant_interface (self);
+		supplicant_interface_release (self);
+		nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE);
 	}
 	
 	g_slice_free (struct state_cb_data, cb_data);
@@ -2174,57 +2198,21 @@
 }
 
 
-static void
-cleanup_supplicant_interface (NMDeviceWifi * self)
-{
-	Supplicant * sup;
-
-	g_return_if_fail (self != NULL);
-
-	sup = &self->priv->supplicant;
-
-	if (sup->iface_error_id > 0) {
-		g_signal_handler_disconnect (sup->iface, sup->iface_error_id);
-		sup->iface_error_id = 0;
-	}
-
-	if (sup->iface_state_id > 0) {
-		g_signal_handler_disconnect (sup->iface, sup->iface_state_id);
-		sup->iface_state_id = 0;
-	}
-
-	if (sup->iface_scanned_ap_id > 0) {
-		g_signal_handler_disconnect (sup->iface, sup->iface_scanned_ap_id);
-		sup->iface_scanned_ap_id = 0;
-	}
-
-	if (sup->iface_scan_result_id > 0) {
-		g_signal_handler_disconnect (sup->iface, sup->iface_scan_result_id);
-		sup->iface_scan_result_id = 0;
-	}
-
-	if (sup->iface_con_state_id > 0) {
-		g_signal_handler_disconnect (sup->iface, sup->iface_con_state_id);
-		sup->iface_con_state_id = 0;
-	}
-
-	if (sup->iface) {
-		nm_supplicant_manager_release_iface (sup->mgr, sup->iface);
-		sup->iface = NULL;
-	}
-}
-
-
 static gboolean
 supplicant_mgr_state_cb_handler (gpointer user_data)
 {
 	struct state_cb_data * cb_data = (struct state_cb_data *) user_data;
-	NMDeviceWifi * self;
+	NMDeviceWifi *self;
+	NMDeviceWifiPrivate *priv;
+	NMDevice *dev;
 	guint32 new_state, old_state;
+	NMDeviceState dev_state;
 
 	g_return_val_if_fail (cb_data != NULL, FALSE);
 
 	self = cb_data->self;
+	priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+	dev = NM_DEVICE (self);
 	new_state = cb_data->new_state;
 	old_state = cb_data->old_state;
 
@@ -2235,20 +2223,26 @@
 
 	/* If the supplicant went away, release the supplicant interface */
 	if (new_state == NM_SUPPLICANT_MANAGER_STATE_DOWN) {
-		if (self->priv->supplicant.iface) {
-			NMDevice * dev = NM_DEVICE (self);
-
+		if (priv->supplicant.iface) {
 			cleanup_association_attempt (self, FALSE);
-			cleanup_supplicant_interface (self);
+			supplicant_interface_release (self);
 
-			if (nm_device_is_activating (dev)) {
-				nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED);
-			}
+			if (nm_device_is_activating (dev))
+				nm_device_state_changed (dev, NM_DEVICE_STATE_UNAVAILABLE);
 		}
 	} else if (new_state == NM_SUPPLICANT_MANAGER_STATE_IDLE) {
-		if (!self->priv->supplicant.iface) {
+		dev_state = nm_device_get_state (dev);
+		if (    priv->enabled
+		    && !priv->supplicant.iface
+		    && (dev_state >= NM_DEVICE_STATE_UNAVAILABLE)) {
 			/* request a supplicant interface from the supplicant manager */
-			init_supplicant_interface (self);
+			supplicant_interface_acquire (self);
+
+			/* if wireless is enabled and we have a supplicant interface,
+			 * we can transition to the DISCONNECTED state.
+			 */
+			if (priv->supplicant.iface)
+				nm_device_state_changed (dev, NM_DEVICE_STATE_DISCONNECTED);
 		}
 	}
 
@@ -3030,7 +3024,31 @@
 
 	priv->dispose_has_run = TRUE;
 
-	device_cleanup (self);
+	if (priv->periodic_source_id) {
+		g_source_remove (priv->periodic_source_id);
+		priv->periodic_source_id = 0;
+	}
+
+	cleanup_association_attempt (self, TRUE);
+	supplicant_interface_release (self);
+
+	if (priv->supplicant.mgr_state_id) {
+		g_signal_handler_disconnect (priv->supplicant.mgr, priv->supplicant.mgr_state_id);
+		priv->supplicant.mgr_state_id = 0;
+	}
+
+	if (priv->supplicant.mgr) {
+		g_object_unref (priv->supplicant.mgr);
+		priv->supplicant.mgr = NULL;
+	}
+
+	if (priv->ssid) {
+		g_byte_array_free (priv->ssid, TRUE);
+		priv->ssid = NULL;
+	}
+
+	set_current_ap (self, NULL);
+	remove_all_aps (self);
 
 	if (priv->state_to_disconnected_id) {
 		g_source_remove (priv->state_to_disconnected_id);
@@ -3206,18 +3224,30 @@
 		priv->state_to_disconnected_id = 0;
 	}
 
+	if (state <= NM_DEVICE_STATE_UNAVAILABLE) {
+		/* Clean up the supplicant interface because in these states the
+		 * device cannot be used.
+		 */
+		if (priv->supplicant.iface)
+			supplicant_interface_release (self);
+	}
+
 	switch (state) {
 	case NM_DEVICE_STATE_UNMANAGED:
 		clear_aps = TRUE;
 		break;
 	case NM_DEVICE_STATE_UNAVAILABLE:
-		/* If transitioning to UNAVAILBLE and the device is not rfkilled,
-		 * transition to DISCONNECTED because the device is ready to use.
-		 * Otherwise the rfkill/enabled handler handle the transition to
-		 * DISCONNECTED when the device is no longer rfkilled.
+		/* If the device is enabled and the supplicant manager is ready,
+		 * acquire a supplicant interface and transition to DISCONNECTED because
+		 * the device is now ready to use.
 		 */
-		if (priv->enabled)
-			priv->state_to_disconnected_id = g_idle_add (unavailable_to_disconnected, self);
+		if (priv->enabled) {
+			if (!priv->supplicant.iface)
+				supplicant_interface_acquire (self);
+
+			if (priv->supplicant.iface)
+				priv->state_to_disconnected_id = g_idle_add (unavailable_to_disconnected, self);
+		}
 		clear_aps = TRUE;
 		break;
 	case NM_DEVICE_STATE_ACTIVATED:
@@ -3308,18 +3338,26 @@
 	priv->enabled = enabled;
 
 	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
-	if (state >= NM_DEVICE_STATE_UNAVAILABLE) {
-		if (enabled) {
-			nm_device_hw_bring_up (NM_DEVICE (self), TRUE);
-			nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED);
+	if (state < NM_DEVICE_STATE_UNAVAILABLE)
+		return;
 
-			/* Request a scan to get results immediately */
-			cancel_pending_scan (self);
-			request_wireless_scan (self);
-		} else {
-			nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE);
-			nm_device_hw_take_down (NM_DEVICE (self), TRUE);
+	if (enabled) {
+		g_warn_if_fail (state == NM_DEVICE_STATE_UNAVAILABLE);
+
+		if (!nm_device_hw_bring_up (NM_DEVICE (self), TRUE)) {
+			/* The device sucks, or HAL was lying to us about the killswitch state */
+			priv->enabled = FALSE;
+			return;
 		}
+
+		if (!priv->supplicant.iface)
+			supplicant_interface_acquire (self);
+
+		if (priv->supplicant.iface)
+			nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED);
+	} else {
+		nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE);
+		nm_device_hw_take_down (NM_DEVICE (self), TRUE);
 	}
 }
 



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