mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-25 04:50:07 +01:00
The parent-active signal is used by the manager to determine when the
parent active-connection is ready and a connection that depend on it
can proceed.
The AC state could transition from ACTIVATING directly to
DEACTIVATING; in such case we should not emit the signal but instead
just stop watching the parent AC.
Fixes: 6e382ea91d ('active-connection: add parent active connection tracking')
https://bugzilla.redhat.com/show_bug.cgi?id=1778073
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/510
1777 lines
62 KiB
C
1777 lines
62 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (C) 2008 - 2014 Red Hat, Inc.
|
|
*/
|
|
|
|
#include "nm-default.h"
|
|
|
|
#include "nm-active-connection.h"
|
|
|
|
#include "nm-libnm-core-intern/nm-common-macros.h"
|
|
#include "nm-dbus-interface.h"
|
|
#include "devices/nm-device.h"
|
|
#include "settings/nm-settings-connection.h"
|
|
#include "nm-simple-connection.h"
|
|
#include "nm-auth-utils.h"
|
|
#include "nm-auth-manager.h"
|
|
#include "nm-libnm-core-intern/nm-auth-subject.h"
|
|
#include "nm-keep-alive.h"
|
|
#include "NetworkManagerUtils.h"
|
|
#include "nm-core-internal.h"
|
|
|
|
#define AUTH_CALL_ID_SHARED_WIFI_PERMISSION_FAILED ((NMAuthManagerCallId *) GINT_TO_POINTER (1))
|
|
|
|
typedef struct _NMActiveConnectionPrivate {
|
|
NMDBusTrackObjPath settings_connection;
|
|
NMConnection *applied_connection;
|
|
char *specific_object;
|
|
NMDevice *device;
|
|
|
|
guint64 version_id;
|
|
|
|
char *pending_activation_id;
|
|
|
|
NMActivationStateFlags state_flags;
|
|
|
|
NMActiveConnectionState state;
|
|
bool is_default:1;
|
|
bool is_default6:1;
|
|
bool state_set:1;
|
|
bool vpn:1;
|
|
bool master_ready:1;
|
|
|
|
NMActivationType activation_type:3;
|
|
|
|
/* capture the original reason why the connection was activated.
|
|
* For example with NM_ACTIVATION_REASON_ASSUME, the connection
|
|
* will later change to become fully managed. But the original
|
|
* reason never changes. */
|
|
NMActivationReason activation_reason:4;
|
|
|
|
NMAuthSubject *subject;
|
|
NMActiveConnection *master;
|
|
|
|
NMActiveConnection *parent;
|
|
|
|
struct {
|
|
NMAuthManagerCallId *call_id_network_control;
|
|
NMAuthManagerCallId *call_id_wifi_shared_permission;
|
|
|
|
NMActiveConnectionAuthResultFunc result_func;
|
|
gpointer user_data;
|
|
} auth;
|
|
|
|
NMKeepAlive *keep_alive;
|
|
} NMActiveConnectionPrivate;
|
|
|
|
NM_GOBJECT_PROPERTIES_DEFINE (NMActiveConnection,
|
|
PROP_CONNECTION,
|
|
PROP_ID,
|
|
PROP_UUID,
|
|
PROP_TYPE,
|
|
PROP_SPECIFIC_OBJECT,
|
|
PROP_DEVICES,
|
|
PROP_STATE,
|
|
PROP_STATE_FLAGS,
|
|
PROP_DEFAULT,
|
|
PROP_IP4_CONFIG,
|
|
PROP_DHCP4_CONFIG,
|
|
PROP_DEFAULT6,
|
|
PROP_IP6_CONFIG,
|
|
PROP_DHCP6_CONFIG,
|
|
PROP_VPN,
|
|
PROP_MASTER,
|
|
|
|
PROP_INT_SETTINGS_CONNECTION,
|
|
PROP_INT_APPLIED_CONNECTION,
|
|
PROP_INT_DEVICE,
|
|
PROP_INT_SUBJECT,
|
|
PROP_INT_MASTER,
|
|
PROP_INT_MASTER_READY,
|
|
PROP_INT_ACTIVATION_TYPE,
|
|
PROP_INT_ACTIVATION_REASON,
|
|
);
|
|
|
|
enum {
|
|
DEVICE_CHANGED,
|
|
DEVICE_METERED_CHANGED,
|
|
PARENT_ACTIVE,
|
|
STATE_CHANGED,
|
|
LAST_SIGNAL
|
|
};
|
|
static guint signals[LAST_SIGNAL] = { 0 };
|
|
|
|
G_DEFINE_ABSTRACT_TYPE (NMActiveConnection, nm_active_connection, NM_TYPE_DBUS_OBJECT)
|
|
|
|
#define NM_ACTIVE_CONNECTION_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMActiveConnection, NM_IS_ACTIVE_CONNECTION)
|
|
|
|
/*****************************************************************************/
|
|
|
|
static const NMDBusInterfaceInfoExtended interface_info_active_connection;
|
|
static const GDBusSignalInfo signal_info_state_changed;
|
|
|
|
static void check_master_ready (NMActiveConnection *self);
|
|
static void _device_cleanup (NMActiveConnection *self);
|
|
static void _settings_connection_flags_changed (NMSettingsConnection *settings_connection,
|
|
NMActiveConnection *self);
|
|
static void _set_activation_type_managed (NMActiveConnection *self);
|
|
|
|
static void auth_complete (NMActiveConnection *self, gboolean result, const char *message);
|
|
|
|
/*****************************************************************************/
|
|
|
|
#define _NMLOG_DOMAIN LOGD_DEVICE
|
|
#define _NMLOG_PREFIX_NAME "active-connection"
|
|
#define _NMLOG(level, ...) \
|
|
G_STMT_START { \
|
|
char _sbuf[64]; \
|
|
NMActiveConnectionPrivate *_priv = self ? NM_ACTIVE_CONNECTION_GET_PRIVATE (self) : NULL; \
|
|
\
|
|
nm_log ((level), _NMLOG_DOMAIN, \
|
|
(_priv && _priv->device) ? nm_device_get_iface (_priv->device) : NULL, \
|
|
(_priv && _priv->applied_connection) ? nm_connection_get_uuid (_priv->applied_connection) : NULL, \
|
|
"%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
|
|
_NMLOG_PREFIX_NAME, \
|
|
self ? nm_sprintf_buf (_sbuf, "[%p]", self) : "" \
|
|
_NM_UTILS_MACRO_REST (__VA_ARGS__)); \
|
|
} G_STMT_END
|
|
|
|
/*****************************************************************************/
|
|
|
|
static
|
|
NM_UTILS_LOOKUP_STR_DEFINE (_state_to_string, NMActiveConnectionState,
|
|
NM_UTILS_LOOKUP_DEFAULT (NULL),
|
|
NM_UTILS_LOOKUP_STR_ITEM (NM_ACTIVE_CONNECTION_STATE_UNKNOWN, "unknown"),
|
|
NM_UTILS_LOOKUP_STR_ITEM (NM_ACTIVE_CONNECTION_STATE_ACTIVATING, "activating"),
|
|
NM_UTILS_LOOKUP_STR_ITEM (NM_ACTIVE_CONNECTION_STATE_ACTIVATED, "activated"),
|
|
NM_UTILS_LOOKUP_STR_ITEM (NM_ACTIVE_CONNECTION_STATE_DEACTIVATING, "deactivating"),
|
|
NM_UTILS_LOOKUP_STR_ITEM (NM_ACTIVE_CONNECTION_STATE_DEACTIVATED, "deactivated"),
|
|
);
|
|
|
|
#define state_to_string_a(state) NM_UTILS_LOOKUP_STR_A (_state_to_string, state)
|
|
|
|
/* the maximum required buffer size for _state_flags_to_string(). */
|
|
#define _NM_ACTIVATION_STATE_FLAG_TO_STRING_BUFSIZE (255)
|
|
|
|
static
|
|
NM_UTILS_FLAGS2STR_DEFINE (_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_LIFETIME_BOUND_TO_PROFILE_VISIBILITY, "lifetime-bound-to-profile-visibility"),
|
|
);
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
_settings_connection_updated (NMSettingsConnection *sett_conn,
|
|
guint update_reason_u,
|
|
gpointer user_data)
|
|
{
|
|
NMActiveConnection *self = user_data;
|
|
|
|
/* we don't know which properties actually changed. Just to be sure,
|
|
* notify about all possible properties. After all, an update of a
|
|
* connection is a rare event. */
|
|
|
|
_notify (self, PROP_ID);
|
|
|
|
/* it's a bit odd to update the TYPE of an active connection. But the alternative
|
|
* is unexpected too. */
|
|
_notify (self, PROP_TYPE);
|
|
|
|
/* currently, the UUID and the exported CONNECTION path cannot change. Later, we might
|
|
* want to support a re-link operation, which associates an active-connection with a different
|
|
* settings-connection. */
|
|
}
|
|
|
|
static void
|
|
_set_settings_connection (NMActiveConnection *self, NMSettingsConnection *sett_conn)
|
|
{
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
if (priv->settings_connection.obj == sett_conn)
|
|
return;
|
|
|
|
if (priv->settings_connection.obj) {
|
|
g_signal_handlers_disconnect_by_func (priv->settings_connection.obj, _settings_connection_updated, self);
|
|
g_signal_handlers_disconnect_by_func (priv->settings_connection.obj, _settings_connection_flags_changed, self);
|
|
}
|
|
if (sett_conn) {
|
|
g_signal_connect (sett_conn, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, (GCallback) _settings_connection_updated, self);
|
|
if (nm_active_connection_get_activation_type (self) == NM_ACTIVATION_TYPE_EXTERNAL)
|
|
g_signal_connect (sett_conn, NM_SETTINGS_CONNECTION_FLAGS_CHANGED, (GCallback) _settings_connection_flags_changed, self);
|
|
}
|
|
|
|
nm_dbus_track_obj_path_set (&priv->settings_connection, sett_conn, TRUE);
|
|
}
|
|
|
|
NMActiveConnectionState
|
|
nm_active_connection_get_state (NMActiveConnection *self)
|
|
{
|
|
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->state;
|
|
}
|
|
|
|
static void
|
|
emit_state_changed (NMActiveConnection *self, guint state, guint reason)
|
|
{
|
|
nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self),
|
|
&interface_info_active_connection,
|
|
&signal_info_state_changed,
|
|
"(uu)",
|
|
(guint32) state,
|
|
(guint32) reason);
|
|
g_signal_emit (self, signals[STATE_CHANGED], 0, state, reason);
|
|
}
|
|
|
|
void
|
|
nm_active_connection_set_state (NMActiveConnection *self,
|
|
NMActiveConnectionState new_state,
|
|
NMActiveConnectionStateReason reason)
|
|
{
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
NMActiveConnectionState old_state;
|
|
|
|
/* DEACTIVATED is a terminal state */
|
|
g_return_if_fail ( priv->state != NM_ACTIVE_CONNECTION_STATE_DEACTIVATED
|
|
|| new_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED);
|
|
|
|
if (priv->state == new_state)
|
|
return;
|
|
|
|
_LOGD ("set state %s (was %s)",
|
|
state_to_string_a (new_state),
|
|
state_to_string_a (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
|
|
* configured device. Once activation is complete, an assumed
|
|
* activation *is* the same as a full activation. */
|
|
_set_activation_type_managed (self);
|
|
}
|
|
|
|
old_state = priv->state;
|
|
priv->state = new_state;
|
|
priv->state_set = TRUE;
|
|
emit_state_changed (self, new_state, reason);
|
|
_notify (self, PROP_STATE);
|
|
|
|
check_master_ready (self);
|
|
|
|
if ( new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED
|
|
|| old_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
|
|
nm_settings_connection_update_timestamp (priv->settings_connection.obj,
|
|
(guint64) time (NULL));
|
|
}
|
|
|
|
if (priv->device) {
|
|
if ( old_state < NM_ACTIVE_CONNECTION_STATE_ACTIVATED
|
|
&& new_state >= NM_ACTIVE_CONNECTION_STATE_ACTIVATED &&
|
|
priv->pending_activation_id)
|
|
{
|
|
nm_device_remove_pending_action (priv->device, priv->pending_activation_id, TRUE);
|
|
nm_clear_g_free (&priv->pending_activation_id);
|
|
}
|
|
}
|
|
|
|
if ( new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED
|
|
|| old_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
|
|
_notify (self, PROP_IP4_CONFIG);
|
|
_notify (self, PROP_DHCP4_CONFIG);
|
|
_notify (self, PROP_IP6_CONFIG);
|
|
_notify (self, PROP_DHCP6_CONFIG);
|
|
}
|
|
|
|
if (priv->state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) {
|
|
_nm_unused gs_unref_object NMActiveConnection *self_keep_alive = g_object_ref (self);
|
|
|
|
auth_complete (self, FALSE, "Authorization request cancelled");
|
|
|
|
/* Device is no longer relevant when deactivated. So remove it and
|
|
* emit property change notification so clients re-read the value,
|
|
* which will be NULL due to conditions in get_property().
|
|
*/
|
|
_device_cleanup (self);
|
|
_notify (self, PROP_DEVICES);
|
|
}
|
|
}
|
|
|
|
void
|
|
nm_active_connection_set_state_fail (NMActiveConnection *self,
|
|
NMActiveConnectionStateReason reason,
|
|
const char *error_desc)
|
|
{
|
|
NMActiveConnectionState s;
|
|
|
|
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
|
|
|
|
if (error_desc) {
|
|
_LOGD ("Failed to activate '%s': %s",
|
|
nm_active_connection_get_settings_connection_id (self),
|
|
error_desc);
|
|
}
|
|
|
|
s = nm_active_connection_get_state (self);
|
|
if ( s >= NM_ACTIVE_CONNECTION_STATE_ACTIVATING
|
|
&& s < NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) {
|
|
nm_active_connection_set_state (self,
|
|
NM_ACTIVE_CONNECTION_STATE_DEACTIVATING,
|
|
reason);
|
|
s = nm_active_connection_get_state (self);
|
|
}
|
|
if (s < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) {
|
|
nm_active_connection_set_state (self,
|
|
NM_ACTIVE_CONNECTION_STATE_DEACTIVATED,
|
|
reason);
|
|
}
|
|
}
|
|
|
|
NMActivationStateFlags
|
|
nm_active_connection_get_state_flags (NMActiveConnection *self)
|
|
{
|
|
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->state_flags;
|
|
}
|
|
|
|
void
|
|
nm_active_connection_set_state_flags_full (NMActiveConnection *self,
|
|
NMActivationStateFlags state_flags,
|
|
NMActivationStateFlags mask)
|
|
{
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
NMActivationStateFlags f;
|
|
|
|
f = (priv->state_flags & ~mask) | (state_flags & mask);
|
|
if (f != priv->state_flags) {
|
|
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);
|
|
}
|
|
}
|
|
|
|
const char *
|
|
nm_active_connection_get_settings_connection_id (NMActiveConnection *self)
|
|
{
|
|
NMSettingsConnection *sett_conn;
|
|
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
|
|
|
|
sett_conn = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection.obj;
|
|
return sett_conn
|
|
? nm_settings_connection_get_id (sett_conn)
|
|
: NULL;
|
|
}
|
|
|
|
NMSettingsConnection *
|
|
_nm_active_connection_get_settings_connection (NMActiveConnection *self)
|
|
{
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
|
|
|
|
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection.obj;
|
|
}
|
|
|
|
NMSettingsConnection *
|
|
nm_active_connection_get_settings_connection (NMActiveConnection *self)
|
|
{
|
|
NMSettingsConnection *sett_conn;
|
|
|
|
sett_conn = _nm_active_connection_get_settings_connection (self);
|
|
|
|
/* Only call this function on an active-connection that is already
|
|
* fully set-up (i.e. that has a settings-connection). Other uses
|
|
* indicate a bug. */
|
|
g_return_val_if_fail (sett_conn, NULL);
|
|
return sett_conn;
|
|
}
|
|
|
|
NMConnection *
|
|
nm_active_connection_get_applied_connection (NMActiveConnection *self)
|
|
{
|
|
NMConnection *connection;
|
|
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
|
|
|
|
connection = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->applied_connection;
|
|
|
|
/* Only call this function on an active-connection that is already
|
|
* fully set-up (i.e. that has a settings-connection). Other uses
|
|
* indicate a bug. */
|
|
g_return_val_if_fail (connection, NULL);
|
|
return connection;
|
|
}
|
|
|
|
static void
|
|
_set_applied_connection_take (NMActiveConnection *self,
|
|
NMConnection *applied_connection)
|
|
{
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
NMSettingConnection *s_con;
|
|
NMActivationStateFlags flags_val = 0;
|
|
|
|
nm_assert (NM_IS_CONNECTION (applied_connection));
|
|
nm_assert (!priv->applied_connection);
|
|
|
|
/* we take ownership of @applied_connection. Ensure to pass in a reference. */
|
|
priv->applied_connection = applied_connection;
|
|
nm_connection_clear_secrets (priv->applied_connection);
|
|
|
|
/* we determine whether the connection is a master/slave, based solely
|
|
* on the connection properties itself. */
|
|
s_con = nm_connection_get_setting_connection (priv->applied_connection);
|
|
if (nm_setting_connection_get_master (s_con))
|
|
flags_val |= NM_ACTIVATION_STATE_FLAG_IS_SLAVE;
|
|
|
|
if (_nm_connection_type_is_master (nm_setting_connection_get_connection_type (s_con)))
|
|
flags_val |= NM_ACTIVATION_STATE_FLAG_IS_MASTER;
|
|
|
|
nm_active_connection_set_state_flags_full (self,
|
|
flags_val,
|
|
NM_ACTIVATION_STATE_FLAG_IS_MASTER
|
|
| NM_ACTIVATION_STATE_FLAG_IS_SLAVE);
|
|
}
|
|
|
|
void
|
|
nm_active_connection_set_settings_connection (NMActiveConnection *self,
|
|
NMSettingsConnection *sett_conn)
|
|
{
|
|
NMActiveConnectionPrivate *priv;
|
|
|
|
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
|
|
|
|
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
g_return_if_fail (NM_IS_SETTINGS_CONNECTION (sett_conn));
|
|
g_return_if_fail (!priv->settings_connection.obj);
|
|
g_return_if_fail (!priv->applied_connection);
|
|
|
|
/* Can't change connection after the ActiveConnection is exported over D-Bus.
|
|
*
|
|
* Later, we want to change the settings-connection of an activated connection.
|
|
* When doing that, this changes the assumption that the settings-connection
|
|
* never changes (once it's set). That has effects for NMVpnConnection and
|
|
* NMActivationRequest.
|
|
* For example, we'd have to cancel all pending seret requests. */
|
|
g_return_if_fail (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (self)));
|
|
|
|
_set_settings_connection (self, sett_conn);
|
|
|
|
_set_applied_connection_take (self,
|
|
nm_simple_connection_new_clone (nm_settings_connection_get_connection (priv->settings_connection.obj)));
|
|
}
|
|
|
|
gboolean
|
|
nm_active_connection_has_unmodified_applied_connection (NMActiveConnection *self, NMSettingCompareFlags compare_flags)
|
|
{
|
|
NMActiveConnectionPrivate *priv;
|
|
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
|
|
|
|
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
g_return_val_if_fail (priv->settings_connection.obj, FALSE);
|
|
|
|
return nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection.obj,
|
|
priv->applied_connection,
|
|
compare_flags);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void
|
|
nm_active_connection_clear_secrets (NMActiveConnection *self)
|
|
{
|
|
NMActiveConnectionPrivate *priv;
|
|
|
|
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
|
|
|
|
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
if (nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection.obj,
|
|
priv->applied_connection,
|
|
NM_SETTING_COMPARE_FLAG_NONE)) {
|
|
nm_settings_connection_clear_secrets (priv->settings_connection.obj,
|
|
FALSE,
|
|
FALSE);
|
|
}
|
|
nm_connection_clear_secrets (priv->applied_connection);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
const char *
|
|
nm_active_connection_get_specific_object (NMActiveConnection *self)
|
|
{
|
|
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->specific_object;
|
|
}
|
|
|
|
void
|
|
nm_active_connection_set_specific_object (NMActiveConnection *self,
|
|
const char *specific_object)
|
|
{
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
/* Nothing that calls this function should be using paths from D-Bus,
|
|
* where NM uses "/" to mean NULL.
|
|
*/
|
|
nm_assert (!nm_streq0 (specific_object, "/"));
|
|
|
|
if (nm_streq0 (priv->specific_object, specific_object))
|
|
return;
|
|
|
|
g_free (priv->specific_object);
|
|
priv->specific_object = g_strdup (specific_object);
|
|
_notify (self, PROP_SPECIFIC_OBJECT);
|
|
}
|
|
|
|
void
|
|
nm_active_connection_set_default (NMActiveConnection *self,
|
|
int addr_family,
|
|
gboolean is_default)
|
|
{
|
|
NMActiveConnectionPrivate *priv;
|
|
|
|
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
|
|
nm_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6));
|
|
|
|
is_default = !!is_default;
|
|
|
|
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET)) {
|
|
if (priv->is_default != is_default) {
|
|
priv->is_default = is_default;
|
|
_notify (self, PROP_DEFAULT);
|
|
}
|
|
}
|
|
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET6)) {
|
|
if (priv->is_default6 != is_default) {
|
|
priv->is_default6 = is_default;
|
|
_notify (self, PROP_DEFAULT6);
|
|
}
|
|
}
|
|
}
|
|
|
|
gboolean
|
|
nm_active_connection_get_default (NMActiveConnection *self, int addr_family)
|
|
{
|
|
NMActiveConnectionPrivate *priv;
|
|
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
|
|
nm_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6));
|
|
|
|
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
switch (addr_family) {
|
|
case AF_INET: return priv->is_default;
|
|
case AF_INET6: return priv->is_default6;
|
|
default: return priv->is_default || priv->is_default6;
|
|
}
|
|
}
|
|
|
|
NMAuthSubject *
|
|
nm_active_connection_get_subject (NMActiveConnection *self)
|
|
{
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
|
|
|
|
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject;
|
|
}
|
|
|
|
gboolean
|
|
nm_active_connection_get_user_requested (NMActiveConnection *self)
|
|
{
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
|
|
|
|
return nm_auth_subject_get_subject_type (
|
|
NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject
|
|
) == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
|
|
}
|
|
|
|
NMDevice *
|
|
nm_active_connection_get_device (NMActiveConnection *self)
|
|
{
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
|
|
|
|
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->device;
|
|
}
|
|
|
|
static void
|
|
device_state_changed (NMDevice *device,
|
|
NMDeviceState new_state,
|
|
NMDeviceState old_state,
|
|
NMDeviceStateReason reason,
|
|
gpointer user_data)
|
|
{
|
|
NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
/* When already deactivated or before activation, device state changes are useless */
|
|
if (priv->state >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)
|
|
return;
|
|
if (old_state < NM_DEVICE_STATE_DISCONNECTED)
|
|
return;
|
|
|
|
/* Let subclasses handle the state change */
|
|
if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->device_state_changed)
|
|
NM_ACTIVE_CONNECTION_GET_CLASS (self)->device_state_changed (self, device, new_state, old_state);
|
|
}
|
|
|
|
static void
|
|
device_master_changed (GObject *object,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
NMDevice *device = NM_DEVICE (object);
|
|
NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
|
|
NMActiveConnection *master;
|
|
NMActiveConnectionState master_state;
|
|
|
|
if (NM_ACTIVE_CONNECTION (nm_device_get_act_request (device)) != self)
|
|
return;
|
|
if (!nm_device_get_master (device))
|
|
return;
|
|
if (!nm_active_connection_get_master (self))
|
|
return;
|
|
g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_master_changed), self);
|
|
|
|
master = nm_active_connection_get_master (self);
|
|
master_state = nm_active_connection_get_state (master);
|
|
if (master_state >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) {
|
|
/* Master failed before attaching the slave */
|
|
if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed)
|
|
NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed (self);
|
|
}
|
|
}
|
|
|
|
static void
|
|
device_metered_changed (GObject *object,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
NMActiveConnection *self = (NMActiveConnection *) user_data;
|
|
NMDevice *device = NM_DEVICE (object);
|
|
|
|
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
|
|
g_signal_emit (self, signals[DEVICE_METERED_CHANGED], 0, nm_device_get_metered (device));
|
|
}
|
|
|
|
gboolean
|
|
nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
|
|
{
|
|
NMActiveConnectionPrivate *priv;
|
|
gs_unref_object NMDevice *old_device = NULL;
|
|
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
|
|
g_return_val_if_fail (!device || NM_IS_DEVICE (device), FALSE);
|
|
|
|
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
if (device == priv->device)
|
|
return TRUE;
|
|
|
|
_LOGD ("set device %s%s%s [%p]",
|
|
NM_PRINT_FMT_QUOTED (device && nm_device_get_iface (device),
|
|
"\"",
|
|
nm_device_get_iface (device),
|
|
"\"",
|
|
device ? "(unknown)" : "(null)"),
|
|
device);
|
|
|
|
old_device = priv->device ? g_object_ref (priv->device) : NULL;
|
|
_device_cleanup (self);
|
|
|
|
if (device) {
|
|
/* Device obviously can't be its own master */
|
|
g_return_val_if_fail (!priv->master || device != nm_active_connection_get_device (priv->master), FALSE);
|
|
|
|
priv->device = g_object_ref (device);
|
|
|
|
g_signal_connect (device, NM_DEVICE_STATE_CHANGED,
|
|
G_CALLBACK (device_state_changed), self);
|
|
g_signal_connect (device, "notify::" NM_DEVICE_MASTER,
|
|
G_CALLBACK (device_master_changed), self);
|
|
g_signal_connect (device, "notify::" NM_DEVICE_METERED,
|
|
G_CALLBACK (device_metered_changed), self);
|
|
|
|
if (priv->activation_type != NM_ACTIVATION_TYPE_EXTERNAL) {
|
|
priv->pending_activation_id = g_strdup_printf (NM_PENDING_ACTIONPREFIX_ACTIVATION"%"G_GUINT64_FORMAT, priv->version_id);
|
|
nm_device_add_pending_action (device, priv->pending_activation_id, TRUE);
|
|
}
|
|
} else {
|
|
/* The ActiveConnection's device can only be cleared after the
|
|
* connection is activated.
|
|
*/
|
|
g_warn_if_fail (priv->state > NM_ACTIVE_CONNECTION_STATE_UNKNOWN);
|
|
priv->device = NULL;
|
|
}
|
|
_notify (self, PROP_INT_DEVICE);
|
|
|
|
g_signal_emit (self, signals[DEVICE_CHANGED], 0, priv->device, old_device);
|
|
|
|
_notify (self, PROP_DEVICES);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
NMActiveConnection *
|
|
nm_active_connection_get_master (NMActiveConnection *self)
|
|
{
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
|
|
|
|
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->master;
|
|
}
|
|
|
|
/**
|
|
* nm_active_connection_get_master_ready:
|
|
* @self: the #NMActiveConnection
|
|
*
|
|
* Returns: %TRUE if the connection has a master connection, and that
|
|
* master connection is ready to accept slaves. Otherwise %FALSE.
|
|
*/
|
|
gboolean
|
|
nm_active_connection_get_master_ready (NMActiveConnection *self)
|
|
{
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
|
|
|
|
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->master_ready;
|
|
}
|
|
|
|
static void
|
|
check_master_ready (NMActiveConnection *self)
|
|
{
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
gboolean signalling = FALSE;
|
|
|
|
/* ActiveConnetions don't enter the ACTIVATING state until they have a
|
|
* NMDevice in PREPARE or higher states, so the master active connection's
|
|
* device will be ready to accept slaves when the master is in ACTIVATING
|
|
* or higher states.
|
|
*/
|
|
if ( !priv->master_ready
|
|
&& priv->master
|
|
&& priv->state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING
|
|
&& NM_IN_SET (nm_active_connection_get_state (priv->master),
|
|
NM_ACTIVE_CONNECTION_STATE_ACTIVATING,
|
|
NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) {
|
|
signalling = TRUE;
|
|
}
|
|
|
|
_LOGD ("check-master-ready: %s (state %s, %s)",
|
|
signalling
|
|
? "signal"
|
|
: (priv->master_ready ? "already signalled" : "not signalling"),
|
|
state_to_string_a (priv->state),
|
|
priv->master
|
|
? nm_sprintf_bufa (128, "master %p is in state %s",
|
|
priv->master,
|
|
state_to_string_a (nm_active_connection_get_state (priv->master)))
|
|
: "no master");
|
|
|
|
if (signalling) {
|
|
priv->master_ready = TRUE;
|
|
_notify (self, PROP_INT_MASTER_READY);
|
|
|
|
/* Also notify clients to recheck the exported 'master' property to
|
|
* ensure that if the master connection was created without a device
|
|
* that we notify clients when the master device is known.
|
|
*/
|
|
_notify (self, PROP_MASTER);
|
|
}
|
|
}
|
|
|
|
static void
|
|
master_state_cb (NMActiveConnection *master,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
|
|
NMActiveConnectionState master_state = nm_active_connection_get_state (master);
|
|
NMDevice *master_device = nm_active_connection_get_device (master);
|
|
|
|
check_master_ready (self);
|
|
|
|
if ( master_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATING
|
|
&& (!master_device || !nm_device_is_real (master_device))) {
|
|
/* Master failed without ever creating or realizing its device */
|
|
if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed)
|
|
NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed (self);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* nm_active_connection_set_master:
|
|
* @self: the #NMActiveConnection
|
|
* @master: if the activation depends on another device (ie, bond or bridge
|
|
* master to which this device will be enslaved) pass the #NMActiveConnection
|
|
* that this activation request is a child of
|
|
*
|
|
* Sets the master active connection of @self.
|
|
*/
|
|
void
|
|
nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *master)
|
|
{
|
|
NMActiveConnectionPrivate *priv;
|
|
|
|
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
|
|
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (master));
|
|
|
|
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
/* Master is write-once, and must be set before exporting the object */
|
|
g_return_if_fail (priv->master == NULL);
|
|
g_return_if_fail (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (self)));
|
|
if (priv->device) {
|
|
/* Note, the master ActiveConnection may not yet have a device */
|
|
g_return_if_fail (priv->device != nm_active_connection_get_device (master));
|
|
}
|
|
|
|
_LOGD ("set master %p, %s, state %s",
|
|
master,
|
|
nm_active_connection_get_settings_connection_id (master),
|
|
state_to_string_a (nm_active_connection_get_state (master)));
|
|
|
|
priv->master = g_object_ref (master);
|
|
g_signal_connect (priv->master,
|
|
"notify::" NM_ACTIVE_CONNECTION_STATE,
|
|
(GCallback) master_state_cb,
|
|
self);
|
|
|
|
check_master_ready (self);
|
|
}
|
|
|
|
NMActivationType
|
|
nm_active_connection_get_activation_type (NMActiveConnection *self)
|
|
{
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NM_ACTIVATION_TYPE_MANAGED);
|
|
|
|
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->activation_type;
|
|
}
|
|
|
|
static void
|
|
_set_activation_type (NMActiveConnection *self,
|
|
NMActivationType activation_type)
|
|
{
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
if (priv->activation_type == activation_type)
|
|
return;
|
|
|
|
priv->activation_type = activation_type;
|
|
|
|
if (priv->settings_connection.obj) {
|
|
if (activation_type == NM_ACTIVATION_TYPE_EXTERNAL)
|
|
g_signal_connect (priv->settings_connection.obj, NM_SETTINGS_CONNECTION_FLAGS_CHANGED, (GCallback) _settings_connection_flags_changed, self);
|
|
else
|
|
g_signal_handlers_disconnect_by_func (priv->settings_connection.obj, _settings_connection_flags_changed, self);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_set_activation_type_managed (NMActiveConnection *self)
|
|
{
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
if (priv->activation_type == NM_ACTIVATION_TYPE_MANAGED)
|
|
return;
|
|
|
|
_LOGD ("update activation type from %s to %s",
|
|
nm_activation_type_to_string (priv->activation_type),
|
|
nm_activation_type_to_string (NM_ACTIVATION_TYPE_MANAGED));
|
|
|
|
_set_activation_type (self, NM_ACTIVATION_TYPE_MANAGED);
|
|
|
|
if ( priv->device
|
|
&& self == NM_ACTIVE_CONNECTION (nm_device_get_act_request (priv->device))
|
|
&& NM_IN_SET (nm_device_sys_iface_state_get (priv->device),
|
|
NM_DEVICE_SYS_IFACE_STATE_EXTERNAL,
|
|
NM_DEVICE_SYS_IFACE_STATE_ASSUME))
|
|
nm_device_sys_iface_state_set (priv->device, NM_DEVICE_SYS_IFACE_STATE_MANAGED);
|
|
}
|
|
|
|
NMActivationReason
|
|
nm_active_connection_get_activation_reason (NMActiveConnection *self)
|
|
{
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NM_ACTIVATION_REASON_UNSET);
|
|
|
|
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->activation_reason;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
|
|
|
|
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->keep_alive;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
_settings_connection_flags_changed (NMSettingsConnection *settings_connection,
|
|
NMActiveConnection *self)
|
|
{
|
|
NMDevice *device;
|
|
|
|
nm_assert (NM_IS_ACTIVE_CONNECTION (self));
|
|
nm_assert (NM_IS_SETTINGS_CONNECTION (settings_connection));
|
|
nm_assert (nm_active_connection_get_activation_type (self) == NM_ACTIVATION_TYPE_EXTERNAL);
|
|
nm_assert (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection.obj == settings_connection);
|
|
|
|
if (NM_FLAGS_HAS (nm_settings_connection_get_flags (settings_connection),
|
|
NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED))
|
|
return;
|
|
|
|
_set_activation_type_managed (self);
|
|
|
|
device = nm_active_connection_get_device (self);
|
|
if (device) {
|
|
gs_free_error GError *error = NULL;
|
|
|
|
if (!nm_device_reapply (device,
|
|
nm_settings_connection_get_connection (nm_active_connection_get_settings_connection (self)),
|
|
&error)) {
|
|
_LOGW ("failed to reapply new device settings on previously externally managed device: %s",
|
|
error->message);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void unwatch_parent (NMActiveConnection *self, gboolean unref);
|
|
|
|
static void
|
|
parent_destroyed (gpointer user_data, GObject *parent)
|
|
{
|
|
NMActiveConnection *self = user_data;
|
|
|
|
unwatch_parent (self, FALSE);
|
|
g_signal_emit (self, signals[PARENT_ACTIVE], 0, NULL);
|
|
}
|
|
|
|
static void
|
|
parent_state_cb (NMActiveConnection *parent_ac,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
NMActiveConnection *self = user_data;
|
|
NMActiveConnectionState parent_state = nm_active_connection_get_state (parent_ac);
|
|
|
|
if (parent_state < NM_ACTIVE_CONNECTION_STATE_ACTIVATED)
|
|
return;
|
|
|
|
unwatch_parent (self, TRUE);
|
|
|
|
if (parent_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED)
|
|
g_signal_emit (self, signals[PARENT_ACTIVE], 0, parent_ac);
|
|
}
|
|
|
|
static void
|
|
unwatch_parent (NMActiveConnection *self, gboolean unref)
|
|
{
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
g_signal_handlers_disconnect_by_func (priv->parent,
|
|
(GCallback) parent_state_cb,
|
|
self);
|
|
if (unref)
|
|
g_object_weak_unref ((GObject *) priv->parent, parent_destroyed, self);
|
|
priv->parent = NULL;
|
|
}
|
|
|
|
/**
|
|
* nm_active_connection_set_parent:
|
|
* @self: the #NMActiveConnection
|
|
* @parent: The #NMActiveConnection that must be active before the manager
|
|
* can proceed progressing the device to disconnected state for us.
|
|
*
|
|
* Sets the parent connection of @self. A "parent-active" signal will be
|
|
* emitted when the parent connection becomes active.
|
|
*/
|
|
void
|
|
nm_active_connection_set_parent (NMActiveConnection *self, NMActiveConnection *parent)
|
|
{
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
g_return_if_fail (priv->parent == NULL);
|
|
priv->parent = parent;
|
|
g_signal_connect (priv->parent,
|
|
"notify::" NM_ACTIVE_CONNECTION_STATE,
|
|
(GCallback) parent_state_cb,
|
|
self);
|
|
g_object_weak_ref ((GObject *) priv->parent, parent_destroyed, self);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
auth_complete (NMActiveConnection *self, gboolean result, const char *message)
|
|
{
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
NMActiveConnectionAuthResultFunc result_func;
|
|
gpointer user_data;
|
|
|
|
if (priv->auth.call_id_network_control)
|
|
nm_auth_manager_check_authorization_cancel (priv->auth.call_id_network_control);
|
|
if (priv->auth.call_id_wifi_shared_permission) {
|
|
if (priv->auth.call_id_wifi_shared_permission == AUTH_CALL_ID_SHARED_WIFI_PERMISSION_FAILED)
|
|
priv->auth.call_id_wifi_shared_permission = NULL;
|
|
else
|
|
nm_auth_manager_check_authorization_cancel (priv->auth.call_id_wifi_shared_permission);
|
|
}
|
|
|
|
nm_assert (!priv->auth.call_id_network_control);
|
|
nm_assert (!priv->auth.call_id_wifi_shared_permission);
|
|
if (priv->auth.result_func) {
|
|
result_func = priv->auth.result_func;
|
|
priv->auth.result_func = NULL;
|
|
user_data = g_steal_pointer (&priv->auth.user_data);
|
|
|
|
result_func (self,
|
|
result,
|
|
message,
|
|
user_data);
|
|
}
|
|
}
|
|
|
|
static void
|
|
auth_complete_keep_alive (NMActiveConnection *self, gboolean result, const char *message)
|
|
{
|
|
_nm_unused gs_unref_object NMActiveConnection *self_keep_alive = g_object_ref (self);
|
|
|
|
auth_complete (self, result, message);
|
|
}
|
|
|
|
static void
|
|
auth_done (NMAuthManager *auth_mgr,
|
|
NMAuthManagerCallId *auth_call_id,
|
|
gboolean is_authorized,
|
|
gboolean is_challenge,
|
|
GError *error,
|
|
gpointer user_data)
|
|
|
|
{
|
|
NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
NMAuthCallResult result;
|
|
|
|
nm_assert (auth_call_id);
|
|
nm_assert (priv->auth.result_func);
|
|
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
|
if (auth_call_id == priv->auth.call_id_network_control)
|
|
priv->auth.call_id_network_control = NULL;
|
|
else {
|
|
nm_assert (auth_call_id == priv->auth.call_id_wifi_shared_permission);
|
|
priv->auth.call_id_wifi_shared_permission = NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
result = nm_auth_call_result_eval (is_authorized, is_challenge, error);
|
|
|
|
if (auth_call_id == priv->auth.call_id_network_control) {
|
|
priv->auth.call_id_network_control = NULL;
|
|
if (result != NM_AUTH_CALL_RESULT_YES) {
|
|
auth_complete_keep_alive (self, FALSE, "Not authorized to control networking.");
|
|
return;
|
|
}
|
|
} else {
|
|
nm_assert (auth_call_id == priv->auth.call_id_wifi_shared_permission);
|
|
if (result != NM_AUTH_CALL_RESULT_YES) {
|
|
/* we don't fail right away. Instead, we mark that wifi-shared-permissions
|
|
* are missing. We prefer to report the failure about network-control.
|
|
* Below, we will wait longer for call_id_network_control (if it's still
|
|
* pending). */
|
|
priv->auth.call_id_wifi_shared_permission = AUTH_CALL_ID_SHARED_WIFI_PERMISSION_FAILED;
|
|
} else
|
|
priv->auth.call_id_wifi_shared_permission = NULL;
|
|
}
|
|
|
|
if (priv->auth.call_id_network_control)
|
|
return;
|
|
|
|
if (priv->auth.call_id_wifi_shared_permission) {
|
|
if (priv->auth.call_id_wifi_shared_permission == AUTH_CALL_ID_SHARED_WIFI_PERMISSION_FAILED)
|
|
auth_complete_keep_alive (self, FALSE, "Not authorized to share connections via wifi.");
|
|
return;
|
|
}
|
|
|
|
auth_complete_keep_alive (self, TRUE, NULL);
|
|
}
|
|
|
|
/**
|
|
* nm_active_connection_authorize:
|
|
* @self: the #NMActiveConnection
|
|
* @initial_connection: (allow-none): for add-and-activate, there
|
|
* is no @settings_connection available when creating the active connection.
|
|
* Instead pass an alternative connection.
|
|
* @result_func: function to be called on success or error
|
|
* @user_data: pointer passed to @result_func
|
|
*
|
|
* Checks whether the subject that initiated the active connection (read from
|
|
* the #NMActiveConnection::subject property) is authorized to complete this
|
|
* activation request.
|
|
*/
|
|
void
|
|
nm_active_connection_authorize (NMActiveConnection *self,
|
|
NMConnection *initial_connection,
|
|
NMActiveConnectionAuthResultFunc result_func,
|
|
gpointer user_data)
|
|
{
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
const char *wifi_permission = NULL;
|
|
NMConnection *connection;
|
|
|
|
g_return_if_fail (result_func);
|
|
g_return_if_fail (!priv->auth.call_id_network_control);
|
|
nm_assert (!priv->auth.call_id_wifi_shared_permission);
|
|
|
|
if (initial_connection) {
|
|
g_return_if_fail (NM_IS_CONNECTION (initial_connection));
|
|
g_return_if_fail (!priv->settings_connection.obj);
|
|
g_return_if_fail (!priv->applied_connection);
|
|
connection = initial_connection;
|
|
} else {
|
|
g_return_if_fail (NM_IS_SETTINGS_CONNECTION (priv->settings_connection.obj));
|
|
g_return_if_fail (NM_IS_CONNECTION (priv->applied_connection));
|
|
connection = priv->applied_connection;
|
|
}
|
|
|
|
priv->auth.call_id_network_control = nm_auth_manager_check_authorization (nm_auth_manager_get (),
|
|
priv->subject,
|
|
NM_AUTH_PERMISSION_NETWORK_CONTROL,
|
|
TRUE,
|
|
auth_done,
|
|
self);
|
|
|
|
/* Shared wifi connections require special permissions too */
|
|
wifi_permission = nm_utils_get_shared_wifi_permission (connection);
|
|
if (wifi_permission) {
|
|
priv->auth.call_id_wifi_shared_permission = nm_auth_manager_check_authorization (nm_auth_manager_get (),
|
|
priv->subject,
|
|
wifi_permission,
|
|
TRUE,
|
|
auth_done,
|
|
self);
|
|
}
|
|
|
|
priv->auth.result_func = result_func;
|
|
priv->auth.user_data = user_data;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static guint64
|
|
_version_id_new (void)
|
|
{
|
|
static guint64 id = 0;
|
|
|
|
return ++id;
|
|
}
|
|
|
|
guint64
|
|
nm_active_connection_version_id_get (NMActiveConnection *self)
|
|
{
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), 0);
|
|
|
|
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->version_id;
|
|
}
|
|
|
|
guint64
|
|
nm_active_connection_version_id_bump (NMActiveConnection *self)
|
|
{
|
|
NMActiveConnectionPrivate *priv;
|
|
|
|
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), 0);
|
|
|
|
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
priv->version_id = _version_id_new ();
|
|
_LOGT ("new version-id %llu", (unsigned long long) priv->version_id);
|
|
return priv->version_id;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
_device_cleanup (NMActiveConnection *self)
|
|
{
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
if (priv->device) {
|
|
g_signal_handlers_disconnect_by_func (priv->device, G_CALLBACK (device_state_changed), self);
|
|
g_signal_handlers_disconnect_by_func (priv->device, G_CALLBACK (device_master_changed), self);
|
|
g_signal_handlers_disconnect_by_func (priv->device, G_CALLBACK (device_metered_changed), self);
|
|
}
|
|
|
|
if (priv->pending_activation_id) {
|
|
nm_device_remove_pending_action (priv->device, priv->pending_activation_id, TRUE);
|
|
nm_clear_g_free (&priv->pending_activation_id);
|
|
}
|
|
|
|
g_clear_object (&priv->device);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
get_property (GObject *object, guint prop_id,
|
|
GValue *value, GParamSpec *pspec)
|
|
{
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
|
|
char **strv;
|
|
NMDevice *master_device = NULL;
|
|
|
|
switch (prop_id) {
|
|
|
|
/* note that while priv->settings_connection.obj might not be set initially,
|
|
* it will be set before the object is exported on D-Bus. Hence,
|
|
* nobody is calling these property getters before the object is
|
|
* exported, at which point we will have a valid settings-connection.
|
|
*
|
|
* Therefore, intentionally not check whether priv->settings_connection.obj
|
|
* is set, to get an assertion failure if somebody tries to access the
|
|
* getters at the wrong time. */
|
|
case PROP_CONNECTION:
|
|
g_value_set_string (value, nm_dbus_track_obj_path_get (&priv->settings_connection));
|
|
break;
|
|
case PROP_ID:
|
|
g_value_set_string (value, nm_settings_connection_get_id (priv->settings_connection.obj));
|
|
break;
|
|
case PROP_UUID:
|
|
g_value_set_string (value, nm_settings_connection_get_uuid (priv->settings_connection.obj));
|
|
break;
|
|
case PROP_TYPE:
|
|
g_value_set_string (value, nm_settings_connection_get_connection_type (priv->settings_connection.obj));
|
|
break;
|
|
|
|
case PROP_SPECIFIC_OBJECT:
|
|
g_value_set_string (value, priv->specific_object);
|
|
break;
|
|
case PROP_DEVICES:
|
|
strv = g_new0 (char *, 2);
|
|
if (priv->device && priv->state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)
|
|
strv[0] = g_strdup (nm_dbus_object_get_path (NM_DBUS_OBJECT (priv->device)));
|
|
g_value_take_boxed (value, strv);
|
|
break;
|
|
case PROP_STATE:
|
|
if (priv->state_set)
|
|
g_value_set_uint (value, priv->state);
|
|
else {
|
|
/* When the AC has just been created, its externally-visible state should
|
|
* be "ACTIVATING", even though internally it is "UNKNOWN".
|
|
*/
|
|
g_value_set_uint (value, NM_ACTIVE_CONNECTION_STATE_ACTIVATING);
|
|
}
|
|
break;
|
|
case PROP_STATE_FLAGS:
|
|
g_value_set_uint (value, priv->state_flags);
|
|
break;
|
|
case PROP_DEFAULT:
|
|
g_value_set_boolean (value, priv->is_default);
|
|
break;
|
|
case PROP_IP4_CONFIG:
|
|
/* The IP and DHCP config properties may be overridden by a subclass */
|
|
g_value_set_string (value, NULL);
|
|
break;
|
|
case PROP_DHCP4_CONFIG:
|
|
g_value_set_string (value, NULL);
|
|
break;
|
|
case PROP_DEFAULT6:
|
|
g_value_set_boolean (value, priv->is_default6);
|
|
break;
|
|
case PROP_IP6_CONFIG:
|
|
g_value_set_string (value, NULL);
|
|
break;
|
|
case PROP_DHCP6_CONFIG:
|
|
g_value_set_string (value, NULL);
|
|
break;
|
|
case PROP_VPN:
|
|
g_value_set_boolean (value, priv->vpn);
|
|
break;
|
|
case PROP_MASTER:
|
|
if (priv->master)
|
|
master_device = nm_active_connection_get_device (priv->master);
|
|
nm_dbus_utils_g_value_set_object_path (value, master_device);
|
|
break;
|
|
case PROP_INT_SUBJECT:
|
|
g_value_set_object (value, priv->subject);
|
|
break;
|
|
case PROP_INT_MASTER_READY:
|
|
g_value_set_boolean (value, priv->master_ready);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
set_property (GObject *object, guint prop_id,
|
|
const GValue *value, GParamSpec *pspec)
|
|
{
|
|
NMActiveConnection *self = (NMActiveConnection *) object;
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
const char *tmp;
|
|
NMSettingsConnection *sett_conn;
|
|
NMConnection *acon;
|
|
int i;
|
|
|
|
switch (prop_id) {
|
|
case PROP_INT_SETTINGS_CONNECTION:
|
|
/* construct-only */
|
|
sett_conn = g_value_get_object (value);
|
|
if (sett_conn)
|
|
_set_settings_connection (self, sett_conn);
|
|
break;
|
|
case PROP_INT_APPLIED_CONNECTION:
|
|
/* construct-only */
|
|
acon = g_value_get_object (value);
|
|
if (acon) {
|
|
/* we don't call _set_applied_connection_take() yet, because the instance
|
|
* is not yet fully initialized. We are currently in the process of setting
|
|
* the constructor properties.
|
|
*
|
|
* For now, just piggyback the connection, but call _set_applied_connection_take()
|
|
* in constructed(). */
|
|
priv->applied_connection = g_object_ref (acon);
|
|
}
|
|
break;
|
|
case PROP_INT_DEVICE:
|
|
/* construct-only */
|
|
nm_active_connection_set_device (self, g_value_get_object (value));
|
|
break;
|
|
case PROP_INT_SUBJECT:
|
|
/* construct-only */
|
|
priv->subject = g_value_dup_object (value);
|
|
break;
|
|
case PROP_INT_MASTER:
|
|
nm_active_connection_set_master (self, g_value_get_object (value));
|
|
break;
|
|
case PROP_INT_ACTIVATION_TYPE:
|
|
/* construct-only */
|
|
i = g_value_get_int (value);
|
|
if (!NM_IN_SET (i, NM_ACTIVATION_TYPE_MANAGED,
|
|
NM_ACTIVATION_TYPE_ASSUME,
|
|
NM_ACTIVATION_TYPE_EXTERNAL))
|
|
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);
|
|
priv->activation_reason = i;
|
|
nm_assert (priv->activation_reason == ((NMActivationReason) i));
|
|
break;
|
|
case PROP_SPECIFIC_OBJECT:
|
|
/* construct-only */
|
|
tmp = g_value_get_string (value);
|
|
tmp = nm_dbus_path_not_empty (tmp);
|
|
priv->specific_object = g_strdup (tmp);
|
|
break;
|
|
case PROP_DEFAULT:
|
|
priv->is_default = g_value_get_boolean (value);
|
|
break;
|
|
case PROP_DEFAULT6:
|
|
priv->is_default6 = g_value_get_boolean (value);
|
|
break;
|
|
case PROP_VPN:
|
|
/* construct-only */
|
|
priv->vpn = g_value_get_boolean (value);
|
|
break;
|
|
case PROP_MASTER:
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
nm_active_connection_init (NMActiveConnection *self)
|
|
{
|
|
NMActiveConnectionPrivate *priv;
|
|
|
|
priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionPrivate);
|
|
self->_priv = priv;
|
|
|
|
nm_dbus_track_obj_path_init (&priv->settings_connection,
|
|
G_OBJECT (self),
|
|
obj_properties[PROP_CONNECTION]);
|
|
|
|
c_list_init (&self->active_connections_lst);
|
|
|
|
_LOGT ("creating");
|
|
|
|
priv->activation_type = NM_ACTIVATION_TYPE_MANAGED;
|
|
priv->version_id = _version_id_new ();
|
|
|
|
/* 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
|
|
constructed (GObject *object)
|
|
{
|
|
NMActiveConnection *self = (NMActiveConnection *) object;
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
G_OBJECT_CLASS (nm_active_connection_parent_class)->constructed (object);
|
|
|
|
if ( !priv->applied_connection
|
|
&& priv->settings_connection.obj)
|
|
priv->applied_connection = nm_simple_connection_new_clone (nm_settings_connection_get_connection (priv->settings_connection.obj));
|
|
|
|
_LOGD ("constructed (%s, version-id %llu, type %s)",
|
|
G_OBJECT_TYPE_NAME (self),
|
|
(unsigned long long) priv->version_id,
|
|
nm_activation_type_to_string (priv->activation_type));
|
|
|
|
if (priv->applied_connection) {
|
|
/* priv->applied_connection was set during the construction of the object.
|
|
* It's not yet fully initialized, so do that now.
|
|
*
|
|
* We delayed that, because we may log in _set_applied_connection_take(), and the
|
|
* first logging line should be "constructed" above). */
|
|
_set_applied_connection_take (self,
|
|
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);
|
|
}
|
|
|
|
static void
|
|
dispose (GObject *object)
|
|
{
|
|
NMActiveConnection *self = NM_ACTIVE_CONNECTION (object);
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
nm_assert (!c_list_is_linked (&self->active_connections_lst));
|
|
|
|
_LOGD ("disposing");
|
|
|
|
auth_complete (self, FALSE, "Authorization aborted");
|
|
|
|
nm_clear_g_free (&priv->specific_object);
|
|
|
|
_set_settings_connection (self, NULL);
|
|
g_clear_object (&priv->applied_connection);
|
|
|
|
_device_cleanup (self);
|
|
|
|
if (priv->master) {
|
|
g_signal_handlers_disconnect_by_func (priv->master,
|
|
(GCallback) master_state_cb,
|
|
self);
|
|
}
|
|
g_clear_object (&priv->master);
|
|
|
|
if (priv->parent)
|
|
unwatch_parent (self, TRUE);
|
|
|
|
g_clear_object (&priv->subject);
|
|
|
|
G_OBJECT_CLASS (nm_active_connection_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
finalize (GObject *object)
|
|
{
|
|
NMActiveConnection *self = NM_ACTIVE_CONNECTION (object);
|
|
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
nm_dbus_track_obj_path_set (&priv->settings_connection, NULL, FALSE);
|
|
|
|
nm_clear_pointer (&priv->keep_alive, nm_keep_alive_destroy);
|
|
|
|
G_OBJECT_CLASS (nm_active_connection_parent_class)->finalize (object);
|
|
}
|
|
|
|
static const GDBusSignalInfo signal_info_state_changed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT (
|
|
"StateChanged",
|
|
.args = NM_DEFINE_GDBUS_ARG_INFOS (
|
|
NM_DEFINE_GDBUS_ARG_INFO ("state", "u"),
|
|
NM_DEFINE_GDBUS_ARG_INFO ("reason", "u"),
|
|
),
|
|
);
|
|
|
|
static const NMDBusInterfaceInfoExtended interface_info_active_connection = {
|
|
.parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT (
|
|
NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
|
|
.signals = NM_DEFINE_GDBUS_SIGNAL_INFOS (
|
|
&nm_signal_info_property_changed_legacy,
|
|
&signal_info_state_changed,
|
|
),
|
|
.properties = NM_DEFINE_GDBUS_PROPERTY_INFOS (
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Connection", "o", NM_ACTIVE_CONNECTION_CONNECTION),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("SpecificObject", "o", NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Id", "s", NM_ACTIVE_CONNECTION_ID),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Uuid", "s", NM_ACTIVE_CONNECTION_UUID),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Type", "s", NM_ACTIVE_CONNECTION_TYPE),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Devices", "ao", NM_ACTIVE_CONNECTION_DEVICES),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("State", "u", NM_ACTIVE_CONNECTION_STATE),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("StateFlags", "u", NM_ACTIVE_CONNECTION_STATE_FLAGS),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Default", "b", NM_ACTIVE_CONNECTION_DEFAULT),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Ip4Config", "o", NM_ACTIVE_CONNECTION_IP4_CONFIG),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Dhcp4Config", "o", NM_ACTIVE_CONNECTION_DHCP4_CONFIG),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Default6", "b", NM_ACTIVE_CONNECTION_DEFAULT6),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Ip6Config", "o", NM_ACTIVE_CONNECTION_IP6_CONFIG),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Dhcp6Config", "o", NM_ACTIVE_CONNECTION_DHCP6_CONFIG),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Vpn", "b", NM_ACTIVE_CONNECTION_VPN),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Master", "o", NM_ACTIVE_CONNECTION_MASTER),
|
|
),
|
|
),
|
|
.legacy_property_changed = TRUE,
|
|
};
|
|
|
|
static void
|
|
nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (ac_class);
|
|
NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (ac_class);
|
|
|
|
g_type_class_add_private (ac_class, sizeof (NMActiveConnectionPrivate));
|
|
|
|
dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/ActiveConnection");
|
|
dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_active_connection);
|
|
|
|
object_class->get_property = get_property;
|
|
object_class->set_property = set_property;
|
|
object_class->constructed = constructed;
|
|
object_class->dispose = dispose;
|
|
object_class->finalize = finalize;
|
|
|
|
obj_properties[PROP_CONNECTION] =
|
|
g_param_spec_string (NM_ACTIVE_CONNECTION_CONNECTION, "", "",
|
|
NULL,
|
|
G_PARAM_READABLE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_ID] =
|
|
g_param_spec_string (NM_ACTIVE_CONNECTION_ID, "", "",
|
|
NULL,
|
|
G_PARAM_READABLE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_UUID] =
|
|
g_param_spec_string (NM_ACTIVE_CONNECTION_UUID, "", "",
|
|
NULL,
|
|
G_PARAM_READABLE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_TYPE] =
|
|
g_param_spec_string (NM_ACTIVE_CONNECTION_TYPE, "", "",
|
|
NULL,
|
|
G_PARAM_READABLE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_SPECIFIC_OBJECT] =
|
|
g_param_spec_string (NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, "", "",
|
|
NULL,
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_DEVICES] =
|
|
g_param_spec_boxed (NM_ACTIVE_CONNECTION_DEVICES, "", "",
|
|
G_TYPE_STRV,
|
|
G_PARAM_READABLE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_STATE] =
|
|
g_param_spec_uint (NM_ACTIVE_CONNECTION_STATE, "", "",
|
|
NM_ACTIVE_CONNECTION_STATE_UNKNOWN,
|
|
NM_ACTIVE_CONNECTION_STATE_DEACTIVATING,
|
|
NM_ACTIVE_CONNECTION_STATE_UNKNOWN,
|
|
G_PARAM_READABLE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_STATE_FLAGS] =
|
|
g_param_spec_uint (NM_ACTIVE_CONNECTION_STATE_FLAGS, "", "",
|
|
0, G_MAXUINT32, NM_ACTIVATION_STATE_FLAG_NONE,
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_DEFAULT] =
|
|
g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT, "", "",
|
|
FALSE,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_IP4_CONFIG] =
|
|
g_param_spec_string (NM_ACTIVE_CONNECTION_IP4_CONFIG, "", "",
|
|
NULL,
|
|
G_PARAM_READABLE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_DHCP4_CONFIG] =
|
|
g_param_spec_string (NM_ACTIVE_CONNECTION_DHCP4_CONFIG, "", "",
|
|
NULL,
|
|
G_PARAM_READABLE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_DEFAULT6] =
|
|
g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT6, "", "",
|
|
FALSE,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_IP6_CONFIG] =
|
|
g_param_spec_string (NM_ACTIVE_CONNECTION_IP6_CONFIG, "", "",
|
|
NULL,
|
|
G_PARAM_READABLE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_DHCP6_CONFIG] =
|
|
g_param_spec_string (NM_ACTIVE_CONNECTION_DHCP6_CONFIG, "", "",
|
|
NULL,
|
|
G_PARAM_READABLE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_VPN] =
|
|
g_param_spec_boolean (NM_ACTIVE_CONNECTION_VPN, "", "",
|
|
FALSE,
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_MASTER] =
|
|
g_param_spec_string (NM_ACTIVE_CONNECTION_MASTER, "", "",
|
|
NULL,
|
|
G_PARAM_READABLE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
/* Internal properties */
|
|
obj_properties[PROP_INT_SETTINGS_CONNECTION] =
|
|
g_param_spec_object (NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION, "", "",
|
|
NM_TYPE_SETTINGS_CONNECTION,
|
|
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_INT_APPLIED_CONNECTION] =
|
|
g_param_spec_object (NM_ACTIVE_CONNECTION_INT_APPLIED_CONNECTION, "", "",
|
|
NM_TYPE_CONNECTION,
|
|
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_INT_DEVICE] =
|
|
g_param_spec_object (NM_ACTIVE_CONNECTION_INT_DEVICE, "", "",
|
|
NM_TYPE_DEVICE,
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_INT_SUBJECT] =
|
|
g_param_spec_object (NM_ACTIVE_CONNECTION_INT_SUBJECT, "", "",
|
|
NM_TYPE_AUTH_SUBJECT,
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_INT_MASTER] =
|
|
g_param_spec_object (NM_ACTIVE_CONNECTION_INT_MASTER, "", "",
|
|
NM_TYPE_ACTIVE_CONNECTION,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_INT_MASTER_READY] =
|
|
g_param_spec_boolean (NM_ACTIVE_CONNECTION_INT_MASTER_READY, "", "",
|
|
FALSE, G_PARAM_READABLE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_INT_ACTIVATION_TYPE] =
|
|
g_param_spec_int (NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE, "", "",
|
|
NM_ACTIVATION_TYPE_MANAGED,
|
|
NM_ACTIVATION_TYPE_EXTERNAL,
|
|
NM_ACTIVATION_TYPE_MANAGED,
|
|
G_PARAM_WRITABLE |
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
obj_properties[PROP_INT_ACTIVATION_REASON] =
|
|
g_param_spec_int (NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON, "", "",
|
|
NM_ACTIVATION_REASON_UNSET,
|
|
NM_ACTIVATION_REASON_USER_REQUEST,
|
|
NM_ACTIVATION_REASON_UNSET,
|
|
G_PARAM_WRITABLE |
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
|
|
|
signals[DEVICE_CHANGED] =
|
|
g_signal_new (NM_ACTIVE_CONNECTION_DEVICE_CHANGED,
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMActiveConnectionClass, device_changed),
|
|
NULL, NULL, NULL,
|
|
G_TYPE_NONE, 2, NM_TYPE_DEVICE, NM_TYPE_DEVICE);
|
|
|
|
signals[DEVICE_METERED_CHANGED] =
|
|
g_signal_new (NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED,
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMActiveConnectionClass, device_metered_changed),
|
|
NULL, NULL, NULL,
|
|
G_TYPE_NONE, 1, G_TYPE_UINT);
|
|
|
|
signals[PARENT_ACTIVE] =
|
|
g_signal_new (NM_ACTIVE_CONNECTION_PARENT_ACTIVE,
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMActiveConnectionClass, parent_active),
|
|
NULL, NULL, NULL,
|
|
G_TYPE_NONE, 1, NM_TYPE_ACTIVE_CONNECTION);
|
|
|
|
signals[STATE_CHANGED] =
|
|
g_signal_new (NM_ACTIVE_CONNECTION_STATE_CHANGED,
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
0, NULL, NULL, NULL,
|
|
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
|
|
}
|