diff options
| author | Michael Biebl <biebl@debian.org> | 2011-05-04 21:35:41 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2011-05-04 21:35:41 +0200 |
| commit | 9f806e97a24bba61417ae312fcc0da40914266fb (patch) | |
| tree | 4a25723414ceac11b4cba0558aa16f6f4b459f4b /src/nm-device-wifi.c | |
| parent | 8baa1aca8dfd35e3190d7d5655eb83b5b901e263 (diff) | |
Imported Upstream version 0.8.999 upstream/0.8.999
Diffstat (limited to 'src/nm-device-wifi.c')
| -rw-r--r-- | src/nm-device-wifi.c | 1059 |
1 files changed, 449 insertions, 610 deletions
diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c index 2e278c7c..9258f77c 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2010 Red Hat, Inc. + * Copyright (C) 2005 - 2011 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -104,43 +104,18 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; -typedef enum { - NM_WIFI_ERROR_CONNECTION_NOT_WIRELESS = 0, - NM_WIFI_ERROR_CONNECTION_INVALID, - NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE, -} NMWifiError; - -#define NM_WIFI_ERROR (nm_wifi_error_quark ()) -#define NM_TYPE_WIFI_ERROR (nm_wifi_error_get_type ()) - -typedef struct SupplicantStateTask { - NMDeviceWifi *self; - guint32 new_state; - guint32 old_state; - gboolean mgr_task; - guint source_id; -} SupplicantStateTask; +#define SUP_SIG_ID_LEN 5 typedef struct Supplicant { NMSupplicantManager *mgr; NMSupplicantInterface *iface; - /* signal handler ids */ - guint mgr_state_id; + guint sig_ids[SUP_SIG_ID_LEN]; guint iface_error_id; - guint iface_state_id; - guint iface_scanned_ap_id; - guint iface_scan_request_result_id; - guint iface_scan_results_id; - guint iface_con_state_id; - guint iface_notify_scanning_id; /* Timeouts and idles */ guint iface_con_error_cb_id; guint con_timeout_id; - - GSList *mgr_tasks; - GSList *iface_tasks; } Supplicant; struct _NMDeviceWifiPrivate { @@ -191,40 +166,23 @@ static void schedule_scan (NMDeviceWifi *self, gboolean backoff); static void cancel_pending_scan (NMDeviceWifi *self); -static int wireless_qual_to_percent (const struct iw_quality *qual, - const struct iw_quality *max_qual); - static void cleanup_association_attempt (NMDeviceWifi * self, gboolean disconnect); static void remove_supplicant_timeouts (NMDeviceWifi *self); -static void supplicant_iface_state_cb (NMSupplicantInterface * iface, +static void supplicant_iface_state_cb (NMSupplicantInterface *iface, guint32 new_state, guint32 old_state, - NMDeviceWifi *self); - -static void supplicant_iface_connection_state_cb (NMSupplicantInterface * iface, - guint32 new_state, - guint32 old_state, - NMDeviceWifi *self); - -static void supplicant_iface_scanned_ap_cb (NMSupplicantInterface * iface, - GHashTable *properties, - NMDeviceWifi * self); + gpointer user_data); -static void supplicant_iface_scan_request_result_cb (NMSupplicantInterface * iface, - gboolean success, - NMDeviceWifi * self); +static void supplicant_iface_new_bss_cb (NMSupplicantInterface * iface, + GHashTable *properties, + NMDeviceWifi * self); -static void supplicant_iface_scan_results_cb (NMSupplicantInterface * iface, - guint32 num_bssids, - NMDeviceWifi * self); - -static void supplicant_mgr_state_cb (NMSupplicantInterface * iface, - guint32 new_state, - guint32 old_state, - NMDeviceWifi *self); +static void supplicant_iface_scan_done_cb (NMSupplicantInterface * iface, + gboolean success, + NMDeviceWifi * self); static void supplicant_iface_notify_scanning_cb (NMSupplicantInterface * iface, GParamSpec * pspec, @@ -234,6 +192,18 @@ static guint32 nm_device_wifi_get_bitrate (NMDeviceWifi *self); static void cull_scan_list (NMDeviceWifi *self); +/*****************************************************************/ + +typedef enum { + NM_WIFI_ERROR_CONNECTION_NOT_WIRELESS = 0, + NM_WIFI_ERROR_CONNECTION_INVALID, + NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE, + NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND, +} NMWifiError; + +#define NM_WIFI_ERROR (nm_wifi_error_quark ()) +#define NM_TYPE_WIFI_ERROR (nm_wifi_error_get_type ()) + static GQuark nm_wifi_error_quark (void) { @@ -259,6 +229,8 @@ nm_wifi_error_get_type (void) ENUM_ENTRY (NM_WIFI_ERROR_CONNECTION_INVALID, "ConnectionInvalid"), /* Connection does not apply to this device. */ ENUM_ENTRY (NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"), + /* Given access point was not in this device's scan list. */ + ENUM_ENTRY (NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND, "AccessPointNotFound"), { 0, 0, 0 } }; etype = g_enum_register_static ("NMWifiError", values); @@ -266,6 +238,8 @@ nm_wifi_error_get_type (void) return etype; } +/*****************************************************************/ + /* IPW rfkill handling (until 2.6.33) */ RfKillState nm_device_wifi_get_ipw_rfkill_state (NMDeviceWifi *self) @@ -324,6 +298,109 @@ ipw_rfkill_state_work (gpointer user_data) return TRUE; } +/*****************************************************************/ + +/* + * wireless_qual_to_percent + * + * Convert an iw_quality structure from SIOCGIWSTATS into a magical signal + * strength percentage. + * + */ +static int +wireless_qual_to_percent (const struct iw_quality *qual, + const struct iw_quality *max_qual) +{ + int percent = -1; + int level_percent = -1; + + g_return_val_if_fail (qual != NULL, -1); + g_return_val_if_fail (max_qual != NULL, -1); + + nm_log_dbg (LOGD_WIFI, + "QL: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X ** MAX: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X", + (__s8) qual->qual, qual->qual, qual->qual, + (__s8) qual->level, qual->level, qual->level, + (__s8) qual->noise, qual->noise, qual->noise, + qual->updated, + (__s8) max_qual->qual, max_qual->qual, max_qual->qual, + (__s8) max_qual->level, max_qual->level, max_qual->level, + (__s8) max_qual->noise, max_qual->noise, max_qual->noise, + max_qual->updated); + + /* Try using the card's idea of the signal quality first as long as it tells us what the max quality is. + * Drivers that fill in quality values MUST treat them as percentages, ie the "Link Quality" MUST be + * bounded by 0 and max_qual->qual, and MUST change in a linear fashion. Within those bounds, drivers + * are free to use whatever they want to calculate "Link Quality". + */ + if ((max_qual->qual != 0) && !(max_qual->updated & IW_QUAL_QUAL_INVALID) && !(qual->updated & IW_QUAL_QUAL_INVALID)) + percent = (int)(100 * ((double)qual->qual / (double)max_qual->qual)); + + /* If the driver doesn't specify a complete and valid quality, we have two options: + * + * 1) dBm: driver must specify max_qual->level = 0, and have valid values for + * qual->level and (qual->noise OR max_qual->noise) + * 2) raw RSSI: driver must specify max_qual->level > 0, and have valid values for + * qual->level and max_qual->level + * + * This is the WEXT spec. If this interpretation is wrong, I'll fix it. Otherwise, + * If drivers don't conform to it, they are wrong and need to be fixed. + */ + + if ( (max_qual->level == 0) && !(max_qual->updated & IW_QUAL_LEVEL_INVALID) /* Valid max_qual->level == 0 */ + && !(qual->updated & IW_QUAL_LEVEL_INVALID) /* Must have valid qual->level */ + && ( ((max_qual->noise > 0) && !(max_qual->updated & IW_QUAL_NOISE_INVALID)) /* Must have valid max_qual->noise */ + || ((qual->noise > 0) && !(qual->updated & IW_QUAL_NOISE_INVALID))) /* OR valid qual->noise */ + ) { + /* Absolute power values (dBm) */ + + /* Reasonable fallbacks for dumb drivers that don't specify either level. */ + #define FALLBACK_NOISE_FLOOR_DBM -90 + #define FALLBACK_SIGNAL_MAX_DBM -20 + int max_level = FALLBACK_SIGNAL_MAX_DBM; + int noise = FALLBACK_NOISE_FLOOR_DBM; + int level = qual->level - 0x100; + + level = CLAMP (level, FALLBACK_NOISE_FLOOR_DBM, FALLBACK_SIGNAL_MAX_DBM); + + if ((qual->noise > 0) && !(qual->updated & IW_QUAL_NOISE_INVALID)) + noise = qual->noise - 0x100; + else if ((max_qual->noise > 0) && !(max_qual->updated & IW_QUAL_NOISE_INVALID)) + noise = max_qual->noise - 0x100; + noise = CLAMP (noise, FALLBACK_NOISE_FLOOR_DBM, FALLBACK_SIGNAL_MAX_DBM); + + /* A sort of signal-to-noise ratio calculation */ + level_percent = (int)(100 - 70 *( + ((double)max_level - (double)level) / + ((double)max_level - (double)noise))); + nm_log_dbg (LOGD_WIFI, "QL1: level_percent is %d. max_level %d, level %d, noise_floor %d.", + level_percent, max_level, level, noise); + } else if ( (max_qual->level != 0) + && !(max_qual->updated & IW_QUAL_LEVEL_INVALID) /* Valid max_qual->level as upper bound */ + && !(qual->updated & IW_QUAL_LEVEL_INVALID)) { + /* Relative power values (RSSI) */ + + int level = qual->level; + + /* Signal level is relavtive (0 -> max_qual->level) */ + level = CLAMP (level, 0, max_qual->level); + level_percent = (int)(100 * ((double)level / (double)max_qual->level)); + nm_log_dbg (LOGD_WIFI, "QL2: level_percent is %d. max_level %d, level %d.", + level_percent, max_qual->level, level); + } else if (percent == -1) { + nm_log_dbg (LOGD_WIFI, "QL: Could not get quality %% value from driver. Driver is probably buggy."); + } + + /* If the quality percent was 0 or doesn't exist, then try to use signal levels instead */ + if ((percent < 1) && (level_percent >= 0)) + percent = level_percent; + + nm_log_dbg (LOGD_WIFI, "QL: Final quality percent is %d (%d).", + percent, CLAMP (percent, 0, 100)); + return (CLAMP (percent, 0, 100)); +} + + /* * nm_device_wifi_update_signal_strength * @@ -625,10 +702,7 @@ constructor (GType type, /* Connect to the supplicant manager */ priv->supplicant.mgr = nm_supplicant_manager_get (); - priv->supplicant.mgr_state_id = g_signal_connect (priv->supplicant.mgr, - "state", - G_CALLBACK (supplicant_mgr_state_cb), - self); + g_assert (priv->supplicant.mgr); /* The ipw2x00 drivers don't integrate with the kernel rfkill subsystem until * 2.6.33. Thus all our nice libgudev magic is useless. So we get to poll. @@ -657,17 +731,13 @@ static gboolean supplicant_interface_acquire (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - guint id, mgr_state; + guint id, i = 0; g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (priv->supplicant.mgr != NULL, FALSE); /* interface already acquired? */ g_return_val_if_fail (priv->supplicant.iface == NULL, TRUE); - mgr_state = nm_supplicant_manager_get_state (priv->supplicant.mgr); - g_return_val_if_fail (mgr_state == NM_SUPPLICANT_MANAGER_STATE_IDLE, FALSE); - - priv->supplicant.iface = nm_supplicant_manager_get_iface (priv->supplicant.mgr, + priv->supplicant.iface = nm_supplicant_manager_iface_get (priv->supplicant.mgr, nm_device_get_iface (NM_DEVICE (self)), TRUE); if (priv->supplicant.iface == NULL) { @@ -676,70 +746,36 @@ supplicant_interface_acquire (NMDeviceWifi *self) return FALSE; } - id = g_signal_connect (priv->supplicant.iface, - "state", - G_CALLBACK (supplicant_iface_state_cb), - self); - priv->supplicant.iface_state_id = id; - - id = g_signal_connect (priv->supplicant.iface, - "scanned-ap", - G_CALLBACK (supplicant_iface_scanned_ap_cb), - self); - priv->supplicant.iface_scanned_ap_id = id; + memset (priv->supplicant.sig_ids, 0, sizeof (priv->supplicant.sig_ids)); id = g_signal_connect (priv->supplicant.iface, - "scan-req-result", - G_CALLBACK (supplicant_iface_scan_request_result_cb), + NM_SUPPLICANT_INTERFACE_STATE, + G_CALLBACK (supplicant_iface_state_cb), self); - priv->supplicant.iface_scan_request_result_id = id; + priv->supplicant.sig_ids[i++] = id; id = g_signal_connect (priv->supplicant.iface, - "scan-results", - G_CALLBACK (supplicant_iface_scan_results_cb), + NM_SUPPLICANT_INTERFACE_NEW_BSS, + G_CALLBACK (supplicant_iface_new_bss_cb), self); - priv->supplicant.iface_scan_results_id = id; + priv->supplicant.sig_ids[i++] = id; id = g_signal_connect (priv->supplicant.iface, - "connection-state", - G_CALLBACK (supplicant_iface_connection_state_cb), + NM_SUPPLICANT_INTERFACE_SCAN_DONE, + G_CALLBACK (supplicant_iface_scan_done_cb), self); - priv->supplicant.iface_con_state_id = id; + priv->supplicant.sig_ids[i++] = id; id = g_signal_connect (priv->supplicant.iface, "notify::scanning", G_CALLBACK (supplicant_iface_notify_scanning_cb), self); - priv->supplicant.iface_notify_scanning_id = id; + priv->supplicant.sig_ids[i++] = id; return TRUE; } static void -finish_supplicant_task (SupplicantStateTask *task, gboolean remove_source) -{ - NMDeviceWifi *self = task->self; - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - /* idle/timeout handlers should pass FALSE for remove_source, since they - * will tell glib to remove their source from the mainloop by returning - * FALSE when they exit. When called from this NMDevice's dispose handler, - * remove_source should be TRUE to cancel all outstanding idle/timeout - * handlers asynchronously. - */ - if (task->source_id && remove_source) - g_source_remove (task->source_id); - - if (task->mgr_task) - priv->supplicant.mgr_tasks = g_slist_remove (priv->supplicant.mgr_tasks, task); - else - priv->supplicant.iface_tasks = g_slist_remove (priv->supplicant.iface_tasks, task); - - memset (task, 0, sizeof (SupplicantStateTask)); - g_slice_free (SupplicantStateTask, task); -} - -static void remove_supplicant_interface_error_handler (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); @@ -762,6 +798,7 @@ static void supplicant_interface_release (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv; + guint i; g_return_if_fail (self != NULL); @@ -777,49 +814,36 @@ supplicant_interface_release (NMDeviceWifi *self) remove_supplicant_interface_error_handler (self); - /* Clean up all pending supplicant interface state idle tasks */ - while (priv->supplicant.iface_tasks) - finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.iface_tasks->data, TRUE); - - if (priv->supplicant.iface_state_id > 0) { - g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_state_id); - priv->supplicant.iface_state_id = 0; - } - - if (priv->supplicant.iface_scanned_ap_id > 0) { - g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_scanned_ap_id); - priv->supplicant.iface_scanned_ap_id = 0; - } - - if (priv->supplicant.iface_scan_request_result_id > 0) { - g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_scan_request_result_id); - priv->supplicant.iface_scan_request_result_id = 0; - } - - if (priv->supplicant.iface_scan_results_id > 0) { - g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_scan_results_id); - priv->supplicant.iface_scan_results_id = 0; - } - - if (priv->supplicant.iface_con_state_id > 0) { - g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_con_state_id); - priv->supplicant.iface_con_state_id = 0; - } - - if (priv->supplicant.iface_notify_scanning_id > 0) { - g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_notify_scanning_id); - priv->supplicant.iface_notify_scanning_id = 0; + /* Clear supplicant interface signal handlers */ + for (i = 0; i < SUP_SIG_ID_LEN; i++) { + if (priv->supplicant.sig_ids[i] > 0) + g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.sig_ids[i]); } + memset (priv->supplicant.sig_ids, 0, sizeof (priv->supplicant.sig_ids)); if (priv->supplicant.iface) { /* Tell the supplicant to disconnect from the current AP */ nm_supplicant_interface_disconnect (priv->supplicant.iface); - nm_supplicant_manager_release_iface (priv->supplicant.mgr, priv->supplicant.iface); + nm_supplicant_manager_iface_release (priv->supplicant.mgr, priv->supplicant.iface); priv->supplicant.iface = NULL; } } + +static NMAccessPoint * +get_ap_by_path (NMDeviceWifi *self, const char *path) +{ + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + GSList *iter; + + for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { + if (strcmp (path, nm_ap_get_dbus_path (NM_AP (iter->data))) == 0) + return NM_AP (iter->data); + } + return NULL; +} + static NMAccessPoint * get_active_ap (NMDeviceWifi *self, NMAccessPoint *ignore_ap, @@ -1226,7 +1250,7 @@ real_take_down (NMDevice *dev) } static void -real_deactivate_quickly (NMDevice *dev) +real_deactivate (NMDevice *dev) { NMDeviceWifi *self = NM_DEVICE_WIFI (dev); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); @@ -1262,16 +1286,11 @@ real_deactivate_quickly (NMDevice *dev) /* Reset MAC address back to initial address */ _set_hw_addr (self, priv->initial_hw_addr, "reset"); -} - -static void -real_deactivate (NMDevice *dev) -{ - NMDeviceWifi *self = NM_DEVICE_WIFI (dev); + /* Ensure we're in infrastructure mode after deactivation; some devices + * (usually older ones) don't scan well in adhoc mode. + */ nm_device_wifi_set_mode (self, NM_802_11_MODE_INFRA); - /* FIXME: Should we reset the scan interval here? */ -/* nm_device_wifi_set_scan_interval (app_data, self, NM_WIRELESS_SCAN_INTERVAL_ACTIVE); */ } static gboolean @@ -1318,6 +1337,178 @@ real_check_connection_compatible (NMDevice *device, return TRUE; } +/* + * List of manufacturer default SSIDs that are often unchanged by users. + * + * NOTE: this list should *not* contain networks that you would like to + * automatically roam to like "Starbucks" or "AT&T" or "T-Mobile HotSpot". + */ +static const char * +manf_defaults[] = { + "linksys", + "linksys-a", + "linksys-g", + "default", + "belkin54g", + "NETGEAR", + "o2DSL", + "WLAN", + "ALICE-WLAN", +}; + +#define ARRAY_SIZE(a) (sizeof (a) / sizeof (a[0])) + +static gboolean +is_manf_default_ssid (const GByteArray *ssid) +{ + int i; + + for (i = 0; i < ARRAY_SIZE (manf_defaults); i++) { + if (ssid->len == strlen (manf_defaults[i])) { + if (memcmp (manf_defaults[i], ssid->data, ssid->len) == 0) + return TRUE; + } + } + return FALSE; +} + +static gboolean +real_complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMDeviceWifi *self = NM_DEVICE_WIFI (device); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + NMSettingWireless *s_wifi; + NMSettingWirelessSecurity *s_wsec; + NMSetting8021x *s_8021x; + const GByteArray *setting_mac; + char *format, *str_ssid = NULL; + NMAccessPoint *ap = NULL; + const GByteArray *ssid = NULL; + GSList *iter; + + s_wifi = nm_connection_get_setting_wireless (connection); + s_wsec = nm_connection_get_setting_wireless_security (connection); + s_8021x = nm_connection_get_setting_802_1x (connection); + + if (!specific_object) { + /* If not given a specific object, we need at minimum an SSID */ + if (!s_wifi) { + g_set_error_literal (error, + NM_WIFI_ERROR, + NM_WIFI_ERROR_CONNECTION_INVALID, + "A 'wireless' setting is required if no AP path was given."); + return FALSE; + } + + ssid = nm_setting_wireless_get_ssid (s_wifi); + if (!ssid || !ssid->len) { + g_set_error_literal (error, + NM_WIFI_ERROR, + NM_WIFI_ERROR_CONNECTION_INVALID, + "A 'wireless' setting with a valid SSID is required if no AP path was given."); + return FALSE; + } + + /* Find a compatible AP in the scan list */ + for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { + if (nm_ap_check_compatible (NM_AP (iter->data), connection)) { + ap = NM_AP (iter->data); + break; + } + } + + /* If we still don't have an AP, then the WiFI settings needs to be + * fully specified by the client. Might not be able to find an AP + * if the network isn't broadcasting the SSID for example. + */ + if (!ap) { + GSList *settings = NULL; + gboolean valid; + + settings = g_slist_prepend (settings, s_wifi); + if (s_wsec) + settings = g_slist_prepend (settings, s_wsec); + if (s_8021x) + settings = g_slist_prepend (settings, s_8021x); + valid = nm_setting_verify (NM_SETTING (s_wifi), settings, error); + g_slist_free (settings); + if (!valid) + return FALSE; + } + } else { + ap = get_ap_by_path (self, specific_object); + if (!ap) { + g_set_error (error, + NM_WIFI_ERROR, + NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND, + "The access point %s was not in the scan list.", + specific_object); + return FALSE; + } + } + + /* Add a wifi setting if one doesn't exist yet */ + if (!s_wifi) { + s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wifi)); + } + + if (ap) { + ssid = nm_ap_get_ssid (ap); + + /* If the SSID is a well-known SSID, lock the connection to the AP's + * specific BSSID so NM doesn't autoconnect to some random wifi net. + */ + if (!nm_ap_complete_connection (ap, + connection, + is_manf_default_ssid (ssid), + error)) + return FALSE; + } + + g_assert (ssid); + str_ssid = nm_utils_ssid_to_utf8 (ssid); + format = g_strdup_printf ("%s %%d", str_ssid); + + nm_utils_complete_generic (connection, + NM_SETTING_WIRELESS_SETTING_NAME, + existing_connections, + format, + str_ssid, + TRUE); + g_free (str_ssid); + g_free (format); + + setting_mac = nm_setting_wireless_get_mac_address (s_wifi); + if (setting_mac) { + /* Make sure the setting MAC (if any) matches the device's permanent MAC */ + if (memcmp (setting_mac->data, priv->perm_hw_addr, ETH_ALEN)) { + g_set_error (error, + NM_SETTING_WIRELESS_ERROR, + NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY, + NM_SETTING_WIRELESS_MAC_ADDRESS); + return FALSE; + } + } else { + GByteArray *mac; + const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + + /* Lock the connection to this device by default */ + if (memcmp (priv->perm_hw_addr, null_mac, ETH_ALEN)) { + mac = g_byte_array_sized_new (ETH_ALEN); + g_byte_array_append (mac, priv->perm_hw_addr, ETH_ALEN); + g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MAC_ADDRESS, mac, NULL); + g_byte_array_free (mac, TRUE); + } + } + + return TRUE; +} + static gboolean real_is_available (NMDevice *dev) { @@ -1591,107 +1782,6 @@ nm_device_wifi_get_frequency (NMDeviceWifi *self) } /* - * wireless_stats_to_percent - * - * Convert an iw_stats structure from a scan or the card into - * a magical signal strength percentage. - * - */ -static int -wireless_qual_to_percent (const struct iw_quality *qual, - const struct iw_quality *max_qual) -{ - int percent = -1; - int level_percent = -1; - - g_return_val_if_fail (qual != NULL, -1); - g_return_val_if_fail (max_qual != NULL, -1); - - nm_log_dbg (LOGD_WIFI, - "QL: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X ** MAX: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X", - (__s8) qual->qual, qual->qual, qual->qual, - (__s8) qual->level, qual->level, qual->level, - (__s8) qual->noise, qual->noise, qual->noise, - qual->updated, - (__s8) max_qual->qual, max_qual->qual, max_qual->qual, - (__s8) max_qual->level, max_qual->level, max_qual->level, - (__s8) max_qual->noise, max_qual->noise, max_qual->noise, - max_qual->updated); - - /* Try using the card's idea of the signal quality first as long as it tells us what the max quality is. - * Drivers that fill in quality values MUST treat them as percentages, ie the "Link Quality" MUST be - * bounded by 0 and max_qual->qual, and MUST change in a linear fashion. Within those bounds, drivers - * are free to use whatever they want to calculate "Link Quality". - */ - if ((max_qual->qual != 0) && !(max_qual->updated & IW_QUAL_QUAL_INVALID) && !(qual->updated & IW_QUAL_QUAL_INVALID)) - percent = (int)(100 * ((double)qual->qual / (double)max_qual->qual)); - - /* If the driver doesn't specify a complete and valid quality, we have two options: - * - * 1) dBm: driver must specify max_qual->level = 0, and have valid values for - * qual->level and (qual->noise OR max_qual->noise) - * 2) raw RSSI: driver must specify max_qual->level > 0, and have valid values for - * qual->level and max_qual->level - * - * This is the WEXT spec. If this interpretation is wrong, I'll fix it. Otherwise, - * If drivers don't conform to it, they are wrong and need to be fixed. - */ - - if ( (max_qual->level == 0) && !(max_qual->updated & IW_QUAL_LEVEL_INVALID) /* Valid max_qual->level == 0 */ - && !(qual->updated & IW_QUAL_LEVEL_INVALID) /* Must have valid qual->level */ - && ( ((max_qual->noise > 0) && !(max_qual->updated & IW_QUAL_NOISE_INVALID)) /* Must have valid max_qual->noise */ - || ((qual->noise > 0) && !(qual->updated & IW_QUAL_NOISE_INVALID))) /* OR valid qual->noise */ - ) { - /* Absolute power values (dBm) */ - - /* Reasonable fallbacks for dumb drivers that don't specify either level. */ - #define FALLBACK_NOISE_FLOOR_DBM -90 - #define FALLBACK_SIGNAL_MAX_DBM -20 - int max_level = FALLBACK_SIGNAL_MAX_DBM; - int noise = FALLBACK_NOISE_FLOOR_DBM; - int level = qual->level - 0x100; - - level = CLAMP (level, FALLBACK_NOISE_FLOOR_DBM, FALLBACK_SIGNAL_MAX_DBM); - - if ((qual->noise > 0) && !(qual->updated & IW_QUAL_NOISE_INVALID)) - noise = qual->noise - 0x100; - else if ((max_qual->noise > 0) && !(max_qual->updated & IW_QUAL_NOISE_INVALID)) - noise = max_qual->noise - 0x100; - noise = CLAMP (noise, FALLBACK_NOISE_FLOOR_DBM, FALLBACK_SIGNAL_MAX_DBM); - - /* A sort of signal-to-noise ratio calculation */ - level_percent = (int)(100 - 70 *( - ((double)max_level - (double)level) / - ((double)max_level - (double)noise))); - nm_log_dbg (LOGD_WIFI, "QL1: level_percent is %d. max_level %d, level %d, noise_floor %d.", - level_percent, max_level, level, noise); - } else if ( (max_qual->level != 0) - && !(max_qual->updated & IW_QUAL_LEVEL_INVALID) /* Valid max_qual->level as upper bound */ - && !(qual->updated & IW_QUAL_LEVEL_INVALID)) { - /* Relative power values (RSSI) */ - - int level = qual->level; - - /* Signal level is relavtive (0 -> max_qual->level) */ - level = CLAMP (level, 0, max_qual->level); - level_percent = (int)(100 * ((double)level / (double)max_qual->level)); - nm_log_dbg (LOGD_WIFI, "QL2: level_percent is %d. max_level %d, level %d.", - level_percent, max_qual->level, level); - } else if (percent == -1) { - nm_log_dbg (LOGD_WIFI, "QL: Could not get quality %% value from driver. Driver is probably buggy."); - } - - /* If the quality percent was 0 or doesn't exist, then try to use signal levels instead */ - if ((percent < 1) && (level_percent >= 0)) - percent = level_percent; - - nm_log_dbg (LOGD_WIFI, "QL: Final quality percent is %d (%d).", - percent, CLAMP (percent, 0, 100)); - return (CLAMP (percent, 0, 100)); -} - - -/* * nm_device_wifi_get_ssid * * If a device is wireless, return the ssid that it is attempting @@ -1828,6 +1918,9 @@ scanning_allowed (NMDeviceWifi *self) case NM_DEVICE_STATE_CONFIG: case NM_DEVICE_STATE_NEED_AUTH: case NM_DEVICE_STATE_IP_CONFIG: + case NM_DEVICE_STATE_IP_CHECK: + case NM_DEVICE_STATE_SECONDARIES: + case NM_DEVICE_STATE_DEACTIVATING: /* Don't scan when unusable or activating */ return FALSE; case NM_DEVICE_STATE_DISCONNECTED: @@ -1840,11 +1933,11 @@ scanning_allowed (NMDeviceWifi *self) } /* Don't scan if the supplicant is busy */ - sup_state = nm_supplicant_interface_get_connection_state (priv->supplicant.iface); - if ( sup_state == NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATING - || sup_state == NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATED - || sup_state == NM_SUPPLICANT_INTERFACE_CON_STATE_4WAY_HANDSHAKE - || sup_state == NM_SUPPLICANT_INTERFACE_CON_STATE_GROUP_HANDSHAKE + sup_state = nm_supplicant_interface_get_state (priv->supplicant.iface); + if ( sup_state == NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING + || sup_state == NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED + || sup_state == NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE + || sup_state == NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE || nm_supplicant_interface_get_scanning (priv->supplicant.iface)) return FALSE; @@ -2000,28 +2093,19 @@ cancel_pending_scan (NMDeviceWifi *self) } } - static void -supplicant_iface_scan_request_result_cb (NMSupplicantInterface *iface, - gboolean success, - NMDeviceWifi *self) +supplicant_iface_scan_done_cb (NMSupplicantInterface *iface, + gboolean success, + NMDeviceWifi *self) { - nm_log_dbg (LOGD_WIFI_SCAN, "(%s): scan request %s", + nm_log_dbg (LOGD_WIFI_SCAN, "(%s): scan %s", nm_device_get_iface (NM_DEVICE (self)), success ? "successful" : "failed"); if (check_scanning_allowed (self)) schedule_scan (self, TRUE); -} -static void -supplicant_iface_scan_results_cb (NMSupplicantInterface *iface, - guint32 num_results, - NMDeviceWifi *self) -{ - nm_log_dbg (LOGD_WIFI_SCAN, "(%s): scan results available (%d APs found)", - nm_device_get_iface (NM_DEVICE (self)), - num_results); +#if 0 if (num_results == 0) { /* ensure that old APs get culled, which otherwise only * happens when there are actual scan results to process. @@ -2029,6 +2113,7 @@ supplicant_iface_scan_results_cb (NMSupplicantInterface *iface, cull_scan_list (self); nm_device_wifi_ap_list_print (self); } +#endif } static gboolean @@ -2248,48 +2333,10 @@ cull_scan_list (NMDeviceWifi *self) removed, total); } -#define SET_QUALITY_MEMBER(qual_item, lc_member, uc_member) \ - if (lc_member != -1) { \ - qual_item.lc_member = lc_member; \ - qual_item.updated |= IW_QUAL_##uc_member##_UPDATED; \ - } else { \ - qual_item.updated |= IW_QUAL_##uc_member##_INVALID; \ - } - -static void -set_ap_strength_from_properties (NMDeviceWifi *self, - NMAccessPoint *ap, - GHashTable *properties) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - int qual, level, noise; - struct iw_quality quality; - GValue *value; - gint8 strength; - - value = (GValue *) g_hash_table_lookup (properties, "quality"); - qual = value ? g_value_get_int (value) : -1; - - value = (GValue *) g_hash_table_lookup (properties, "level"); - level = value ? g_value_get_int (value) : -1; - - value = (GValue *) g_hash_table_lookup (properties, "noise"); - noise = value ? g_value_get_int (value) : -1; - - /* Calculate and set the AP's signal quality */ - memset (&quality, 0, sizeof (struct iw_quality)); - SET_QUALITY_MEMBER (quality, qual, QUAL); - SET_QUALITY_MEMBER (quality, level, LEVEL); - SET_QUALITY_MEMBER (quality, noise, NOISE); - - strength = wireless_qual_to_percent (&quality, &priv->max_qual); - nm_ap_set_strength (ap, strength); -} - static void -supplicant_iface_scanned_ap_cb (NMSupplicantInterface *iface, - GHashTable *properties, - NMDeviceWifi *self) +supplicant_iface_new_bss_cb (NMSupplicantInterface *iface, + GHashTable *properties, + NMDeviceWifi *self) { NMDeviceState state; NMAccessPoint *ap; @@ -2305,8 +2352,6 @@ supplicant_iface_scanned_ap_cb (NMSupplicantInterface *iface, ap = nm_ap_new_from_properties (properties); if (ap) { - set_ap_strength_from_properties (self, ap, properties); - nm_ap_print_self (ap, "AP: "); /* Add the AP to the device's AP list */ @@ -2335,6 +2380,27 @@ cleanup_association_attempt (NMDeviceWifi *self, gboolean disconnect) nm_supplicant_interface_disconnect (priv->supplicant.iface); } +static void +wifi_secrets_cb (NMActRequest *req, + guint32 call_id, + NMConnection *connection, + GError *error, + gpointer user_data) +{ + NMDevice *dev = NM_DEVICE (user_data); + + g_return_if_fail (req == nm_device_get_act_request (dev)); + g_return_if_fail (nm_device_get_state (dev) == NM_DEVICE_STATE_NEED_AUTH); + g_return_if_fail (nm_act_request_get_connection (req) == connection); + + if (error) { + nm_log_warn (LOGD_WIFI, "%s", error->message); + nm_device_state_changed (dev, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_NO_SECRETS); + } else + nm_device_activate_schedule_stage1_device_prepare (dev); +} static void remove_link_timeout (NMDeviceWifi *self) @@ -2431,10 +2497,10 @@ link_timeout_cb (gpointer user_data) nm_device_state_changed (dev, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); nm_act_request_get_secrets (req, setting_name, - TRUE, - SECRETS_CALLER_WIFI, + NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW, NULL, - NULL); + wifi_secrets_cb, + self); return FALSE; } @@ -2444,253 +2510,97 @@ time_out: return FALSE; } -static gboolean -schedule_state_handler (NMDeviceWifi *self, - GSourceFunc handler, - guint32 new_state, - guint32 old_state, - gboolean mgr_task) +static void +supplicant_iface_state_cb (NMSupplicantInterface *iface, + guint32 new_state, + guint32 old_state, + gpointer user_data) { - NMDeviceWifiPrivate *priv; - SupplicantStateTask *task; - - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (handler != NULL, FALSE); + NMDeviceWifi *self = NM_DEVICE_WIFI (user_data); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + NMDevice *device = NM_DEVICE (self); + NMDeviceState devstate; + gboolean scanning; if (new_state == old_state) - return TRUE; - - priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - task = g_slice_new0 (SupplicantStateTask); - if (!task) { - nm_log_err (LOGD_WIFI, "Not enough memory to process supplicant manager state change."); - return FALSE; - } - - task->self = self; - task->new_state = new_state; - task->old_state = old_state; - task->mgr_task = mgr_task; - - task->source_id = g_idle_add (handler, task); - if (mgr_task) - priv->supplicant.mgr_tasks = g_slist_append (priv->supplicant.mgr_tasks, task); - else - priv->supplicant.iface_tasks = g_slist_append (priv->supplicant.iface_tasks, task); - - return TRUE; -} - -static gboolean -supplicant_iface_state_cb_handler (gpointer user_data) -{ - SupplicantStateTask *task = (SupplicantStateTask *) user_data; - NMDeviceWifi *self; - NMDeviceWifiPrivate *priv; - - g_return_val_if_fail (task != NULL, FALSE); + return; - self = task->self; - priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + nm_log_info (LOGD_DEVICE | LOGD_WIFI, + "(%s): supplicant interface state: %s -> %s", + nm_device_get_iface (device), + nm_supplicant_interface_state_to_string (old_state), + nm_supplicant_interface_state_to_string (new_state)); - nm_log_info (LOGD_WIFI, "(%s): supplicant interface state: %s -> %s", - nm_device_get_iface (NM_DEVICE (self)), - nm_supplicant_interface_state_to_string (task->old_state), - nm_supplicant_interface_state_to_string (task->new_state)); + devstate = nm_device_get_state (device); + scanning = nm_supplicant_interface_get_scanning (iface); - if (task->new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) { + switch (new_state) { + case NM_SUPPLICANT_INTERFACE_STATE_READY: priv->scan_interval = SCAN_INTERVAL_MIN; /* If the interface can now be activated because the supplicant is now * available, transition to DISCONNECTED. */ - if ( (nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_UNAVAILABLE) - && nm_device_is_available (NM_DEVICE (self))) { - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, + if ((devstate == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device)) { + nm_device_state_changed (device, + NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE); } - nm_log_dbg (LOGD_WIFI_SCAN, "(%s): supplicant ready, requesting initial scan", - nm_device_get_iface (NM_DEVICE (self))); + nm_log_dbg (LOGD_WIFI_SCAN, + "(%s): supplicant ready, requesting initial scan", + nm_device_get_iface (device)); /* Request a scan to get latest results */ cancel_pending_scan (self); request_wireless_scan (self); - } else if (task->new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { - cleanup_association_attempt (self, FALSE); - supplicant_interface_release (self); - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - } - - finish_supplicant_task (task, FALSE); - return FALSE; -} - - -static void -supplicant_iface_state_cb (NMSupplicantInterface * iface, - guint32 new_state, - guint32 old_state, - NMDeviceWifi *self) -{ - g_return_if_fail (self != NULL); - - schedule_state_handler (self, - supplicant_iface_state_cb_handler, - new_state, - old_state, - FALSE); -} - - -static gboolean -supplicant_iface_connection_state_cb_handler (gpointer user_data) -{ - SupplicantStateTask *task = (SupplicantStateTask *) user_data; - NMDeviceWifi *self = task->self; - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - NMDevice *dev = NM_DEVICE (self); - gboolean scanning; - - if (!nm_device_get_act_request (dev)) { - /* The device is not activating or already activated; do nothing. */ - goto out; - } - - nm_log_info (LOGD_WIFI, "(%s): supplicant connection state: %s -> %s", - nm_device_get_iface (dev), - nm_supplicant_interface_connection_state_to_string (task->old_state), - nm_supplicant_interface_connection_state_to_string (task->new_state)); - - scanning = nm_supplicant_interface_get_scanning (priv->supplicant.iface); - - if (task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED) { + break; + case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED: remove_supplicant_interface_error_handler (self); remove_supplicant_timeouts (self); /* If this is the initial association during device activation, * schedule the next activation stage. */ - if (nm_device_get_state (dev) == NM_DEVICE_STATE_CONFIG) { + if (devstate == NM_DEVICE_STATE_CONFIG) { NMAccessPoint *ap = nm_device_wifi_get_activation_ap (self); - const GByteArray * ssid = nm_ap_get_ssid (ap); + const GByteArray *ssid = nm_ap_get_ssid (ap); nm_log_info (LOGD_DEVICE | LOGD_WIFI, "Activation (%s/wireless) Stage 2 of 5 (Device Configure) " "successful. Connected to wireless network '%s'.", - nm_device_get_iface (dev), + nm_device_get_iface (device), ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)"); - nm_device_activate_schedule_stage3_ip_config_start (dev); + nm_device_activate_schedule_stage3_ip_config_start (device); } - } else if (task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED) { - if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED || nm_device_is_activating (dev)) { + break; + case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED: + if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) { /* Start the link timeout so we allow some time for reauthentication, * use a longer timeout if we are scanning since some cards take a * while to scan. */ if (!priv->link_timeout_id) { priv->link_timeout_id = g_timeout_add_seconds (scanning ? 30 : 15, - link_timeout_cb, self); + link_timeout_cb, self); } } + break; + case NM_SUPPLICANT_INTERFACE_STATE_DOWN: + cleanup_association_attempt (self, FALSE); + supplicant_interface_release (self); + nm_device_state_changed (device, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + break; + default: + break; } -out: /* Signal scanning state changes */ - if ( task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING - || task->old_state == NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING) + if ( new_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING + || old_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING) g_object_notify (G_OBJECT (self), "scanning"); - - finish_supplicant_task (task, FALSE); - return FALSE; -} - - -static void -supplicant_iface_connection_state_cb (NMSupplicantInterface * iface, - guint32 new_state, - guint32 old_state, - NMDeviceWifi *self) -{ - g_return_if_fail (self != NULL); - - schedule_state_handler (self, - supplicant_iface_connection_state_cb_handler, - new_state, - old_state, - FALSE); -} - - -static gboolean -supplicant_mgr_state_cb_handler (gpointer user_data) -{ - SupplicantStateTask *task = (SupplicantStateTask *) user_data; - NMDeviceWifi *self; - NMDeviceWifiPrivate *priv; - NMDevice *dev; - NMDeviceState dev_state; - - g_return_val_if_fail (task != NULL, FALSE); - - self = task->self; - priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - dev = NM_DEVICE (self); - - nm_log_info (LOGD_WIFI, "(%s): supplicant manager state: %s -> %s", - nm_device_get_iface (NM_DEVICE (self)), - nm_supplicant_manager_state_to_string (task->old_state), - nm_supplicant_manager_state_to_string (task->new_state)); - - /* If the supplicant went away, release the supplicant interface */ - if (task->new_state == NM_SUPPLICANT_MANAGER_STATE_DOWN) { - if (priv->supplicant.iface) { - cleanup_association_attempt (self, FALSE); - supplicant_interface_release (self); - } - - if (nm_device_get_state (dev) > NM_DEVICE_STATE_UNAVAILABLE) { - nm_device_state_changed (dev, NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - } - } else if (task->new_state == NM_SUPPLICANT_MANAGER_STATE_IDLE) { - dev_state = nm_device_get_state (dev); - if ( priv->enabled - && !priv->supplicant.iface - && (dev_state >= NM_DEVICE_STATE_UNAVAILABLE) - && (nm_device_get_firmware_missing (NM_DEVICE (self)) == FALSE)) { - /* request a supplicant interface from the supplicant manager */ - supplicant_interface_acquire (self); - - /* if wireless is enabled and we have a supplicant interface, - * we can transition to the DISCONNECTED state. - */ - if (priv->supplicant.iface) { - nm_device_state_changed (dev, NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_NONE); - } - } - } - - finish_supplicant_task (task, FALSE); - return FALSE; -} - -static void -supplicant_mgr_state_cb (NMSupplicantInterface * iface, - guint32 new_state, - guint32 old_state, - NMDeviceWifi *self) -{ - g_return_if_fail (self != NULL); - - schedule_state_handler (self, - supplicant_mgr_state_cb_handler, - new_state, - old_state, - TRUE); } struct iface_con_error_cb_data { @@ -2802,6 +2712,7 @@ handle_auth_or_fail (NMDeviceWifi *self, guint32 tries; NMAccessPoint *ap; NMConnection *connection; + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; g_return_val_if_fail (NM_IS_DEVICE_WIFI (self), NM_ACT_STAGE_RETURN_FAILURE); @@ -2825,24 +2736,21 @@ handle_auth_or_fail (NMDeviceWifi *self, nm_connection_clear_secrets (connection); setting_name = nm_connection_need_secrets (connection, NULL); if (setting_name) { - gboolean get_new; + NMSettingsGetSecretsFlags flags = NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION; /* If the caller doesn't necessarily want completely new secrets, * only ask for new secrets after the first failure. */ - get_new = new_secrets ? TRUE : (tries ? TRUE : FALSE); - nm_act_request_get_secrets (req, - setting_name, - get_new, - SECRETS_CALLER_WIFI, - NULL, - NULL); + if (new_secrets || tries) + flags |= NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW; + nm_act_request_get_secrets (req, setting_name, flags, NULL, wifi_secrets_cb, self); g_object_set_data (G_OBJECT (connection), WIRELESS_SECRETS_TRIES, GUINT_TO_POINTER (++tries)); - } else { + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } else nm_log_warn (LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); - } - return NM_ACT_STAGE_RETURN_POSTPONE; + + return ret; } /* @@ -3212,42 +3120,6 @@ done: return NM_ACT_STAGE_RETURN_SUCCESS; } - -static void -real_connection_secrets_updated (NMDevice *dev, - NMConnection *connection, - GSList *updated_settings, - RequestSecretsCaller caller) -{ - NMActRequest *req; - gboolean valid = FALSE; - GSList *iter; - - g_return_if_fail (caller == SECRETS_CALLER_WIFI); - - if (nm_device_get_state (dev) != NM_DEVICE_STATE_NEED_AUTH) - return; - - for (iter = updated_settings; iter; iter = g_slist_next (iter)) { - const char *setting_name = (const char *) iter->data; - - if ( !strcmp (setting_name, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) - || !strcmp (setting_name, NM_SETTING_802_1X_SETTING_NAME)) { - valid = TRUE; - } else { - nm_log_warn (LOGD_DEVICE, "Ignoring updated secrets for setting '%s'.", - setting_name); - } - } - - req = nm_device_get_act_request (dev); - g_assert (req); - - g_return_if_fail (nm_act_request_get_connection (req) == connection); - - nm_device_activate_schedule_stage1_device_prepare (dev); -} - static NMActStageReturn real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason) { @@ -3260,7 +3132,6 @@ real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason) NMActRequest *req; NMAccessPoint *ap; NMConnection *connection; - NMSettingConnection *s_connection; const char *setting_name; NMSettingWireless *s_wireless; @@ -3277,9 +3148,6 @@ real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason) connection = nm_act_request_get_connection (req); g_assert (connection); - s_connection = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); - g_assert (s_connection); - s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS); g_assert (s_wireless); @@ -3289,7 +3157,7 @@ real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason) nm_log_info (LOGD_DEVICE | LOGD_WIFI, "Activation (%s/wireless): access point '%s' has security," " but secrets are required.", - iface, nm_setting_connection_get_id (s_connection)); + iface, nm_connection_get_id (connection)); ret = handle_auth_or_fail (self, req, FALSE); if (ret == NM_ACT_STAGE_RETURN_FAILURE) @@ -3302,12 +3170,12 @@ real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason) nm_log_info (LOGD_DEVICE | LOGD_WIFI, "Activation (%s/wireless): connection '%s' has security" ", and secrets exist. No new secrets needed.", - iface, nm_setting_connection_get_id (s_connection)); + iface, nm_connection_get_id (connection)); } else { nm_log_info (LOGD_DEVICE | LOGD_WIFI, "Activation (%s/wireless): connection '%s' requires no " "security. No secrets needed.", - iface, nm_setting_connection_get_id (s_connection)); + iface, nm_connection_get_id (connection)); } config = build_supplicant_config (self, connection, ap); @@ -3321,7 +3189,7 @@ real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason) /* Hook up error signal handler to capture association errors */ id = g_signal_connect (priv->supplicant.iface, - "connection-error", + NM_SUPPLICANT_INTERFACE_CONNECTION_ERROR, G_CALLBACK (supplicant_iface_connection_error_cb), self); priv->supplicant.iface_error_id = id; @@ -3413,16 +3281,12 @@ handle_ip_config_timeout (NMDeviceWifi *self, */ auth_enforced = ap_auth_enforced (connection, ap, &encrypted); if (encrypted && !auth_enforced && !may_fail) { - NMSettingConnection *s_con; - - s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); - /* Activation failed, we must have bad encryption key */ nm_log_warn (LOGD_DEVICE | LOGD_WIFI, "Activation (%s/wireless): could not get IP configuration for " "connection '%s'.", - nm_device_get_iface (NM_DEVICE (self)), - nm_setting_connection_get_id (s_con)); + nm_device_get_iface (NM_DEVICE (self)), + nm_connection_get_id (connection)); ret = handle_auth_or_fail (self, NULL, TRUE); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { @@ -3708,10 +3572,8 @@ device_state_changed (NMDevice *device, NMAccessPoint * nm_device_wifi_get_activation_ap (NMDeviceWifi *self) { - NMDeviceWifiPrivate *priv; NMActRequest *req; const char *ap_path; - GSList * elt; g_return_val_if_fail (NM_IS_DEVICE_WIFI (self), NULL); @@ -3720,18 +3582,8 @@ nm_device_wifi_get_activation_ap (NMDeviceWifi *self) return NULL; ap_path = nm_act_request_get_specific_object (req); - if (!ap_path) - return NULL; - - /* Find the AP by it's object path */ - priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - for (elt = priv->ap_list; elt; elt = g_slist_next (elt)) { - NMAccessPoint *ap = NM_AP (elt->data); - if (!strcmp (ap_path, nm_ap_get_dbus_path (ap))) - return ap; - } - return NULL; + return ap_path ? get_ap_by_path (self, ap_path) : NULL; } static void @@ -3781,12 +3633,11 @@ real_set_enabled (NMDeviceInterface *device, gboolean enabled) /* Wait for some drivers like ipw3945 to come back to life */ success = wireless_get_range (self, &range, NULL); - /* iface should be NULL here, but handle it anyway if it's not */ - g_warn_if_fail (priv->supplicant.iface == NULL); + /* Re-initialize the supplicant interface and wait for it to be ready */ if (priv->supplicant.iface) supplicant_interface_release (self); - supplicant_interface_acquire (self); + nm_log_dbg (LOGD_WIFI, "(%s): enable waiting on supplicant state", nm_device_get_iface (NM_DEVICE (device))); } else { @@ -3848,20 +3699,9 @@ dispose (GObject *object) priv->periodic_source_id = 0; } - /* Clean up all pending supplicant tasks */ - while (priv->supplicant.iface_tasks) - finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.iface_tasks->data, TRUE); - while (priv->supplicant.mgr_tasks) - finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.mgr_tasks->data, TRUE); - cleanup_association_attempt (self, TRUE); supplicant_interface_release (self); - if (priv->supplicant.mgr_state_id) { - g_signal_handler_disconnect (priv->supplicant.mgr, priv->supplicant.mgr_state_id); - priv->supplicant.mgr_state_id = 0; - } - if (priv->supplicant.mgr) { g_object_unref (priv->supplicant.mgr); priv->supplicant.mgr = NULL; @@ -3969,8 +3809,8 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) parent_class->update_initial_hw_address = real_update_initial_hw_address; parent_class->get_best_auto_connection = real_get_best_auto_connection; parent_class->is_available = real_is_available; - parent_class->connection_secrets_updated = real_connection_secrets_updated; parent_class->check_connection_compatible = real_check_connection_compatible; + parent_class->complete_connection = real_complete_connection; parent_class->act_stage1_prepare = real_act_stage1_prepare; parent_class->act_stage2_config = real_act_stage2_config; @@ -3978,7 +3818,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) parent_class->act_stage4_ip4_config_timeout = real_act_stage4_ip4_config_timeout; parent_class->act_stage4_ip6_config_timeout = real_act_stage4_ip6_config_timeout; parent_class->deactivate = real_deactivate; - parent_class->deactivate_quickly = real_deactivate_quickly; parent_class->can_interrupt_activation = real_can_interrupt_activation; parent_class->spec_match_list = spec_match_list; |