2005-10-15 Dan Williams <dcbw@redhat.com>

Move scanning code into NetworkManager rather than use iwlib's
	iw_scan() function, so that we can figure out AP capabilities.

	* NetworkManager.h
		- Add AP capability bits

	* src/NetworkManagerAP.[ch]
		- Add capability field to NMAccessPoint structure
		- Add WPA & RSN Information Element fields and accessor
			functions to NMAccessPoint

	* src/NetworkManagerDevice.c
		- Remove usage of iw_scan
		- Add scanning code to NetworkManager rather than use
			iw_scan() from iwlib

	* src/NetworkManagerUtils.[ch]
		- (nm_dispose_scan_results): remove, unused


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@1023 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Dan Williams
2005-10-15 04:11:01 +00:00
parent 150bf7ca2d
commit 994948d758
7 changed files with 518 additions and 234 deletions

View File

@@ -1,3 +1,24 @@
2005-10-15 Dan Williams <dcbw@redhat.com>
Move scanning code into NetworkManager rather than use iwlib's
iw_scan() function, so that we can figure out AP capabilities.
* NetworkManager.h
- Add AP capability bits
* src/NetworkManagerAP.[ch]
- Add capability field to NMAccessPoint structure
- Add WPA & RSN Information Element fields and accessor
functions to NMAccessPoint
* src/NetworkManagerDevice.c
- Remove usage of iw_scan
- Add scanning code to NetworkManager rather than use
iw_scan() from iwlib
* src/NetworkManagerUtils.[ch]
- (nm_dispose_scan_results): remove, unused
2005-10-14 Christopher Aillon <caillon@redhat.com> 2005-10-14 Christopher Aillon <caillon@redhat.com>
* gnome/libnm_glib/libnm_glib.c: * gnome/libnm_glib/libnm_glib.c:

View File

@@ -132,6 +132,16 @@ typedef enum NMEncKeyType
#define NM_DEVICE_CAP_WPA_PSK 0x0008 #define NM_DEVICE_CAP_WPA_PSK 0x0008
/*
* Access Point capability bits
*
*/
#define NM_AP_CAP_NONE 0x0000
#define NM_AP_CAP_WEP 0x0001
#define NM_AP_CAP_WPA1 0x0002
#define NM_AP_CAP_WPA2 0x0004
/* /*
* Wireless network modes * Wireless network modes
*/ */

View File

@@ -38,6 +38,13 @@ struct NMAccessPoint
double freq; double freq;
guint16 rate; guint16 rate;
gboolean encrypted; gboolean encrypted;
guint32 capabilities;
/* WPA auxiliary information */
guint8 * wpa_ie;
guint32 wpa_ie_len;
guint8 * rsn_ie;
guint32 rsn_ie_len;
/* Non-scanned attributes */ /* Non-scanned attributes */
gboolean invalid; gboolean invalid;
@@ -639,3 +646,67 @@ gboolean nm_ap_has_manufacturer_default_essid (NMAccessPoint *ap)
return FALSE; return FALSE;
} }
const guint8 * nm_ap_get_wpa_ie (NMAccessPoint *ap, guint32 *length)
{
g_return_val_if_fail (ap != NULL, NULL);
g_return_val_if_fail (length != NULL, NULL);
*length = ap->wpa_ie_len;
return ap->wpa_ie;
}
void nm_ap_set_wpa_ie (NMAccessPoint *ap, const guint8 *wpa_ie, guint32 length)
{
g_return_if_fail (ap != NULL);
if (wpa_ie)
g_return_if_fail ((length > 0) && (length <= AP_MAX_WPA_IE_LEN));
if (ap->wpa_ie)
{
g_free (ap->wpa_ie);
ap->wpa_ie = NULL;
ap->wpa_ie_len = 0;
}
if (wpa_ie)
{
ap->wpa_ie = g_malloc0 (length);
ap->wpa_ie_len = length;
memcpy (ap->wpa_ie, wpa_ie, length);
}
}
const guint8 * nm_ap_get_rsn_ie (NMAccessPoint *ap, guint32 *length)
{
g_return_val_if_fail (ap != NULL, NULL);
g_return_val_if_fail (length != NULL, NULL);
*length = ap->rsn_ie_len;
return ap->rsn_ie;
}
void nm_ap_set_rsn_ie (NMAccessPoint *ap, const guint8 *rsn_ie, guint32 length)
{
g_return_if_fail (ap != NULL);
if (rsn_ie)
g_return_if_fail ((length > 0) && (length <= AP_MAX_WPA_IE_LEN));
if (ap->rsn_ie)
{
g_free (ap->rsn_ie);
ap->rsn_ie = NULL;
ap->rsn_ie_len = 0;
}
if (rsn_ie)
{
ap->rsn_ie = g_malloc0 (length);
ap->rsn_ie_len = length;
memcpy (ap->rsn_ie, rsn_ie, length);
}
}

View File

@@ -28,6 +28,9 @@
typedef struct NMAccessPoint NMAccessPoint; typedef struct NMAccessPoint NMAccessPoint;
#define AP_MAX_WPA_IE_LEN 40
NMAccessPoint * nm_ap_new (void); NMAccessPoint * nm_ap_new (void);
NMAccessPoint * nm_ap_new_from_ap (NMAccessPoint *ap); NMAccessPoint * nm_ap_new_from_ap (NMAccessPoint *ap);
@@ -91,6 +94,12 @@ void nm_ap_set_user_addresses (NMAccessPoint *ap, GSList *list);
gboolean nm_ap_is_enc_key_valid (NMAccessPoint *ap); gboolean nm_ap_is_enc_key_valid (NMAccessPoint *ap);
gboolean nm_is_enc_key_valid (const char *key, NMEncKeyType key_type); gboolean nm_is_enc_key_valid (const char *key, NMEncKeyType key_type);
const guint8 * nm_ap_get_wpa_ie (NMAccessPoint *ap, guint32 *length);
void nm_ap_set_wpa_ie (NMAccessPoint *ap, const guint8 *wpa_ie, guint32 length);
const guint8 * nm_ap_get_rsn_ie (NMAccessPoint *ap, guint32 *length);
void nm_ap_set_rsn_ie (NMAccessPoint *ap, const guint8 *rsn_ie, guint32 length);
/* /*
* NOTE: * NOTE:
* This is not intended to return true for all APs with manufacturer defaults. It is intended to return true for * This is not intended to return true for all APs with manufacturer defaults. It is intended to return true for

View File

@@ -56,6 +56,10 @@ static guint32 nm_device_discover_capabilities (NMDevice *dev);
static gboolean nm_is_driver_supported (NMDevice *dev); static gboolean nm_is_driver_supported (NMDevice *dev);
static guint32 nm_device_wireless_discover_capabilities (NMDevice *dev); static guint32 nm_device_wireless_discover_capabilities (NMDevice *dev);
static guint8 * get_scan_results(NMDevice *dev, NMSock *sk, guint32 *data_len);
static gboolean process_scan_results (NMDevice *dev, const guint8 *res_buf, guint32 res_buf_len);
static void nm_device_activate_schedule_stage1_device_prepare (NMActRequest *req); static void nm_device_activate_schedule_stage1_device_prepare (NMActRequest *req);
static void nm_device_activate_schedule_stage2_device_config (NMActRequest *req); static void nm_device_activate_schedule_stage2_device_config (NMActRequest *req);
static void nm_device_activate_schedule_stage3_ip_config_start (NMActRequest *req); static void nm_device_activate_schedule_stage3_ip_config_start (NMActRequest *req);
@@ -64,7 +68,8 @@ static void nm_device_activate_schedule_stage5_ip_config_commit (NMActRequest *r
typedef struct typedef struct
{ {
NMDevice * dev; NMDevice * dev;
struct wireless_scan_head scan_head; guint8 * results;
guint32 results_len;
} NMWirelessScanResults; } NMWirelessScanResults;
typedef struct typedef struct
@@ -637,9 +642,9 @@ static guint32 nm_device_wireless_discover_capabilities (NMDevice *dev)
{ {
if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL))) if ((sk = nm_dev_sock_open (dev, DEV_WIRELESS, __FUNCTION__, NULL)))
{ {
guint8 we_ver = dev->options.wireless.we_version; struct iwreq wrq;
err = iw_scan (nm_dev_sock_get_fd (sk), (char *) nm_device_get_iface (dev), we_ver, &scan_data); memset (&wrq, 0, sizeof (struct iwreq));
nm_dispose_scan_results (scan_data.result); err = iw_set_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCSIWSCAN, &wrq);
if (!((err == -1) && (errno == EOPNOTSUPP))) if (!((err == -1) && (errno == EOPNOTSUPP)))
caps |= NM_DEVICE_CAP_WIRELESS_SCAN; caps |= NM_DEVICE_CAP_WIRELESS_SCAN;
nm_dev_sock_close (sk); nm_dev_sock_close (sk);
@@ -3937,120 +3942,24 @@ static void nm_device_wireless_schedule_scan (NMDevice *dev)
*/ */
static gboolean nm_device_wireless_process_scan_results (gpointer user_data) static gboolean nm_device_wireless_process_scan_results (gpointer user_data)
{ {
NMWirelessScanResults *results = (NMWirelessScanResults *)user_data; NMWirelessScanResults * cb_data = (NMWirelessScanResults *)user_data;
NMDevice * dev; NMDevice * dev;
wireless_scan *tmp_ap;
NMAPListIter *iter;
GTimeVal cur_time; GTimeVal cur_time;
gboolean list_changed = FALSE; NMAPListIter * iter = NULL;
g_return_val_if_fail (results != NULL, FALSE); g_return_val_if_fail (cb_data != NULL, FALSE);
dev = results->dev; dev = cb_data->dev;
if (!dev || !results->scan_head.result) if (!dev || !cb_data->results)
return FALSE; return FALSE;
g_get_current_time (&cur_time); if (!process_scan_results (dev, cb_data->results, cb_data->results_len))
nm_warning ("nm_device_wireless_process_scan_results(%s): process_scan_results() returned an error.", nm_device_get_iface (dev));
/* Translate iwlib scan results to NM access point list */
for (tmp_ap = results->scan_head.result; tmp_ap; tmp_ap = tmp_ap->next)
{
/* We need at least an ESSID or a MAC address for each access point */
if (tmp_ap->b.has_essid || tmp_ap->has_ap_addr)
{
NMAccessPoint *nm_ap = nm_ap_new ();
int percent;
gboolean new = FALSE;
gboolean strength_changed = FALSE;
gboolean success = FALSE;
/* Copy over info from scan to local structure */
/* ipw2x00 drivers fill in an essid of "<hidden>" if they think the access point
* is hiding its MAC address. Sigh.
*/
if ( !tmp_ap->b.has_essid
|| (tmp_ap->b.essid && !strlen (tmp_ap->b.essid))
|| (tmp_ap->b.essid && !strcmp (tmp_ap->b.essid, "<hidden>"))) /* Stupid ipw drivers use <hidden> */
nm_ap_set_essid (nm_ap, NULL);
else
nm_ap_set_essid (nm_ap, tmp_ap->b.essid);
if (tmp_ap->b.has_key && (tmp_ap->b.key_flags & IW_ENCODE_DISABLED))
{
nm_ap_set_encrypted (nm_ap, FALSE);
nm_ap_set_auth_method (nm_ap, NM_DEVICE_AUTH_METHOD_NONE);
}
else
{
nm_ap_set_encrypted (nm_ap, TRUE);
nm_ap_set_auth_method (nm_ap, NM_DEVICE_AUTH_METHOD_OPEN_SYSTEM);
}
if (tmp_ap->has_ap_addr)
nm_ap_set_address (nm_ap, (const struct ether_addr *)(tmp_ap->ap_addr.sa_data));
if (tmp_ap->b.has_mode)
{
NMNetworkMode mode = NETWORK_MODE_INFRA;
switch (tmp_ap->b.mode)
{
case IW_MODE_INFRA:
mode = NETWORK_MODE_INFRA;
break;
case IW_MODE_ADHOC:
mode = NETWORK_MODE_ADHOC;
break;
default:
mode = NETWORK_MODE_INFRA;
break;
}
nm_ap_set_mode (nm_ap, mode);
}
else
nm_ap_set_mode (nm_ap, NETWORK_MODE_INFRA);
percent = nm_wireless_qual_to_percent (&(tmp_ap->stats.qual),
(const iwqual *)(&dev->options.wireless.max_qual),
(const iwqual *)(&dev->options.wireless.avg_qual));
nm_ap_set_strength (nm_ap, percent);
if (tmp_ap->b.has_freq)
nm_ap_set_freq (nm_ap, tmp_ap->b.freq);
nm_ap_set_last_seen (nm_ap, &cur_time);
/* If the AP is not broadcasting its ESSID, try to fill it in here from our
* allowed list where we cache known MAC->ESSID associations.
*/
if (!nm_ap_get_essid (nm_ap))
nm_ap_list_copy_one_essid_by_address (nm_ap, dev->app_data->allowed_ap_list);
/* Add the AP to the device's AP list */
success = nm_ap_list_merge_scanned_ap (nm_device_ap_list_get (dev), nm_ap, &new, &strength_changed);
if (success)
{
/* Handle dbus signals that we need to broadcast when the AP is added to the list or changes strength */
if (new)
{
nm_dbus_signal_wireless_network_change (dev->app_data->dbus_connection, dev, nm_ap,
NETWORK_STATUS_APPEARED, -1);
list_changed = TRUE;
}
else if (strength_changed)
{
nm_dbus_signal_wireless_network_change (dev->app_data->dbus_connection, dev, nm_ap,
NETWORK_STATUS_STRENGTH_CHANGED, nm_ap_get_strength (nm_ap));
}
}
nm_ap_unref (nm_ap);
}
}
/* Once we have the list, copy in any relevant information from our Allowed list. */ /* Once we have the list, copy in any relevant information from our Allowed list. */
nm_ap_list_copy_properties (nm_device_ap_list_get (dev), dev->app_data->allowed_ap_list); nm_ap_list_copy_properties (nm_device_ap_list_get (dev), dev->app_data->allowed_ap_list);
/* Walk the access point list and remove any access points older than 120s */ /* Walk the access point list and remove any access points older than 180s */
g_get_current_time (&cur_time); g_get_current_time (&cur_time);
if (nm_device_ap_list_get (dev) && (iter = nm_ap_list_iter_new (nm_device_ap_list_get (dev)))) if (nm_device_ap_list_get (dev) && (iter = nm_ap_list_iter_new (nm_device_ap_list_get (dev))))
{ {
@@ -4071,12 +3980,12 @@ static gboolean nm_device_wireless_process_scan_results (gpointer user_data)
const GTimeVal *ap_time = nm_ap_get_last_seen (outdated_ap); const GTimeVal *ap_time = nm_ap_get_last_seen (outdated_ap);
gboolean keep_around = FALSE; gboolean keep_around = FALSE;
/* Don't ever get prune the AP we're currently associated with */ /* Don't ever prune the AP we're currently associated with */
if ( nm_ap_get_essid (outdated_ap) if ( nm_ap_get_essid (outdated_ap)
&& (cur_ap && (nm_null_safe_strcmp (nm_ap_get_essid (cur_ap), nm_ap_get_essid (outdated_ap))) == 0)) && (cur_ap && (nm_null_safe_strcmp (nm_ap_get_essid (cur_ap), nm_ap_get_essid (outdated_ap))) == 0))
keep_around = TRUE; keep_around = TRUE;
if (!keep_around && (ap_time->tv_sec + 120 < cur_time.tv_sec)) if (!keep_around && (ap_time->tv_sec + 180 < cur_time.tv_sec))
outdated_list = g_slist_append (outdated_list, outdated_ap); outdated_list = g_slist_append (outdated_list, outdated_ap);
} }
nm_ap_list_iter_free (iter); nm_ap_list_iter_free (iter);
@@ -4090,7 +3999,6 @@ static gboolean nm_device_wireless_process_scan_results (gpointer user_data)
{ {
nm_dbus_signal_wireless_network_change (dev->app_data->dbus_connection, dev, outdated_ap, NETWORK_STATUS_DISAPPEARED, -1); nm_dbus_signal_wireless_network_change (dev->app_data->dbus_connection, dev, outdated_ap, NETWORK_STATUS_DISAPPEARED, -1);
nm_ap_list_remove_ap (nm_device_ap_list_get (dev), outdated_ap); nm_ap_list_remove_ap (nm_device_ap_list_get (dev), outdated_ap);
list_changed = TRUE;
} }
} }
g_slist_free (outdated_list); g_slist_free (outdated_list);
@@ -4102,58 +4010,6 @@ static gboolean nm_device_wireless_process_scan_results (gpointer user_data)
} }
static gboolean nm_completion_scan_has_results (int tries, nm_completion_args args)
{
NMDevice * dev = args[0];
gboolean * err = args[1];
NMSock * sk = args[2];
NMWirelessScanResults * scan_results = args[3];
int rc;
guint8 we_ver;
g_return_val_if_fail (dev != NULL, TRUE);
g_return_val_if_fail (err != NULL, TRUE);
g_return_val_if_fail (scan_results != NULL, TRUE);
we_ver = dev->options.wireless.we_version;
rc = iw_scan (nm_dev_sock_get_fd (sk), (char *)nm_device_get_iface (dev), we_ver, &(scan_results->scan_head));
*err = FALSE;
if (rc == -1 && errno == ETIME)
{
/* Scans take time. iw_scan's timeout is 15 seconds, so if the card hasn't returned
* scan results after two consecutive runs of iw_scan(), the card sucks.
*/
if (tries >= 1)
{
nm_warning ("Warning: the wireless card (%s) requires too much time for scans. Its driver needs to be fixed.", nm_device_get_iface (dev));
scan_results->scan_head.result = NULL;
*err = TRUE;
return TRUE;
}
else
{
/* Give the card one more chance to return scan results */
scan_results->scan_head.result = NULL;
return FALSE;
}
}
if ((rc == -1 && errno == ENODATA) || (rc == 0 && scan_results->scan_head.result == NULL))
{
/* Card hasn't had time yet to compile full access point list.
* Give it some more time and scan again. If that doesn't
* work, we eventually give up. */
scan_results->scan_head.result = NULL;
return FALSE;
}
else if (rc == -1)
{
scan_results->scan_head.result = NULL;
return TRUE;
}
return TRUE;
}
/* /*
* nm_device_wireless_scan * nm_device_wireless_scan
* *
@@ -4166,6 +4022,8 @@ static gboolean nm_device_wireless_scan (gpointer user_data)
NMDevice * dev = NULL; NMDevice * dev = NULL;
NMWirelessScanResults * scan_results = NULL; NMWirelessScanResults * scan_results = NULL;
guint32 caps; guint32 caps;
guint8 * results = NULL;
guint32 results_len = 0;
g_return_val_if_fail (scan_cb != NULL, FALSE); g_return_val_if_fail (scan_cb != NULL, FALSE);
@@ -4234,10 +4092,7 @@ static gboolean nm_device_wireless_scan (gpointer user_data)
double orig_freq = 0; double orig_freq = 0;
int orig_rate = 0; int orig_rate = 0;
const int interval = 20; const int interval = 20;
const int assoc_pause = nm_device_get_association_pause_value (dev); struct iwreq wrq;
const int delay = G_USEC_PER_SEC / interval;
const int max_tries = assoc_pause * interval;
nm_completion_args args;
orig_mode = nm_device_get_mode (dev); orig_mode = nm_device_get_mode (dev);
if (orig_mode == NETWORK_MODE_ADHOC) if (orig_mode == NETWORK_MODE_ADHOC)
@@ -4252,13 +4107,30 @@ static gboolean nm_device_wireless_scan (gpointer user_data)
nm_device_set_mode (dev, NETWORK_MODE_INFRA); nm_device_set_mode (dev, NETWORK_MODE_INFRA);
nm_device_set_frequency (dev, 0); nm_device_set_frequency (dev, 0);
scan_results = g_malloc0 (sizeof (NMWirelessScanResults)); 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), nm_device_get_iface (dev), SIOCSIWSCAN, &wrq) < 0)
{
nm_warning ("nm_device_wireless_scan(%s): couldn't trigger wireless scan. errno = %d",
nm_device_get_iface (dev), errno);
}
else
{
/* Initial pause for card to return data */
g_usleep (G_USEC_PER_SEC / 4);
args[0] = dev; if ((results = get_scan_results (dev, sk, &results_len)))
args[1] = &err; {
args[2] = sk; scan_results = g_malloc0 (sizeof (NMWirelessScanResults));
args[3] = scan_results; nm_device_ref (dev);
nm_wait_for_completion (max_tries, delay, nm_completion_scan_has_results, NULL, args); scan_results->dev = dev;
scan_results->results = results;
scan_results->results_len = results_len;
}
else
nm_warning ("nm_device_wireless_scan(%s): get_scan_results() returned an error.", nm_device_get_iface (dev));
}
nm_device_set_mode (dev, orig_mode); nm_device_set_mode (dev, orig_mode);
/* Only set frequency if ad-hoc mode */ /* Only set frequency if ad-hoc mode */
@@ -4269,28 +4141,20 @@ static gboolean nm_device_wireless_scan (gpointer user_data)
} }
nm_dev_sock_close (sk); nm_dev_sock_close (sk);
if (!scan_results->scan_head.result)
{
g_free (scan_results);
scan_results = NULL;
}
} }
nm_unlock_mutex (dev->options.wireless.scan_mutex, __FUNCTION__); nm_unlock_mutex (dev->options.wireless.scan_mutex, __FUNCTION__);
} }
/* We run the scan processing function from the main thread, since it must deliver /* 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 * messages over DBUS. Plus, that way the main thread is the only thread that has
* to modify the device's access point list. * to modify the device's access point list.
*/ */
if ((scan_results != NULL) && (scan_results->scan_head.result != NULL)) if (scan_results != NULL)
{ {
guint scan_process_source_id = 0; guint scan_process_source_id = 0;
GSource * scan_process_source = g_idle_source_new (); GSource * scan_process_source = g_idle_source_new ();
GTimeVal cur_time; GTimeVal cur_time;
scan_results->dev = dev;
g_source_set_callback (scan_process_source, nm_device_wireless_process_scan_results, scan_results, NULL); g_source_set_callback (scan_process_source, nm_device_wireless_process_scan_results, scan_results, NULL);
scan_process_source_id = g_source_attach (scan_process_source, dev->app_data->main_context); scan_process_source_id = g_source_attach (scan_process_source, dev->app_data->main_context);
g_source_unref (scan_process_source); g_source_unref (scan_process_source);
@@ -4500,10 +4364,6 @@ out:
return supports_mii; return supports_mii;
} }
/****************************************/
/* End Code ripped from HAL */
/****************************************/
/****************************************/ /****************************************/
/* Test device routes */ /* Test device routes */
@@ -4520,3 +4380,338 @@ gboolean nm_device_is_test_device (NMDevice *dev)
return (dev->test_device); return (dev->test_device);
} }
/*****************************************/
/* Start code ripped from wpa_supplicant */
/*****************************************/
/*
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
static int hex2num(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
return -1;
}
static int hex2byte(const char *hex)
{
int a, b;
a = hex2num(*hex++);
if (a < 0)
return -1;
b = hex2num(*hex++);
if (b < 0)
return -1;
return (a << 4) | b;
}
static int hexstr2bin(const char *hex, u8 *buf, size_t len)
{
int i, a;
const char *ipos = hex;
u8 *opos = buf;
for (i = 0; i < len; i++) {
a = hex2byte(ipos);
if (a < 0)
return -1;
*opos++ = a;
ipos += 2;
}
return 0;
}
static guint8 * get_scan_results (NMDevice *dev, NMSock *sk, guint32 *data_len)
{
struct iwreq iwr;
guint8 *res_buf;
size_t len, res_buf_len = 1000;
guint8 tries = 0;
g_return_val_if_fail (dev != NULL, NULL);
g_return_val_if_fail (nm_device_is_wireless (dev), NULL);
g_return_val_if_fail (sk != NULL, NULL);
*data_len = 0;
res_buf_len = IW_SCAN_MAX_DATA;
for (;;)
{
res_buf = g_malloc (res_buf_len);
if (res_buf == NULL)
return NULL;
memset (&iwr, 0, sizeof(iwr));
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 (dev), SIOCGIWSCAN, &iwr) == 0)
break;
if ((errno == E2BIG) && (res_buf_len < 100000))
{
g_free (res_buf);
res_buf = NULL;
res_buf_len *= 2;
}
else if (errno == EAGAIN)
{
/* If the card doesn't return results after 20s, it sucks. */
if (tries > 20)
{
nm_warning ("get_scan_results(): card took too much time scanning. Get a better one.");
free (res_buf);
return NULL;
}
g_free (res_buf);
g_usleep (G_USEC_PER_SEC / 10);
tries++;
}
else
{
nm_warning ("get_scan_results(): card returned too much scan info.");
g_free (res_buf);
return NULL;
}
}
*data_len = iwr.u.data.length;
return res_buf;
}
static gboolean process_scan_results (NMDevice *dev, const guint8 *res_buf, guint32 res_buf_len)
{
char *pos, *end, *custom, *genie, *gpos, *gend;
NMAccessPoint *ap = NULL;
size_t clen;
struct iw_event iwe_buf, *iwe = &iwe_buf;
g_return_val_if_fail (dev != NULL, FALSE);
g_return_val_if_fail (res_buf != NULL, FALSE);
g_return_val_if_fail (res_buf_len > 0, FALSE);
pos = (char *) res_buf;
end = (char *) res_buf + res_buf_len;
while (pos + IW_EV_LCP_LEN <= end)
{
int ssid_len;
/* Event data may be unaligned, so make a local, aligned copy
* before processing. */
memcpy (&iwe_buf, pos, IW_EV_LCP_LEN);
if (iwe->len <= IW_EV_LCP_LEN)
break;
custom = pos + IW_EV_POINT_LEN;
if (dev->options.wireless.we_version > 18 &&
(iwe->cmd == SIOCGIWESSID ||
iwe->cmd == SIOCGIWENCODE ||
iwe->cmd == IWEVGENIE ||
iwe->cmd == IWEVCUSTOM))
{
/* WE-19 removed the pointer from struct iw_point */
char *dpos = (char *) &iwe_buf.u.data.length;
int dlen = dpos - (char *) &iwe_buf;
memcpy (dpos, pos + IW_EV_LCP_LEN, sizeof (struct iw_event) - dlen);
}
else
{
memcpy (&iwe_buf, pos, sizeof (struct iw_event));
custom += IW_EV_POINT_OFF;
}
switch (iwe->cmd)
{
case SIOCGIWAP:
/* New access point record */
/* Merge previous AP */
if (ap)
{
gboolean new = FALSE;
gboolean strength_changed = FALSE;
GTimeVal cur_time;
g_get_current_time (&cur_time);
nm_ap_set_last_seen (ap, &cur_time);
/* If the AP is not broadcasting its ESSID, try to fill it in here from our
* allowed list where we cache known MAC->ESSID associations.
*/
if (!nm_ap_get_essid (ap))
nm_ap_list_copy_one_essid_by_address (ap, dev->app_data->allowed_ap_list);
/* Add the AP to the device's AP list */
if (nm_ap_list_merge_scanned_ap (nm_device_ap_list_get (dev), ap, &new, &strength_changed))
{
DBusConnection *con = dev->app_data->dbus_connection;
/* Handle dbus signals that we need to broadcast when the AP is added to the list or changes strength */
if (new)
nm_dbus_signal_wireless_network_change (con, dev, ap, NETWORK_STATUS_APPEARED, -1);
else if (strength_changed)
{
nm_dbus_signal_wireless_network_change (con, dev, ap, NETWORK_STATUS_STRENGTH_CHANGED,
nm_ap_get_strength (ap));
}
}
nm_ap_unref (ap);
ap = NULL;
}
/* New AP with some defaults */
ap = nm_ap_new ();
nm_ap_set_address (ap, (const struct ether_addr *)(iwe->u.ap_addr.sa_data));
nm_ap_set_auth_method (ap, NM_DEVICE_AUTH_METHOD_NONE);
nm_ap_set_mode (ap, NETWORK_MODE_INFRA);
break;
case SIOCGIWMODE:
switch (iwe->u.mode)
{
case IW_MODE_ADHOC:
nm_ap_set_mode (ap, NETWORK_MODE_ADHOC);
break;
case IW_MODE_MASTER:
case IW_MODE_INFRA:
nm_ap_set_mode (ap, NETWORK_MODE_INFRA);
break;
default:
break;
}
break;
case SIOCGIWESSID:
ssid_len = iwe->u.essid.length;
if (custom + ssid_len > end)
break;
if (iwe->u.essid.flags && (ssid_len > 0) && (ssid_len <= IW_ESSID_MAX_SIZE))
{
gboolean set = TRUE;
char *essid = g_malloc (IW_ESSID_MAX_SIZE + 1);
memcpy (essid, custom, ssid_len);
essid[ssid_len] = '\0';
if ((strlen (essid) >= 8) && (strcmp (essid, "<hidden>") != 0)) /* Stupid ipw drivers use <hidden> */
set = FALSE;
if (set)
nm_ap_set_essid (ap, essid);
g_free (essid);
}
break;
case SIOCGIWFREQ:
nm_ap_set_freq (ap, iw_freq2float(&(iwe->u.freq)));
break;
case IWEVQUAL:
nm_ap_set_strength (ap, nm_wireless_qual_to_percent (&(iwe->u.qual),
(const iwqual *)(&dev->options.wireless.max_qual),
(const iwqual *)(&dev->options.wireless.avg_qual)));
break;
case SIOCGIWENCODE:
if (!(iwe->u.data.flags & IW_ENCODE_DISABLED))
{
nm_ap_set_encrypted (ap, TRUE);
nm_ap_set_auth_method (ap, NM_DEVICE_AUTH_METHOD_OPEN_SYSTEM);
}
break;
#if 0
case SIOCGIWRATE:
custom = pos + IW_EV_LCP_LEN;
clen = iwe->len;
if (custom + clen > end)
break;
maxrate = 0;
while (((ssize_t) clen) >= sizeof(struct iw_param)) {
/* Note: may be misaligned, make a local,
* aligned copy */
memcpy(&p, custom, sizeof(struct iw_param));
if (p.value > maxrate)
maxrate = p.value;
clen -= sizeof(struct iw_param);
custom += sizeof(struct iw_param);
}
results[ap_num].maxrate = maxrate;
break;
#endif
case IWEVGENIE:
#define GENERIC_INFO_ELEM 0xdd
#define RSN_INFO_ELEM 0x30
gpos = genie = custom;
gend = genie + iwe->u.data.length;
if (gend > end)
{
nm_warning ("get_scan_results(): IWEVGENIE overflow.");
break;
}
while ((gpos + 1 < gend) && (gpos + 2 + (u8) gpos[1] <= gend))
{
u8 ie = gpos[0], ielen = gpos[1] + 2;
if (ielen > AP_MAX_WPA_IE_LEN)
{
gpos += ielen;
continue;
}
switch (ie)
{
case GENERIC_INFO_ELEM:
if ((ielen < 2 + 4) || (memcmp (&gpos[2], "\x00\x50\xf2\x01", 4) != 0))
break;
nm_ap_set_wpa_ie (ap, gpos, ielen);
break;
case RSN_INFO_ELEM:
nm_ap_set_rsn_ie (ap, gpos, ielen);
break;
}
gpos += ielen;
}
break;
case IWEVCUSTOM:
clen = iwe->u.data.length;
if (custom + clen > end)
break;
if (clen > 7 && ((strncmp (custom, "wpa_ie=", 7) == 0) || (strncmp (custom, "rsn_ie=", 7) == 0)))
{
char *spos;
int bytes;
char *ie_buf;
spos = custom + 7;
bytes = custom + clen - spos;
if (bytes & 1)
break;
bytes /= 2;
if (bytes > AP_MAX_WPA_IE_LEN)
{
nm_warning ("get_scan_results(): IE was too long (%d bytes).", bytes);
break;
}
ie_buf = g_malloc0 (bytes);
hexstr2bin (spos, ie_buf, bytes);
if (strncmp (custom, "wpa_ie=", 7) == 0)
nm_ap_set_wpa_ie (ap, ie_buf, bytes);
else if (strncmp (custom, "rsn_ie=", 7) == 0)
nm_ap_set_rsn_ie (ap, ie_buf, bytes);
g_free (ie_buf);
}
break;
}
pos += iwe->len;
}
return TRUE;
}
/*****************************************/
/* End code ripped from wpa_supplicant */
/*****************************************/

View File

@@ -351,26 +351,6 @@ gboolean nm_ethernet_address_is_valid (const struct ether_addr *test_addr)
} }
/*
* nm_dispose_scan_results
*
* Free memory used by the wireless scan results structure
*
*/
void nm_dispose_scan_results (wireless_scan *result_list)
{
wireless_scan *tmp = result_list;
while (tmp)
{
wireless_scan *tmp2 = tmp;
tmp = tmp->next;
free (tmp2);
}
}
/* /*
* nm_spawn_process * nm_spawn_process
* *

View File

@@ -58,8 +58,6 @@ int nm_null_safe_strcmp (const char *s1, const char *s2);
gboolean nm_ethernet_address_is_valid (const struct ether_addr *test_addr); gboolean nm_ethernet_address_is_valid (const struct ether_addr *test_addr);
void nm_dispose_scan_results (wireless_scan *result_list);
int nm_spawn_process (const char *args); int nm_spawn_process (const char *args);
void nm_print_device_capabilities (NMDevice *dev); void nm_print_device_capabilities (NMDevice *dev);