mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-05 01:47:58 +02:00
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:
parent
f2042467b5
commit
4a0434fa70
2 changed files with 318 additions and 258 deletions
35
ChangeLog
35
ChangeLog
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue