From fdfbe00aac3f17b19bb8d84cba1c8f210d90e8a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Klime=C5=A1?= Date: Fri, 17 Jun 2011 12:43:28 +0200 Subject: policy: remove "invalid mark" for failed connections after 5 mins If there is a temporary connection failure (e.g. due to unavailable DHCP), the connection is marked as invalid after several retries. Reset the flag after 5 mins to allow next auto-reconnection. --- src/nm-policy.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/src/nm-policy.c b/src/nm-policy.c index 3eead414be..e3c899f5e3 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -66,12 +66,16 @@ struct NMPolicy { HostnameThread *lookup; + gint reset_retries_id; /* idle handler for resetting the retries count */ + char *orig_hostname; /* hostname at NM start time */ char *cur_hostname; /* hostname we want to assign */ }; #define RETRIES_TAG "autoconnect-retries" #define RETRIES_DEFAULT 4 +#define RESET_RETRIES_TIMESTAMP_TAG "reset-retries-timestamp-tag" +#define RESET_RETRIES_TIMER 300 static NMDevice * get_best_ip4_device (NMManager *manager, NMActRequest **out_req) @@ -870,6 +874,37 @@ schedule_activate_check (NMPolicy *policy, NMDevice *device, guint delay_seconds } } +static gboolean +reset_connections_retries (gpointer user_data) +{ + NMPolicy *policy = (NMPolicy *) user_data; + GSList *connections, *iter; + time_t con_stamp, min_stamp, now; + + policy->reset_retries_id = 0; + + min_stamp = now = time (NULL); + connections = nm_settings_get_connections (policy->settings); + for (iter = connections; iter; iter = g_slist_next (iter)) { + con_stamp = GPOINTER_TO_SIZE (g_object_get_data (G_OBJECT (iter->data), RESET_RETRIES_TIMESTAMP_TAG)); + if (con_stamp == 0) + continue; + if (con_stamp + RESET_RETRIES_TIMER <= now) { + set_connection_auto_retries (NM_CONNECTION (iter->data), RETRIES_DEFAULT); + g_object_set_data (G_OBJECT (iter->data), RESET_RETRIES_TIMESTAMP_TAG, GSIZE_TO_POINTER (0)); + continue; + } + if (con_stamp < min_stamp) + min_stamp = con_stamp; + } + g_slist_free (connections); + + /* Schedule the handler again if there are some stamps left */ + if (min_stamp != now) + policy->reset_retries_id = g_timeout_add_seconds (RESET_RETRIES_TIMER - (now - min_stamp), reset_connections_retries, policy); + return FALSE; +} + static NMConnection * get_device_connection (NMDevice *device) { @@ -914,8 +949,13 @@ device_state_changed (NMDevice *device, set_connection_auto_retries (connection, tries - 1); } - if (get_connection_auto_retries (connection) == 0) + if (get_connection_auto_retries (connection) == 0) { nm_log_info (LOGD_DEVICE, "Marking connection '%s' invalid.", nm_connection_get_id (connection)); + /* Schedule a handler to reset retries count */ + g_object_set_data (G_OBJECT (connection), RESET_RETRIES_TIMESTAMP_TAG, GSIZE_TO_POINTER ((gsize) time (NULL))); + if (!policy->reset_retries_id) + policy->reset_retries_id = g_timeout_add_seconds (RESET_RETRIES_TIMER, reset_connections_retries, policy); + } nm_connection_clear_secrets (connection); } schedule_activate_check (policy, device, 3); @@ -938,7 +978,7 @@ device_state_changed (NMDevice *device, update_routing_and_dns (policy, FALSE); break; case NM_DEVICE_STATE_DISCONNECTED: - /* Clear INVALID_TAG when carrier on. If cable was unplugged + /* Reset RETRIES_TAG when carrier on. If cable was unplugged * and plugged again, we should try to reconnect */ if (reason == NM_DEVICE_STATE_REASON_CARRIER && old_state == NM_DEVICE_STATE_UNAVAILABLE) reset_retries_all (policy->settings, device); @@ -1246,6 +1286,9 @@ nm_policy_destroy (NMPolicy *policy) } g_slist_free (policy->dev_ids); + if (policy->reset_retries_id) + g_source_remove (policy->reset_retries_id); + g_free (policy->orig_hostname); g_free (policy->cur_hostname); -- cgit v1.2.1 From a27cd8e5d95e4f5a1c54d6dc2515feb2bb861444 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 29 Jun 2011 18:15:05 -0500 Subject: wifi: allow supplicant disconnect request more often Use a broader range of supplicant interface states to determine when to tell the supplicant to idle; we want to allow the disconnect in all of these states, not just some of them. Second, allow the active network to be removed from the supplicant's list in most of these states, even when the supplicant interface is inactive or disconnected. --- src/supplicant-manager/nm-supplicant-interface.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c index e9e58f39fe..2459f589ae 100644 --- a/src/supplicant-manager/nm-supplicant-interface.c +++ b/src/supplicant-manager/nm-supplicant-interface.c @@ -682,12 +682,13 @@ nm_supplicant_interface_disconnect (NMSupplicantInterface * self) if (!priv->iface_proxy) return; - /* Don't try to disconnect if the supplicant interface is already disconnected */ - if ( priv->state == NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED - || priv->state == NM_SUPPLICANT_INTERFACE_STATE_INACTIVE) { - g_free (priv->net_path); - priv->net_path = NULL; - return; + /* Disconnect from the current AP */ + if ( (priv->state >= NM_SUPPLICANT_INTERFACE_STATE_SCANNING) + && (priv->state <= NM_SUPPLICANT_INTERFACE_STATE_COMPLETED)) { + dbus_g_proxy_begin_call (priv->iface_proxy, "Disconnect", + disconnect_cb, + NULL, NULL, + G_TYPE_INVALID); } /* Remove any network that was added by NetworkManager */ @@ -700,11 +701,6 @@ nm_supplicant_interface_disconnect (NMSupplicantInterface * self) g_free (priv->net_path); priv->net_path = NULL; } - - dbus_g_proxy_begin_call (priv->iface_proxy, "Disconnect", - disconnect_cb, - NULL, NULL, - G_TYPE_INVALID); } static void -- cgit v1.2.1 From 6187b85052644f212d12ba6f76c60c4c14f70f79 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 29 Jun 2011 18:17:43 -0500 Subject: wifi: immediately request new 802.1x 'always-ask' passwords if they fail Instead of retrying the password a number of times, immediately fail the connection and ask for a new pasword if (1) the request fails during the 802.1x authentication and (2) the password is an 'always-ask' 802.1x password. The password is bad anyway, and in the case of RSA/OTP tokens the code may have already changed, so it's pointless to keep retrying the same password when it's already stale. --- src/nm-device-wifi.c | 144 +++++++++++++++++++++++++++------------------------ 1 file changed, 76 insertions(+), 68 deletions(-) diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c index a98347688f..491b856ce2 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -2450,88 +2450,86 @@ remove_link_timeout (NMDeviceWifi *self) static gboolean link_timeout_cb (gpointer user_data) { - NMDevice * dev = NM_DEVICE (user_data); - NMDeviceWifi * self = NM_DEVICE_WIFI (dev); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - NMActRequest * req = NULL; - NMAccessPoint * ap = NULL; - NMConnection * connection; - const char * setting_name; - gboolean auth_enforced, encrypted = FALSE; + NMDevice *dev = NM_DEVICE (user_data); - g_assert (dev); + nm_log_warn (LOGD_WIFI, "(%s): link timed out.", nm_device_get_iface (dev)); - priv->link_timeout_id = 0; - - req = nm_device_get_act_request (dev); - ap = nm_device_wifi_get_activation_ap (self); - if (req == NULL || ap == NULL) { - /* shouldn't ever happen */ - nm_log_err (LOGD_WIFI, "couldn't get activation request or activation AP."); - if (nm_device_is_activating (dev)) { - cleanup_association_attempt (self, TRUE); - nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NONE); - } - return FALSE; - } + NM_DEVICE_WIFI_GET_PRIVATE (dev)->link_timeout_id = 0; /* Disconnect event while activated; the supplicant hasn't been able * to reassociate within the timeout period, so the connection must * fail. */ - if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) { + if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) nm_device_state_changed (dev, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT); - return FALSE; - } - /* Disconnect event during initial authentication and credentials - * ARE checked - we are likely to have wrong key. Ask the user for - * another one. + return FALSE; +} + +static gboolean +handle_authenticate_fail (NMDeviceWifi *self, guint32 new_state, guint32 old_state) +{ + NMDevice *device = NM_DEVICE (self); + NMSetting8021x *s_8021x; + NMSettingWirelessSecurity *s_wsec; + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + NMActRequest *req; + NMConnection *connection; + const char *setting_name = NULL; + gboolean handled = FALSE; + + g_return_val_if_fail (new_state == NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED, FALSE); + + /* Only care about ASSOCIATED -> DISCONNECTED transitions since 802.1x stuff + * happens between the ASSOCIATED and AUTHENTICATED states. */ - if (nm_device_get_state (dev) != NM_DEVICE_STATE_CONFIG) - goto time_out; + if (old_state != NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED) + return FALSE; - connection = nm_act_request_get_connection (req); - if (!connection) - goto time_out; + req = nm_device_get_act_request (NM_DEVICE (self)); + g_return_val_if_fail (req != NULL, FALSE); - auth_enforced = ap_auth_enforced (connection, ap, &encrypted); - if (!encrypted || !auth_enforced) - goto time_out; + connection = nm_act_request_get_connection (req); + g_return_val_if_fail (connection != NULL, FALSE); - /* Drivers are still just too crappy, and emit too many disassociation - * events during connection. So for now, just let the driver and supplicant - * keep trying to associate, and don't ask for new secrets when we get - * disconnected during association. + /* If it's an 802.1x or LEAP connection with "always ask"/unsaved secrets + * then we need to ask again because it might be an OTP token and the PIN + * may have changed. */ - if (0) { + s_8021x = nm_connection_get_setting_802_1x (connection); + s_wsec = nm_connection_get_setting_wireless_security (connection); + + if (s_8021x) { + nm_setting_get_secret_flags (NM_SETTING (s_8021x), + NM_SETTING_802_1X_PASSWORD, + &secret_flags, + NULL); + setting_name = NM_SETTING_802_1X_SETTING_NAME; + } else if (s_wsec) { + nm_setting_get_secret_flags (NM_SETTING (s_wsec), + NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, + &secret_flags, + NULL); + setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME; + } + + if (setting_name && (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED)) { + NMSettingsGetSecretsFlags flags = NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION + | NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW; + nm_connection_clear_secrets (connection); - setting_name = nm_connection_need_secrets (connection, NULL); - if (!setting_name) - goto time_out; - /* Association/authentication failed during association, probably have a - * bad encryption key and the authenticating entity (AP, RADIUS server, etc) - * denied the association due to bad credentials. - */ nm_log_info (LOGD_DEVICE | LOGD_WIFI, "Activation (%s/wireless): disconnected during association," - " asking for new key.", nm_device_get_iface (dev)); - cleanup_association_attempt (self, TRUE); - nm_device_state_changed (dev, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - nm_act_request_get_secrets (req, - setting_name, - NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW, - NULL, - wifi_secrets_cb, - self); + " asking for new key.", nm_device_get_iface (device)); - return FALSE; + cleanup_association_attempt (self, TRUE); + nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); + nm_act_request_get_secrets (req, setting_name, flags, NULL, wifi_secrets_cb, self); + handled = TRUE; } -time_out: - nm_log_warn (LOGD_WIFI, "(%s): link timed out.", nm_device_get_iface (dev)); - return FALSE; + return handled; } static void @@ -2600,14 +2598,20 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, 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. + /* Disconnect during authentication means the 802.1x password is wrong */ + if (handle_authenticate_fail (self, new_state, old_state)) + break; + } + + if (devstate == NM_DEVICE_STATE_ACTIVATED) { + /* If it's a disconnect while activated then start the link timer + * to let the supplicant reconnect for a bit and if that doesn't + * work kill the connection and try something else. Allow a bit + * more time if the card is scanning since sometimes the link will + * drop while scanning and come back when the scan is done. */ - if (!priv->link_timeout_id) { - priv->link_timeout_id = g_timeout_add_seconds (scanning ? 30 : 15, - link_timeout_cb, self); - } + if (priv->link_timeout_id == 0) + priv->link_timeout_id = g_timeout_add_seconds (scanning ? 30 : 15, link_timeout_cb, self); } break; case NM_SUPPLICANT_INTERFACE_STATE_DOWN: @@ -3571,6 +3575,10 @@ device_state_changed (NMDevice *device, } clear_aps = TRUE; break; + case NM_DEVICE_STATE_NEED_AUTH: + if (priv->supplicant.iface) + nm_supplicant_interface_disconnect (priv->supplicant.iface); + break; case NM_DEVICE_STATE_ACTIVATED: activation_success_handler (device); break; -- cgit v1.2.1