diff options
Diffstat (limited to 'src/nm-policy.c')
-rw-r--r-- | src/nm-policy.c | 160 |
1 files changed, 141 insertions, 19 deletions
diff --git a/src/nm-policy.c b/src/nm-policy.c index 194d11116..a42a0fa9b 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -46,6 +46,7 @@ #include "nm-dns-manager.h" #include "nm-vpn-manager.h" #include "nm-policy-hostname.h" +#include "nm-manager-auth.h" struct NMPolicy { NMManager *manager; @@ -66,12 +67,17 @@ 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 +#define FAILURE_REASON_TAG "failure-reason" static NMDevice * get_best_ip4_device (NMManager *manager, NMActRequest **out_req) @@ -316,36 +322,36 @@ update_system_hostname (NMPolicy *policy, NMDevice *best4, NMDevice *best6) /* Grab a hostname out of the device's DHCP4 config */ dhcp4_config = nm_device_get_dhcp4_config (best4); if (dhcp4_config) { - p = dhcp_hostname = nm_dhcp4_config_get_option (dhcp4_config, "host_name"); + p = dhcp_hostname = nm_dhcp4_config_get_option (dhcp4_config, "new_host_name"); if (dhcp_hostname && strlen (dhcp_hostname)) { /* Sanity check; strip leading spaces */ while (*p) { if (!isblank (*p++)) { - _set_hostname (policy, TRUE, dhcp_hostname, "from DHCPv4"); + _set_hostname (policy, TRUE, p-1, "from DHCPv4"); return; } } nm_log_warn (LOGD_DNS, "DHCPv4-provided hostname '%s' looks invalid; ignoring it", - dhcp_hostname); + dhcp_hostname); } } } else if (best6) { NMDHCP6Config *dhcp6_config; - /* Grab a hostname out of the device's DHCP4 config */ + /* Grab a hostname out of the device's DHCP6 config */ dhcp6_config = nm_device_get_dhcp6_config (best6); if (dhcp6_config) { - p = dhcp_hostname = nm_dhcp6_config_get_option (dhcp6_config, "host_name"); + p = dhcp_hostname = nm_dhcp6_config_get_option (dhcp6_config, "new_host_name"); if (dhcp_hostname && strlen (dhcp_hostname)) { /* Sanity check; strip leading spaces */ while (*p) { if (!isblank (*p++)) { - _set_hostname (policy, TRUE, dhcp_hostname, "from DHCPv6"); + _set_hostname (policy, TRUE, p-1, "from DHCPv6"); return; } } nm_log_warn (LOGD_DNS, "DHCPv6-provided hostname '%s' looks invalid; ignoring it", - dhcp_hostname); + dhcp_hostname); } } } @@ -722,16 +728,29 @@ auto_activate_device (gpointer user_data) /* Remove connections that shouldn't be auto-activated */ while (iter) { - NMConnection *candidate = NM_CONNECTION (iter->data); + NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (iter->data); + gboolean remove_it = FALSE; + const char *permission; /* Grab next item before we possibly delete the current item */ iter = g_slist_next (iter); /* Ignore connections that were tried too many times or are not visible - * to any logged-in users. + * to any logged-in users. Also ignore shared wifi connections for + * which no user has the shared wifi permission. */ - if ( get_connection_auto_retries (candidate) == 0 - || nm_settings_connection_is_visible (NM_SETTINGS_CONNECTION (candidate)) == FALSE) + if ( get_connection_auto_retries (NM_CONNECTION (candidate)) == 0 + || nm_settings_connection_is_visible (candidate) == FALSE) + remove_it = TRUE; + else { + permission = nm_utils_get_shared_wifi_permission (NM_CONNECTION (candidate)); + if (permission) { + if (nm_settings_connection_check_permission (candidate, permission) == FALSE) + remove_it = TRUE; + } + } + + if (remove_it) connections = g_slist_remove (connections, candidate); } @@ -739,6 +758,8 @@ auto_activate_device (gpointer user_data) if (best_connection) { GError *error = NULL; + nm_log_info (LOGD_DEVICE, "Auto-activating connection '%s'.", + nm_connection_get_id (best_connection)); if (!nm_manager_activate_connection (policy->manager, best_connection, specific_object, @@ -817,13 +838,34 @@ hostname_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) } static void -reset_retries_all (NMSettings *settings) +reset_retries_all (NMSettings *settings, NMDevice *device) +{ + GSList *connections, *iter; + GError *error = NULL; + + connections = nm_settings_get_connections (settings); + for (iter = connections; iter; iter = g_slist_next (iter)) { + if (!device || nm_device_interface_check_connection_compatible (NM_DEVICE_INTERFACE (device), iter->data, &error)) + set_connection_auto_retries (NM_CONNECTION (iter->data), RETRIES_DEFAULT); + g_clear_error (&error); + } + g_slist_free (connections); +} + +static void +reset_retries_for_failed_secrets (NMSettings *settings) { GSList *connections, *iter; connections = nm_settings_get_connections (settings); - for (iter = connections; iter; iter = g_slist_next (iter)) - set_connection_auto_retries (NM_CONNECTION (iter->data), RETRIES_DEFAULT); + for (iter = connections; iter; iter = g_slist_next (iter)) { + NMDeviceStateReason reason = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (iter->data), FAILURE_REASON_TAG)); + + if (reason == NM_DEVICE_STATE_REASON_NO_SECRETS) { + set_connection_auto_retries (NM_CONNECTION (iter->data), RETRIES_DEFAULT); + g_object_set_data (G_OBJECT (iter->data), FAILURE_REASON_TAG, GUINT_TO_POINTER (0)); + } + } g_slist_free (connections); } @@ -838,7 +880,7 @@ sleeping_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) /* Reset retries on all connections so they'll checked on wakeup */ if (sleeping || !enabled) - reset_retries_all (policy->settings); + reset_retries_all (policy->settings, NULL); } static void @@ -854,6 +896,9 @@ schedule_activate_check (NMPolicy *policy, NMDevice *device, guint delay_seconds if (state < NM_DEVICE_STATE_DISCONNECTED) return; + if (!nm_device_interface_get_enabled (NM_DEVICE_INTERFACE (device))) + return; + if (!nm_device_autoconnect_allowed (device)) return; @@ -864,6 +909,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) { @@ -886,6 +962,9 @@ device_state_changed (NMDevice *device, NMPolicy *policy = (NMPolicy *) user_data; NMConnection *connection = get_device_connection (device); + if (connection) + g_object_set_data (G_OBJECT (connection), FAILURE_REASON_TAG, GUINT_TO_POINTER (0)); + switch (new_state) { case NM_DEVICE_STATE_FAILED: /* Mark the connection invalid if it failed during activation so that @@ -900,6 +979,11 @@ device_state_changed (NMDevice *device, * automatically retrying because it's just going to fail anyway. */ set_connection_auto_retries (connection, 0); + + /* Mark the connection as failed due to missing secrets so that we can reset + * RETRIES_TAG and automatically re-try when an secret agent registers. + */ + g_object_set_data (G_OBJECT (connection), FAILURE_REASON_TAG, GUINT_TO_POINTER (NM_DEVICE_STATE_REASON_NO_SECRETS)); } else if (tries > 0) { /* Otherwise if it's a random failure, just decrease the number * of automatic retries so that the connection gets tried again @@ -908,8 +992,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); @@ -932,6 +1021,11 @@ device_state_changed (NMDevice *device, update_routing_and_dns (policy, FALSE); break; case NM_DEVICE_STATE_DISCONNECTED: + /* 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); + /* Device is now available for auto-activation */ update_routing_and_dns (policy, FALSE); schedule_activate_check (policy, device, 0); @@ -963,6 +1057,12 @@ nsps_changed (NMDeviceWimax *device, NMWimaxNsp *nsp, gpointer user_data) } #endif +static void +modem_enabled_changed (NMDeviceModem *device, gpointer user_data) +{ + schedule_activate_check ((NMPolicy *) (user_data), NM_DEVICE (device), 0); +} + typedef struct { gulong id; NMDevice *device; @@ -997,6 +1097,8 @@ device_added (NMManager *manager, NMDevice *device, gpointer user_data) _connect_device_signal (policy, device, "nsp-added", nsps_changed); _connect_device_signal (policy, device, "nsp-removed", nsps_changed); #endif + } else if (NM_IS_DEVICE_MODEM (device)) { + _connect_device_signal (policy, device, NM_DEVICE_MODEM_ENABLE_CHANGED, modem_enabled_changed); } } @@ -1058,7 +1160,7 @@ connections_loaded (NMSettings *settings, gpointer user_data) // that by calling reset_retries_all() in nm_policy_new() /* Initialize connections' auto-retries */ - reset_retries_all (settings); + reset_retries_all (settings, NULL); schedule_activate_all ((NMPolicy *) user_data); } @@ -1122,6 +1224,19 @@ connection_visibility_changed (NMSettings *settings, } static void +secret_agent_registered (NMSettings *settings, + NMSecretAgent *agent, + gpointer user_data) +{ + /* The registered secret agent may provide some missing secrets. Thus we + * reset retries count here and schedule activation, so that the + * connections failed due to missing secrets may re-try auto-connection. + */ + reset_retries_for_failed_secrets (settings); + schedule_activate_all ((NMPolicy *) user_data); +} + +static void _connect_manager_signal (NMPolicy *policy, const char *name, gpointer callback) { guint id; @@ -1161,7 +1276,10 @@ nm_policy_new (NMManager *manager, memset (hostname, 0, sizeof (hostname)); if (gethostname (&hostname[0], HOST_NAME_MAX) == 0) { /* only cache it if it's a valid hostname */ - if (strlen (hostname) && strcmp (hostname, "localhost") && strcmp (hostname, "localhost.localdomain")) + if ( strlen (hostname) + && strcmp (hostname, "localhost") + && strcmp (hostname, "localhost.localdomain") + && strcmp (hostname, "(none)")) policy->orig_hostname = g_strdup (hostname); } @@ -1186,9 +1304,10 @@ nm_policy_new (NMManager *manager, _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, connection_removed); _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, connection_visibility_changed); + _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_AGENT_REGISTERED, secret_agent_registered); /* Initialize connections' auto-retries */ - reset_retries_all (policy->settings); + reset_retries_all (policy->settings, NULL); initialized = TRUE; return policy; @@ -1232,6 +1351,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); |