summaryrefslogtreecommitdiff
path: root/src/nm-active-connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-active-connection.c')
-rw-r--r--src/nm-active-connection.c668
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);
}