cooperative scanning patch



Hi,

Here's a reworked patch that makes use of the netlink/wireless event
stuff from about a month ago.  It's got a few features:

* Notices driver-provided scan completion events and pulls from them
* Uses wpa_supplicant for scanning when a wireless connection is active
* Works around older drivers that don't send scan completion events
* Doesn't block waiting for scan results

Please test it out (against HEAD) and see if it works for you.

I've noticed one fairly large issue though...  wpa_supplicant seems to
get its link state confused and doesn't reconnect.  I don't know if this
is due to the driver not sending reconnect events or whether
wpa_supplicant is just dumb.  It doesn't appear that wpa_supplicant has
much special logic to 'fake' a connection through a scan, which sucks
for us.  More investigation is certainly needed.

Dan

Index: src/nm-device-802-11-wireless.c
===================================================================
RCS file: /cvs/gnome/NetworkManager/src/nm-device-802-11-wireless.c,v
retrieving revision 1.66
diff -u -r1.66 nm-device-802-11-wireless.c
--- src/nm-device-802-11-wireless.c	8 Mar 2006 14:45:14 -0000	1.66
+++ src/nm-device-802-11-wireless.c	30 Mar 2006 04:12:11 -0000
@@ -73,10 +73,12 @@
 	gint8			num_freqs;
 	double			freqs[IW_MAX_FREQUENCIES];
 
-	GMutex *			scan_mutex;
+	gboolean			scanning;
 	NMAccessPointList *	ap_list;
 	guint8			scan_interval; /* seconds */
 	guint32			last_scan;
+	GSource *			scan_timeout;
+	GSource *			pending_scan;
 
 	struct _Supplicant	supplicant;
 
@@ -97,25 +99,21 @@
 	guint32		results_len;
 } NMWirelessScanResults;
 
-typedef struct
-{
-	NMDevice80211Wireless *	dev;
-	gboolean		force;
-} NMWirelessScanCB;
-
 
 static void	nm_device_802_11_wireless_ap_list_clear (NMDevice80211Wireless *self);
 
 static gboolean nm_device_802_11_wireless_scan (gpointer user_data);
 
+static void	cancel_scan_results_timeout (NMDevice80211Wireless *self);
+
+static void	cancel_pending_scan (NMDevice80211Wireless *self);
+
+static void	request_and_convert_scan_results (NMDevice80211Wireless *self);
+
 static gboolean	process_scan_results (NMDevice80211Wireless *dev,
                                           const guint8 *res_buf,
                                           guint32 res_buf_len);
-
-static gboolean	get_scan_results (NMDevice80211Wireless *dev,
-                                      NMSock *sk,
-                                      guint8 **out_res_buf,
-                                      guint32 *data_len);
+static void	schedule_scan (NMDevice80211Wireless *self);
 
 static int	wireless_qual_to_percent (const struct iw_quality *qual,
                                          const struct iw_quality *max_qual,
@@ -140,7 +138,7 @@
                                                      char *data,
                                                      int data_len,
                                                      NMDevice80211Wireless *self);
-
+                                                     
 static guint nm_wireless_scan_interval_to_seconds (NMWirelessScanInterval interval)
 {
 	guint seconds;
@@ -263,9 +261,7 @@
 	NMSock *				sk;
 	NmNetlinkMonitor *		monitor;
 
-	self->priv->scan_mutex = g_mutex_new ();
-	nm_register_mutex_desc (self->priv->scan_mutex, "Scan Mutex");
-
+	self->priv->scanning = FALSE;
 	self->priv->ap_list = nm_ap_list_new (NETWORK_TYPE_DEVICE);
 
 	app_data = nm_device_get_app_data (NM_DEVICE (self));
@@ -395,7 +391,10 @@
 				}
 				break;
 			case SIOCGIWSCAN:
-				/* Got some scan results */
+nm_info ("(%s) got scan results wireless event.", nm_device_get_iface (NM_DEVICE (self)));
+				cancel_scan_results_timeout (self);
+				request_and_convert_scan_results (self);
+				schedule_scan (self);
 				break;
 		}
 		pos += iwe->len;
@@ -475,16 +474,11 @@
 	/* Start the scanning timeout for devices that can do scanning */
 	if (nm_device_get_capabilities (dev) & NM_DEVICE_CAP_WIRELESS_SCAN)
 	{
-		NMWirelessScanCB *	scan_cb;
-
-		scan_cb = g_malloc0 (sizeof (NMWirelessScanCB));
-		scan_cb->dev = self;
-		scan_cb->force = TRUE;
-
-		source = g_idle_source_new ();
-		g_source_set_callback (source, nm_device_802_11_wireless_scan, scan_cb, NULL);
-		source_id = g_source_attach (source, nm_device_get_main_context (dev));
-		g_source_unref (source);
+		self->priv->pending_scan = g_idle_source_new ();
+		g_source_set_callback (self->priv->pending_scan,
+				nm_device_802_11_wireless_scan, self, NULL);
+		source_id = g_source_attach (self->priv->pending_scan,
+				nm_device_get_main_context (dev));
 	}
 
 	/* Peridoically update link status and signal strength */
@@ -616,8 +610,11 @@
 {
 	gboolean have_link = FALSE;
 
-	/* Checking hardware's ESSID during a scan is doesn't work. */
-	nm_lock_mutex (self->priv->scan_mutex, __func__);
+	/* Fake a link if we're scanning, we'll drop it later
+	 * if it's really dead.
+	 */
+	if (self->priv->scanning)
+		return TRUE;
 
 	if (is_associated (self))
 	{
@@ -631,8 +628,6 @@
 		}
 	}
 
-	nm_unlock_mutex (self->priv->scan_mutex, __func__);
-
 	if (!have_link)
 	{
 		self->priv->failed_link_count++;
@@ -1261,20 +1256,20 @@
 
 	g_return_if_fail (self != NULL);
 
+	/* Signal strength is pretty meaningless during a scan */
+	if (self->priv->scanning)
+		return;
+
 	app_data = nm_device_get_app_data (NM_DEVICE (self));
 	g_assert (app_data);
 
-	/* Grab the scan lock since our strength is meaningless during a scan. */
-	if (!nm_try_acquire_mutex (self->priv->scan_mutex, __FUNCTION__))
-		return;
-
 	/* If we aren't the active device, we don't really have a signal strength
 	 * that would mean anything.
 	 */
 	if (!nm_device_get_act_request (NM_DEVICE (self)))
 	{
 		self->priv->strength = -1;
-		goto out;
+		return;
 	}
 
 	if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL)))
@@ -1310,9 +1305,6 @@
 		nm_dbus_signal_device_strength_change (app_data->dbus_connection, self, percent);
 
 	self->priv->strength = percent;
-
-out:
-	nm_unlock_mutex (self->priv->scan_mutex, __func__);
 }
 
 
@@ -1419,6 +1411,7 @@
 }
 
 
+#if 0
 /*
  * nm_device_get_frequency
  *
@@ -1458,7 +1451,6 @@
 	return freq;
 }
 
-
 /*
  * nm_device_set_frequency
  *
@@ -1534,7 +1526,7 @@
 		nm_dev_sock_close (sk);
 	}
 }
-
+#endif
 
 /*
  * nm_device_get_bitrate
@@ -1566,7 +1558,7 @@
 	return ((err >= 0) ? wrq.u.bitrate.value / 1000000 : 0);
 }
 
-
+#if 0
 /*
  * nm_device_set_bitrate
  *
@@ -1611,6 +1603,7 @@
 		nm_dev_sock_close (sk);
 	}
 }
+#endif
 
 
 /*
@@ -1738,34 +1731,6 @@
 	} else nm_warning ("could not get wireless control socket for device %s", iface);
 }
 
-/*
- * nm_device_wireless_schedule_scan
- *
- * Schedule a wireless scan in the /device's/ thread.
- *
- */
-static void
-schedule_scan (NMDevice80211Wireless *self)
-{
-	GSource *			wscan_source;
-	guint			wscan_source_id;
-	NMWirelessScanCB *	scan_cb;
-	GMainContext *		context;
-
-	g_return_if_fail (self != NULL);
-
-	scan_cb = g_malloc0 (sizeof (NMWirelessScanCB));
-	scan_cb->dev = self;
-	scan_cb->force = FALSE;
-
-	wscan_source = g_timeout_source_new (self->priv->scan_interval * 1000);
-	g_source_set_callback (wscan_source, nm_device_802_11_wireless_scan, scan_cb, NULL);
-	context = nm_device_get_main_context (NM_DEVICE (self));
-	wscan_source_id = g_source_attach (wscan_source, context);
-	g_source_unref (wscan_source);
-}
-
-
 static void
 free_process_scan_cb_data (NMWirelessScanResults *cb_data)
 {
@@ -1780,14 +1745,14 @@
 }
 
 /*
- * nm_device_wireless_process_scan_results
+ * convert_scan_results
  *
  * Process results of an iwscan() into our own AP lists.  We're an idle function,
  * but we never reschedule ourselves.
  *
  */
 static gboolean
-handle_scan_results (gpointer user_data)
+convert_scan_results (gpointer user_data)
 {
 	NMWirelessScanResults *	cb_data = (NMWirelessScanResults *) user_data;
 	NMDevice80211Wireless *	self;
@@ -1800,6 +1765,7 @@
 	g_return_val_if_fail (cb_data != NULL, FALSE);	
 
 	self = NM_DEVICE_802_11_WIRELESS (cb_data->dev);
+nm_info ("(%s) converting scan results.", nm_device_get_iface (NM_DEVICE (self)));
 	if (!self || !cb_data->results)
 	{
 		free_process_scan_cb_data (cb_data);
@@ -1876,37 +1842,198 @@
 }
 
 
+#define SCAN_SLEEP_CENTISECONDS		10	/* sleep 1/10 of a second, waiting for data */
+static void
+request_and_convert_scan_results (NMDevice80211Wireless *self)
+{
+	NMSock *sk;
+	NMWirelessScanResults *scan_results = NULL;
+	const char *iface;
+	struct iwreq iwr;
+	guint8 tries = 0;
+	gboolean success = FALSE;
+	guint8 *buf = NULL;
+	size_t buflen = IW_SCAN_MAX_DATA;
+
+	g_return_if_fail (self != NULL);
+
+	if (!(sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL)))
+		return;
+
+nm_info ("(%s) request_and_convert called.", nm_device_get_iface (NM_DEVICE (self)));
+	iface = nm_device_get_iface (NM_DEVICE (self));
+	for (;;)
+	{
+		if (!(buf = g_malloc0 (buflen)))
+			break;
+		iwr.u.data.pointer = buf;
+		iwr.u.data.flags = 0;
+		iwr.u.data.length = buflen;
+
+		if (iw_get_ext (nm_dev_sock_get_fd (sk), iface, SIOCGIWSCAN, &iwr) == 0)
+		{
+			/* success */
+			buflen = iwr.u.data.length;
+			success = TRUE;
+			break;
+		}
+
+		g_free (buf);
+		buf = NULL;
+
+		if ((errno == E2BIG) && (buflen < 100000))	/* Buffer not big enough */
+		{
+			buflen *= 2;
+		}
+		else if (errno == EAGAIN)	/* Card doesn't have results yet */
+		{
+			/* We've already waited for the scan data, so don't give
+			 * drivers too much slack here.
+			 */
+			if (tries > 4 * SCAN_SLEEP_CENTISECONDS)
+			{
+				nm_warning ("card took too much time scanning.  Get a better one.");
+				break;
+			}
+			g_usleep (G_USEC_PER_SEC / SCAN_SLEEP_CENTISECONDS);
+			tries++;
+		}
+		else if (errno == ENODATA)	/* No scan results */
+		{
+			buflen = 0;
+			success = TRUE;
+			break;
+		}
+		else		/* Random errors */
+		{
+			nm_warning ("unknown error, or the card returned too much scan info: %s",
+					  strerror (errno));
+			break;
+		}
+	}
+	nm_dev_sock_close (sk);
+
+	if (success)
+	{
+		NMData *	app_data = nm_device_get_app_data (NM_DEVICE (self));
+		GSource *	convert_source = g_idle_source_new ();
+		GTimeVal	cur_time;
+
+		/* We run the scan processing function from the main thread, since it must deliver
+		 * messages over DBUS.  Plus, that way the main thread is the only thread that has
+		 * to modify the device's access point list.
+		 */
+nm_info ("(%s) scheduling scan request conversion in main context.", nm_device_get_iface (NM_DEVICE (self)));
+		scan_results = g_malloc0 (sizeof (NMWirelessScanResults));
+		g_object_ref (G_OBJECT (self));
+		scan_results->dev = self;
+		scan_results->results = buf;
+		scan_results->results_len = buflen;
+
+		g_source_set_callback (convert_source, convert_scan_results, scan_results, NULL);
+		g_source_attach (convert_source, app_data->main_context);
+		g_source_unref (convert_source);
+		g_get_current_time (&cur_time);
+		self->priv->last_scan = cur_time.tv_sec;
+	}
+}
+
+
+/*
+ * scan_results_timeout
+ *
+ * Request scan results from the card if it has taken more time than
+ * we allow.  Also works around drivers that don't send notifications of
+ * completed scans to userspace.
+ */
+static gboolean
+scan_results_timeout (NMDevice80211Wireless *self)
+{
+	g_return_val_if_fail (self != NULL, FALSE);
+
+nm_info ("(%s) scan_request_timeout called.", nm_device_get_iface (NM_DEVICE (self)));
+	request_and_convert_scan_results (self);
+	schedule_scan (self);
+	g_source_unref (self->priv->scan_timeout);  /* Balance g_timeout_source_new() */
+	self->priv->scan_timeout = NULL;
+	return FALSE;  /* Balance g_source_attach(), destroyed on return */
+}
+
+
+/*
+ * schedule_scan_results_timeout
+ *
+ * For cards that don't send a wireless event for scan results,
+ * we hit the card after the timeout and explicitly ask for them.
+ *
+ */
+static void
+schedule_scan_results_timeout (NMDevice80211Wireless *self)
+{
+	GMainContext *	context;
+
+	g_return_if_fail (self != NULL);
+
+	cancel_scan_results_timeout (self);
+
+	/* Wait 10 seconds for scan results */
+nm_info ("(%s) scheduling scan request timeout.", nm_device_get_iface (NM_DEVICE (self)));
+	self->priv->scan_timeout = g_timeout_source_new (10000);
+	g_source_set_callback (self->priv->scan_timeout,
+			(GSourceFunc) scan_results_timeout, self, NULL);
+	context = nm_device_get_main_context (NM_DEVICE (self));
+	g_source_attach (self->priv->scan_timeout, context);
+}
+
+
+/*
+ * cancel_scan_results_timeout
+ *
+ * Cancel an existing scan results timeout
+ *
+ */
+static void
+cancel_scan_results_timeout (NMDevice80211Wireless *self)
+{
+	g_return_if_fail (self != NULL);
+
+nm_info ("(%s) cancel_scan_results_timeout called.", nm_device_get_iface (NM_DEVICE (self)));
+	if (self->priv->scan_timeout)
+	{
+		g_source_destroy (self->priv->scan_timeout);  /* Balance g_source_attach() */
+		g_source_unref (self->priv->scan_timeout); /* Balance g_timeout_source_new() */
+		self->priv->scan_timeout = NULL;
+nm_info ("(%s) cancelled scan request timeout.", nm_device_get_iface (NM_DEVICE (self)));
+	}
+}
+
+
 /*
  * nm_device_802_11_wireless_scan
  *
- * Get a list of access points this device can see.
+ * Trigger a scan request
  *
  */
 static gboolean
 nm_device_802_11_wireless_scan (gpointer user_data)
 {
-	NMWirelessScanCB *		scan_cb = (NMWirelessScanCB *)(user_data);
-	NMDevice80211Wireless *	self = NULL;
-	NMWirelessScanResults *	scan_results = NULL;
+	NMDevice80211Wireless *	self = NM_DEVICE_802_11_WIRELESS (user_data);
 	guint32				caps;
 	NMData *				app_data;
+	gboolean				success = FALSE;
+	const char *			iface;
 
-	g_return_val_if_fail (scan_cb != NULL, FALSE);
+	g_return_val_if_fail (self != NULL, FALSE);
 
-	self = scan_cb->dev;
-	if (!self || !nm_device_get_app_data (NM_DEVICE (self)))
-	{
-		g_free (scan_cb);
-		return FALSE;
-	}
-	app_data = nm_device_get_app_data (NM_DEVICE (self));
+	if (!(app_data = nm_device_get_app_data (NM_DEVICE (self))))
+		goto out;
 
 	caps = nm_device_get_capabilities (NM_DEVICE (self));
 	if (!(caps & NM_DEVICE_CAP_NM_SUPPORTED) || !(caps & NM_DEVICE_CAP_WIRELESS_SCAN))
-	{
-		g_free (scan_cb);
-		return FALSE;
-	}
+		goto out;
+
+	g_source_unref (self->priv->pending_scan);	/* Balance g_timeout_source_new() */
+	self->priv->pending_scan = NULL;
 
 	/* Reschedule ourselves if all wireless is disabled, we're asleep,
 	 * or we are currently activating.
@@ -1916,7 +2043,8 @@
 		|| (nm_device_is_activating (NM_DEVICE (self)) == TRUE))
 	{
 		nm_device_802_11_wireless_set_scan_interval (app_data, self, NM_WIRELESS_SCAN_INTERVAL_INIT);
-		goto reschedule;
+		schedule_scan (self);
+		goto out;
 	}
 
 	/*
@@ -1927,115 +2055,102 @@
 	if ((self->priv->num_freqs > 14) && nm_device_is_activated (NM_DEVICE (self)) == TRUE)
 	{
 		nm_device_802_11_wireless_set_scan_interval (app_data, self, NM_WIRELESS_SCAN_INTERVAL_ACTIVE);
-		goto reschedule;
+		schedule_scan (self);
+		goto out;
 	}
 
-	/* Grab the scan mutex */
-	if (nm_try_acquire_mutex (self->priv->scan_mutex, __func__))
+nm_info ("(%s) Requesting a scan.", nm_device_get_iface (NM_DEVICE (self)));
+	self->priv->scanning = TRUE;
+
+	/* Device must be up before we can scan */
+	if (nm_device_bring_up_wait (NM_DEVICE (self), 1))
 	{
-		NMSock *	sk;
-		gboolean	devup_err;
-		const char *	iface;
+		schedule_scan (self);
+		goto out;
+	}
 
-		/* Device must be up before we can scan */
-		devup_err = nm_device_bring_up_wait (NM_DEVICE (self), 1);
-		if (devup_err)
-		{
-			nm_unlock_mutex (self->priv->scan_mutex, __func__);
-			goto reschedule;
-		}
+	/* If we're currently connected to an AP, let wpa_supplicant initiate
+	 * the scan request rather than doing it ourselves.
+	 */
+	iface = nm_device_get_iface (NM_DEVICE (self));
+	if (self->priv->supplicant.ctrl)
+	{
+		if (nm_utils_supplicant_request_with_check (self->priv->supplicant.ctrl,
+				"OK", __func__, NULL, "SCAN"))
+{
+nm_info ("(%s) triggered supplicant scan.", nm_device_get_iface (NM_DEVICE (self)));
+			success = TRUE;
+}
+	}
+	else
+	{
+		NMSock *		sk;
 
-		iface = nm_device_get_iface (NM_DEVICE (self));
 		if ((sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __FUNCTION__, NULL)))
 		{
-			int			orig_mode;
-			double		orig_freq = 0;
-			int			orig_rate = 0;
-			struct iwreq	wrq;
-
-			orig_mode = nm_device_802_11_wireless_get_mode (self);
-			if (orig_mode == IW_MODE_ADHOC)
-			{
-				orig_freq = nm_device_802_11_wireless_get_frequency (self);
-				orig_rate = nm_device_802_11_wireless_get_bitrate (self);
-			}
-
-			/* Must be in infrastructure mode during scan, otherwise we don't get a full
-			 * list of scan results.  Scanning doesn't work well in Ad-Hoc mode :( 
-			 */
-			nm_device_802_11_wireless_set_mode (self, IW_MODE_INFRA);
-
-			/* We only unlock the frequency if the card is in adhoc mode, in case it is
-			 * a costly operation for the driver.
-			 */
-			if (orig_mode == IW_MODE_ADHOC)
-				nm_device_802_11_wireless_set_frequency (self, 0);
+			struct iwreq wrq;
 
 			wrq.u.data.pointer = NULL;
 			wrq.u.data.flags = 0;
 			wrq.u.data.length = 0;
-			if (iw_set_ext (nm_dev_sock_get_fd (sk), iface, SIOCSIWSCAN, &wrq) < 0)
-			{
-				nm_warning ("could not trigger wireless scan on device %s: %s",
-						iface, strerror (errno));
-			}
-			else
-			{
-				guint8 * 	results = NULL;
-				guint32	results_len = 0;
-
-				/* Initial pause for card to return data */
-				g_usleep (G_USEC_PER_SEC / 4);
-
-				if (get_scan_results (self, sk, &results, &results_len))
-				{
-					scan_results = g_malloc0 (sizeof (NMWirelessScanResults));
-					g_object_ref (G_OBJECT (self));
-					scan_results->dev = self;
-					scan_results->results = results;
-					scan_results->results_len = results_len;
-				}
-				else
-					nm_warning ("device %s returned an error.", iface);
-			}
-
-			nm_device_802_11_wireless_set_mode (self, orig_mode);
-			/* Only set frequency if ad-hoc mode */
-			if (orig_mode == IW_MODE_ADHOC)
-			{
-				nm_device_802_11_wireless_set_frequency (self, orig_freq);
-				nm_device_802_11_wireless_set_bitrate (self, orig_rate);
-			}
-
+			if (iw_set_ext (nm_dev_sock_get_fd (sk), iface, SIOCSIWSCAN, &wrq) == 0)
+{
+nm_info ("(%s) triggered manual scan.", nm_device_get_iface (NM_DEVICE (self)));
+				success = TRUE;
+}
 			nm_dev_sock_close (sk);
 		}
-		nm_unlock_mutex (self->priv->scan_mutex, __func__);
 	}
 
-	/* We run the scan processing function from the main thread, since it must deliver
-	 * messages over DBUS.  Plus, that way the main thread is the only thread that has
-	 * to modify the device's access point list.
-	 */
-	if (scan_results != NULL)
+	if (success)
 	{
-		guint	scan_process_source_id = 0;
-		GSource *	scan_process_source = g_idle_source_new ();
-		GTimeVal	cur_time;
+		schedule_scan_results_timeout (self);
+	}
+	else
+	{
+		nm_warning ("could not trigger wireless scan on device %s: %s",
+				iface, strerror (errno));
+		schedule_scan (self);
+	}
 
-		g_source_set_callback (scan_process_source, handle_scan_results, scan_results, NULL);
-		scan_process_source_id = g_source_attach (scan_process_source, app_data->main_context);
-		g_source_unref (scan_process_source);
+out:
+	return FALSE;	/* Balance g_source_attach(), destroyed on return */
+}
 
-		g_get_current_time (&cur_time);
-		self->priv->last_scan = cur_time.tv_sec;
-	}
 
-reschedule:
-	/* Make sure we reschedule ourselves so we keep scanning */
-	schedule_scan (self);
+/*
+ * nm_device_wireless_schedule_scan
+ *
+ * Schedule a wireless scan in the /device's/ thread.
+ *
+ */
+static void
+schedule_scan (NMDevice80211Wireless *self)
+{
+	g_return_if_fail (self != NULL);
 
-	g_free (scan_cb);
-	return FALSE;
+	cancel_pending_scan (self);
+
+nm_info ("(%s) Scheduling wireless scan.", nm_device_get_iface (NM_DEVICE (self)));
+	self->priv->pending_scan = g_timeout_source_new (self->priv->scan_interval * 1000);
+	g_source_set_callback (self->priv->pending_scan, nm_device_802_11_wireless_scan, self, NULL);
+	g_source_attach (self->priv->pending_scan, nm_device_get_main_context (NM_DEVICE (self)));
+}
+
+
+static void
+cancel_pending_scan (NMDevice80211Wireless *self)
+{
+	g_return_if_fail (self != NULL);
+
+	self->priv->scanning = FALSE;
+	if (self->priv->pending_scan)
+	{
+		g_source_destroy (self->priv->pending_scan);  /* Balance g_source_attach() */
+		g_source_unref (self->priv->pending_scan);  /* Balance g_timeout_source_new() */
+		self->priv->pending_scan = NULL;
+nm_info ("(%s) cancelled pending scan.", nm_device_get_iface (NM_DEVICE (self)));
+	}
 }
 
 
@@ -2289,7 +2404,7 @@
 static gboolean
 link_timeout_cb (gpointer user_data)
 {
-	NMDevice *			dev = NM_DEVICE (user_data);
+	NMDevice * dev = NM_DEVICE (user_data);
 
 	g_assert (dev);
 
@@ -2332,6 +2447,8 @@
 	wpa_ctrl_recv (ctrl, message, &len);
 	message[len] = '\0';
 
+nm_info ("(%s): supplicant said '%s'\n", nm_device_get_iface (NM_DEVICE (self)), message);
+
 	if (strstr (message, WPA_EVENT_CONNECTED) != NULL)
 	{
 		remove_link_timeout (self);
@@ -2357,7 +2474,7 @@
 		if (nm_device_is_activated (dev) || nm_device_is_activating (dev))
 		{
 			/* Start the link timeout so we allow some time for reauthentication */
-			if (self->priv->link_timeout == NULL)
+			if ((self->priv->link_timeout == NULL) && !self->priv->scanning)
 			{
 				GMainContext *	context = nm_device_get_main_context (dev);
 				self->priv->link_timeout = g_timeout_source_new (8000);
@@ -3032,7 +3149,9 @@
 	nm_device_802_11_wireless_ap_list_clear (self);
 	if (self->priv->ap_list)
 		nm_ap_list_unref (self->priv->ap_list);
-	g_mutex_free (self->priv->scan_mutex);
+
+	cancel_scan_results_timeout (self);
+	cancel_pending_scan (self);
 
 	g_signal_handler_disconnect (G_OBJECT (data->netlink_monitor),
 		self->priv->wireless_event_id);
@@ -3162,81 +3281,6 @@
 	}
 	return 0;
 }
-
-#define SCAN_SLEEP_CENTISECONDS		10	/* sleep 1/10 of a second, waiting for data */
-static gboolean
-get_scan_results (NMDevice80211Wireless *dev,
-                  NMSock *sk,
-                  guint8 **out_res_buf,
-                  guint32 *data_len)
-{
-	struct iwreq iwr;
-	guint8 *res_buf;
-	size_t res_buf_len = IW_SCAN_MAX_DATA;
-	guint8 tries = 0;
-	gboolean success = FALSE;
-
-	g_return_val_if_fail (dev != NULL, FALSE);
-	g_return_val_if_fail (sk != NULL, FALSE);
-	g_return_val_if_fail (out_res_buf != NULL, FALSE);
-	g_return_val_if_fail (*out_res_buf == NULL, FALSE);
-	g_return_val_if_fail (data_len != NULL, FALSE);
-
-	*data_len = 0;
-
-	for (;;)
-	{
-		res_buf = g_malloc (res_buf_len);
-		if (!res_buf)
-			break;
-		memset (&iwr, 0, sizeof (struct iwreq));
-		iwr.u.data.pointer = res_buf;
-		iwr.u.data.flags = 0;
-		iwr.u.data.length = res_buf_len;
-
-		if (iw_get_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (NM_DEVICE (dev)), SIOCGIWSCAN, &iwr) == 0)
-		{
-			/* success */
-			*data_len = iwr.u.data.length;
-			*out_res_buf = res_buf;
-			success = TRUE;
-			break;
-		}
-
-		g_free (res_buf);
-		res_buf = NULL;
-
-		if ((errno == E2BIG) && (res_buf_len < 100000))	/* Buffer not big enough */
-		{
-			res_buf_len *= 2;
-		}
-		else if (errno == EAGAIN)	/* Card doesn't have results yet */
-		{
-			if (tries > 20 * SCAN_SLEEP_CENTISECONDS)
-			{
-				nm_warning ("card took too much time scanning.  Get a better one.");
-				break;
-			}
-
-			g_usleep (G_USEC_PER_SEC / SCAN_SLEEP_CENTISECONDS);
-			tries++;
-		}
-		else if (errno == ENODATA)	/* No scan results */
-		{
-			success = TRUE;
-			break;
-		}
-		else		/* Random errors */
-		{
-			nm_warning ("unknown error, or the card returned too much scan info: %s",
-					  strerror (errno));
-			break;
-		}
-	}
-
-	return success;
-}
-
 
 static void
 add_new_ap_to_device_list (NMDevice80211Wireless *dev,


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