diff options
Diffstat (limited to 'src/nm-active-connection.c')
-rw-r--r-- | src/nm-active-connection.c | 668 |
1 files changed, 575 insertions, 93 deletions
diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 6e3a5da63..172aa6141 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2008 - 2012 Red Hat, Inc. + * Copyright (C) 2008 - 2014 Red Hat, Inc. */ #include <glib.h> @@ -25,9 +25,10 @@ #include "nm-logging.h" #include "nm-dbus-glib-types.h" #include "nm-dbus-manager.h" -#include "nm-properties-changed-signal.h" #include "nm-device.h" #include "nm-settings-connection.h" +#include "nm-manager-auth.h" +#include "NetworkManagerUtils.h" #include "nm-active-connection-glue.h" @@ -44,47 +45,76 @@ typedef struct { char *specific_object; NMDevice *device; + char *pending_activation_id; + gboolean is_default; gboolean is_default6; NMActiveConnectionState state; gboolean vpn; - gboolean user_requested; - gulong user_uid; + NMAuthSubject *subject; + NMActiveConnection *master; + gboolean master_ready; + gboolean assumed; - NMDevice *master; + + NMAuthChain *chain; + const char *wifi_shared_permission; + NMActiveConnectionAuthResultFunc result_func; + gpointer user_data1; + gpointer user_data2; } NMActiveConnectionPrivate; enum { PROP_0, PROP_CONNECTION, + PROP_ID, PROP_UUID, + PROP_TYPE, PROP_SPECIFIC_OBJECT, PROP_DEVICES, PROP_STATE, PROP_DEFAULT, + PROP_IP4_CONFIG, + PROP_DHCP4_CONFIG, PROP_DEFAULT6, + PROP_IP6_CONFIG, + PROP_DHCP6_CONFIG, PROP_VPN, PROP_MASTER, PROP_INT_CONNECTION, PROP_INT_DEVICE, - PROP_INT_USER_REQUESTED, - PROP_INT_USER_UID, - PROP_INT_ASSUMED, + PROP_INT_SUBJECT, PROP_INT_MASTER, + PROP_INT_MASTER_READY, LAST_PROP }; -enum { - PROPERTIES_CHANGED, - LAST_SIGNAL -}; -static guint signals[LAST_SIGNAL] = { 0 }; +static void check_master_ready (NMActiveConnection *self); +static void _device_cleanup (NMActiveConnection *self); /****************************************************************/ +static const char * +state_to_string (NMActiveConnectionState state) +{ + switch (state) { + case NM_ACTIVE_CONNECTION_STATE_UNKNOWN: + return "unknown"; + case NM_ACTIVE_CONNECTION_STATE_ACTIVATING: + return "activating"; + case NM_ACTIVE_CONNECTION_STATE_ACTIVATED: + return "activated"; + case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING: + return "deactivating"; + case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED: + return "deactivated"; + } + return "(none)"; +} + NMActiveConnectionState nm_active_connection_get_state (NMActiveConnection *self) { @@ -109,33 +139,79 @@ nm_active_connection_set_state (NMActiveConnection *self, priv->state = new_state; g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_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 (NM_SETTINGS_CONNECTION (priv->connection), (guint64) time (NULL), TRUE); } + 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); + g_clear_pointer (&priv->pending_activation_id, g_free); + } + } + + if ( new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED + || old_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_IP4_CONFIG); + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DHCP4_CONFIG); + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_IP6_CONFIG); + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DHCP6_CONFIG); + } + if (priv->state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) { - /* Device is no longer relevant when deactivated */ - g_clear_object (&priv->device); + /* 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); g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEVICES); } } const char * -nm_active_connection_get_name (NMActiveConnection *self) +nm_active_connection_get_id (NMActiveConnection *self) { g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); return nm_connection_get_id (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection); } +const char * +nm_active_connection_get_uuid (NMActiveConnection *self) +{ + g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); + + return nm_connection_get_uuid (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection); +} + NMConnection * nm_active_connection_get_connection (NMActiveConnection *self) { return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection; } +void +nm_active_connection_set_connection (NMActiveConnection *self, + NMConnection *connection) +{ + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + + /* Can't change connection after the ActiveConnection is exported over D-Bus */ + g_return_if_fail (priv->path == NULL); + g_return_if_fail (priv->connection == NULL || !NM_IS_SETTINGS_CONNECTION (priv->connection)); + + if (priv->connection) + g_object_unref (priv->connection); + priv->connection = g_object_ref (connection); +} + const char * nm_active_connection_get_path (NMActiveConnection *self) { @@ -154,6 +230,11 @@ nm_active_connection_set_specific_object (NMActiveConnection *self, { 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. + */ + g_assert (g_strcmp0 (specific_object, "/") != 0); + if (g_strcmp0 (priv->specific_object, specific_object) == 0) return; @@ -212,14 +293,20 @@ void nm_active_connection_export (NMActiveConnection *self) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - NMDBusManager *dbus_mgr; static guint32 counter = 0; + g_assert (priv->device || priv->vpn); + priv->path = g_strdup_printf (NM_DBUS_PATH "/ActiveConnection/%d", counter++); - dbus_mgr = nm_dbus_manager_get (); - dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (dbus_mgr), - priv->path, G_OBJECT (self)); - g_object_unref (dbus_mgr); + nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->path, self); +} + +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 @@ -227,34 +314,98 @@ nm_active_connection_get_user_requested (NMActiveConnection *self) { g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE); - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->user_requested; + return !nm_auth_subject_get_internal (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject); } -gulong -nm_active_connection_get_user_uid (NMActiveConnection *self) +NMDevice * +nm_active_connection_get_device (NMActiveConnection *self) { - g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), G_MAXULONG); + g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->user_uid; + return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->device; } -gboolean -nm_active_connection_get_assumed (NMActiveConnection *self) +static void +device_state_changed (NMDevice *device, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason, + gpointer user_data) { - g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE); + NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data); + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->assumed; + /* 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); } -NMDevice * -nm_active_connection_get_device (NMActiveConnection *self) +static void +device_master_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) { - g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); + NMDevice *device = NM_DEVICE (object); + NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data); + NMActiveConnection *master; + NMActiveConnectionState master_state; - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->device; + if (NM_ACTIVE_CONNECTION (nm_device_get_act_request (device)) != self) + return; + if (!nm_device_get_master (device)) + return; + g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_master_changed), self); + + master = nm_active_connection_get_master (self); + g_assert (master); + + 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); + } } -NMDevice * +gboolean +nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device) +{ + NMActiveConnectionPrivate *priv; + + 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) { + g_return_val_if_fail (priv->device == NULL, FALSE); + + /* 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_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_DEVICE); + + g_signal_connect (device, "state-changed", + G_CALLBACK (device_state_changed), self); + g_signal_connect (device, "notify::master", + G_CALLBACK (device_master_changed), self); + + if (!priv->assumed) { + priv->pending_activation_id = g_strdup_printf ("activation::%p", (void *)self); + nm_device_add_pending_action (device, priv->pending_activation_id, TRUE); + } + } + return TRUE; +} + +NMActiveConnection * nm_active_connection_get_master (NMActiveConnection *self) { g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); @@ -262,6 +413,247 @@ nm_active_connection_get_master (NMActiveConnection *self) 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); + NMActiveConnectionState master_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; + + if (priv->state != NM_ACTIVE_CONNECTION_STATE_ACTIVATING) { + nm_log_dbg (LOGD_DEVICE, "(%p): not signalling master-ready (not activating)", self); + return; + } + if (!priv->master) { + nm_log_dbg (LOGD_DEVICE, "(%p): not signalling master-ready (no master)", self); + return; + } + if (priv->master_ready) { + nm_log_dbg (LOGD_DEVICE, "(%p): not signalling master-ready (already signaled)", self); + return; + } + + /* 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. + */ + master_state = nm_active_connection_get_state (priv->master); + nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection [%p] state now '%s' (%d)", + self, priv->master, state_to_string (master_state), master_state); + + if ( master_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING + || master_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { + nm_log_dbg (LOGD_DEVICE, "(%p): signalling master-ready", self); + + priv->master_ready = TRUE; + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_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. + */ + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_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); + + check_master_ready (self); + + nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection [%p] state now '%s' (%d)", + self, master, state_to_string (master_state), master_state); + + if (master_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATING && + nm_active_connection_get_device (master) == NULL) { + /* Master failed without ever creating 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 (priv->path == NULL); + 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)); + } + + nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection is [%p] %s", + self, master, nm_active_connection_get_id (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); +} + +void +nm_active_connection_set_assumed (NMActiveConnection *self, gboolean assumed) +{ + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + + g_return_if_fail (priv->assumed == FALSE); + priv->assumed = assumed; + + if (priv->pending_activation_id) { + nm_device_remove_pending_action (priv->device, priv->pending_activation_id, TRUE); + g_clear_pointer (&priv->pending_activation_id, g_free); + } +} + +gboolean +nm_active_connection_get_assumed (NMActiveConnection *self) +{ + return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->assumed; +} + +/****************************************************************/ + +static void +auth_done (NMAuthChain *chain, + GError *error, + DBusGMethodInvocation *unused, + gpointer user_data) +{ + NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data); + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + NMAuthCallResult result; + + g_assert (priv->chain == chain); + g_assert (priv->result_func != NULL); + + /* Must stay alive over the callback */ + g_object_ref (self); + + if (error) { + priv->result_func (self, FALSE, error->message, priv->user_data1, priv->user_data2); + goto done; + } + + /* Caller has had a chance to obtain authorization, so we only need to + * check for 'yes' here. + */ + result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL); + if (result != NM_AUTH_CALL_RESULT_YES) { + priv->result_func (self, + FALSE, + "Not authorized to control networking.", + priv->user_data1, + priv->user_data2); + goto done; + } + + if (priv->wifi_shared_permission) { + result = nm_auth_chain_get_result (chain, priv->wifi_shared_permission); + if (result != NM_AUTH_CALL_RESULT_YES) { + priv->result_func (self, + FALSE, + "Not authorized to share connections via wifi.", + priv->user_data1, + priv->user_data2); + goto done; + } + } + + /* Otherwise authorized and available to activate */ + priv->result_func (self, TRUE, NULL, priv->user_data1, priv->user_data2); + +done: + nm_auth_chain_unref (chain); + priv->chain = NULL; + priv->result_func = NULL; + priv->user_data1 = NULL; + priv->user_data2 = NULL; + + g_object_unref (self); +} + +/** + * nm_active_connection_authorize: + * @self: the #NMActiveConnection + * @result_func: function to be called on success or error + * @user_data1: pointer passed to @result_func + * @user_data2: additional 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, + NMActiveConnectionAuthResultFunc result_func, + gpointer user_data1, + gpointer user_data2) +{ + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + const char *wifi_permission = NULL; + + g_return_if_fail (result_func != NULL); + g_return_if_fail (priv->chain == NULL); + + priv->chain = nm_auth_chain_new_subject (priv->subject, NULL, auth_done, self); + g_assert (priv->chain); + + /* Check that the subject is allowed to use networking at all */ + nm_auth_chain_add_call (priv->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); + + /* Shared wifi connections require special permissions too */ + wifi_permission = nm_utils_get_shared_wifi_permission (priv->connection); + if (wifi_permission) { + priv->wifi_shared_permission = wifi_permission; + nm_auth_chain_add_call (priv->chain, wifi_permission, TRUE); + } + + /* Wait for authorization */ + priv->result_func = result_func; + priv->user_data1 = user_data1; + priv->user_data2 = user_data2; +} + /****************************************************************/ static void @@ -270,10 +662,18 @@ nm_active_connection_init (NMActiveConnection *self) } static void +constructed (GObject *object) +{ + G_OBJECT_CLASS (nm_active_connection_parent_class)->constructed (object); + g_assert (NM_ACTIVE_CONNECTION_GET_PRIVATE (object)->subject); +} + +static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object); + const char *tmp; switch (prop_id) { case PROP_INT_CONNECTION: @@ -281,28 +681,19 @@ set_property (GObject *object, guint prop_id, priv->connection = g_value_dup_object (value); break; case PROP_INT_DEVICE: - g_warn_if_fail (priv->device == NULL); - priv->device = g_value_dup_object (value); - if (priv->device) - g_warn_if_fail (priv->device != priv->master); + nm_active_connection_set_device (NM_ACTIVE_CONNECTION (object), g_value_get_object (value)); break; - case PROP_INT_USER_REQUESTED: - priv->user_requested = g_value_get_boolean (value); - break; - case PROP_INT_USER_UID: - priv->user_uid = g_value_get_ulong (value); - break; - case PROP_INT_ASSUMED: - priv->assumed = g_value_get_boolean (value); + case PROP_INT_SUBJECT: + priv->subject = g_value_dup_object (value); break; case PROP_INT_MASTER: - g_warn_if_fail (priv->master == NULL); - priv->master = g_value_dup_object (value); - if (priv->master) - g_warn_if_fail (priv->master != priv->device); + nm_active_connection_set_master (NM_ACTIVE_CONNECTION (object), g_value_get_object (value)); break; case PROP_SPECIFIC_OBJECT: - priv->specific_object = g_value_dup_boxed (value); + tmp = g_value_get_boxed (value); + /* NM uses "/" to mean NULL */ + if (g_strcmp0 (tmp, "/") != 0) + priv->specific_object = g_value_dup_boxed (value); break; case PROP_DEFAULT: priv->is_default = g_value_get_boolean (value); @@ -327,20 +718,27 @@ get_property (GObject *object, guint prop_id, { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object); GPtrArray *devices; + NMDevice *master_device = NULL; switch (prop_id) { case PROP_CONNECTION: g_value_set_boxed (value, nm_connection_get_path (priv->connection)); break; + case PROP_ID: + g_value_set_string (value, nm_connection_get_id (priv->connection)); + break; case PROP_UUID: g_value_set_string (value, nm_connection_get_uuid (priv->connection)); break; + case PROP_TYPE: + g_value_set_string (value, nm_connection_get_connection_type (priv->connection)); + break; case PROP_SPECIFIC_OBJECT: g_value_set_boxed (value, priv->specific_object ? priv->specific_object : "/"); break; case PROP_DEVICES: devices = g_ptr_array_sized_new (1); - if (priv->device) + if (priv->device && priv->state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) g_ptr_array_add (devices, g_strdup (nm_device_get_path (priv->device))); g_value_take_boxed (value, devices); break; @@ -350,14 +748,35 @@ get_property (GObject *object, guint prop_id, 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_boxed (value, "/"); + break; + case PROP_DHCP4_CONFIG: + g_value_set_boxed (value, "/"); + break; case PROP_DEFAULT6: g_value_set_boolean (value, priv->is_default6); break; + case PROP_IP6_CONFIG: + g_value_set_boxed (value, "/"); + break; + case PROP_DHCP6_CONFIG: + g_value_set_boxed (value, "/"); + break; case PROP_VPN: g_value_set_boolean (value, priv->vpn); break; case PROP_MASTER: - g_value_set_boxed (value, priv->master ? nm_device_get_path (priv->master) : "/"); + if (priv->master) + master_device = nm_active_connection_get_device (priv->master); + g_value_set_boxed (value, master_device ? nm_device_get_path (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); @@ -366,9 +785,33 @@ get_property (GObject *object, guint prop_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); + } + + if (priv->pending_activation_id) { + nm_device_remove_pending_action (priv->device, priv->pending_activation_id, TRUE); + g_clear_pointer (&priv->pending_activation_id, g_free); + } + + g_clear_object (&priv->device); +} + +static void dispose (GObject *object) { - NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object); + NMActiveConnection *self = NM_ACTIVE_CONNECTION (object); + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + + if (priv->chain) { + nm_auth_chain_unref (priv->chain); + priv->chain = NULL; + } g_free (priv->path); priv->path = NULL; @@ -376,22 +819,31 @@ dispose (GObject *object) priv->specific_object = NULL; g_clear_object (&priv->connection); - g_clear_object (&priv->device); + + _device_cleanup (self); + + if (priv->master) { + g_signal_handlers_disconnect_by_func (priv->master, + (GCallback) master_state_cb, + self); + } g_clear_object (&priv->master); + g_clear_object (&priv->subject); G_OBJECT_CLASS (nm_active_connection_parent_class)->dispose (object); } static void -nm_active_connection_class_init (NMActiveConnectionClass *vpn_class) +nm_active_connection_class_init (NMActiveConnectionClass *ac_class) { - GObjectClass *object_class = G_OBJECT_CLASS (vpn_class); + GObjectClass *object_class = G_OBJECT_CLASS (ac_class); - g_type_class_add_private (vpn_class, sizeof (NMActiveConnectionPrivate)); + g_type_class_add_private (ac_class, sizeof (NMActiveConnectionPrivate)); /* virtual methods */ object_class->get_property = get_property; object_class->set_property = set_property; + object_class->constructed = constructed; object_class->dispose = dispose; /* D-Bus exported properties */ @@ -402,6 +854,13 @@ nm_active_connection_class_init (NMActiveConnectionClass *vpn_class) DBUS_TYPE_G_OBJECT_PATH, G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_ID, + g_param_spec_string (NM_ACTIVE_CONNECTION_ID, + "Connection ID", + "Connection ID", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_UUID, g_param_spec_string (NM_ACTIVE_CONNECTION_UUID, "Connection UUID", @@ -409,6 +868,13 @@ nm_active_connection_class_init (NMActiveConnectionClass *vpn_class) NULL, G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_TYPE, + g_param_spec_string (NM_ACTIVE_CONNECTION_TYPE, + "Connection Type", + "Connection Type", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_SPECIFIC_OBJECT, g_param_spec_boxed (NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, "Specific object", @@ -439,6 +905,20 @@ nm_active_connection_class_init (NMActiveConnectionClass *vpn_class) FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_IP4_CONFIG, + g_param_spec_boxed (NM_ACTIVE_CONNECTION_IP4_CONFIG, + "IP4 Config", + "IP4 Config", + DBUS_TYPE_G_OBJECT_PATH, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, PROP_DHCP4_CONFIG, + g_param_spec_boxed (NM_ACTIVE_CONNECTION_DHCP4_CONFIG, + "DHCP4 Config", + "DHCP4 Config", + DBUS_TYPE_G_OBJECT_PATH, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_DEFAULT6, g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT6, "Default6", @@ -446,6 +926,20 @@ nm_active_connection_class_init (NMActiveConnectionClass *vpn_class) FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_IP6_CONFIG, + g_param_spec_boxed (NM_ACTIVE_CONNECTION_IP6_CONFIG, + "IP6 Config", + "IP6 Config", + DBUS_TYPE_G_OBJECT_PATH, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, PROP_DHCP6_CONFIG, + g_param_spec_boxed (NM_ACTIVE_CONNECTION_DHCP6_CONFIG, + "DHCP6 Config", + "DHCP6 Config", + DBUS_TYPE_G_OBJECT_PATH, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_VPN, g_param_spec_boolean (NM_ACTIVE_CONNECTION_VPN, "VPN", @@ -466,49 +960,37 @@ nm_active_connection_class_init (NMActiveConnectionClass *vpn_class) "Internal Connection", "Internal connection", NM_TYPE_CONNECTION, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT)); + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_INT_DEVICE, g_param_spec_object (NM_ACTIVE_CONNECTION_INT_DEVICE, "Internal device", "Internal device", NM_TYPE_DEVICE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT)); + G_PARAM_READWRITE)); - g_object_class_install_property (object_class, PROP_INT_USER_REQUESTED, - g_param_spec_boolean (NM_ACTIVE_CONNECTION_INT_USER_REQUESTED, - "User requested", - "User requested", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT)); - - g_object_class_install_property (object_class, PROP_INT_USER_UID, - g_param_spec_ulong (NM_ACTIVE_CONNECTION_INT_USER_UID, - "User UID", - "User UID (if user requested)", - 0, G_MAXULONG, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT)); - - g_object_class_install_property (object_class, PROP_INT_ASSUMED, - g_param_spec_boolean (NM_ACTIVE_CONNECTION_INT_ASSUMED, - "Assumed", - "Assumed", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT)); + g_object_class_install_property (object_class, PROP_INT_SUBJECT, + g_param_spec_object (NM_ACTIVE_CONNECTION_INT_SUBJECT, + "Subject", + "Subject", + NM_TYPE_AUTH_SUBJECT, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_INT_MASTER, g_param_spec_object (NM_ACTIVE_CONNECTION_INT_MASTER, - "Internal master device", - "Internal device", - NM_TYPE_DEVICE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT)); - - /* Signals */ - signals[PROPERTIES_CHANGED] = - nm_properties_changed_signal_new (object_class, - G_STRUCT_OFFSET (NMActiveConnectionClass, properties_changed)); - - dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (vpn_class), - &dbus_glib_nm_active_connection_object_info); + "Internal master active connection", + "Internal active connection", + NM_TYPE_ACTIVE_CONNECTION, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, PROP_INT_MASTER_READY, + g_param_spec_boolean (NM_ACTIVE_CONNECTION_INT_MASTER_READY, + "Internal master active connection ready for slaves", + "Internal active connection ready", + FALSE, G_PARAM_READABLE)); + + nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), + G_TYPE_FROM_CLASS (ac_class), + &dbus_glib_nm_active_connection_object_info); } |