about 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.c166
1 files changed, 107 insertions, 59 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 529b3cd8..dde9af94 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -1195,17 +1195,67 @@ nm_device_master_release_one_slave (NMDevice *self, NMDevice *slave, gboolean co
 static gboolean
 can_unmanaged_external_down (NMDevice *self)
 {
-	return nm_device_is_software (self) && !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned;
+	return    !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned
+	       && nm_device_is_software (self);
 }
 
-static void
-update_dynamic_ip_setup (NMDevice *self)
+static NMUnmanFlagOp
+is_unmanaged_external_down (NMDevice *self, gboolean consider_can)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+	if (   consider_can
+	    && !NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self))
+		return NM_UNMAN_FLAG_OP_FORGET;
+
+	/* Manage externally-created software interfaces only when they are IFF_UP */
+	if (   priv->ifindex <= 0
+	    || !priv->up
+	    || !nm_platform_link_can_assume (NM_PLATFORM_GET, priv->ifindex))
+		return NM_UNMAN_FLAG_OP_SET_UNMANAGED;
+
+	return NM_UNMAN_FLAG_OP_SET_MANAGED;
+}
+
+static void
+set_unmanaged_external_down (NMDevice *self, gboolean only_if_unmanaged)
+{
+	NMUnmanFlagOp ext_flags;
+
+	if (!nm_device_get_unmanaged_mask (self, NM_UNMANAGED_EXTERNAL_DOWN))
+		return;
+
+	if (only_if_unmanaged) {
+		if (!nm_device_get_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN))
+			return;
+	}
+
+	ext_flags = is_unmanaged_external_down (self, FALSE);
+	if (ext_flags != NM_UNMAN_FLAG_OP_SET_UNMANAGED) {
+		/* Ensure the assume check is queued before any queued state changes
+		 * from the transition to UNAVAILABLE.
+		 */
+		nm_device_queue_recheck_assume (self);
+	}
+
+	nm_device_set_unmanaged_by_flags (self,
+	                                  NM_UNMANAGED_EXTERNAL_DOWN,
+	                                  ext_flags,
+	                                  NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
+}
+
+void
+nm_device_update_dynamic_ip_setup (NMDevice *self)
+{
+	NMDevicePrivate *priv;
 	GError *error;
 	gconstpointer addr;
 	size_t addr_length;
 
+	g_return_if_fail (NM_IS_DEVICE (self));
+
+	priv = NM_DEVICE_GET_PRIVATE (self);
+
 	g_hash_table_remove_all (priv->ip6_saved_properties);
 
 	if (priv->dhcp4_client) {
@@ -1295,7 +1345,7 @@ carrier_changed (NMDevice *self, gboolean carrier)
 			 * tagged for carrier ignore) ensure that when the carrier appears we
 			 * renew DHCP leases and such.
 			 */
-			update_dynamic_ip_setup (self);
+			nm_device_update_dynamic_ip_setup (self);
 		}
 	} else {
 		if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) {
@@ -1422,7 +1472,6 @@ device_link_changed (NMDevice *self)
 	NMPlatformLink info;
 	const NMPlatformLink *pllink;
 	int ifindex;
-	gboolean was_up;
 
 	priv->device_link_changed_id = 0;
 
@@ -1493,25 +1542,21 @@ device_link_changed (NMDevice *self)
 
 	/* Update DHCP, etc, if needed */
 	if (ip_ifname_changed)
-		update_dynamic_ip_setup (self);
+		nm_device_update_dynamic_ip_setup (self);
 
-	was_up = priv->up;
 	priv->up = NM_FLAGS_HAS (info.n_ifi_flags, IFF_UP);
 
-	if (   priv->ifindex > 0
-	    && info.initialized
+	if (   info.initialized
 	    && nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) {
 		NMDeviceStateReason reason;
 
 		nm_device_set_unmanaged_by_user_udev (self);
 
-		/* If the devices that need an external IFF_UP go managed below,
-		 * it means they're already up. In that case we should use an "assumed"
-		 * reason to prevent the cleanup sequence from being run on transition
-		 * from "unmanaged" to "unavailable". */
-		if (   priv->up
-		    && !nm_device_get_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN)
-		    && NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)) {
+		/* If the device is a external-down candidated but no longer has external
+		 * down set, we must clear the platform-unmanaged flag with reason
+		 * "assumed". */
+		if (    nm_device_get_unmanaged_mask (self, NM_UNMANAGED_EXTERNAL_DOWN)
+		    && !nm_device_get_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN)) {
 			/* Ensure the assume check is queued before any queued state changes
 			 * from the transition to UNAVAILABLE.
 			 */
@@ -1523,35 +1568,7 @@ device_link_changed (NMDevice *self)
 		nm_device_set_unmanaged_by_flags (self, NM_UNMANAGED_PLATFORM_INIT, FALSE, reason);
 	}
 
-	if (   priv->ifindex > 0
-	    && priv->up != was_up
-	    && NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)) {
-		/* Manage externally-created software interfaces only when they are IFF_UP */
-		if (   priv->up
-		    && nm_device_get_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN)) {
-			/* Ensure the assume check is queued before any queued state changes
-			 * from the transition to UNAVAILABLE.
-			 */
-			nm_device_queue_recheck_assume (self);
-		}
-
-		/* In case of @priv->up, resetting the EXTERNAL_DOWN flag may change the device's
-		 * state to UNAVAILABLE. To ensure that the state change doesn't touch
-		 * the device before assumption occurs, pass NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED
-		 * as the reason.
-		 *
-		 * In case of !@priv->up, and the device is already unmanaged for other reasons, the
-		 * state-change-reason has no effect.
-		 * If the device is managed for an explict user-request, the state-change-reason
-		 * also has no effect, because the device stays managed.
-		 *
-		 * The state-change-reason only has effect if the device was assumed
-		 * and is now to be unmanaged. */
-		nm_device_set_unmanaged_by_flags (self,
-		                                  NM_UNMANAGED_EXTERNAL_DOWN,
-		                                  !priv->up,
-		                                  NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
-	}
+	set_unmanaged_external_down (self, FALSE);
 
 	device_recheck_slave_status (self, &info);
 	return G_SOURCE_REMOVE;
@@ -1580,7 +1597,7 @@ device_ip_link_changed (NMDevice *self)
 		priv->ip_iface = g_strdup (pllink->name);
 
 		_notify (self, PROP_IP_IFACE);
-		update_dynamic_ip_setup (self);
+		nm_device_update_dynamic_ip_setup (self);
 	}
 	return G_SOURCE_REMOVE;
 }
@@ -1921,12 +1938,11 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
 
 	klass->realize_start_notify (self, plink);
 
-	/* Do not manage externally created software devices until they are IFF_UP */
-	if (   priv->ifindex > 0
-	    && plink
-	    && !priv->up
-	    && NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self))
-		nm_device_set_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN, TRUE);
+	/* Do not manage externally created software devices until they are IFF_UP
+	 * or have IP addressing */
+	nm_device_set_unmanaged_flags (self,
+	                               NM_UNMANAGED_EXTERNAL_DOWN,
+	                               is_unmanaged_external_down (self, TRUE));
 
 	/* Unmanaged the loopback device with an explicit NM_UNMANAGED_LOOPBACK flag.
 	 * Later we might want to manage 'lo' too. Currently that doesn't work because
@@ -2569,6 +2585,18 @@ nm_device_removed (NMDevice *self)
 		 * Release the slave from master, but don't touch the device. */
 		nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
 	}
+
+	/* Clean up IP configs; this does not actually deconfigure the
+	 * interface, it just clears the configuration to which policy
+	 * is reacting via NM_DEVICE_IP4_CONFIG_CHANGED/NM_DEVICE_IP6_CONFIG_CHANGED
+	 * signal. As NMPolicy registered the NMIPxConfig instances in NMDnsManager,
+	 * these would be leaked otherwise. */
+	priv->default_route.v4_has = FALSE;
+	priv->default_route.v4_is_assumed = TRUE;
+	nm_device_set_ip4_config (self, NULL, 0, FALSE, FALSE, NULL);
+	priv->default_route.v6_has = FALSE;
+	priv->default_route.v6_is_assumed = TRUE;
+	nm_device_set_ip6_config (self, NULL, FALSE, FALSE, NULL);
 }
 
 static gboolean
@@ -3050,8 +3078,7 @@ nm_device_check_slave_connection_compatible (NMDevice *self, NMConnection *slave
 static gboolean
 nm_device_can_assume_connections (NMDevice *self)
 {
-	return   !!NM_DEVICE_GET_CLASS (self)->update_connection
-	      && !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned;
+	return   !!NM_DEVICE_GET_CLASS (self)->update_connection;
 }
 
 /**
@@ -8869,6 +8896,8 @@ queued_ip4_config_change (gpointer user_data)
 	update_ip4_config (self, FALSE);
 	g_object_unref (self);
 
+	set_unmanaged_external_down (self, TRUE);
+
 	return FALSE;
 }
 
@@ -8923,6 +8952,8 @@ queued_ip6_config_change (gpointer user_data)
 
 	g_object_unref (self);
 
+	set_unmanaged_external_down (self, TRUE);
+
 	return FALSE;
 }
 
@@ -9124,6 +9155,24 @@ nm_device_get_managed (NMDevice *self, gboolean for_user_request)
 }
 
 /**
+ * nm_device_get_unmanaged_mask:
+ * @self: the #NMDevice
+ * @flag: the unmanaged flags to check.
+ *
+ * Return the unmanaged flags mask set on this device.
+ *
+ * Returns: the flags of the device ( & @flag)
+ */
+NMUnmanagedFlags
+nm_device_get_unmanaged_mask (NMDevice *self, NMUnmanagedFlags flag)
+{
+	g_return_val_if_fail (NM_IS_DEVICE (self), NM_UNMANAGED_NONE);
+	g_return_val_if_fail (flag != NM_UNMANAGED_NONE, NM_UNMANAGED_NONE);
+
+	return NM_DEVICE_GET_PRIVATE (self)->unmanaged_mask & flag;
+}
+
+/**
  * nm_device_get_unmanaged_flags:
  * @self: the #NMDevice
  * @flag: the unmanaged flags to check.
@@ -9135,8 +9184,8 @@ nm_device_get_managed (NMDevice *self, gboolean for_user_request)
 NMUnmanagedFlags
 nm_device_get_unmanaged_flags (NMDevice *self, NMUnmanagedFlags flag)
 {
-	g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
-	g_return_val_if_fail (flag != NM_UNMANAGED_NONE, FALSE);
+	g_return_val_if_fail (NM_IS_DEVICE (self), NM_UNMANAGED_NONE);
+	g_return_val_if_fail (flag != NM_UNMANAGED_NONE, NM_UNMANAGED_NONE);
 
 	return NM_DEVICE_GET_PRIVATE (self)->unmanaged_flags & flag;
 }
@@ -9943,7 +9992,6 @@ static void
 _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-	NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE;
 
 	priv->default_route.v4_has = FALSE;
 	priv->default_route.v6_has = FALSE;
@@ -9968,8 +10016,8 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
 	/* Clean up IP configs; this does not actually deconfigure the
 	 * interface; the caller must flush routes and addresses explicitly.
 	 */
-	nm_device_set_ip4_config (self, NULL, 0, TRUE, TRUE, &ignored);
-	nm_device_set_ip6_config (self, NULL, TRUE, TRUE, &ignored);
+	nm_device_set_ip4_config (self, NULL, 0, TRUE, TRUE, NULL);
+	nm_device_set_ip6_config (self, NULL, TRUE, TRUE, NULL);
 	g_clear_object (&priv->con_ip4_config);
 	g_clear_object (&priv->dev_ip4_config);
 	g_clear_object (&priv->ext_ip4_config);