core: merge branch 'th/keep-alive-fixes'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/50
This commit is contained in:
Thomas Haller 2018-12-09 14:51:05 +01:00
commit e9d1cbb2f3
15 changed files with 547 additions and 187 deletions

View file

@ -960,20 +960,25 @@ typedef enum { /*< flags >*/
* @NM_ACTIVATION_STATE_FLAG_IP6_READY: IPv6 setting is completed.
* @NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES: The master has any slave devices attached.
* This only makes sense if the device is a master.
* @NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY: the lifetime
* of the activation is bound to the visilibity of the connection profile,
* which in turn depends on "connection.permissions" and whether a session
* for the user exists. Since: 1.16
*
* Flags describing the current activation state.
*
* Since: 1.10
**/
typedef enum { /*< flags >*/
NM_ACTIVATION_STATE_FLAG_NONE = 0,
NM_ACTIVATION_STATE_FLAG_NONE = 0,
NM_ACTIVATION_STATE_FLAG_IS_MASTER = (1LL << 0),
NM_ACTIVATION_STATE_FLAG_IS_SLAVE = (1LL << 1),
NM_ACTIVATION_STATE_FLAG_LAYER2_READY = (1LL << 2),
NM_ACTIVATION_STATE_FLAG_IP4_READY = (1LL << 3),
NM_ACTIVATION_STATE_FLAG_IP6_READY = (1LL << 4),
NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES = (1LL << 5),
NM_ACTIVATION_STATE_FLAG_IS_MASTER = (1LL << 0),
NM_ACTIVATION_STATE_FLAG_IS_SLAVE = (1LL << 1),
NM_ACTIVATION_STATE_FLAG_LAYER2_READY = (1LL << 2),
NM_ACTIVATION_STATE_FLAG_IP4_READY = (1LL << 3),
NM_ACTIVATION_STATE_FLAG_IP6_READY = (1LL << 4),
NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES = (1LL << 5),
NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY = (1LL << 6),
} NMActivationStateFlags;
/**

View file

@ -67,6 +67,7 @@
#include "settings/nm-settings.h"
#include "nm-setting-ethtool.h"
#include "nm-auth-utils.h"
#include "nm-keep-alive.h"
#include "nm-netns.h"
#include "nm-dispatcher.h"
#include "nm-config.h"
@ -2383,10 +2384,27 @@ nm_device_get_act_request (NMDevice *self)
return NM_DEVICE_GET_PRIVATE (self)->act_request.obj;
}
NMActivationStateFlags
nm_device_get_activation_state_flags (NMDevice *self)
{
NMActRequest *ac;
g_return_val_if_fail (NM_IS_DEVICE (self), NM_ACTIVATION_STATE_FLAG_NONE);
ac = NM_DEVICE_GET_PRIVATE (self)->act_request.obj;
if (!ac)
return NM_ACTIVATION_STATE_FLAG_NONE;
return nm_active_connection_get_state_flags (NM_ACTIVE_CONNECTION (ac));
}
NMSettingsConnection *
nm_device_get_settings_connection (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
priv = NM_DEVICE_GET_PRIVATE (self);
return priv->act_request.obj ? nm_act_request_get_settings_connection (priv->act_request.obj) : NULL;
}
@ -11619,14 +11637,15 @@ disconnect_cb (NMDevice *self,
}
static void
_clear_queued_act_request (NMDevicePrivate *priv)
_clear_queued_act_request (NMDevicePrivate *priv,
NMActiveConnectionStateReason active_reason)
{
if (priv->queued_act_request) {
gs_unref_object NMActRequest *ac = NULL;
ac = g_steal_pointer (&priv->queued_act_request);
nm_active_connection_set_state_fail ((NMActiveConnection *) ac,
NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED,
active_reason,
NULL);
}
}
@ -11768,7 +11787,8 @@ _carrier_wait_check_queued_act_request (NMDevice *self)
priv->queued_act_request_is_waiting_for_carrier = FALSE;
if (!priv->carrier) {
_LOGD (LOGD_DEVICE, "Cancel queued activation request as we have no carrier after timeout");
_clear_queued_act_request (priv);
_clear_queued_act_request (priv,
NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
} else {
gs_unref_object NMActRequest *queued_req = NULL;
@ -11823,7 +11843,9 @@ _carrier_wait_check_act_request_must_queue (NMDevice *self, NMActRequest *req)
}
void
nm_device_disconnect_active_connection (NMActiveConnection *active)
nm_device_disconnect_active_connection (NMActiveConnection *active,
NMDeviceStateReason device_reason,
NMActiveConnectionStateReason active_reason)
{
NMDevice *self;
NMDevicePrivate *priv;
@ -11831,38 +11853,59 @@ nm_device_disconnect_active_connection (NMActiveConnection *active)
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (active));
self = nm_active_connection_get_device (active);
if (!self) {
/* hm, no device? Just fail the active connection. */
nm_active_connection_set_state_fail (active,
NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN,
NULL);
return;
goto do_fail;
}
priv = NM_DEVICE_GET_PRIVATE (self);
if (NM_ACTIVE_CONNECTION (priv->queued_act_request) == active) {
_clear_queued_act_request (priv);
_clear_queued_act_request (priv, active_reason);
return;
}
if (NM_ACTIVE_CONNECTION (priv->act_request.obj) == active) {
if (priv->state < NM_DEVICE_STATE_DEACTIVATING) {
nm_device_state_changed (self,
NM_DEVICE_STATE_DEACTIVATING,
NM_DEVICE_STATE_REASON_NEW_ACTIVATION);
device_reason);
} else {
/* it's going down already... */
/* @active is the current ac of @self, but it's going down already.
* Nothing to do. */
}
return;
}
/* the active connection references this device, but it's neither the
* queued_act_request nor the current act_request. Just set it to fail... */
do_fail:
nm_active_connection_set_state_fail (active,
active_reason,
NULL);
}
void
nm_device_queue_activation (NMDevice *self, NMActRequest *req)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMDevicePrivate *priv;
gboolean must_queue;
g_return_if_fail (NM_IS_DEVICE (self));
g_return_if_fail (NM_IS_ACT_REQUEST (req));
nm_keep_alive_arm (nm_active_connection_get_keep_alive (NM_ACTIVE_CONNECTION (req)));
if (nm_active_connection_get_state (NM_ACTIVE_CONNECTION (req)) >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) {
/* it's already deactivating. Nothing to do. */
nm_assert (NM_IN_SET (nm_active_connection_get_device (NM_ACTIVE_CONNECTION (req)), NULL, self));
return;
}
nm_assert (self == nm_active_connection_get_device (NM_ACTIVE_CONNECTION (req)));
priv = NM_DEVICE_GET_PRIVATE (self);
must_queue = _carrier_wait_check_act_request_must_queue (self, req);
if ( !priv->act_request.obj
@ -11873,7 +11916,8 @@ nm_device_queue_activation (NMDevice *self, NMActRequest *req)
}
/* supersede any already-queued request */
_clear_queued_act_request (priv);
_clear_queued_act_request (priv,
NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
priv->queued_act_request = g_object_ref (req);
priv->queued_act_request_is_waiting_for_carrier = must_queue;
@ -14742,8 +14786,10 @@ _set_state_full (NMDevice *self,
if (state <= NM_DEVICE_STATE_UNAVAILABLE) {
if (available_connections_del_all (self))
_notify (self, PROP_AVAILABLE_CONNECTIONS);
if (old_state > NM_DEVICE_STATE_UNAVAILABLE)
_clear_queued_act_request (priv);
if (old_state > NM_DEVICE_STATE_UNAVAILABLE) {
_clear_queued_act_request (priv,
NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
}
}
/* Update the available connections list when a device first becomes available */
@ -16188,7 +16234,8 @@ dispose (GObject *object)
if (nm_clear_g_source (&priv->carrier_wait_id))
nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE);
_clear_queued_act_request (priv);
_clear_queued_act_request (priv,
NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
nm_clear_g_source (&priv->device_link_changed_id);
nm_clear_g_source (&priv->device_ip_link_changed_id);

View file

@ -543,6 +543,7 @@ NMConnection * nm_device_get_settings_connection_get_connection (NMDevice *self
NMConnection * nm_device_get_applied_connection (NMDevice *dev);
gboolean nm_device_has_unmodified_applied_connection (NMDevice *self,
NMSettingCompareFlags compare_flags);
NMActivationStateFlags nm_device_get_activation_state_flags (NMDevice *self);
gpointer /* (NMSetting *) */ nm_device_get_applied_setting (NMDevice *dev,
GType setting_type);
@ -769,7 +770,9 @@ void nm_device_queue_state (NMDevice *self,
gboolean nm_device_get_firmware_missing (NMDevice *self);
void nm_device_disconnect_active_connection (NMActiveConnection *active);
void nm_device_disconnect_active_connection (NMActiveConnection *active,
NMDeviceStateReason device_reason,
NMActiveConnectionStateReason active_reason);
void nm_device_queue_activation (NMDevice *device, NMActRequest *req);

View file

@ -539,6 +539,7 @@ nm_act_request_init (NMActRequest *req)
* @subject: the #NMAuthSubject representing the requestor of the activation
* @activation_type: the #NMActivationType
* @activation_reason: the reason for activation
* @initial_state_flags: the initial state flags.
* @device: the device/interface to configure according to @connection
*
* Creates a new device-based activation request. If an applied connection is
@ -553,6 +554,7 @@ nm_act_request_new (NMSettingsConnection *settings_connection,
NMAuthSubject *subject,
NMActivationType activation_type,
NMActivationReason activation_reason,
NMActivationStateFlags initial_state_flags,
NMDevice *device)
{
g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL);
@ -567,6 +569,7 @@ nm_act_request_new (NMSettingsConnection *settings_connection,
NM_ACTIVE_CONNECTION_INT_SUBJECT, subject,
NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE, (int) activation_type,
NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON, (int) activation_reason,
NM_ACTIVE_CONNECTION_STATE_FLAGS, (guint) initial_state_flags,
NULL);
}

View file

@ -42,6 +42,7 @@ NMActRequest *nm_act_request_new (NMSettingsConnection *settings_connec
NMAuthSubject *subject,
NMActivationType activation_type,
NMActivationReason activation_reason,
NMActivationStateFlags initial_state_flags,
NMDevice *device);
NMSettingsConnection *nm_act_request_get_settings_connection (NMActRequest *req);

View file

@ -105,7 +105,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMActiveConnection,
PROP_INT_MASTER_READY,
PROP_INT_ACTIVATION_TYPE,
PROP_INT_ACTIVATION_REASON,
PROP_INT_KEEP_ALIVE,
);
enum {
@ -164,26 +163,22 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_state_to_string, NMActiveConnectionState,
);
#define state_to_string(state) NM_UTILS_LOOKUP_STR (_state_to_string, state)
/* the maximum required buffer size for _state_flags_to_string(). */
#define _NM_ACTIVATION_STATE_FLAG_TO_STRING_BUFSIZE (255)
NM_UTILS_FLAGS2STR_DEFINE_STATIC (_state_flags_to_string, NMActivationStateFlags,
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_NONE, "none"),
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IS_MASTER, "is-master"),
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IS_SLAVE, "is-slave"),
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_LAYER2_READY, "layer2-ready"),
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IP4_READY, "ip4-ready"),
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IP6_READY, "ip6-ready"),
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES, "master-has-slaves"),
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_NONE, "none"),
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IS_MASTER, "is-master"),
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IS_SLAVE, "is-slave"),
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_LAYER2_READY, "layer2-ready"),
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IP4_READY, "ip4-ready"),
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IP6_READY, "ip6-ready"),
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES, "master-has-slaves"),
NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY, "lifetime-bound-to-profile-visibility"),
);
/*****************************************************************************/
static void
keep_alive_alive_changed (NMActiveConnection *ac,
GParamSpec *pspec,
NMKeepAlive *keep_alive)
{
_notify (ac, PROP_INT_KEEP_ALIVE);
}
static void
_settings_connection_updated (NMSettingsConnection *sett_conn,
gboolean by_user,
@ -264,6 +259,12 @@ nm_active_connection_set_state (NMActiveConnection *self,
state_to_string (new_state),
state_to_string (priv->state));
if (new_state > NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
/* once we are about to deactivate, we don't need the keep-alive instance
* anymore. Freeze/disarm it. */
nm_keep_alive_disarm (priv->keep_alive);
}
if ( new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED
&& priv->activation_type == NM_ACTIVATION_TYPE_ASSUME) {
/* assuming connections mean to gracefully take over an externally
@ -364,14 +365,20 @@ nm_active_connection_set_state_flags_full (NMActiveConnection *self,
f = (priv->state_flags & ~mask) | (state_flags & mask);
if (f != priv->state_flags) {
char buf1[G_N_ELEMENTS (_nm_utils_to_string_buffer)];
char buf2[G_N_ELEMENTS (_nm_utils_to_string_buffer)];
char buf1[_NM_ACTIVATION_STATE_FLAG_TO_STRING_BUFSIZE];
char buf2[_NM_ACTIVATION_STATE_FLAG_TO_STRING_BUFSIZE];
_LOGD ("set state-flags %s (was %s)",
_state_flags_to_string (f, buf1, sizeof (buf1)),
_state_flags_to_string (priv->state_flags, buf2, sizeof (buf2)));
priv->state_flags = f;
_notify (self, PROP_STATE_FLAGS);
nm_keep_alive_set_settings_connection_watch_visible (priv->keep_alive,
NM_FLAGS_HAS (priv->state_flags,
NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY)
? priv->settings_connection.obj
: NULL);
}
}
@ -915,12 +922,30 @@ nm_active_connection_get_activation_reason (NMActiveConnection *self)
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->activation_reason;
}
gboolean
/*****************************************************************************/
/**
* nm_active_connection_get_keep_alive:
* @self: the #NMActiveConnection instance
*
* Gives the #NMKeepAlive instance of the active connection. Note that
* @self is guaranteed not to swap the keep-alive instance, so it is
* in particular safe to assume that the keep-alive instance is alive
* as long as @self, and that nm_active_connection_get_keep_alive()
* will return always the same instance.
*
* In particular this means, that it is safe and encouraged, that you
* register to the notify:alive property changed signal of the returned
* instance.
*
* Returns: the #NMKeepAlive instance.
*/
NMKeepAlive *
nm_active_connection_get_keep_alive (NMActiveConnection *self)
{
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
return nm_keep_alive_is_alive (priv->keep_alive);
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->keep_alive;
}
/*****************************************************************************/
@ -1014,23 +1039,6 @@ nm_active_connection_set_parent (NMActiveConnection *self, NMActiveConnection *p
g_object_weak_ref ((GObject *) priv->parent, parent_destroyed, self);
}
/**
* nm_active_connection_bind_dbus_client:
* @self: the #NMActiveConnection
* @dbus_client: The dbus client to watch.
*
* Binds the lifetime of this active connection to the given dbus client. If
* the dbus client disappears, then the connection will be disconnected.
*/
void
nm_active_connection_bind_dbus_client (NMActiveConnection *self, GDBusConnection *dbus_con, const char *dbus_client)
{
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
nm_keep_alive_set_dbus_client_watch (priv->keep_alive, dbus_con, dbus_client);
nm_keep_alive_sink (priv->keep_alive);
}
/*****************************************************************************/
static void
@ -1329,9 +1337,6 @@ get_property (GObject *object, guint prop_id,
case PROP_INT_MASTER_READY:
g_value_set_boolean (value, priv->master_ready);
break;
case PROP_INT_KEEP_ALIVE:
g_value_set_boolean (value, nm_keep_alive_is_alive (priv->keep_alive));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1389,6 +1394,12 @@ set_property (GObject *object, guint prop_id,
g_return_if_reached ();
_set_activation_type (self, (NMActivationType) i);
break;
case PROP_STATE_FLAGS:
/* construct-only */
priv->state_flags = g_value_get_uint (value);
nm_assert ((guint) priv->state_flags == g_value_get_uint (value));
nm_assert (!NM_FLAGS_ANY (priv->state_flags, ~NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY));
break;
case PROP_INT_ACTIVATION_REASON:
/* construct-only */
i = g_value_get_int (value);
@ -1440,11 +1451,9 @@ nm_active_connection_init (NMActiveConnection *self)
priv->activation_type = NM_ACTIVATION_TYPE_MANAGED;
priv->version_id = _version_id_new ();
priv->keep_alive = nm_keep_alive_new (TRUE);
g_signal_connect_object (priv->keep_alive, "notify::" NM_KEEP_ALIVE_ALIVE,
(GCallback) keep_alive_alive_changed,
self,
G_CONNECT_SWAPPED);
/* the keep-alive instance must never change. Callers rely on that. */
priv->keep_alive = nm_keep_alive_new ();
_nm_keep_alive_set_owner (priv->keep_alive, G_OBJECT (self));
}
static void
@ -1474,15 +1483,12 @@ constructed (GObject *object)
g_steal_pointer (&priv->applied_connection));
}
if (NM_FLAGS_HAS (priv->state_flags,
NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY))
nm_keep_alive_set_settings_connection_watch_visible (priv->keep_alive, priv->settings_connection.obj);
g_return_if_fail (priv->subject);
g_return_if_fail (priv->activation_reason != NM_ACTIVATION_REASON_UNSET);
if (NM_IN_SET ((NMActivationReason) priv->activation_reason,
NM_ACTIVATION_REASON_AUTOCONNECT,
NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES)) {
nm_keep_alive_set_settings_connection_watch_visible (priv->keep_alive, priv->settings_connection.obj);
nm_keep_alive_sink (priv->keep_alive);
}
}
static void
@ -1526,6 +1532,8 @@ finalize (GObject *object)
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
nm_dbus_track_obj_path_set (&priv->settings_connection, NULL, FALSE);
_nm_keep_alive_set_owner (priv->keep_alive, NULL);
g_clear_object (&priv->keep_alive);
G_OBJECT_CLASS (nm_active_connection_parent_class)->finalize (object);
@ -1632,7 +1640,7 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
obj_properties[PROP_STATE_FLAGS] =
g_param_spec_uint (NM_ACTIVE_CONNECTION_STATE_FLAGS, "", "",
0, G_MAXUINT32, NM_ACTIVATION_STATE_FLAG_NONE,
G_PARAM_READABLE |
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_DEFAULT] =
@ -1737,11 +1745,6 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_INT_KEEP_ALIVE] =
g_param_spec_boolean (NM_ACTIVE_CONNECTION_INT_KEEP_ALIVE, "", "",
TRUE, G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
signals[DEVICE_CHANGED] =

View file

@ -59,7 +59,6 @@
#define NM_ACTIVE_CONNECTION_INT_MASTER_READY "int-master-ready"
#define NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE "int-activation-type"
#define NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON "int-activation-reason"
#define NM_ACTIVE_CONNECTION_INT_KEEP_ALIVE "int-keep-alive"
/* Signals */
#define NM_ACTIVE_CONNECTION_STATE_CHANGED "state-changed"
@ -164,6 +163,13 @@ nm_active_connection_set_state_flags (NMActiveConnection *self,
nm_active_connection_set_state_flags_full (self, state_flags, state_flags);
}
static inline void
nm_active_connection_set_state_flags_clear (NMActiveConnection *self,
NMActivationStateFlags state_flags)
{
nm_active_connection_set_state_flags_full (self, NM_ACTIVATION_STATE_FLAG_NONE, state_flags);
}
NMDevice * nm_active_connection_get_device (NMActiveConnection *self);
gboolean nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device);
@ -186,12 +192,8 @@ NMActivationType nm_active_connection_get_activation_type (NMActiveConnection *s
NMActivationReason nm_active_connection_get_activation_reason (NMActiveConnection *self);
gboolean nm_active_connection_get_keep_alive (NMActiveConnection *self);
NMKeepAlive *nm_active_connection_get_keep_alive (NMActiveConnection *self);
void nm_active_connection_clear_secrets (NMActiveConnection *self);
void nm_active_connection_bind_dbus_client (NMActiveConnection *self,
GDBusConnection *dbus_con,
const char *dbus_name);
#endif /* __NETWORKMANAGER_ACTIVE_CONNECTION_H__ */

View file

@ -46,6 +46,7 @@ typedef struct {
guint64 ac_version_id;
NMDeviceState state;
bool realized:1;
bool activation_lifetime_bound_to_profile_visiblity:1;
NMUnmanFlagOp unmanaged_explicit;
NMActivationReason activation_reason;
} DeviceCheckpoint;
@ -335,6 +336,9 @@ activate:
subject,
NM_ACTIVATION_TYPE_MANAGED,
dev_checkpoint->activation_reason,
dev_checkpoint->activation_lifetime_bound_to_profile_visiblity
? NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY
: NM_ACTIVATION_STATE_FLAG_NONE,
&local_error)) {
_LOGW ("rollback: reactivation of connection %s/%s failed: %s",
nm_settings_connection_get_id (connection),
@ -439,6 +443,8 @@ device_checkpoint_create (NMDevice *device)
dev_checkpoint->settings_connection = nm_simple_connection_new_clone (nm_settings_connection_get_connection (settings_connection));
dev_checkpoint->ac_version_id = nm_active_connection_version_id_get (NM_ACTIVE_CONNECTION (act_request));
dev_checkpoint->activation_reason = nm_active_connection_get_activation_reason (NM_ACTIVE_CONNECTION (act_request));
dev_checkpoint->activation_lifetime_bound_to_profile_visiblity = NM_FLAGS_HAS (nm_active_connection_get_state_flags (NM_ACTIVE_CONNECTION (act_request)),
NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY);
}
return dev_checkpoint;

View file

@ -34,6 +34,8 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMKeepAlive,
);
typedef struct {
GObject *owner;
NMSettingsConnection *connection;
GDBusConnection *dbus_connection;
char *dbus_client;
@ -41,10 +43,13 @@ typedef struct {
GCancellable *dbus_client_confirm_cancellable;
guint subscription_id;
bool floating:1;
bool forced:1;
bool armed:1;
bool disarmed:1;
bool alive:1;
bool dbus_client_confirmed:1;
bool dbus_client_watching:1;
bool connection_was_visible:1;
} NMKeepAlivePrivate;
struct _NMKeepAlive {
@ -77,22 +82,42 @@ _is_alive (NMKeepAlive *self)
{
NMKeepAlivePrivate *priv = NM_KEEP_ALIVE_GET_PRIVATE (self);
if ( priv->floating
|| priv->forced)
nm_assert (!priv->disarmed);
if (!priv->armed) {
/* before arming, the instance is always alive. */
return TRUE;
}
if (priv->dbus_client_watching) {
if (_is_alive_dbus_client (self)) {
/* no matter what, the keep-alive is alive, because there is a D-Bus client
* still around keeping it alive. */
return TRUE;
}
/* the D-Bus client is gone. The only other binding (below) for the connection's
* visibility cannot keep the instance alive.
*
* As such, a D-Bus client watch is authorative and overrules other conditions (that
* we have so far). */
return FALSE;
}
if ( priv->connection
&& NM_FLAGS_HAS (nm_settings_connection_get_flags (priv->connection),
NM_SETTINGS_CONNECTION_INT_FLAGS_VISIBLE))
return TRUE;
&& priv->connection_was_visible
&& !NM_FLAGS_HAS (nm_settings_connection_get_flags (priv->connection),
NM_SETTINGS_CONNECTION_INT_FLAGS_VISIBLE)) {
/* note that we only declare the keep-alive as dead due to invisible
* connection, if
* (1) we monitor a connection, obviously
* (2) the connection was visible earlier and is no longer. It was
* was invisible all the time, it does not suffice.
*/
return FALSE;
}
/* Perform this check as last. We want to confirm whether the dbus-client
* is alive lazyly, so if we already decided above that the keep-alive
* is good, we don't rely on the outcome of this check. */
if (_is_alive_dbus_client (self))
return TRUE;
return FALSE;
/* by default, the instance is alive. */
return TRUE;
}
static void
@ -100,9 +125,15 @@ _notify_alive (NMKeepAlive *self)
{
NMKeepAlivePrivate *priv = NM_KEEP_ALIVE_GET_PRIVATE (self);
if (priv->disarmed) {
/* once disarmed, the alive state is frozen. */
return;
}
if (priv->alive == _is_alive (self))
return;
priv->alive = !priv->alive;
_LOGD ("instance is now %s", priv->alive ? "alive" : "dead");
_notify (self, PROP_ALIVE);
}
@ -114,34 +145,28 @@ nm_keep_alive_is_alive (NMKeepAlive *self)
/*****************************************************************************/
void
nm_keep_alive_sink (NMKeepAlive *self)
{
NMKeepAlivePrivate *priv = NM_KEEP_ALIVE_GET_PRIVATE (self);
if (priv->floating) {
priv->floating = FALSE;
_notify_alive (self);
}
}
void
nm_keep_alive_set_forced (NMKeepAlive *self, gboolean forced)
{
NMKeepAlivePrivate *priv = NM_KEEP_ALIVE_GET_PRIVATE (self);
if (priv->forced != (!!forced)) {
priv->forced = forced;
_notify_alive (self);
}
}
/*****************************************************************************/
static void
connection_flags_changed (NMSettingsConnection *connection,
NMKeepAlive *self)
{
NMKeepAlivePrivate *priv = NM_KEEP_ALIVE_GET_PRIVATE (self);
if ( !priv->connection_was_visible
&& NM_FLAGS_HAS (nm_settings_connection_get_flags (priv->connection),
NM_SETTINGS_CONNECTION_INT_FLAGS_VISIBLE)) {
/* the profile was never visible but now it becomes visible.
* Remember that.
*
* Before this happens (that is, if the device was invisible all along),
* the keep alive instance is considered alive (w.r.t. watching the connection).
*
* The reason is to allow a user to manually activate an invisible profile and keep
* it alive. At least, as long until the user logs out the first time (which is the
* first time, the profiles changes from visible to invisible).
*
* Yes, that is odd. How to improve? */
priv->connection_was_visible = TRUE;
}
_notify_alive (self);
}
@ -163,8 +188,11 @@ _set_settings_connection_watch_visible (NMKeepAlive *self,
old_connection = g_steal_pointer (&priv->connection);
}
if (connection) {
if ( connection
&& !priv->disarmed) {
priv->connection = g_object_ref (connection);
priv->connection_was_visible = NM_FLAGS_HAS (nm_settings_connection_get_flags (priv->connection),
NM_SETTINGS_CONNECTION_INT_FLAGS_VISIBLE);
g_signal_connect (priv->connection,
NM_SETTINGS_CONNECTION_FLAGS_CHANGED,
G_CALLBACK (connection_flags_changed),
@ -298,12 +326,16 @@ nm_keep_alive_set_dbus_client_watch (NMKeepAlive *self,
{
NMKeepAlivePrivate *priv = NM_KEEP_ALIVE_GET_PRIVATE (self);
if (priv->disarmed)
return;
cleanup_dbus_watch (self);
if (client_address) {
_LOGD ("Registering dbus client watch for keep alive");
priv->dbus_client = g_strdup (client_address);
priv->dbus_client_watching = TRUE;
priv->dbus_client_confirmed = FALSE;
priv->dbus_connection = g_object_ref (connection);
priv->subscription_id = g_dbus_connection_signal_subscribe (connection,
@ -316,13 +348,65 @@ nm_keep_alive_set_dbus_client_watch (NMKeepAlive *self,
name_owner_changed_cb,
self,
NULL);
}
} else
priv->dbus_client_watching = FALSE;
_notify_alive (self);
}
/*****************************************************************************/
/**
* nm_keep_alive_arm:
* @self: the #NMKeepAlive
*
* A #NMKeepAlive instance is unarmed by default. That means, it's
* alive and stays alive until being armed. Arming means, that the conditions
* start to be actively evaluated, that the alive state may change, and
* that property changed signals are emitted.
*
* The opposite is nm_keep_alive_disarm() which freezes the alive state
* for good. Once disarmed, the instance cannot be armed again. Arming an
* instance multiple times has no effect. Arming an already disarmed instance
* also has no effect. */
void
nm_keep_alive_arm (NMKeepAlive *self)
{
NMKeepAlivePrivate *priv = NM_KEEP_ALIVE_GET_PRIVATE (self);
if (!priv->armed) {
priv->armed = TRUE;
_notify_alive (self);
}
}
/**
* nm_keep_alive_disarm:
* @self: the #NMKeepAlive instance
*
* Once the instance is disarmed, it will not change its alive state
* anymore and will not emit anymore property changed signals about
* alive state changed.
*
* As such, it will also free internal resources (since they no longer
* affect the externally visible state).
*
* Once disarmed, the instance is frozen and cannot change anymore.
*/
void
nm_keep_alive_disarm (NMKeepAlive *self)
{
NMKeepAlivePrivate *priv = NM_KEEP_ALIVE_GET_PRIVATE (self);
priv->disarmed = TRUE;
/* release internal data. */
_set_settings_connection_watch_visible (self, NULL, FALSE);
cleanup_dbus_watch (self);
}
/*****************************************************************************/
static void
get_property (GObject *object,
guint prop_id,
@ -343,22 +427,76 @@ get_property (GObject *object,
/*****************************************************************************/
/**
* nm_keep_alive_get_owner:
* @self: the #NMKeepAlive
*
* Returns: the owner instance associated with this @self. This commonly
* is set to be the target instance, which @self guards for being alive.
* Returns a gpointer, but of course it's some GObject instance. */
gpointer /* GObject * */
nm_keep_alive_get_owner (NMKeepAlive *self)
{
NMKeepAlivePrivate *priv = NM_KEEP_ALIVE_GET_PRIVATE (self);
nm_assert (!priv->owner || G_IS_OBJECT (priv->owner));
return priv->owner;
}
/**
* _nm_keep_alive_set_owner:
* @self: the #NMKeepAlive
* @owner: the owner to set or unset.
*
* Sets or unsets the owner instance. Think of the owner the target
* instance that is guarded by @self. It's the responsibility of the
* owner to set and properly unset this pointer. As the owner also
* controls the lifetime of the NMKeepAlive instance.
*
* This API is not to be called by everybody, but only the owner of
* @self.
*/
void
_nm_keep_alive_set_owner (NMKeepAlive *self,
GObject *owner)
{
NMKeepAlivePrivate *priv = NM_KEEP_ALIVE_GET_PRIVATE (self);
nm_assert (!owner || G_IS_OBJECT (owner));
/* it's bad style to reset the owner object. You are supposed to
* set it once, and clear it once. That's it. */
nm_assert (!owner || !priv->owner);
/* optimally, we would take a reference to @owner. But the
* owner already owns a refrence to the keep-alive, so we cannot
* just own a reference back.
*
* We could register a weak-pointer here. But instead, declare that
* owner is required to set itself as owner when creating the
* keep-alive instance, and unset itself when it lets go of the
* keep-alive instance (at latest, when the owner itself gets destroyed).
*/
priv->owner = owner;
}
/*****************************************************************************/
static void
nm_keep_alive_init (NMKeepAlive *self)
{
nm_assert (NM_KEEP_ALIVE_GET_PRIVATE (self)->alive == _is_alive (self));
NMKeepAlivePrivate *priv = NM_KEEP_ALIVE_GET_PRIVATE (self);
priv->alive = TRUE;
nm_assert (priv->alive == _is_alive (self));
}
NMKeepAlive *
nm_keep_alive_new (gboolean floating)
nm_keep_alive_new (void)
{
NMKeepAlive *self = g_object_new (NM_TYPE_KEEP_ALIVE, NULL);
NMKeepAlivePrivate *priv = NM_KEEP_ALIVE_GET_PRIVATE (self);
priv->floating = floating;
priv->alive = TRUE;
nm_assert (priv->alive == _is_alive (self));
return self;
return g_object_new (NM_TYPE_KEEP_ALIVE, NULL);
}
static void
@ -366,8 +504,10 @@ dispose (GObject *object)
{
NMKeepAlive *self = NM_KEEP_ALIVE (object);
_set_settings_connection_watch_visible (self, NULL, FALSE);
cleanup_dbus_watch (self);
nm_assert (!NM_KEEP_ALIVE_GET_PRIVATE (self)->owner);
/* disarm also happens to free all resources. */
nm_keep_alive_disarm (self);
}
static void

View file

@ -36,14 +36,12 @@ typedef struct _NMKeepAliveClass NMKeepAliveClass;
GType nm_keep_alive_get_type (void) G_GNUC_CONST;
NMKeepAlive* nm_keep_alive_new (gboolean floating);
NMKeepAlive* nm_keep_alive_new (void);
gboolean nm_keep_alive_is_alive (NMKeepAlive *self);
void nm_keep_alive_sink (NMKeepAlive *self);
void nm_keep_alive_set_forced (NMKeepAlive *self,
gboolean forced);
void nm_keep_alive_arm (NMKeepAlive *self);
void nm_keep_alive_disarm (NMKeepAlive *self);
void nm_keep_alive_set_settings_connection_watch_visible (NMKeepAlive *self,
NMSettingsConnection *connection);
@ -52,4 +50,10 @@ void nm_keep_alive_set_dbus_client_watch (NMKeepAlive *self,
GDBusConnection *connection,
const char *client_address);
gpointer /* GObject * */ nm_keep_alive_get_owner (NMKeepAlive *self);
/* _nm_keep_alive_set_owner() is reserved for the owner to set/unset itself. */
void _nm_keep_alive_set_owner (NMKeepAlive *self,
GObject *owner);
#endif /* __NETWORKMANAGER_KEEP_ALIVE_H__ */

View file

@ -39,6 +39,7 @@
#include "platform/nm-platform.h"
#include "platform/nmp-object.h"
#include "nm-hostname-manager.h"
#include "nm-keep-alive.h"
#include "nm-rfkill-manager.h"
#include "dhcp/nm-dhcp-manager.h"
#include "settings/nm-settings.h"
@ -319,6 +320,7 @@ static NMActiveConnection *_new_active_connection (NMManager *self,
NMAuthSubject *subject,
NMActivationType activation_type,
NMActivationReason activation_reason,
NMActivationStateFlags initial_state_flags,
GError **error);
static void policy_activating_ac_changed (GObject *object, GParamSpec *pspec, gpointer user_data);
@ -2697,6 +2699,18 @@ recheck_assume_connection (NMManager *self,
GError *error = NULL;
subject = nm_auth_subject_new_internal ();
/* Note: the lifetime of the activation connection is always bound to the profiles visiblity
* via NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY.
*
* This only makes a difference, if the profile actually has "connection.permissions"
* set to limit visibility (which is not the case for externally managed, generated profiles).
*
* If we assume a previously active connection whose lifetime was unbound, we now bind it
* after restart. That is not correct, and can mean that the profile becomes subject to
* deactivation after restart (if the user logs out).
*
* This should be improved, but it's unclear how. */
active = _new_active_connection (self,
FALSE,
sett_conn,
@ -2707,6 +2721,7 @@ recheck_assume_connection (NMManager *self,
subject,
generated ? NM_ACTIVATION_TYPE_EXTERNAL : NM_ACTIVATION_TYPE_ASSUME,
generated ? NM_ACTIVATION_REASON_EXTERNAL : NM_ACTIVATION_REASON_ASSUME,
NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY,
&error);
if (!active) {
@ -3891,11 +3906,16 @@ ensure_master_active_connection (NMManager *self,
GError **error)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMActiveConnection *ac;
NMActiveConnection *master_ac = NULL;
NMDeviceState master_state;
gboolean bind_lifetime_to_profile_visibility;
g_assert (connection);
g_assert (master_connection || master_device);
g_return_val_if_fail (connection, NULL);
g_return_val_if_fail (master_connection || master_device, FALSE);
bind_lifetime_to_profile_visibility = NM_FLAGS_HAS (nm_device_get_activation_state_flags (device),
NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY);
/* If the master device isn't activated then we need to activate it using
* compatible connection. If it's already activating we can just proceed.
@ -3920,8 +3940,16 @@ ensure_master_active_connection (NMManager *self,
if ( (master_state == NM_DEVICE_STATE_ACTIVATED)
|| nm_device_is_activating (master_device)) {
/* Device already using master_connection */
g_assert (device_connection);
return NM_ACTIVE_CONNECTION (nm_device_get_act_request (master_device));
ac = NM_ACTIVE_CONNECTION (nm_device_get_act_request (master_device));
g_return_val_if_fail (device_connection, ac);
if (!bind_lifetime_to_profile_visibility) {
/* unbind the lifetime. */
nm_active_connection_set_state_flags_clear (ac,
NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY);
}
return ac;
}
/* If the device is disconnected, find a compatible connection and
@ -3958,6 +3986,9 @@ ensure_master_active_connection (NMManager *self,
subject,
NM_ACTIVATION_TYPE_MANAGED,
activation_reason,
bind_lifetime_to_profile_visibility
? NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY
: NM_ACTIVATION_STATE_FLAG_NONE,
error);
return master_ac;
}
@ -4006,6 +4037,9 @@ ensure_master_active_connection (NMManager *self,
subject,
NM_ACTIVATION_TYPE_MANAGED,
activation_reason,
bind_lifetime_to_profile_visibility
? NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY
: NM_ACTIVATION_STATE_FLAG_NONE,
error);
return master_ac;
}
@ -4167,6 +4201,7 @@ autoconnect_slaves (NMManager *self,
master_device)) {
gs_free SlaveConnectionInfo *slaves = NULL;
guint i, n_slaves = 0;
gboolean bind_lifetime_to_profile_visibility;
slaves = find_slaves (self, master_connection, master_device, &n_slaves);
if (n_slaves > 1) {
@ -4181,6 +4216,10 @@ autoconnect_slaves (NMManager *self,
GINT_TO_POINTER (!nm_streq0 (value, "index")));
}
bind_lifetime_to_profile_visibility = n_slaves > 0
&& NM_FLAGS_HAS (nm_device_get_activation_state_flags (master_device),
NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY);
for (i = 0; i < n_slaves; i++) {
SlaveConnectionInfo *slave = &slaves[i];
const char *uuid;
@ -4235,6 +4274,9 @@ autoconnect_slaves (NMManager *self,
subject,
NM_ACTIVATION_TYPE_MANAGED,
NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES,
bind_lifetime_to_profile_visibility
? NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY
: NM_ACTIVATION_STATE_FLAG_NONE,
&local_err);
if (local_err) {
_LOGW (LOGD_CORE, "Slave connection activation failed: %s", local_err->message);
@ -4295,6 +4337,40 @@ unmanaged_to_disconnected (NMDevice *device)
}
}
static NMActivationStateFlags
_activation_bind_lifetime_to_profile_visibility (NMAuthSubject *subject)
{
if ( nm_auth_subject_is_internal (subject)
|| nm_auth_subject_get_unix_process_uid (subject) == 0) {
/* internal requests and requests from root are always unbound. */
return NM_ACTIVATION_STATE_FLAG_NONE;
}
/* if the activation was not done by internal decision nor root, there
* are the following cases:
*
* - the connection has "connection.permissions" unset and the profile
* is not restricted to a user and commonly always visible. It does
* not hurt to bind the lifetime, because we expect the profile to be
* visible at the moment. If the profile changes (while still being active),
* we want to pick-up changes to the visibility and possibly disconnect.
*
* - the connection has "connection.permissions" set, and the current user
* is the owner:
*
* - Usually, we would expect that the profile is visible at the moment,
* and of course we want to bind the lifetime. The moment the user
* logs out, the connection becomes invisible and disconnects.
*
* - the profile at this time could already be invisible (e.g. if the
* user didn't ceate a proper session (sudo) and manually activates
* an invisible profile. In this case, we still want to bind the
* lifetime, and it will disconnect after the user logs in and logs
* out again. NMKeepAlive takes care of that.
*/
return NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY;
}
/* The parent connection is ready; we can proceed realizing the device and
* progressing the device to disconencted state.
*/
@ -4424,6 +4500,8 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
subject,
NM_ACTIVATION_TYPE_MANAGED,
nm_active_connection_get_activation_reason (active),
nm_active_connection_get_state_flags (active)
& NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY,
error);
if (!parent_ac) {
g_prefix_error (error, "%s failed to activate parent: ", nm_device_get_iface (device));
@ -4549,7 +4627,9 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
for (i = 0; i < n_all; i++) {
nm_device_disconnect_active_connection ( all_ac_arr
? all_ac_arr->pdata[i]
: ac);
: ac,
NM_DEVICE_STATE_REASON_NEW_ACTIVATION,
NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN);
}
}
}
@ -4622,6 +4702,7 @@ _new_active_connection (NMManager *self,
NMAuthSubject *subject,
NMActivationType activation_type,
NMActivationReason activation_reason,
NMActivationStateFlags initial_state_flags,
GError **error)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
@ -4693,6 +4774,7 @@ _new_active_connection (NMManager *self,
parent_device,
nm_dbus_object_get_path (NM_DBUS_OBJECT (parent)),
activation_reason,
initial_state_flags,
subject);
}
@ -4702,6 +4784,7 @@ _new_active_connection (NMManager *self,
subject,
activation_type,
activation_reason,
initial_state_flags,
device);
}
@ -4765,6 +4848,7 @@ fail:
* @activation_type: whether to assume the connection. That is, take over gracefully,
* non-destructible.
* @activation_reason: the reason for activation
* @initial_state_flags: the inital state flags for the activation.
* @error: return location for an error
*
* Begins a new internally-initiated activation of @sett_conn on @device.
@ -4786,6 +4870,7 @@ nm_manager_activate_connection (NMManager *self,
NMAuthSubject *subject,
NMActivationType activation_type,
NMActivationReason activation_reason,
NMActivationStateFlags initial_state_flags,
GError **error)
{
NMManagerPrivate *priv;
@ -4839,6 +4924,7 @@ nm_manager_activate_connection (NMManager *self,
subject,
activation_type,
activation_reason,
initial_state_flags,
error);
if (!active)
return NULL;
@ -5098,6 +5184,7 @@ impl_manager_activate_connection (NMDBusObject *obj,
subject,
NM_ACTIVATION_TYPE_MANAGED,
NM_ACTIVATION_REASON_USER_REQUEST,
_activation_bind_lifetime_to_profile_visibility (subject),
&error);
if (!active)
goto error;
@ -5372,12 +5459,18 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj,
subject,
NM_ACTIVATION_TYPE_MANAGED,
NM_ACTIVATION_REASON_USER_REQUEST,
_activation_bind_lifetime_to_profile_visibility (subject),
&error);
if (!active)
goto error;
if (bind_dbus_client)
nm_active_connection_bind_dbus_client (active, dbus_connection, sender);
if (bind_dbus_client) {
NMKeepAlive *keep_alive;
keep_alive = nm_active_connection_get_keep_alive (active);
nm_keep_alive_set_dbus_client_watch (keep_alive, dbus_connection, sender);
nm_keep_alive_arm (keep_alive);
}
nm_active_connection_authorize (active,
incompl_conn,
@ -5406,31 +5499,26 @@ nm_manager_deactivate_connection (NMManager *manager,
NMDeviceStateReason reason,
GError **error)
{
gboolean success = FALSE;
if (NM_IS_VPN_CONNECTION (active)) {
NMActiveConnectionStateReason vpn_reason = NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED;
if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_CONNECTION_REMOVED)
vpn_reason = NM_ACTIVE_CONNECTION_STATE_REASON_CONNECTION_REMOVED;
if (nm_vpn_connection_deactivate (NM_VPN_CONNECTION (active), vpn_reason, FALSE))
success = TRUE;
else
if (!nm_vpn_connection_deactivate (NM_VPN_CONNECTION (active), vpn_reason, FALSE)) {
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
"The VPN connection was not active.");
return FALSE;
}
} else {
g_assert (NM_IS_ACT_REQUEST (active));
nm_device_state_changed (nm_active_connection_get_device (active),
NM_DEVICE_STATE_DEACTIVATING,
reason);
success = TRUE;
nm_assert (NM_IS_ACT_REQUEST (active));
nm_device_disconnect_active_connection (active,
reason,
NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN);
}
if (success)
_notify (manager, PROP_ACTIVE_CONNECTIONS);
return success;
_notify (manager, PROP_ACTIVE_CONNECTIONS);
return TRUE;
}
static void

View file

@ -97,6 +97,19 @@ const CList * nm_manager_get_active_connections (NMManager *manager);
}); \
iter = c_list_entry (iter->active_connections_lst.next, NMActiveConnection, active_connections_lst))
#define nm_manager_for_each_active_connection_safe(manager, iter, tmp_list, iter_safe) \
for (tmp_list = nm_manager_get_active_connections (manager), \
iter_safe = tmp_list->next; \
({ \
if (iter_safe != tmp_list) { \
iter = c_list_entry (iter_safe, NMActiveConnection, active_connections_lst); \
iter_safe = iter_safe->next; \
} else \
iter = NULL; \
(iter != NULL); \
}); \
)
NMSettingsConnection **nm_manager_get_activatable_connections (NMManager *manager,
gboolean for_auto_activation,
gboolean sort,
@ -121,6 +134,19 @@ const CList * nm_manager_get_devices (NMManager *manager);
}); \
iter = c_list_entry (iter->devices_lst.next, NMDevice, devices_lst))
#define nm_manager_for_each_device_safe(manager, iter, tmp_list, iter_safe) \
for (tmp_list = nm_manager_get_devices (manager), \
iter_safe = tmp_list->next; \
({ \
if (iter_safe != tmp_list) { \
iter = c_list_entry (iter_safe, NMDevice, devices_lst); \
iter_safe = iter_safe->next; \
} else \
iter = NULL; \
(iter != NULL); \
}); \
)
NMDevice * nm_manager_get_device_by_ifindex (NMManager *manager,
int ifindex);
NMDevice * nm_manager_get_device_by_path (NMManager *manager,
@ -149,6 +175,7 @@ NMActiveConnection *nm_manager_activate_connection (NMManager *manager,
NMAuthSubject *subject,
NMActivationType activation_type,
NMActivationReason activation_reason,
NMActivationStateFlags initial_state_flags,
GError **error);
gboolean nm_manager_deactivate_connection (NMManager *manager,

View file

@ -30,6 +30,7 @@
#include "NetworkManagerUtils.h"
#include "nm-act-request.h"
#include "nm-keep-alive.h"
#include "devices/nm-device.h"
#include "nm-setting-ip4-config.h"
#include "nm-setting-connection.h"
@ -1283,6 +1284,7 @@ auto_activate_device (NMPolicy *self,
subject,
NM_ACTIVATION_TYPE_MANAGED,
NM_ACTIVATION_REASON_AUTOCONNECT,
NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY,
&error);
if (!ac) {
_LOGI (LOGD_DEVICE, "connection '%s' auto-activation failed: %s",
@ -1673,9 +1675,14 @@ activate_secondary_connections (NMPolicy *self,
GError *error = NULL;
guint32 i;
gboolean success = TRUE;
NMActivationStateFlags initial_state_flags;
s_con = nm_connection_get_setting_connection (connection);
nm_assert (s_con);
nm_assert (NM_IS_SETTING_CONNECTION (s_con));
/* we propagate the activation's state flags. */
initial_state_flags = nm_device_get_activation_state_flags (device)
& NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY;
for (i = 0; i < nm_setting_connection_get_num_secondaries (s_con); i++) {
NMSettingsConnection *sett_conn;
@ -1699,7 +1706,6 @@ activate_secondary_connections (NMPolicy *self,
}
req = nm_device_get_act_request (device);
g_assert (req);
_LOGD (LOGD_DEVICE, "activating secondary connection '%s (%s)' for base connection '%s (%s)'",
nm_settings_connection_get_id (sett_conn), sec_uuid,
@ -1712,6 +1718,7 @@ activate_secondary_connections (NMPolicy *self,
nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (req)),
NM_ACTIVATION_TYPE_MANAGED,
nm_active_connection_get_activation_reason (NM_ACTIVE_CONNECTION (req)),
initial_state_flags,
&error);
if (ac)
secondary_ac_list = g_slist_append (secondary_ac_list, g_object_ref (ac));
@ -2161,6 +2168,8 @@ vpn_connection_retry_after_failure (NMVpnConnection *vpn, NMPolicy *self)
nm_active_connection_get_subject (ac),
NM_ACTIVATION_TYPE_MANAGED,
nm_active_connection_get_activation_reason (ac),
( nm_active_connection_get_state_flags (ac)
& NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY),
&error)) {
_LOGW (LOGD_DEVICE, "VPN '%s' reconnect failed: %s",
nm_settings_connection_get_id (connection),
@ -2183,26 +2192,36 @@ active_connection_state_changed (NMActiveConnection *active,
}
static void
active_connection_keep_alive_changed (NMActiveConnection *ac,
active_connection_keep_alive_changed (NMKeepAlive *keep_alive,
GParamSpec *pspec,
NMPolicy *self)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
NMPolicyPrivate *priv;
NMActiveConnection *ac;
GError *error = NULL;
if (nm_active_connection_get_keep_alive (ac))
nm_assert (NM_IS_POLICY (self));
nm_assert (NM_IS_KEEP_ALIVE (keep_alive));
nm_assert (NM_IS_ACTIVE_CONNECTION (nm_keep_alive_get_owner (keep_alive)));
if (nm_keep_alive_is_alive (keep_alive))
return;
if (nm_active_connection_get_state (ac) <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
if (!nm_manager_deactivate_connection (priv->manager,
ac,
NM_DEVICE_STATE_REASON_CONNECTION_REMOVED,
&error)) {
_LOGW (LOGD_DEVICE, "connection '%s' is no longer kept alive, but error deactivating it: %s",
nm_active_connection_get_settings_connection_id (ac),
error->message);
g_clear_error (&error);
}
ac = nm_keep_alive_get_owner (keep_alive);
if (nm_active_connection_get_state (ac) > NM_ACTIVE_CONNECTION_STATE_ACTIVATED)
return;
priv = NM_POLICY_GET_PRIVATE (self);
if (!nm_manager_deactivate_connection (priv->manager,
ac,
NM_DEVICE_STATE_REASON_CONNECTION_REMOVED,
&error)) {
_LOGW (LOGD_DEVICE, "connection '%s' is no longer kept alive, but error deactivating it: %s",
nm_active_connection_get_settings_connection_id (ac),
error->message);
g_clear_error (&error);
}
}
@ -2213,6 +2232,7 @@ active_connection_added (NMManager *manager,
{
NMPolicyPrivate *priv = user_data;
NMPolicy *self = _PRIV_TO_SELF (priv);
NMKeepAlive *keep_alive;
if (NM_IS_VPN_CONNECTION (active)) {
g_signal_connect (active, NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED,
@ -2223,13 +2243,18 @@ active_connection_added (NMManager *manager,
self);
}
keep_alive = nm_active_connection_get_keep_alive (active);
nm_keep_alive_arm (keep_alive);
g_signal_connect (active, "notify::" NM_ACTIVE_CONNECTION_STATE,
G_CALLBACK (active_connection_state_changed),
self);
g_signal_connect (active, "notify::" NM_ACTIVE_CONNECTION_INT_KEEP_ALIVE,
g_signal_connect (keep_alive,
"notify::" NM_KEEP_ALIVE_ALIVE,
G_CALLBACK (active_connection_keep_alive_changed),
self);
active_connection_keep_alive_changed (active, NULL, self);
active_connection_keep_alive_changed (keep_alive, NULL, self);
}
static void
@ -2249,6 +2274,9 @@ active_connection_removed (NMManager *manager,
g_signal_handlers_disconnect_by_func (active,
active_connection_state_changed,
self);
g_signal_handlers_disconnect_by_func (nm_active_connection_get_keep_alive (active),
active_connection_keep_alive_changed,
self);
}
/*****************************************************************************/
@ -2386,12 +2414,12 @@ _deactivate_if_active (NMPolicy *self, NMSettingsConnection *connection)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
NMActiveConnection *ac;
const CList *tmp_list;
const CList *tmp_list, *tmp_safe;
GError *error = NULL;
nm_assert (NM_IS_SETTINGS_CONNECTION (connection));
nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) {
nm_manager_for_each_active_connection_safe (priv->manager, ac, tmp_list, tmp_safe) {
if ( nm_active_connection_get_settings_connection (ac) == connection
&& (nm_active_connection_get_state (ac) <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) {

View file

@ -851,6 +851,7 @@ nm_vpn_connection_new (NMSettingsConnection *settings_connection,
NMDevice *parent_device,
const char *specific_object,
NMActivationReason activation_reason,
NMActivationStateFlags initial_state_flags,
NMAuthSubject *subject)
{
g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL);
@ -864,6 +865,7 @@ nm_vpn_connection_new (NMSettingsConnection *settings_connection,
NM_ACTIVE_CONNECTION_INT_SUBJECT, subject,
NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON, activation_reason,
NM_ACTIVE_CONNECTION_VPN, TRUE,
NM_ACTIVE_CONNECTION_STATE_FLAGS, (guint) initial_state_flags,
NULL);
}

View file

@ -53,6 +53,7 @@ NMVpnConnection * nm_vpn_connection_new (NMSettingsConnection *settings_connecti
NMDevice *parent_device,
const char *specific_object,
NMActivationReason activation_reason,
NMActivationStateFlags initial_state_flags,
NMAuthSubject *subject);
void nm_vpn_connection_activate (NMVpnConnection *self,