diff options
author | Thomas Haller <thaller@redhat.com> | 2016-02-15 21:42:57 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2016-02-15 21:43:45 +0100 |
commit | 6f3d7cbd22a281afc8f374a883a7c3281f890622 (patch) | |
tree | cf69bc00078d192f80f3939c317744036fe1477b | |
parent | 30ce8c305bc65543a5a53f2d492c3d32335d2b89 (diff) | |
parent | 87a3df2e572ed47b5f76f6d1cad63ce622296e21 (diff) | |
download | NetworkManager-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.c | 2 | ||||
-rw-r--r-- | src/devices/nm-device-macvlan.c | 10 | ||||
-rw-r--r-- | src/devices/nm-device-private.h | 1 | ||||
-rw-r--r-- | src/devices/nm-device-vlan.c | 10 | ||||
-rw-r--r-- | src/devices/nm-device.c | 706 | ||||
-rw-r--r-- | src/devices/nm-device.h | 73 | ||||
-rw-r--r-- | src/nm-manager.c | 101 | ||||
-rw-r--r-- | src/settings/nm-settings.c | 2 |
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; |