summary refs log tree commit diff
path: root/src/devices/nm-device.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/nm-device.c')
-rw-r--r--src/devices/nm-device.c160
1 files changed, 84 insertions, 76 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index e979b875..6a1a10f4 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -354,6 +354,8 @@ typedef struct _NMDevicePrivate {
 	bool            v4_route_table_initalized:1;
 	bool            v6_route_table_initalized:1;
 
+	NMDeviceAutoconnectBlockedFlags autoconnect_blocked_flags:4;
+
 	/* Generic DHCP stuff */
 	char *          dhcp_anycast_address;
 
@@ -466,10 +468,6 @@ typedef struct _NMDevicePrivate {
 
 	gboolean needs_ip6_subnet;
 
-	/* allow autoconnect feature */
-	bool autoconnect_intern:1;
-	bool autoconnect_user:1;
-
 	/* master interface for bridge/bond/team slave */
 	NMDevice *      master;
 	bool            is_enslaved;
@@ -533,9 +531,6 @@ static NMActStageReturn linklocal6_start (NMDevice *self);
 
 static void _carrier_wait_check_queued_act_request (NMDevice *self);
 
-static void nm_device_set_autoconnect_both (NMDevice *self, gboolean autoconnect);
-static void nm_device_set_autoconnect_full (NMDevice *self, int autoconnect_intern, int autoconnect_user);
-
 static const char *_activation_func_to_string (ActivationHandleFunc func);
 static void activation_source_handle_cb (NMDevice *self, int addr_family);
 
@@ -3392,8 +3387,6 @@ realize_start_setup (NMDevice *self,
 	if (real_rate)
 		priv->stats.timeout_id = g_timeout_add (real_rate, _stats_timeout_cb, self);
 
-	nm_device_set_autoconnect_full (self, !!DEFAULT_AUTOCONNECT, TRUE);
-
 	klass->realize_start_notify (self, plink);
 
 	nm_assert (!nm_device_get_unmanaged_mask (self, NM_UNMANAGED_USER_EXPLICIT));
@@ -3593,8 +3586,6 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
 	priv->real = FALSE;
 	_notify (self, PROP_REAL);
 
-	nm_device_set_autoconnect_both (self, FALSE);
-
 	g_object_thaw_notify (G_OBJECT (self));
 
 	nm_device_set_unmanaged_flags (self,
@@ -4219,62 +4210,55 @@ nm_device_set_enabled (NMDevice *self, gboolean enabled)
 		NM_DEVICE_GET_CLASS (self)->set_enabled (self, enabled);
 }
 
-/**
- * nm_device_get_autoconnect:
- * @self: the #NMDevice
- *
- * Returns: %TRUE if the device allows autoconnect connections, or %FALSE if the
- * device is explicitly blocking all autoconnect connections.  Does not take
- * into account transient conditions like companion devices that may wish to
- * block the device.
- */
-gboolean
-nm_device_get_autoconnect (NMDevice *self)
+NM_UTILS_FLAGS2STR_DEFINE_STATIC (_autoconnect_blocked_flags_to_string, NMDeviceAutoconnectBlockedFlags,
+	NM_UTILS_FLAGS2STR (NM_DEVICE_AUTOCONNECT_BLOCKED_NONE,              "none"),
+	NM_UTILS_FLAGS2STR (NM_DEVICE_AUTOCONNECT_BLOCKED_USER,              "user"),
+	NM_UTILS_FLAGS2STR (NM_DEVICE_AUTOCONNECT_BLOCKED_WRONG_PIN,         "wrong-pin"),
+	NM_UTILS_FLAGS2STR (NM_DEVICE_AUTOCONNECT_BLOCKED_MANUAL_DISCONNECT, "manual-disconnect"),
+);
+
+NMDeviceAutoconnectBlockedFlags
+nm_device_autoconnect_blocked_get (NMDevice *self, NMDeviceAutoconnectBlockedFlags mask)
 {
 	NMDevicePrivate *priv;
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
 
+	if (mask == 0)
+		mask = NM_DEVICE_AUTOCONNECT_BLOCKED_ALL;
+
 	priv = NM_DEVICE_GET_PRIVATE (self);
-	return priv->autoconnect_intern && priv->autoconnect_user;
+	return priv->autoconnect_blocked_flags & mask;
 }
 
-static void
-nm_device_set_autoconnect_full (NMDevice *self, int autoconnect_intern, int autoconnect_user)
+void
+nm_device_autoconnect_blocked_set_full (NMDevice *self, NMDeviceAutoconnectBlockedFlags mask, NMDeviceAutoconnectBlockedFlags value)
 {
 	NMDevicePrivate *priv;
-	gboolean old_value;
+	gboolean changed;
+	char buf1[128], buf2[128];
 
 	g_return_if_fail (NM_IS_DEVICE (self));
+	nm_assert (mask);
+	nm_assert (!NM_FLAGS_ANY (mask, ~NM_DEVICE_AUTOCONNECT_BLOCKED_ALL));
+	nm_assert (!NM_FLAGS_ANY (value, ~mask));
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
 
-	old_value = nm_device_get_autoconnect (self);
-	if (autoconnect_intern != -1)
-		priv->autoconnect_intern = autoconnect_intern;
-	if (autoconnect_user != -1)
-		priv->autoconnect_user = autoconnect_user;
-	if (old_value != nm_device_get_autoconnect (self))
-		_notify (self, PROP_AUTOCONNECT);
-}
+	value = (priv->autoconnect_blocked_flags & ~mask) | (mask & value);
+	if (value == priv->autoconnect_blocked_flags)
+		return;
 
-void
-nm_device_set_autoconnect_intern (NMDevice *self, gboolean autoconnect)
-{
-	nm_device_set_autoconnect_full (self, !!autoconnect, -1);
-}
+	changed = ((!value) != (!priv->autoconnect_blocked_flags));
 
-static void
-nm_device_set_autoconnect_both (NMDevice *self, gboolean autoconnect)
-{
-	autoconnect = !!autoconnect;
-	nm_device_set_autoconnect_full (self, autoconnect, autoconnect);
-}
+	_LOGT (LOGD_DEVICE, "autoconnect-blocked: set \"%s\" (was \"%s\")",
+	       _autoconnect_blocked_flags_to_string (value, buf1, sizeof (buf1)),
+	       _autoconnect_blocked_flags_to_string (priv->autoconnect_blocked_flags, buf2, sizeof (buf2)));
 
-static gboolean
-get_autoconnect_allowed (NMDevice *self)
-{
-	return TRUE;
+	priv->autoconnect_blocked_flags = value;
+	nm_assert (priv->autoconnect_blocked_flags == value);
+	if (changed)
+		_notify (self, PROP_AUTOCONNECT);
 }
 
 static gboolean
@@ -4303,14 +4287,23 @@ nm_device_autoconnect_allowed (NMDevice *self)
 	GValue instance = G_VALUE_INIT;
 	GValue retval = G_VALUE_INIT;
 
-	if (   !nm_device_get_autoconnect (self)
-	    || !klass->get_autoconnect_allowed (self))
+	if (nm_device_autoconnect_blocked_get (self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL))
 		return FALSE;
 
-	/* Unrealized devices can always autoconnect. */
-	if (nm_device_is_real (self) && priv->state < NM_DEVICE_STATE_DISCONNECTED)
+	if (   klass->get_autoconnect_allowed
+	    && !klass->get_autoconnect_allowed (self))
 		return FALSE;
 
+	if (!nm_device_get_enabled (self))
+		return FALSE;
+
+	if (nm_device_is_real (self)) {
+		if (priv->state < NM_DEVICE_STATE_DISCONNECTED)
+			return FALSE;
+	} else {
+		/* Unrealized devices can always autoconnect. */
+	}
+
 	/* The 'autoconnect-allowed' signal is emitted on a device to allow
 	 * other listeners to block autoconnect on the device if they wish.
 	 * This is mainly used by the OLPC Mesh devices to block autoconnect
@@ -4337,15 +4330,8 @@ can_auto_connect (NMDevice *self,
                   NMConnection *connection,
                   char **specific_object)
 {
-	NMSettingConnection *s_con;
-
 	nm_assert (!specific_object || !*specific_object);
-
-	s_con = nm_connection_get_setting_connection (connection);
-	if (!nm_setting_connection_get_autoconnect (s_con))
-		return FALSE;
-
-	return nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL);
+	return TRUE;
 }
 
 /**
@@ -4372,11 +4358,24 @@ nm_device_can_auto_connect (NMDevice *self,
 {
 	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
-	g_return_val_if_fail (specific_object && !*specific_object, FALSE);
+	g_return_val_if_fail (!specific_object || !*specific_object, FALSE);
 
-	if (nm_device_autoconnect_allowed (self))
-		return NM_DEVICE_GET_CLASS (self)->can_auto_connect (self, connection, specific_object);
-	return FALSE;
+	/* the caller must ensure that nm_device_autoconnect_allowed() returns
+	 * TRUE as well. This is done, because nm_device_can_auto_connect()
+	 * has only one caller, and it iterates over a list of available
+	 * connections.
+	 *
+	 * Hence, we don't need to re-check nm_device_autoconnect_allowed()
+	 * over and over again. The caller is supposed to do that. */
+	nm_assert (nm_device_autoconnect_allowed (self));
+
+	if (!nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL))
+		return FALSE;
+
+	if (!NM_DEVICE_GET_CLASS (self)->can_auto_connect (self, connection, specific_object))
+		return FALSE;
+
+	return TRUE;
 }
 
 static gboolean
@@ -4975,7 +4974,7 @@ static void
 activation_source_schedule (NMDevice *self, ActivationHandleFunc func, int addr_family)
 {
 	ActivationHandleData *act_data;
-	GSourceFunc source_func;
+	GSourceFunc source_func = NULL;
 	guint new_id = 0;
 
 	act_data = activation_source_get_by_family (self, addr_family, &source_func);
@@ -5396,8 +5395,8 @@ ipv4_manual_method_apply (NMDevice *self, NMIP4Config **configs, gboolean succes
 		nm_device_activate_schedule_ip4_config_result (self, empty);
 		g_object_unref (empty);
 	} else {
-		nm_device_queue_state (self, NM_DEVICE_STATE_FAILED,
-		                       NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+		nm_device_ip_method_failed (self, AF_INET,
+		                            NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
 	}
 }
 
@@ -5977,8 +5976,8 @@ dhcp4_dad_cb (NMDevice *self, NMIP4Config **configs, gboolean success)
 	if (success)
 		nm_device_activate_schedule_ip4_config_result (self, configs[1]);
 	else {
-		nm_device_state_changed (self, NM_DEVICE_STATE_FAILED,
-		                         NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+		nm_device_ip_method_failed (self, AF_INET,
+		                            NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
 	}
 }
 
@@ -9732,7 +9731,7 @@ disconnect_cb (NMDevice *self,
 		nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, FALSE, NULL, subject, local->message);
 		g_dbus_method_invocation_take_error (context, local);
 	} else {
-		nm_device_set_autoconnect_intern (self, FALSE);
+		nm_device_autoconnect_blocked_set (self, NM_DEVICE_AUTOCONNECT_BLOCKED_MANUAL_DISCONNECT);
 
 		nm_device_state_changed (self,
 		                         NM_DEVICE_STATE_DEACTIVATING,
@@ -12988,10 +12987,10 @@ _set_state_full (NMDevice *self,
 		break;
 	}
 
-	/* Reset autoconnect flag when the device is activating or connected. */
+	/* Reset intern autoconnect flags when the device is activating or connected. */
 	if (   state >= NM_DEVICE_STATE_PREPARE
 	    && state <= NM_DEVICE_STATE_ACTIVATED)
-		nm_device_set_autoconnect_intern  (self, TRUE);
+		nm_device_autoconnect_blocked_unset (self, NM_DEVICE_AUTOCONNECT_BLOCKED_INTERNAL);
 
 	_notify (self, PROP_STATE);
 	_notify (self, PROP_STATE_REASON);
@@ -14116,6 +14115,10 @@ nm_device_init (NMDevice *self)
 
 	priv->netns = g_object_ref (NM_NETNS_GET);
 
+	priv->autoconnect_blocked_flags = DEFAULT_AUTOCONNECT
+	                                  ? NM_DEVICE_AUTOCONNECT_BLOCKED_NONE
+	                                  : NM_DEVICE_AUTOCONNECT_BLOCKED_USER;
+
 	priv->auth_retries = NM_DEVICE_AUTH_RETRIES_UNSET;
 	priv->type = NM_DEVICE_TYPE_UNKNOWN;
 	priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED;
@@ -14402,7 +14405,10 @@ set_property (GObject *object, guint prop_id,
 		}
 		break;
 	case PROP_AUTOCONNECT:
-		nm_device_set_autoconnect_both (self, g_value_get_boolean (value));
+		if (g_value_get_boolean (value))
+			nm_device_autoconnect_blocked_unset (self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL);
+		else
+			nm_device_autoconnect_blocked_set (self, NM_DEVICE_AUTOCONNECT_BLOCKED_USER);
 		break;
 	case PROP_FIRMWARE_MISSING:
 		/* construct-only */
@@ -14539,7 +14545,10 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_boolean (value, nm_device_get_state (self) > NM_DEVICE_STATE_UNMANAGED);
 		break;
 	case PROP_AUTOCONNECT:
-		g_value_set_boolean (value, nm_device_get_autoconnect (self));
+		g_value_set_boolean (value,
+		                     nm_device_autoconnect_blocked_get (self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL)
+		                       ? FALSE
+		                       : TRUE);
 		break;
 	case PROP_FIRMWARE_MISSING:
 		g_value_set_boolean (value, priv->firmware_missing);
@@ -14668,7 +14677,6 @@ nm_device_class_init (NMDeviceClass *klass)
 	klass->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout;
 
 	klass->get_type_description = get_type_description;
-	klass->get_autoconnect_allowed = get_autoconnect_allowed;
 	klass->can_auto_connect = can_auto_connect;
 	klass->check_connection_compatible = check_connection_compatible;
 	klass->check_connection_available = check_connection_available;