summary refs log tree commit diff
path: root/src/nm-policy.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2011-08-23 19:16:47 +0200
committerMichael Biebl <biebl@debian.org>2011-08-23 19:16:47 +0200
commit263bf4c0c89bb88dc995acd9a6a2de9095fbd461 (patch)
tree7224326afe367409e7150e49fad9029f81fe24b8 /src/nm-policy.c
parentd465e5fac63f36bcf4069e36827f4b62c494556d (diff)
Imported Upstream version 0.9.0 upstream/0.9.0
Diffstat (limited to 'src/nm-policy.c')
-rw-r--r--src/nm-policy.c160
1 files changed, 141 insertions, 19 deletions
diff --git a/src/nm-policy.c b/src/nm-policy.c
index 194d1111..a42a0fa9 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);