2006-04-24 Dan Williams <dcbw@redhat.com>

Commit the async scanning patch

	* src/nm-device-802-11-wireless.c
		- get rid of scan_mutex
		- (wireless_event_helper): act on wireless scan events
		- (real_start): schedule a pending scan
		- (link_to_specific_ap): fake the link to the AP during a scan
		- (nm_device_802_11_wireless_update_signal_strength): ignore signal
			strength during scans
		- (nm_device_get_frequency, nm_device_set_frequency, nm_device_get_bitrate,
			nm_device_set_bitrate): unused with new scanning code, disable
		- (nm_device_wireless_schedule_scan): removed
		- (nm_device_wireless_process_scan_results): renamed to convert_scan_results()
		- (request_and_convert_scan_results): new function; retrieve scan
			results from the driver and schedule the processing function
		- (scan_results_timeout): timeout triggered when card doesn't send
			a scan results wireless event during a certain interval
		- (schedule_scan_results_timeout): new function; schedule the scan
			results timeout
		- (cancel_scan_results_timeout): new function; cancel the scan
			results timeout
		- (nm_device_802_11_wireless_scan): if wpa_supplicant is running, ask it
			to do the scanning.  Otherwise, just request a scan but don't
			grab results here; instead schedule a timeout for scan results and
			let netlink notify us of scan completion events
		- (nm_device_wireless_schedule_scan): new function; schedule a wireless scan
		- (cancel_pending_scan): new function; cancel a pending wireless scan
		- (supplicant_status_cb): ignore disconnect events while scanning
		- (supplicant_exec): wait a bit longer for the supplicant to start up
		- (nm_device_802_11_wireless_dispose): cancel pending scans and results
			timeouts
		- (get_scan_results): removed; folded into request_and_convert_scan_results()


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@1703 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Dan Williams 2006-04-24 21:09:38 +00:00
parent f2042467b5
commit 4a0434fa70
2 changed files with 318 additions and 258 deletions

View file

@ -1,3 +1,38 @@
2006-04-24 Dan Williams <dcbw@redhat.com>
Commit the async scanning patch
* src/nm-device-802-11-wireless.c
- get rid of scan_mutex
- (wireless_event_helper): act on wireless scan events
- (real_start): schedule a pending scan
- (link_to_specific_ap): fake the link to the AP during a scan
- (nm_device_802_11_wireless_update_signal_strength): ignore signal
strength during scans
- (nm_device_get_frequency, nm_device_set_frequency, nm_device_get_bitrate,
nm_device_set_bitrate): unused with new scanning code, disable
- (nm_device_wireless_schedule_scan): removed
- (nm_device_wireless_process_scan_results): renamed to convert_scan_results()
- (request_and_convert_scan_results): new function; retrieve scan
results from the driver and schedule the processing function
- (scan_results_timeout): timeout triggered when card doesn't send
a scan results wireless event during a certain interval
- (schedule_scan_results_timeout): new function; schedule the scan
results timeout
- (cancel_scan_results_timeout): new function; cancel the scan
results timeout
- (nm_device_802_11_wireless_scan): if wpa_supplicant is running, ask it
to do the scanning. Otherwise, just request a scan but don't
grab results here; instead schedule a timeout for scan results and
let netlink notify us of scan completion events
- (nm_device_wireless_schedule_scan): new function; schedule a wireless scan
- (cancel_pending_scan): new function; cancel a pending wireless scan
- (supplicant_status_cb): ignore disconnect events while scanning
- (supplicant_exec): wait a bit longer for the supplicant to start up
- (nm_device_802_11_wireless_dispose): cancel pending scans and results
timeouts
- (get_scan_results): removed; folded into request_and_convert_scan_results()
2006-04-24 Dan Williams <dcbw@redhat.com>
* gnome/applet/applet-dbus.c

View file

@ -73,10 +73,12 @@ struct _NMDevice80211WirelessPrivate
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 @@ typedef struct
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,
@ -263,9 +261,7 @@ real_init (NMDevice *dev)
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,9 @@ wireless_event_helper (gpointer user_data)
}
break;
case SIOCGIWSCAN:
/* Got some scan results */
cancel_scan_results_timeout (self);
request_and_convert_scan_results (self);
schedule_scan (self);
break;
}
pos += iwe->len;
@ -475,16 +473,11 @@ real_start (NMDevice *dev)
/* 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 +609,11 @@ link_to_specific_ap (NMDevice80211Wireless *self,
{
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 +627,6 @@ link_to_specific_ap (NMDevice80211Wireless *self,
}
}
nm_unlock_mutex (self->priv->scan_mutex, __func__);
if (!have_link)
{
self->priv->failed_link_count++;
@ -1261,20 +1255,20 @@ nm_device_802_11_wireless_update_signal_strength (NMDevice80211Wireless *self)
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 +1304,6 @@ nm_device_802_11_wireless_update_signal_strength (NMDevice80211Wireless *self)
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 +1410,7 @@ nm_device_802_11_wireless_set_essid (NMDevice80211Wireless *self,
}
#if 0
/*
* nm_device_get_frequency
*
@ -1458,7 +1450,6 @@ nm_device_802_11_wireless_get_frequency (NMDevice80211Wireless *self)
return freq;
}
/*
* nm_device_set_frequency
*
@ -1534,7 +1525,7 @@ nm_device_802_11_wireless_set_frequency (NMDevice80211Wireless *self,
nm_dev_sock_close (sk);
}
}
#endif
/*
* nm_device_get_bitrate
@ -1566,7 +1557,7 @@ nm_device_802_11_wireless_get_bitrate (NMDevice80211Wireless *self)
return ((err >= 0) ? wrq.u.bitrate.value / 1000000 : 0);
}
#if 0
/*
* nm_device_set_bitrate
*
@ -1611,6 +1602,7 @@ nm_device_802_11_wireless_set_bitrate (NMDevice80211Wireless *self,
nm_dev_sock_close (sk);
}
}
#endif
/*
@ -1738,34 +1730,6 @@ nm_device_802_11_wireless_set_wep_enc_key (NMDevice80211Wireless *self,
} 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 +1744,14 @@ free_process_scan_cb_data (NMWirelessScanResults *cb_data)
}
/*
* 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;
@ -1876,37 +1840,192 @@ handle_scan_results (gpointer user_data)
}
#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;
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.
*/
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);
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 */
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);
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_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 +2035,8 @@ nm_device_802_11_wireless_scan (gpointer user_data)
|| (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 +2047,93 @@ nm_device_802_11_wireless_scan (gpointer user_data)
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__))
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"))
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)
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;
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);
g_get_current_time (&cur_time);
self->priv->last_scan = cur_time.tv_sec;
schedule_scan_results_timeout (self);
}
else
{
nm_warning ("could not trigger wireless scan on device %s: %s",
iface, strerror (errno));
schedule_scan (self);
}
reschedule:
/* Make sure we reschedule ourselves so we keep scanning */
schedule_scan (self);
out:
return FALSE; /* Balance g_source_attach(), destroyed on return */
}
g_free (scan_cb);
return FALSE;
/*
* 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);
cancel_pending_scan (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;
}
}
@ -2289,7 +2387,7 @@ supplicant_watch_cb (GPid pid,
static gboolean
link_timeout_cb (gpointer user_data)
{
NMDevice * dev = NM_DEVICE (user_data);
NMDevice * dev = NM_DEVICE (user_data);
g_assert (dev);
@ -2357,10 +2455,10 @@ supplicant_status_cb (GIOChannel *source,
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);
self->priv->link_timeout = g_timeout_source_new (20000);
g_source_set_callback (self->priv->link_timeout, link_timeout_cb, self, NULL);
g_source_attach (self->priv->link_timeout, context);
}
@ -2526,7 +2624,7 @@ supplicant_exec (NMDevice80211Wireless *self)
/* Crackrock delay so we don't try to talk to wpa_supplicant too early */
/* FIXME: poll the global control socket instead of just sleeping */
g_usleep (G_USEC_PER_SEC);
g_usleep (G_USEC_PER_SEC * 2);
/* Monitor the child process so we know when it stops */
self->priv->supplicant.pid = pid;
@ -3032,7 +3130,9 @@ nm_device_802_11_wireless_dispose (GObject *object)
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);
@ -3163,81 +3263,6 @@ static int hexstr2bin(const char *hex, char *buf, size_t len)
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,
NMAccessPoint *ap)