diff --git a/ChangeLog b/ChangeLog index 7e4c3cddb0..b65ea12678 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2005-10-15 Dan Williams + + 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 * gnome/libnm_glib/libnm_glib.c: diff --git a/NetworkManager.h b/NetworkManager.h index a5ea290320..ca15693b85 100644 --- a/NetworkManager.h +++ b/NetworkManager.h @@ -132,6 +132,16 @@ typedef enum NMEncKeyType #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 */ diff --git a/src/NetworkManagerAP.c b/src/NetworkManagerAP.c index 43540dd0cd..279f184443 100644 --- a/src/NetworkManagerAP.c +++ b/src/NetworkManagerAP.c @@ -30,29 +30,36 @@ */ struct NMAccessPoint { - guint refcount; - char *essid; - struct ether_addr *address; - NMNetworkMode mode; - gint8 strength; - double freq; - guint16 rate; - gboolean encrypted; + guint refcount; + char * essid; + struct ether_addr * address; + NMNetworkMode mode; + gint8 strength; + double freq; + guint16 rate; + gboolean encrypted; + guint32 capabilities; + + /* WPA auxiliary information */ + guint8 * wpa_ie; + guint32 wpa_ie_len; + guint8 * rsn_ie; + guint32 rsn_ie_len; /* Non-scanned attributes */ - gboolean invalid; - gboolean matched; /* used in ap list diffing */ - gboolean artificial; /* Whether or not the AP is from a scan */ - gboolean user_created; /* Whether or not the AP was created by the user with "Create network..." */ - GTimeVal last_seen; /* Last time the AP was seen in a scan */ + gboolean invalid; + gboolean matched; /* used in ap list diffing */ + gboolean artificial; /* Whether or not the AP is from a scan */ + gboolean user_created; /* Whether or not the AP was created by the user with "Create network..." */ + GTimeVal last_seen; /* Last time the AP was seen in a scan */ /* Things from user prefs/NetworkManagerInfo */ - gboolean trusted; - char *enc_key; - NMEncKeyType enc_type; - NMDeviceAuthMethod auth_method; - GTimeVal timestamp; - GSList *user_addresses; + gboolean trusted; + char * enc_key; + NMEncKeyType enc_type; + NMDeviceAuthMethod auth_method; + GTimeVal timestamp; + GSList * user_addresses; }; /* This is a controlled list. Want to add to it? Stop. Ask first. */ @@ -639,3 +646,67 @@ gboolean nm_ap_has_manufacturer_default_essid (NMAccessPoint *ap) 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); + } +} + diff --git a/src/NetworkManagerAP.h b/src/NetworkManagerAP.h index 0ba2a8238a..9080e30b83 100644 --- a/src/NetworkManagerAP.h +++ b/src/NetworkManagerAP.h @@ -28,6 +28,9 @@ typedef struct NMAccessPoint NMAccessPoint; +#define AP_MAX_WPA_IE_LEN 40 + + NMAccessPoint * nm_ap_new (void); NMAccessPoint * nm_ap_new_from_ap (NMAccessPoint *ap); @@ -43,7 +46,7 @@ void nm_ap_set_essid (NMAccessPoint *ap, const char *essid); const char * nm_ap_get_enc_key_source (const NMAccessPoint *ap); char * nm_ap_get_enc_key_hashed (const NMAccessPoint *ap); void nm_ap_set_enc_key_source (NMAccessPoint *ap, const char *key, NMEncKeyType type); -NMEncKeyType nm_ap_get_enc_type (const NMAccessPoint *ap); +NMEncKeyType nm_ap_get_enc_type (const NMAccessPoint *ap); NMDeviceAuthMethod nm_ap_get_auth_method (const NMAccessPoint *ap); void nm_ap_set_auth_method (NMAccessPoint *ap, const NMDeviceAuthMethod auth_method); @@ -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_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: * This is not intended to return true for all APs with manufacturer defaults. It is intended to return true for diff --git a/src/NetworkManagerDevice.c b/src/NetworkManagerDevice.c index 38fccd0c7b..4a72e4ad80 100644 --- a/src/NetworkManagerDevice.c +++ b/src/NetworkManagerDevice.c @@ -56,6 +56,10 @@ static guint32 nm_device_discover_capabilities (NMDevice *dev); static gboolean nm_is_driver_supported (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_stage2_device_config (NMActRequest *req); static void nm_device_activate_schedule_stage3_ip_config_start (NMActRequest *req); @@ -63,8 +67,9 @@ static void nm_device_activate_schedule_stage5_ip_config_commit (NMActRequest *r typedef struct { - NMDevice *dev; - struct wireless_scan_head scan_head; + NMDevice * dev; + guint8 * results; + guint32 results_len; } NMWirelessScanResults; 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))) { - guint8 we_ver = dev->options.wireless.we_version; - err = iw_scan (nm_dev_sock_get_fd (sk), (char *) nm_device_get_iface (dev), we_ver, &scan_data); - nm_dispose_scan_results (scan_data.result); + struct iwreq wrq; + memset (&wrq, 0, sizeof (struct iwreq)); + err = iw_set_ext (nm_dev_sock_get_fd (sk), nm_device_get_iface (dev), SIOCSIWSCAN, &wrq); if (!((err == -1) && (errno == EOPNOTSUPP))) caps |= NM_DEVICE_CAP_WIRELESS_SCAN; 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) { - NMWirelessScanResults *results = (NMWirelessScanResults *)user_data; - NMDevice *dev; - wireless_scan *tmp_ap; - NMAPListIter *iter; - GTimeVal cur_time; - gboolean list_changed = FALSE; + NMWirelessScanResults * cb_data = (NMWirelessScanResults *)user_data; + NMDevice * dev; + GTimeVal cur_time; + NMAPListIter * iter = NULL; - g_return_val_if_fail (results != NULL, FALSE); + g_return_val_if_fail (cb_data != NULL, FALSE); - dev = results->dev; - if (!dev || !results->scan_head.result) + dev = cb_data->dev; + if (!dev || !cb_data->results) return FALSE; - g_get_current_time (&cur_time); - - /* 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 "" 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, ""))) /* Stupid ipw drivers use */ - 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); - } - } + 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)); /* 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); - /* 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); 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); 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) && (cur_ap && (nm_null_safe_strcmp (nm_ap_get_essid (cur_ap), nm_ap_get_essid (outdated_ap))) == 0)) 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); } 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_ap_list_remove_ap (nm_device_ap_list_get (dev), outdated_ap); - list_changed = TRUE; } } 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 * @@ -4166,6 +4022,8 @@ static gboolean nm_device_wireless_scan (gpointer user_data) NMDevice * dev = NULL; NMWirelessScanResults * scan_results = NULL; guint32 caps; + guint8 * results = NULL; + guint32 results_len = 0; 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; int orig_rate = 0; const int interval = 20; - const int assoc_pause = nm_device_get_association_pause_value (dev); - const int delay = G_USEC_PER_SEC / interval; - const int max_tries = assoc_pause * interval; - nm_completion_args args; + struct iwreq wrq; orig_mode = nm_device_get_mode (dev); 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_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; - args[1] = &err; - args[2] = sk; - args[3] = scan_results; - nm_wait_for_completion (max_tries, delay, nm_completion_scan_has_results, NULL, args); + if ((results = get_scan_results (dev, sk, &results_len))) + { + scan_results = g_malloc0 (sizeof (NMWirelessScanResults)); + nm_device_ref (dev); + 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); /* 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); - - if (!scan_results->scan_head.result) - { - g_free (scan_results); - scan_results = NULL; - } } nm_unlock_mutex (dev->options.wireless.scan_mutex, __FUNCTION__); } - /* 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) && (scan_results->scan_head.result != NULL)) + if (scan_results != NULL) { - guint scan_process_source_id = 0; - GSource *scan_process_source = g_idle_source_new (); - GTimeVal cur_time; + guint scan_process_source_id = 0; + GSource * scan_process_source = g_idle_source_new (); + GTimeVal cur_time; - scan_results->dev = dev; 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); g_source_unref (scan_process_source); @@ -4500,10 +4364,6 @@ out: return supports_mii; } -/****************************************/ -/* End Code ripped from HAL */ -/****************************************/ - /****************************************/ /* Test device routes */ @@ -4520,3 +4380,338 @@ gboolean nm_device_is_test_device (NMDevice *dev) return (dev->test_device); } + +/*****************************************/ +/* Start code ripped from wpa_supplicant */ +/*****************************************/ +/* + * Copyright (c) 2003-2005, Jouni Malinen + * + * 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, "") != 0)) /* Stupid ipw drivers use */ + 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 */ +/*****************************************/ diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index b46ba2d79a..83f970beff 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -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 * diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index ebf533fe40..f9e77d2608 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -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); -void nm_dispose_scan_results (wireless_scan *result_list); - int nm_spawn_process (const char *args); void nm_print_device_capabilities (NMDevice *dev);