summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2016-02-15 21:42:57 +0100
committerThomas Haller <thaller@redhat.com>2016-02-15 21:43:45 +0100
commit6f3d7cbd22a281afc8f374a883a7c3281f890622 (patch)
treecf69bc00078d192f80f3939c317744036fe1477b
parent30ce8c305bc65543a5a53f2d492c3d32335d2b89 (diff)
parent87a3df2e572ed47b5f76f6d1cad63ce622296e21 (diff)
downloadNetworkManager-6f3d7cbd22a281afc8f374a883a7c3281f890622.tar.gz
core: merge branch 'lr/default-unmanaged-bgo746566'
https://bugzilla.gnome.org/show_bug.cgi?id=746566
-rw-r--r--src/devices/nm-device-generic.c2
-rw-r--r--src/devices/nm-device-macvlan.c10
-rw-r--r--src/devices/nm-device-private.h1
-rw-r--r--src/devices/nm-device-vlan.c10
-rw-r--r--src/devices/nm-device.c706
-rw-r--r--src/devices/nm-device.h73
-rw-r--r--src/nm-manager.c101
-rw-r--r--src/settings/nm-settings.c2
8 files changed, 534 insertions, 371 deletions
diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c
index 2e9c134a3d..9f3fa90dc0 100644
--- a/src/devices/nm-device-generic.c
+++ b/src/devices/nm-device-generic.c
@@ -138,7 +138,7 @@ constructor (GType type,
n_construct_params,
construct_params);
- nm_device_set_unmanaged_flags_initial (NM_DEVICE (object), NM_UNMANAGED_DEFAULT, TRUE);
+ nm_device_set_unmanaged_flags ((NMDevice *) object, NM_UNMANAGED_BY_DEFAULT, TRUE);
return object;
}
diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c
index e8d8b4e193..912449e8fc 100644
--- a/src/devices/nm-device-macvlan.c
+++ b/src/devices/nm-device-macvlan.c
@@ -127,7 +127,7 @@ parent_state_changed (NMDevice *parent,
if (reason == NM_DEVICE_STATE_REASON_CARRIER)
return;
- nm_device_set_unmanaged_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason);
+ nm_device_set_unmanaged_by_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent, FALSE), reason);
}
static void
@@ -151,10 +151,10 @@ nm_device_macvlan_set_parent (NMDeviceMacvlan *self, NMDevice *parent)
device);
/* Set parent-dependent unmanaged flag */
- nm_device_set_unmanaged_flags (device,
- NM_UNMANAGED_PARENT,
- !nm_device_get_managed (parent),
- NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED);
+ nm_device_set_unmanaged_by_flags (device,
+ NM_UNMANAGED_PARENT,
+ !nm_device_get_managed (parent, FALSE),
+ NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED);
}
/* Recheck availability now that the parent has changed */
diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h
index 5010e90655..602c2c8575 100644
--- a/src/devices/nm-device-private.h
+++ b/src/devices/nm-device-private.h
@@ -95,7 +95,6 @@ void nm_device_master_check_slave_physical_port (NMDevice *self, NMDevice *slave
void nm_device_set_carrier (NMDevice *self, gboolean carrier);
-void nm_device_emit_recheck_auto_activate (NMDevice *device);
void nm_device_queue_recheck_assume (NMDevice *device);
void nm_device_queue_recheck_available (NMDevice *device,
NMDeviceStateReason available_reason,
diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c
index ac8808c918..e2b0e50605 100644
--- a/src/devices/nm-device-vlan.c
+++ b/src/devices/nm-device-vlan.c
@@ -77,7 +77,7 @@ parent_state_changed (NMDevice *parent,
if (reason == NM_DEVICE_STATE_REASON_CARRIER)
return;
- nm_device_set_unmanaged_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason);
+ nm_device_set_unmanaged_by_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent, FALSE), reason);
}
static void
@@ -145,10 +145,10 @@ nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent)
G_CALLBACK (parent_hwaddr_changed), device);
/* Set parent-dependent unmanaged flag */
- nm_device_set_unmanaged_flags (device,
- NM_UNMANAGED_PARENT,
- !nm_device_get_managed (parent),
- NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED);
+ nm_device_set_unmanaged_by_flags (device,
+ NM_UNMANAGED_PARENT,
+ !nm_device_get_managed (parent, FALSE),
+ NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED);
}
/* Recheck availability now that the parent has changed */
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index ef67230641..c986a0f709 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -204,8 +204,6 @@ typedef struct {
typedef struct _NMDevicePrivate {
gboolean in_state_changed;
- gboolean initialized;
- gboolean platform_link_initialized;
guint device_link_changed_id;
guint device_ip_link_changed_id;
@@ -243,7 +241,7 @@ typedef struct _NMDevicePrivate {
char * physical_port_id;
guint dev_id;
- gboolean managed_touched_by_user;
+ NMUnmanagedFlags unmanaged_mask;
NMUnmanagedFlags unmanaged_flags;
gboolean is_nm_owned; /* whether the device is a device owned and created by NM */
DeleteOnDeactivateData *delete_on_deactivate_data; /* data for scheduled cleanup when deleting link (g_idle_add) */
@@ -409,8 +407,6 @@ static NMActStageReturn linklocal6_start (NMDevice *self);
static void _carrier_wait_check_queued_act_request (NMDevice *self);
-static gboolean nm_device_get_default_unmanaged (NMDevice *self);
-
static const char *_activation_func_to_string (ActivationHandleFunc func);
static void activation_source_handle_cb (NMDevice *self, int family);
@@ -422,10 +418,6 @@ static void _set_state_full (NMDevice *self,
static gboolean queued_ip4_config_change (gpointer user_data);
static gboolean queued_ip6_config_change (gpointer user_data);
-static void _set_unmanaged_flags (NMDevice *self,
- NMUnmanagedFlags flags,
- gboolean unmanaged);
-
/***********************************************************/
#define QUEUED_PREFIX "queued state change to "
@@ -1193,6 +1185,9 @@ nm_device_master_release_one_slave (NMDevice *self, NMDevice *slave, gboolean co
* when slaves change.
*/
nm_device_update_hw_address (self);
+
+ g_warn_if_fail (NM_FLAGS_HAS (slave_priv->unmanaged_mask, NM_UNMANAGED_IS_SLAVE));
+ nm_device_set_unmanaged_by_flags (slave, NM_UNMANAGED_IS_SLAVE, NM_UNMAN_FLAG_OP_FORGET, NM_DEVICE_STATE_REASON_REMOVED);
}
/**
@@ -1208,54 +1203,6 @@ can_unmanaged_external_down (NMDevice *self)
return nm_device_is_software (self) && !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned;
}
-/**
- * nm_device_finish_init:
- * @self: the master device
- *
- * Whatever needs to be done post-initialization, when the device has a DBus
- * object name.
- */
-void
-nm_device_finish_init (NMDevice *self)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-
- g_assert (priv->initialized == FALSE);
-
- /* Do not manage externally created software devices until they are IFF_UP */
- if ( NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)
- && priv->ifindex > 0
- && ( !priv->up
- || !priv->platform_link_initialized))
- nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_EXTERNAL_DOWN, TRUE);
-
- if (priv->master)
- nm_device_master_enslave_slave (priv->master, self, NULL);
-
- if (priv->ifindex > 0) {
- if (priv->ifindex == 1) {
- /* 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
- * NetworkManager might down the interface or remove the 127.0.0.1 address. */
- nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_LOOPBACK, TRUE);
- } else if (priv->platform_link_initialized || (priv->is_nm_owned && nm_device_is_software (self))) {
- gboolean platform_unmanaged = FALSE;
-
- if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged))
- nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_DEFAULT, platform_unmanaged);
- } else {
- /* Hardware and externally-created software links stay unmanaged
- * until they are fully initialized by the platform. NM created
- * links must be available for activation immediately and thus
- * do not get the PLATFORM_INIT unmanaged flag set.
- */
- nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_PLATFORM_INIT, TRUE);
- }
- }
-
- priv->initialized = TRUE;
-}
-
static void
update_dynamic_ip_setup (NMDevice *self)
{
@@ -1481,7 +1428,6 @@ device_link_changed (NMDevice *self)
NMPlatformLink info;
const NMPlatformLink *pllink;
int ifindex;
- gboolean just_initialized = FALSE;
gboolean was_up;
priv->device_link_changed_id = 0;
@@ -1555,71 +1501,45 @@ device_link_changed (NMDevice *self)
if (ip_ifname_changed)
update_dynamic_ip_setup (self);
- if (priv->ifindex > 0 && !priv->platform_link_initialized && info.initialized) {
- gboolean platform_unmanaged = FALSE;
-
- priv->platform_link_initialized = TRUE;
-
- if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged)) {
- nm_device_set_unmanaged_flags (self,
- NM_UNMANAGED_DEFAULT,
- platform_unmanaged,
- NM_DEVICE_STATE_REASON_USER_REQUESTED);
- }
-
- nm_device_set_unmanaged_flags (self,
- NM_UNMANAGED_PLATFORM_INIT,
- FALSE,
- NM_DEVICE_STATE_REASON_NOW_MANAGED);
-
- just_initialized = TRUE;
- }
-
was_up = priv->up;
priv->up = NM_FLAGS_HAS (info.flags, IFF_UP);
- if ( priv->platform_link_initialized
- && ( just_initialized
- || priv->up != was_up)) {
+ if ( priv->ifindex > 0
+ && info.initialized
+ && nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) {
+ nm_device_set_unmanaged_by_user_udev (self);
+ nm_device_set_unmanaged_by_flags (self, NM_UNMANAGED_PLATFORM_INIT, FALSE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
+ }
+
+ 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 */
- g_assert (priv->ifindex > 0);
- if (NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)) {
- gboolean external_down = !!nm_device_get_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN);
-
- if (external_down && NM_FLAGS_HAS (info.flags, IFF_UP)) {
- if (nm_device_get_state (self) < NM_DEVICE_STATE_DISCONNECTED) {
- /* Ensure the assume check is queued before any queued state changes
- * from the transition to UNAVAILABLE.
- */
- nm_device_queue_recheck_assume (self);
-
- /* 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.
- */
- nm_device_set_unmanaged_flags (self,
- NM_UNMANAGED_EXTERNAL_DOWN,
- FALSE,
- NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
- } else {
- /* Don't trigger a state change; if the device is in a
- * state higher than UNAVAILABLE, it is already IFF_UP
- * or an explicit activation request was received.
- */
- _set_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN, FALSE);
- }
- } else if (!external_down && !NM_FLAGS_HAS (info.flags, IFF_UP) && nm_device_get_state (self) <= NM_DEVICE_STATE_DISCONNECTED) {
- /* If the device is already disconnected and is set !IFF_UP,
- * unmanage it.
- */
- nm_device_set_unmanaged_flags (self,
- NM_UNMANAGED_EXTERNAL_DOWN,
- TRUE,
- NM_DEVICE_STATE_REASON_USER_REQUESTED);
- }
+ 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);
}
device_recheck_slave_status (self, &info);
@@ -1813,7 +1733,11 @@ nm_device_create_and_realize (NMDevice *self,
realize_start_setup (self, plink);
nm_device_realize_finish (self, plink);
- g_return_val_if_fail (nm_device_check_connection_compatible (self, connection), TRUE);
+ if (nm_device_get_managed (self, FALSE)) {
+ nm_device_state_changed (self,
+ NM_DEVICE_STATE_UNAVAILABLE,
+ NM_DEVICE_STATE_REASON_NOW_MANAGED);
+ }
return TRUE;
}
@@ -1847,7 +1771,6 @@ update_device_from_platform_link (NMDevice *self, const NMPlatformLink *plink)
priv->driver = g_strdup (plink->driver);
g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER);
}
- priv->platform_link_initialized = plink->initialized;
}
static void
@@ -1905,6 +1828,7 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
/* The device should not be realized */
g_return_if_fail (!priv->real);
+ g_return_if_fail (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT));
g_return_if_fail (priv->ip_ifindex <= 0);
g_return_if_fail (priv->ip_iface == NULL);
@@ -1985,6 +1909,23 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
g_object_notify (G_OBJECT (self), NM_DEVICE_CAPABILITIES);
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);
+
+ /* 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
+ * NetworkManager might down the interface or remove the 127.0.0.1 address. */
+ nm_device_set_unmanaged_flags (self, NM_UNMANAGED_LOOPBACK, priv->ifindex == 1);
+
+ nm_device_set_unmanaged_by_user_udev (self);
+
+ nm_device_set_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT,
+ plink && !plink->initialized);
}
/**
@@ -2008,17 +1949,15 @@ nm_device_realize_finish (NMDevice *self, const NMPlatformLink *plink)
g_return_if_fail (!priv->real);
- if (plink) {
- update_device_from_platform_link (self, plink);
+ if (plink)
device_recheck_slave_status (self, plink);
- }
priv->real = TRUE;
g_object_notify (G_OBJECT (self), NM_DEVICE_REAL);
nm_device_recheck_available_connections (self);
- /* Balanced by a freeze in realize_start_setup() */
+ /* Balanced by a freeze in realize_start_setup(). */
g_object_thaw_notify (G_OBJECT (self));
}
@@ -2152,6 +2091,18 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
g_object_thaw_notify (G_OBJECT (self));
+ nm_device_set_unmanaged_flags (self,
+ NM_UNMANAGED_PLATFORM_INIT,
+ TRUE);
+
+ nm_device_set_unmanaged_flags (self,
+ NM_UNMANAGED_PARENT |
+ NM_UNMANAGED_LOOPBACK |
+ NM_UNMANAGED_USER_UDEV |
+ NM_UNMANAGED_EXTERNAL_DOWN |
+ NM_UNMANAGED_IS_SLAVE,
+ NM_UNMAN_FLAG_OP_FORGET);
+
nm_device_state_changed (self,
NM_DEVICE_STATE_UNMANAGED,
remove_resources ?
@@ -2330,6 +2281,9 @@ nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure)
*
* because slave_priv->is_enslaved is not true, thus the value
* didn't change yet. */
+
+ g_warn_if_fail (!NM_FLAGS_HAS (slave_priv->unmanaged_mask, NM_UNMANAGED_IS_SLAVE));
+ nm_device_set_unmanaged_by_flags (slave, NM_UNMANAGED_IS_SLAVE, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
} else
g_return_if_fail (slave_priv->master == self);
@@ -2693,18 +2647,11 @@ nm_device_set_autoconnect (NMDevice *self, gboolean autoconnect)
g_return_if_fail (NM_IS_DEVICE (self));
- priv = NM_DEVICE_GET_PRIVATE (self);
- if (priv->autoconnect == autoconnect)
- return;
+ autoconnect = !!autoconnect;
- if (autoconnect) {
- /* Default-unmanaged devices never autoconnect */
- if (!nm_device_get_default_unmanaged (self)) {
- priv->autoconnect = TRUE;
- g_object_notify (G_OBJECT (self), NM_DEVICE_AUTOCONNECT);
- }
- } else {
- priv->autoconnect = FALSE;
+ priv = NM_DEVICE_GET_PRIVATE (self);
+ if (priv->autoconnect != autoconnect) {
+ priv->autoconnect = autoconnect;
g_object_notify (G_OBJECT (self), NM_DEVICE_AUTOCONNECT);
}
}
@@ -7503,6 +7450,7 @@ _device_activate (NMDevice *self, NMActRequest *req)
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE);
+ g_return_val_if_fail (nm_device_get_managed (self, FALSE), FALSE);
/* Ensure the activation request is still valid; the master may have
* already failed in which case activation of this device should not proceed.
@@ -7521,13 +7469,6 @@ _device_activate (NMDevice *self, NMActRequest *req)
delete_on_deactivate_unschedule (self);
- /* Move default unmanaged devices to DISCONNECTED state here */
- if (nm_device_get_default_unmanaged (self) && priv->state == NM_DEVICE_STATE_UNMANAGED) {
- nm_device_state_changed (self,
- NM_DEVICE_STATE_DISCONNECTED,
- NM_DEVICE_STATE_REASON_NOW_MANAGED);
- }
-
/* note: don't notify D-Bus of the new AC here, but do it later when
* changing state to PREPARE so that the two properties change together.
*/
@@ -8864,119 +8805,331 @@ device_ipx_changed (NMPlatform *platform,
}
}
+/*****************************************************************************/
+
+NM_UTILS_FLAGS2STR_DEFINE (nm_unmanaged_flags2str, NMUnmanagedFlags,
+ NM_UTILS_FLAGS2STR (NM_UNMANAGED_SLEEPING, "sleeping"),
+ NM_UTILS_FLAGS2STR (NM_UNMANAGED_QUITTING, "quitting"),
+ NM_UTILS_FLAGS2STR (NM_UNMANAGED_PARENT, "parent"),
+ NM_UTILS_FLAGS2STR (NM_UNMANAGED_LOOPBACK, "loopback"),
+ NM_UTILS_FLAGS2STR (NM_UNMANAGED_PLATFORM_INIT, "platform-init"),
+ NM_UTILS_FLAGS2STR (NM_UNMANAGED_USER_EXPLICIT, "user-explicit"),
+ NM_UTILS_FLAGS2STR (NM_UNMANAGED_BY_DEFAULT, "by-default"),
+ NM_UTILS_FLAGS2STR (NM_UNMANAGED_USER_CONFIG, "user-config"),
+ NM_UTILS_FLAGS2STR (NM_UNMANAGED_USER_UDEV, "user-udev"),
+ NM_UTILS_FLAGS2STR (NM_UNMANAGED_EXTERNAL_DOWN, "external-down"),
+ NM_UTILS_FLAGS2STR (NM_UNMANAGED_IS_SLAVE, "is-slave"),
+);
+
+static const char *
+_unmanaged_flags2str (NMUnmanagedFlags flags, NMUnmanagedFlags mask, char *buf, gsize len)
+{
+ char buf2[512];
+ char *b;
+ char *tmp, *tmp2;
+ gsize l;
+
+ nm_utils_to_string_buffer_init (&buf, &len);
+ if (!len)
+ return buf;
+
+ b = buf;
+
+ mask |= flags;
+
+ nm_unmanaged_flags2str (flags, b, len);
+ l = strlen (b);
+ b += l;
+ len -= l;
+
+ nm_unmanaged_flags2str (mask & ~flags, buf2, sizeof (buf2));
+ if (buf2[0]) {
+ gboolean add_separator = l > 0;
+
+ tmp = buf2;
+ while (TRUE) {
+ if (add_separator)
+ nm_utils_strbuf_append_c (&b, &len, ',');
+ add_separator = TRUE;
+
+ tmp2 = strchr (tmp, ',');
+ if (tmp2)
+ tmp2[0] = '\0';
+
+ nm_utils_strbuf_append_c (&b, &len, '!');
+ nm_utils_strbuf_append_str (&b, &len, tmp);
+ if (!tmp2)
+ break;
+
+ tmp = &tmp2[1];
+ }
+ }
+
+ return buf;
+}
+
+static gboolean
+_get_managed_by_flags(NMUnmanagedFlags flags, NMUnmanagedFlags mask, gboolean for_user_request)
+{
+ /* Evaluate the managed state based on the unmanaged flags.
+ *
+ * Some flags are authoritative, meaning they always cause
+ * the device to be unmanaged (e.g. @NM_UNMANAGED_PLATFORM_INIT).
+ *
+ * OTOH, some flags can be overwritten. For example NM_UNMANAGED_USER_CONFIG
+ * is ignored once NM_UNMANAGED_USER_EXPLICIT is set. The idea is that
+ * the flag from the configuration has no effect once the user explicitly
+ * touches the unmanaged flags. */
+
+ if (for_user_request) {
+
+ /* @for_user_request can make the result only ~more~ managed.
+ * If the flags already indicate a managed state for a non-user-request,
+ * then it is also managed for an explict user-request.
+ *
+ * Effectively, this check is redundant, as the code below already
+ * already ensures that. Still, express this invariant explictly here. */
+ if (_get_managed_by_flags (flags, mask, FALSE))
+ return TRUE;
+
+ /* A for-user-request, is effectively the same as pretending
+ * that user-dbus flag is cleared. */
+ mask |= NM_UNMANAGED_USER_EXPLICIT;
+ flags &= ~NM_UNMANAGED_USER_EXPLICIT;
+ }
+
+ if ( NM_FLAGS_ANY (mask, NM_UNMANAGED_USER_CONFIG)
+ && !NM_FLAGS_ANY (flags, NM_UNMANAGED_USER_CONFIG)) {
+ /* NM_UNMANAGED_USER_CONFIG can only explicitly unmanage a device. It cannot
+ * *manage* it. Having NM_UNMANAGED_USER_CONFIG explicitly not set, is the
+ * same as having it not set at all. */
+ mask &= ~NM_UNMANAGED_USER_CONFIG;
+ }
+
+ if (NM_FLAGS_ANY (mask, NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_USER_CONFIG)) {
+ /* configuration from udev or nm-config overwrites the by-default flag
+ * which is based on the device type. */
+ flags &= ~NM_UNMANAGED_BY_DEFAULT;
+ }
+
+ if (NM_FLAGS_HAS (mask, NM_UNMANAGED_USER_CONFIG)) {
+ /* configuration from configuration overwrites the setting
+ * originating from udev.
+ *
+ * Actually, this check has no effect, because at this point,
+ * the device also is NM_UNMANAGED_USER_CONFIG. Thus clearing
+ * NM_UNMANAGED_USER_UDEV doesn't change the outcome.
+ * Just be explicit about this. */
+ flags &= ~NM_UNMANAGED_USER_UDEV;
+ }
+
+ if ( NM_FLAGS_HAS (mask, NM_UNMANAGED_IS_SLAVE)
+ && !NM_FLAGS_HAS (flags, NM_UNMANAGED_IS_SLAVE)) {
+ /* for an enslaved device, by-default doesn't matter */
+ flags &= ~NM_UNMANAGED_BY_DEFAULT;
+ }
+
+ if (NM_FLAGS_HAS (mask, NM_UNMANAGED_USER_EXPLICIT)) {
+ /* if the device is managed by user-decision, certain other flags
+ * are ignored. */
+
+ flags &= ~( NM_UNMANAGED_BY_DEFAULT
+ | NM_UNMANAGED_USER_CONFIG
+ | NM_UNMANAGED_USER_UDEV
+ | NM_UNMANAGED_EXTERNAL_DOWN);
+ }
+
+ return flags == NM_UNMANAGED_NONE;
+}
+
/**
- * nm_device_get_managed():
+ * nm_device_get_managed:
* @self: the #NMDevice
+ * @for_user_request: whether to check the flags for an explict user-request
*
- * Returns: %TRUE if the device is managed
+ * Whether the device is unmanaged according to the unmanaged flags.
+ *
+ * Returns: %TRUE if the device is unmanaged because of the flags.
*/
gboolean
-nm_device_get_managed (NMDevice *self)
+nm_device_get_managed (NMDevice *self, gboolean for_user_request)
{
NMDevicePrivate *priv;
- gboolean managed;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
- priv = NM_DEVICE_GET_PRIVATE (self);
+ if (!nm_device_is_real (self)) {
+ /* a unrealized device is always considered unmanaged. */
+ return FALSE;
+ }
- /* Return the composite of all managed flags. However, if the device
- * is a default-unmanaged device, and would be managed except for the
- * default-unmanaged flag (eg, only NM_UNMANAGED_DEFAULT is set) then
- * the device is managed whenever it's not in the UNMANAGED state.
- */
- managed = !NM_FLAGS_ANY (priv->unmanaged_flags, ~NM_UNMANAGED_DEFAULT);
- if (managed && NM_FLAGS_HAS (priv->unmanaged_flags, NM_UNMANAGED_DEFAULT))
- managed = (priv->state > NM_DEVICE_STATE_UNMANAGED);
+ priv = NM_DEVICE_GET_PRIVATE (self);
- return managed;
+ return _get_managed_by_flags (priv->unmanaged_flags, priv->unmanaged_mask, for_user_request);
}
/**
- * nm_device_get_unmanaged_flags():
+ * nm_device_get_unmanaged_flags:
* @self: the #NMDevice
- * @flag: return only the selected flags
+ * @flag: the unmanaged flags to check.
*
- * Returns: the unmanage flags of the device (filtered with @flag)
+ * Return the unmanaged flags of the device.
+ *
+ * Returns: the flags of the device ( & @flag)
*/
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);
+
return NM_DEVICE_GET_PRIVATE (self)->unmanaged_flags & flag;
}
/**
- * nm_device_get_default_unmanaged():
- * @self: the #NMDevice
+ * _set_unmanaged_flags:
+ * @self: the #NMDevice instance
+ * @flags: which #NMUnmanagedFlags to set.
+ * @set_op: whether to set/clear/forget the flags. You can also pass
+ * boolean values %TRUE and %FALSE, which mean %NM_UNMAN_FLAG_OP_SET_UNMANAGED
+ * and %NM_UNMAN_FLAG_OP_SET_MANAGED, respectively.
+ * @allow_state_transition: if %FALSE, setting flags never triggers a device
+ * state change. If %TRUE, the device can change state, if it is real and
+ * switches from managed to unmanaged (or vice versa).
+ * @reason: the device state reason passed to nm_device_state_changed() if
+ * the device becomes managed/unmanaged. This is only relevant if the
+ * device switches state and if @allow_state_transition is %TRUE.
*
- * Returns: %TRUE if the device is by default unmanaged
- */
-static gboolean
-nm_device_get_default_unmanaged (NMDevice *self)
-{
- return !!nm_device_get_unmanaged_flags (self, NM_UNMANAGED_DEFAULT);
-}
-
+ * Set the unmanaged flags of the device.
+ **/
static void
_set_unmanaged_flags (NMDevice *self,
NMUnmanagedFlags flags,
- gboolean unmanaged)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
-
- if (unmanaged) {
- if (!NM_FLAGS_ALL (priv->unmanaged_flags, flags)) {
- _LOGD (LOGD_DEVICE, "unmanaged: flags set to 0x%0llx (was 0x%0llx, %s 0x%0llx)",
- (long long unsigned) (priv->unmanaged_flags | flags),
- (long long unsigned) priv->unmanaged_flags,
- "set",
- (long long unsigned) flags);
- priv->unmanaged_flags |= flags;
- }
- } else {
- if (NM_FLAGS_ANY (priv->unmanaged_flags, flags)) {
- _LOGD (LOGD_DEVICE, "unmanaged: flags set to 0x%0llx (was 0x%0llx, %s 0x%0llx)",
- (long long unsigned) (priv->unmanaged_flags & (~flags)),
- (long long unsigned) priv->unmanaged_flags,
- "clear",
- (long long unsigned) flags);
- priv->unmanaged_flags &= ~flags;
- }
- }
-}
-
-void
-nm_device_set_unmanaged_flags (NMDevice *self,
- NMUnmanagedFlags flag,
- gboolean unmanaged,
- NMDeviceStateReason reason)
+ NMUnmanFlagOp set_op,
+ gboolean allow_state_transition,
+ NMDeviceStateReason reason)
{
NMDevicePrivate *priv;
- gboolean was_managed, now_managed;
+ gboolean was_managed, transition_state;
+ NMUnmanagedFlags old_flags, old_mask;
+ const char *operation = NULL;
+ char str1[512];
+ char str2[512];
g_return_if_fail (NM_IS_DEVICE (self));
- g_return_if_fail (flag <= NM_UNMANAGED_LAST);
+ g_return_if_fail (flags);
priv = NM_DEVICE_GET_PRIVATE (self);
- was_managed = nm_device_get_managed (self);
- _set_unmanaged_flags (self, flag, unmanaged);
- now_managed = nm_device_get_managed (self);
+ if (!priv->real)
+ allow_state_transition = FALSE;
+ was_managed = allow_state_transition && nm_device_get_managed (self, FALSE);
- if (was_managed != now_managed) {
- _LOGD (LOGD_DEVICE, "now %s", unmanaged ? "unmanaged" : "managed");
+ old_flags = priv->unmanaged_flags;
+ old_mask = priv->unmanaged_mask;
- g_object_notify (G_OBJECT (self), NM_DEVICE_MANAGED);
+ switch (set_op) {
+ case NM_UNMAN_FLAG_OP_FORGET:
+ priv->unmanaged_mask &= ~flags;
+ priv->unmanaged_flags &= ~flags;
+ operation = "forget";
+ break;
+ case NM_UNMAN_FLAG_OP_SET_UNMANAGED:
+ priv->unmanaged_mask |= flags;
+ priv->unmanaged_flags |= flags;
+ operation = "set-unmanaged";
+ break;
+ case NM_UNMAN_FLAG_OP_SET_MANAGED:
+ priv->unmanaged_mask |= flags;
+ priv->unmanaged_flags &= ~flags;
+ operation = "set-managed";
+ break;
+ default:
+ g_return_if_reached ();
+ }
+
+ if ( old_flags == priv->unmanaged_flags
+ && old_mask == priv->unmanaged_mask)
+ return;
- if (unmanaged)
+ transition_state = allow_state_transition
+ && was_managed != nm_device_get_managed (self, FALSE)
+ && ( was_managed
+ || ( !was_managed
+ && nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED));
+
+#define _FMTX "[%s%s0x%0x/0x%x/%s"
+#define _FMT(flags, mask, str) \
+ _unmanaged_flags2str ((flags), (mask), str, sizeof (str)), \
+ ((flags) | (mask)) ? "=" : "", \
+ (flags), \
+ (mask), \
+ (_get_managed_by_flags (flags, mask, FALSE) \
+ ? "managed" \
+ : (_get_managed_by_flags (flags, mask, TRUE) \
+ ? "manageable" \
+ : "unmanaged"))
+ _LOGD (LOGD_DEVICE, "unmanaged: flags set to "_FMTX"%s, %s [%s=0x%0x]%s%s%s)",
+ _FMT (priv->unmanaged_flags, priv->unmanaged_mask, str1),
+ priv->real ? "" : "/unrealized",
+ operation,
+ nm_unmanaged_flags2str (flags, str2, sizeof (str2)),
+ flags,
+ NM_PRINT_FMT_QUOTED (allow_state_transition,
+ ", reason ",
+ reason_to_string (reason),
+ transition_state ? ", transition-state" : "",
+ ""));
+#undef _FMT
+
+ if (transition_state) {
+ if (was_managed)
nm_device_state_changed (self, NM_DEVICE_STATE_UNMANAGED, reason);
- else if (nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED)
+ else
nm_device_state_changed (self, NM_DEVICE_STATE_UNAVAILABLE, reason);
}
}
+/**
+ * @self: the #NMDevice instance
+ * @flags: which #NMUnmanagedFlags to set.
+ * @set_op: whether to set/clear/forget the flags. You can also pass
+ * boolean values %TRUE and %FALSE, which mean %NM_UNMAN_FLAG_OP_SET_UNMANAGED
+ * and %NM_UNMAN_FLAG_OP_SET_MANAGED, respectively.
+ *
+ * Set the unmanaged flags of the device (does not trigger a state change).
+ **/
+void
+nm_device_set_unmanaged_flags (NMDevice *self,
+ NMUnmanagedFlags flags,
+ NMUnmanFlagOp set_op)
+{
+ _set_unmanaged_flags (self, flags, set_op, FALSE, NM_DEVICE_STATE_REASON_NONE);
+}
+
+/**
+ * nm_device_set_unmanaged_by_flags:
+ * @self: the #NMDevice instance
+ * @flags: which #NMUnmanagedFlags to set.
+ * @set_op: whether to set/clear/forget the flags. You can also pass
+ * boolean values %TRUE and %FALSE, which mean %NM_UNMAN_FLAG_OP_SET_UNMANAGED
+ * and %NM_UNMAN_FLAG_OP_SET_MANAGED, respectively.
+ * @reason: the device state reason passed to nm_device_state_changed() if
+ * the device becomes managed/unmanaged.
+ *
+ * Set the unmanaged flags of the device and possibly trigger a state change.
+ **/
+void
+nm_device_set_unmanaged_by_flags (NMDevice *self,
+ NMUnmanagedFlags flags,
+ NMUnmanFlagOp set_op,
+ NMDeviceStateReason reason)
+{
+ _set_unmanaged_flags (self, flags, set_op, TRUE, reason);
+}
+
void
-nm_device_set_unmanaged_flags_by_device_spec (NMDevice *self, const GSList *unmanaged_specs)
+nm_device_set_unmanaged_by_user_config (NMDevice *self, const GSList *unmanaged_specs)
{
NMDevicePrivate *priv;
gboolean unmanaged;
@@ -8985,46 +9138,36 @@ nm_device_set_unmanaged_flags_by_device_spec (NMDevice *self, const GSList *unma
priv = NM_DEVICE_GET_PRIVATE (self);
- if (priv->managed_touched_by_user)
- return;
-
unmanaged = nm_device_spec_match_list (self, unmanaged_specs);
- nm_device_set_unmanaged_flags (self,
- NM_UNMANAGED_USER,
- unmanaged,
- unmanaged
- ? NM_DEVICE_STATE_REASON_NOW_UNMANAGED
- : NM_DEVICE_STATE_REASON_NOW_MANAGED);
+
+ nm_device_set_unmanaged_by_flags (self,
+ NM_UNMANAGED_USER_CONFIG,
+ unmanaged,
+ unmanaged
+ ? NM_DEVICE_STATE_REASON_NOW_UNMANAGED
+ : NM_DEVICE_STATE_REASON_NOW_MANAGED);
}
-/**
- * nm_device_set_unmanaged_flags_initial():
- * @self: the #NMDevice
- * @flag: an #NMUnmanagedFlag
- * @unmanaged: %TRUE or %FALSE to set or clear @flag
- *
- * Like nm_device_set_unmanaged_flags(), but must be set before the device is
- * initialized by nm_device_finish_init(), and does not trigger state changes.
- * Should only be used when initializing a device.
- */
void
-nm_device_set_unmanaged_flags_initial (NMDevice *self,
- NMUnmanagedFlags flag,
- gboolean unmanaged)
+nm_device_set_unmanaged_by_user_udev (NMDevice *self)
{
- NMDevicePrivate *priv;
+ int ifindex;
+ gboolean platform_unmanaged = FALSE;
- g_return_if_fail (NM_IS_DEVICE (self));
- g_return_if_fail (flag <= NM_UNMANAGED_LAST);
+ ifindex = self->priv->ifindex;
- priv = NM_DEVICE_GET_PRIVATE (self);
- g_return_if_fail (priv->initialized == FALSE);
+ if ( ifindex <= 0
+ || !nm_platform_link_get_unmanaged (NM_PLATFORM_GET, ifindex, &platform_unmanaged))
+ return;
- _set_unmanaged_flags (self, flag, unmanaged);
+ nm_device_set_unmanaged_by_flags (self,
+ NM_UNMANAGED_USER_UDEV,
+ platform_unmanaged,
+ NM_DEVICE_STATE_REASON_USER_REQUESTED);
}
void
-nm_device_set_unmanaged_quitting (NMDevice *self)
+nm_device_set_unmanaged_by_quitting (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gboolean need_deactivate = nm_device_is_activating (self) ||
@@ -9034,11 +9177,11 @@ nm_device_set_unmanaged_quitting (NMDevice *self)
if (need_deactivate)
_set_state_full (self, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_NOW_UNMANAGED, TRUE);
- nm_device_set_unmanaged_flags (self,
- NM_UNMANAGED_INTERNAL,
- TRUE,
- need_deactivate ? NM_DEVICE_STATE_REASON_REMOVED
- : NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
+ nm_device_set_unmanaged_by_flags (self,
+ NM_UNMANAGED_QUITTING,
+ TRUE,
+ need_deactivate ? NM_DEVICE_STATE_REASON_REMOVED
+ : NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
}
/*****************************************************************************/
@@ -9203,11 +9346,21 @@ _nm_device_check_connection_available (NMDevice *self,
{
NMDeviceState state;
+ /* an unrealized software device is always available, hardware devices never. */
+ if (!nm_device_is_real (self)) {
+ if (nm_device_is_software (self))
+ return nm_device_check_connection_compatible (self, connection);
+ return FALSE;
+ }
+
state = nm_device_get_state (self);
if (state < NM_DEVICE_STATE_UNMANAGED)
return FALSE;
if ( state < NM_DEVICE_STATE_UNAVAILABLE
- && nm_device_get_unmanaged_flags (self, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT))
+ && ( ( !NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST)
+ && !nm_device_get_managed (self, FALSE))
+ || ( NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST)
+ && !nm_device_get_managed (self, TRUE))))
return FALSE;
if ( state < NM_DEVICE_STATE_DISCONNECTED
&& !nm_device_is_software (self)
@@ -9412,7 +9565,7 @@ nm_device_get_available_connections (NMDevice *self, const char *specific_object
* compatible with it.
*/
if ( !specific_object /* << Optimization: we know that the connection is available without @specific_object. */
- || nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, specific_object))
+ || nm_device_check_connection_available (self, connection, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, specific_object))
g_ptr_array_add (array, connection);
}
}
@@ -9430,7 +9583,7 @@ cp_connection_added_or_updated (NMConnectionProvider *cp, NMConnection *connecti
if (nm_device_check_connection_available (self,
connection,
- NM_DEVICE_CHECK_CON_AVAILABLE_NONE,
+ _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST,
NULL))
changed = available_connections_add (self, connection);
else
@@ -10037,14 +10190,16 @@ _set_state_full (NMDevice *self,
* can retry device initialization.
*/
if ( (priv->state == state)
- && !(state == NM_DEVICE_STATE_UNAVAILABLE && priv->firmware_missing)) {
- _LOGD (LOGD_DEVICE, "device state change: %s -> %s (reason '%s') [%d %d %d] (skip due to missing firmware)",
+ && ( state != NM_DEVICE_STATE_UNAVAILABLE
+ || !priv->firmware_missing)) {
+ _LOGD (LOGD_DEVICE, "device state change: %s -> %s (reason '%s') [%d %d %d]%s",
state_to_string (old_state),
state_to_string (state),
reason_to_string (reason),
old_state,
state,
- reason);
+ reason,
+ priv->firmware_missing ? " (missing firmware)" : "");
return;
}
@@ -10078,8 +10233,7 @@ _set_state_full (NMDevice *self,
}
/* Update the available connections list when a device first becomes available */
- if ( (state >= NM_DEVICE_STATE_DISCONNECTED && old_state < NM_DEVICE_STATE_DISCONNECTED)
- || nm_device_get_default_unmanaged (self))
+ if (state >= NM_DEVICE_STATE_DISCONNECTED && old_state < NM_DEVICE_STATE_DISCONNECTED)
nm_device_recheck_available_connections (self);
/* Handle the new state here; but anything that could trigger
@@ -10180,11 +10334,7 @@ _set_state_full (NMDevice *self,
NM_DEVICE_STATE_REASON_NONE,
NM_DEVICE_STATE_REASON_NONE);
} else {
- if (old_state == NM_DEVICE_STATE_UNMANAGED)
- _LOGD (LOGD_DEVICE, "device not yet available for transition to DISCONNECTED");
- else if ( old_state > NM_DEVICE_STATE_UNAVAILABLE
- && nm_device_get_default_unmanaged (self))
- nm_device_queue_state (self, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NONE);
+ _LOGD (LOGD_DEVICE, "device not yet available for transition to DISCONNECTED");
}
break;
case NM_DEVICE_STATE_DEACTIVATING:
@@ -10230,9 +10380,6 @@ _set_state_full (NMDevice *self,
break;
/* fall through */
}
- if ( old_state > NM_DEVICE_STATE_DISCONNECTED
- && nm_device_get_default_unmanaged (self))
- nm_device_queue_state (self, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NONE);
break;
case NM_DEVICE_STATE_ACTIVATED:
_LOGI (LOGD_DEVICE, "Activation: successful, device activated.");
@@ -10347,6 +10494,9 @@ _set_state_full (NMDevice *self,
g_object_unref (req);
priv->in_state_changed = FALSE;
+
+ if ((old_state > NM_DEVICE_STATE_UNMANAGED) != (state > NM_DEVICE_STATE_UNMANAGED))
+ g_object_notify (G_OBJECT (self), NM_DEVICE_MANAGED);
}
void
@@ -10696,7 +10846,8 @@ nm_device_init (NMDevice *self)
priv->dhcp_timeout = 0;
priv->rfkill_type = RFKILL_TYPE_UNKNOWN;
priv->autoconnect = DEFAULT_AUTOCONNECT;
- priv->unmanaged_flags = NM_UNMANAGED_INTERNAL;
+ priv->unmanaged_flags = NM_UNMANAGED_PLATFORM_INIT;
+ priv->unmanaged_mask = priv->unmanaged_flags;
priv->available_connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
priv->ip6_saved_properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
@@ -10774,15 +10925,6 @@ constructed (GObject *object)
G_CALLBACK (cp_connection_added_or_updated),
self);
- /* Update default-unmanaged device available connections immediately,
- * since they don't transition from UNMANAGED (and thus the state handler
- * doesn't run and update them) until something external happens.
- */
- if (nm_device_get_default_unmanaged (self)) {
- nm_device_set_autoconnect (self, FALSE);
- nm_device_recheck_available_connections (self);
- }
-
G_OBJECT_CLASS (nm_device_parent_class)->constructed (object);
_LOGD (LOGD_DEVICE, "constructed (%s)", G_OBJECT_TYPE_NAME (self));
@@ -10900,7 +11042,6 @@ set_property (GObject *object, guint prop_id,
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
const char *hw_addr, *p;
guint count;
- gboolean val_bool;
switch (prop_id) {
case PROP_UDI:
@@ -10934,18 +11075,26 @@ set_property (GObject *object, guint prop_id,
case PROP_IP4_ADDRESS:
priv->ip4_address = g_value_get_uint (value);
break;
- case PROP_MANAGED:
- val_bool = g_value_get_boolean (value);
- priv->managed_touched_by_user = TRUE;
- nm_device_set_unmanaged_flags (self,
- NM_UNMANAGED_USER | (val_bool ? NM_UNMANAGED_DEFAULT : NM_UNMANAGED_NONE),
- !val_bool,
- NM_DEVICE_STATE_REASON_USER_REQUESTED);
+ case PROP_MANAGED: {
+ gboolean managed;
+ NMDeviceStateReason reason;
+
+ managed = g_value_get_boolean (value);
+ if (managed)
+ reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED;
+ else
+ reason = NM_DEVICE_STATE_REASON_REMOVED;
+ nm_device_set_unmanaged_by_flags (self,
+ NM_UNMANAGED_USER_EXPLICIT,
+ !managed,
+ reason);
break;
+ }
case PROP_AUTOCONNECT:
nm_device_set_autoconnect (self, g_value_get_boolean (value));
break;
case PROP_FIRMWARE_MISSING:
+ /* construct only */
priv->firmware_missing = g_value_get_boolean (value);
break;
case PROP_NM_PLUGIN_MISSING:
@@ -11080,7 +11229,8 @@ get_property (GObject *object, guint prop_id,
g_value_set_uint (value, priv->link_type);
break;
case PROP_MANAGED:
- g_value_set_boolean (value, nm_device_get_managed (self));
+ /* The managed state exposed on D-Bus only depends on the current device state alone. */
+ g_value_set_boolean (value, nm_device_get_state (self) > NM_DEVICE_STATE_UNMANAGED);
break;
case PROP_AUTOCONNECT:
g_value_set_boolean (value, priv->autoconnect);
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 2d168f6df9..e203d2a5f5 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -326,8 +326,6 @@ typedef void (*NMDeviceAuthRequestFunc) (NMDevice *device,
GType nm_device_get_type (void);
-void nm_device_finish_init (NMDevice *device);
-
const char * nm_device_get_udi (NMDevice *dev);
const char * nm_device_get_iface (NMDevice *dev);
int nm_device_get_ifindex (NMDevice *dev);
@@ -424,45 +422,65 @@ RfKillType nm_device_get_rfkill_type (NMDevice *device);
/**
* NMUnmanagedFlags:
* @NM_UNMANAGED_NONE: placeholder value
- * @NM_UNMANAGED_INTERNAL: %TRUE when unmanaged by internal decision (ie,
- * because NM is sleeping or not managed for some other reason)
+ * @NM_UNMANAGED_SLEEPING: %TRUE when unmanaged because NM is sleeping.
+ * @NM_UNMANAGED_QUITTING: %TRUE when unmanaged because NM is shutting down.
* @NM_UNMANAGED_PARENT: %TRUE when unmanaged due to parent device being unmanaged
* @NM_UNMANAGED_LOOPBACK: %TRUE for unmanaging loopback device
* @NM_UNMANAGED_PLATFORM_INIT: %TRUE when unmanaged because platform link not
- * yet initialized
- * @NM_UNMANAGED_USER: %TRUE when unmanaged by user decision (via unmanaged-specs)
- * @NM_UNMANAGED_DEFAULT: %TRUE when unmanaged by default (ie, Generic devices)
+ * yet initialized. Unrealized device are also unmanaged for this reason.
+ * @NM_UNMANAGED_USER_EXPLICIT: %TRUE when unmanaged by explicit user decision
+ * (e.g. via a D-Bus command)
+ * @NM_UNMANAGED_BY_DEFAULT: %TRUE for certain device types where we unmanage
+ * them by default
+ * @NM_UNMANAGED_USER_CONFIG: %TRUE when unmanaged by user decision (via unmanaged-specs)
+ * @NM_UNMANAGED_USER_UDEV: %TRUE when unmanaged by user decision (via UDev rule)
* @NM_UNMANAGED_EXTERNAL_DOWN: %TRUE when unmanaged because !IFF_UP and not created by NM
+ * @NM_UNMANAGED_IS_SLAVE: indicates that the device is enslaved. Note that
+ * setting the NM_UNMANAGED_IS_SLAVE to %TRUE makes no sense, this flag has only
+ * meaning to set a slave device as managed if the parent is managed too.
*/
typedef enum { /*< skip >*/
NM_UNMANAGED_NONE = 0,
- NM_UNMANAGED_INTERNAL = (1LL << 0),
- NM_UNMANAGED_PARENT = (1LL << 1),
- NM_UNMANAGED_LOOPBACK = (1LL << 2),
- NM_UNMANAGED_PLATFORM_INIT = (1LL << 3),
- NM_UNMANAGED_USER = (1LL << 4),
-
- NM_UNMANAGED_DEFAULT = (1LL << 8),
+ /* these flags are authorative. If one of them is set,
+ * the device cannot be managed. */
+ NM_UNMANAGED_SLEEPING = (1LL << 0),
+ NM_UNMANAGED_QUITTING = (1LL << 1),
+ NM_UNMANAGED_PARENT = (1LL << 2),
+ NM_UNMANAGED_LOOPBACK = (1LL << 3),
+ NM_UNMANAGED_PLATFORM_INIT = (1LL << 4),
+ NM_UNMANAGED_USER_EXPLICIT = (1LL << 5),
+
+ /* These flags can be non-effective and be overwritten
+ * by other flags. */
+ NM_UNMANAGED_BY_DEFAULT = (1LL << 8),
+ NM_UNMANAGED_USER_CONFIG = (1LL << 9),
+ NM_UNMANAGED_USER_UDEV = (1LL << 10),
NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 11),
+ NM_UNMANAGED_IS_SLAVE = (1LL << 12),
- /* Boundary value */
- __NM_UNMANAGED_LAST,
- NM_UNMANAGED_LAST = __NM_UNMANAGED_LAST - 1,
- NM_UNMANAGED_ALL = ((NM_UNMANAGED_LAST << 1) - 1),
} NMUnmanagedFlags;
-gboolean nm_device_get_managed (NMDevice *device);
+typedef enum {
+ NM_UNMAN_FLAG_OP_SET_MANAGED = FALSE,
+ NM_UNMAN_FLAG_OP_SET_UNMANAGED = TRUE,
+ NM_UNMAN_FLAG_OP_FORGET = 2,
+} NMUnmanFlagOp;
+
+const char *nm_unmanaged_flags2str (NMUnmanagedFlags flags, char *buf, gsize len);
+
+gboolean nm_device_get_managed (NMDevice *device, gboolean for_user_request);
NMUnmanagedFlags nm_device_get_unmanaged_flags (NMDevice *device, NMUnmanagedFlags flag);
void nm_device_set_unmanaged_flags (NMDevice *device,
- NMUnmanagedFlags flag,
- gboolean unmanaged,
- NMDeviceStateReason reason);
-void nm_device_set_unmanaged_flags_by_device_spec (NMDevice *self, const GSList *unmanaged_specs);
-void nm_device_set_unmanaged_flags_initial (NMDevice *device,
- NMUnmanagedFlags flag,
- gboolean unmanaged);
-void nm_device_set_unmanaged_quitting (NMDevice *device);
+ NMUnmanagedFlags flags,
+ NMUnmanFlagOp set_op);
+void nm_device_set_unmanaged_by_flags (NMDevice *device,
+ NMUnmanagedFlags flags,
+ NMUnmanFlagOp set_op,
+ NMDeviceStateReason reason);
+void nm_device_set_unmanaged_by_user_config (NMDevice *self, const GSList *unmanaged_specs);
+void nm_device_set_unmanaged_by_user_udev (NMDevice *self);
+void nm_device_set_unmanaged_by_quitting (NMDevice *device);
gboolean nm_device_get_is_nm_owned (NMDevice *device);
@@ -484,6 +502,7 @@ gboolean nm_device_unrealize (NMDevice *device,
gboolean nm_device_get_autoconnect (NMDevice *device);
void nm_device_set_autoconnect (NMDevice *device, gboolean autoconnect);
+void nm_device_emit_recheck_auto_activate (NMDevice *device);
void nm_device_state_changed (NMDevice *device,
NMDeviceState state,
diff --git a/src/nm-manager.c b/src/nm-manager.c
index e8d73a5020..5b5273126b 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -833,9 +833,9 @@ remove_device (NMManager *manager,
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
nm_log_dbg (LOGD_DEVICE, "(%s): removing device (allow_unmanage %d, managed %d)",
- nm_device_get_iface (device), allow_unmanage, nm_device_get_managed (device));
+ nm_device_get_iface (device), allow_unmanage, nm_device_get_managed (device, FALSE));
- if (allow_unmanage && nm_device_get_managed (device)) {
+ if (allow_unmanage && nm_device_get_managed (device, FALSE)) {
NMActRequest *req = nm_device_get_act_request (device);
gboolean unmanage = FALSE;
@@ -853,9 +853,9 @@ remove_device (NMManager *manager,
if (unmanage) {
if (quitting)
- nm_device_set_unmanaged_quitting (device);
+ nm_device_set_unmanaged_by_quitting (device);
else
- nm_device_set_unmanaged_flags (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_REMOVED);
+ nm_device_set_unmanaged_by_flags (device, NM_UNMANAGED_PLATFORM_INIT, TRUE, NM_DEVICE_STATE_REASON_REMOVED);
} else if (quitting && nm_config_get_configure_and_quit (nm_config_get ())) {
nm_device_spawn_iface_helper (device);
}
@@ -1171,7 +1171,7 @@ system_unmanaged_devices_changed_cb (NMSettings *settings,
unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
for (iter = priv->devices; iter; iter = g_slist_next (iter))
- nm_device_set_unmanaged_flags_by_device_spec (NM_DEVICE (iter->data), unmanaged_specs);
+ nm_device_set_unmanaged_by_user_config (NM_DEVICE (iter->data), unmanaged_specs);
}
static void
@@ -1664,14 +1664,6 @@ assume_connection (NMManager *self, NMDevice *device, NMSettingsConnection *conn
}
static gboolean
-can_start_device (NMManager *self, NMDevice *device)
-{
- return nm_device_is_real (device)
- && !manager_sleeping (self)
- && !nm_device_get_unmanaged_flags (device, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT);
-}
-
-static gboolean
recheck_assume_connection (NMManager *self, NMDevice *device)
{
NMSettingsConnection *connection;
@@ -1684,7 +1676,7 @@ recheck_assume_connection (NMManager *self, NMDevice *device)
if (nm_device_get_is_nm_owned (device))
return FALSE;
- if (!can_start_device (self, device))
+ if (!nm_device_get_managed (device, FALSE))
return FALSE;
state = nm_device_get_state (device);
@@ -1711,13 +1703,6 @@ recheck_assume_connection (NMManager *self, NMDevice *device)
nm_device_state_changed (device,
NM_DEVICE_STATE_UNAVAILABLE,
NM_DEVICE_STATE_REASON_CONFIG_FAILED);
-
- /* Return default-unmanaged devices to their original state */
- if (nm_device_get_unmanaged_flags (device, NM_UNMANAGED_DEFAULT)) {
- nm_device_state_changed (device,
- NM_DEVICE_STATE_UNMANAGED,
- NM_DEVICE_STATE_REASON_CONFIG_FAILED);
- }
}
if (generated) {
@@ -1779,26 +1764,31 @@ device_realized (NMDevice *device,
GParamSpec *pspec,
NMManager *self)
{
- int ifindex;
-
/* Emit D-Bus signals */
g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
g_object_notify (G_OBJECT (self), NM_MANAGER_DEVICES);
+}
- /* Loopback device never gets managed */
- ifindex = nm_device_get_ifindex (device);
- if (ifindex > 0 && nm_platform_link_get_type (NM_PLATFORM_GET, ifindex) == NM_LINK_TYPE_LOOPBACK)
+static void
+_device_realize_finish (NMManager *self, NMDevice *device, const NMPlatformLink *plink)
+{
+ g_return_if_fail (NM_IS_MANAGER (self));
+ g_return_if_fail (NM_IS_DEVICE (device));
+
+ nm_device_realize_finish (device, plink);
+
+ if (!nm_device_get_managed (device, FALSE))
return;
- if (!can_start_device (self, device))
+ if (recheck_assume_connection (self, device))
return;
- if ( !recheck_assume_connection (self, device)
- && nm_device_get_managed (device)) {
- nm_device_state_changed (device,
- NM_DEVICE_STATE_UNAVAILABLE,
- NM_DEVICE_STATE_REASON_NOW_MANAGED);
- }
+ /* if we failed to assume a connection for the managed device, but the device
+ * is still unavailable. Set UNAVAILABLE state again, this time with NOW_MANAGED. */
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_UNAVAILABLE,
+ NM_DEVICE_STATE_REASON_NOW_MANAGED);
+ nm_device_emit_recheck_auto_activate (device);
}
/**
@@ -1815,7 +1805,6 @@ add_device (NMManager *self, NMDevice *device, GError **error)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
const char *iface, *type_desc;
- const GSList *unmanaged_specs;
RfKillType rtype;
GSList *iter, *remove = NULL;
int ifindex;
@@ -1898,19 +1887,15 @@ add_device (NMManager *self, NMDevice *device, GError **error)
type_desc = nm_device_get_type_desc (device);
g_assert (type_desc);
- unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
- nm_device_set_unmanaged_flags_initial (device,
- NM_UNMANAGED_USER,
- nm_device_spec_match_list (device, unmanaged_specs));
- nm_device_set_unmanaged_flags_initial (device,
- NM_UNMANAGED_INTERNAL,
- manager_sleeping (self));
+ nm_device_set_unmanaged_by_user_config (device, nm_settings_get_unmanaged_specs (priv->settings));
+
+ nm_device_set_unmanaged_flags (device,
+ NM_UNMANAGED_SLEEPING,
+ manager_sleeping (self));
dbus_path = nm_exported_object_export (NM_EXPORTED_OBJECT (device));
nm_log_info (LOGD_DEVICE, "(%s): new %s device (%s)", iface, type_desc, dbus_path);
- nm_device_finish_init (device);
-
nm_settings_device_added (priv->settings, device);
g_signal_emit (self, signals[INTERNAL_DEVICE_ADDED], 0, device);
g_object_notify (G_OBJECT (self), NM_MANAGER_ALL_DEVICES);
@@ -1937,11 +1922,14 @@ factory_device_added_cb (NMDeviceFactory *factory,
NMDevice *device,
gpointer user_data)
{
+ NMManager *self = user_data;
GError *error = NULL;
+ g_return_if_fail (NM_IS_MANAGER (self));
+
if (nm_device_realize_start (device, NULL, NULL, &error)) {
- add_device (NM_MANAGER (user_data), device, NULL);
- nm_device_realize_finish (device, NULL);
+ add_device (self, device, NULL);
+ _device_realize_finish (self, device, NULL);
} else {
nm_log_warn (LOGD_DEVICE, "(%s): failed to realize device: %s",
nm_device_get_iface (device), error->message);
@@ -2013,7 +2001,7 @@ platform_link_added (NMManager *self,
return;
} else if (nm_device_realize_start (candidate, plink, &compatible, &error)) {
/* Success */
- nm_device_realize_finish (candidate, plink);
+ _device_realize_finish (self, candidate, plink);
return;
}
@@ -2062,7 +2050,7 @@ platform_link_added (NMManager *self,
nm_device_set_nm_plugin_missing (device, TRUE);
if (nm_device_realize_start (device, plink, NULL, &error)) {
add_device (self, device, NULL);
- nm_device_realize_finish (device, plink);
+ _device_realize_finish (self, device, plink);
} else {
nm_log_warn (LOGD_DEVICE, "%s: failed to realize device: %s",
plink->name, error->message);
@@ -2849,6 +2837,16 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
if (existing)
nm_device_steal_connection (existing, connection);
+ /* when creating the software device, it can happen that the device is
+ * still unmanaged by NM_UNMANAGED_PLATFORM_INIT because we didn't yet
+ * get the udev event. At this point, we can no longer delay the activation
+ * and force the device to be managed. */
+ nm_device_set_unmanaged_by_flags (device, NM_UNMANAGED_PLATFORM_INIT, FALSE, NM_DEVICE_STATE_REASON_USER_REQUESTED);
+
+ nm_device_set_unmanaged_by_flags (device, NM_UNMANAGED_USER_EXPLICIT, FALSE, NM_DEVICE_STATE_REASON_USER_REQUESTED);
+
+ g_return_val_if_fail (nm_device_get_managed (device, FALSE), FALSE);
+
if (nm_device_get_state (device) == NM_DEVICE_STATE_UNMANAGED) {
nm_device_state_changed (device,
NM_DEVICE_STATE_UNAVAILABLE,
@@ -3809,7 +3807,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
if (suspending && device_is_wake_on_lan (device))
continue;
- nm_device_set_unmanaged_flags (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_SLEEPING);
+ nm_device_set_unmanaged_by_flags (device, NM_UNMANAGED_SLEEPING, TRUE, NM_DEVICE_STATE_REASON_SLEEPING);
}
} else {
nm_log_info (LOGD_SUSPEND, "%s...", waking_from_suspend ? "waking up" : "re-enabling");
@@ -3824,7 +3822,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
if (nm_device_is_software (device))
continue;
if (device_is_wake_on_lan (device))
- nm_device_set_unmanaged_flags (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_SLEEPING);
+ nm_device_set_unmanaged_by_flags (device, NM_UNMANAGED_SLEEPING, TRUE, NM_DEVICE_STATE_REASON_SLEEPING);
}
}
@@ -3860,7 +3858,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
nm_device_set_autoconnect (device, TRUE);
- nm_device_set_unmanaged_flags (device, NM_UNMANAGED_INTERNAL, FALSE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
+ nm_device_set_unmanaged_by_flags (device, NM_UNMANAGED_SLEEPING, FALSE, NM_DEVICE_STATE_REASON_NOW_MANAGED);
}
}
@@ -4433,9 +4431,6 @@ handle_firmware_changed (gpointer user_data)
priv->fw_changed_id = 0;
- if (manager_sleeping (self))
- return FALSE;
-
/* Try to re-enable devices with missing firmware */
for (iter = priv->devices; iter; iter = iter->next) {
NMDevice *candidate = NM_DEVICE (iter->data);
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 49697f760d..377d52793c 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -1881,7 +1881,7 @@ device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self)
/* If the device isn't managed or it already has a default wired connection,
* ignore it.
*/
- if ( !nm_device_get_managed (device)
+ if ( !nm_device_get_managed (device, FALSE)
|| g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG)
|| have_connection_for_device (self, device))
return;