From 4b76d866981b65f9e9ee282dc901ab907f546221 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 12 Feb 2016 14:03:48 +0100 Subject: [PATCH 1/7] core/trivial: rename local function in "nm-settings-connection.c" Only D-Bus implementations should be named "^impl_.*", not a helper function. --- src/settings/nm-settings-connection.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index f7e5002cd3..287cb69a7c 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -1716,10 +1716,10 @@ get_update_modify_permission (NMConnection *old, NMConnection *new) } static void -impl_settings_connection_update_helper (NMSettingsConnection *self, - GDBusMethodInvocation *context, - GVariant *new_settings, - gboolean save_to_disk) +settings_connection_update_helper (NMSettingsConnection *self, + GDBusMethodInvocation *context, + GVariant *new_settings, + gboolean save_to_disk) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); NMAuthSubject *subject = NULL; @@ -1790,7 +1790,7 @@ impl_settings_connection_update (NMSettingsConnection *self, GDBusMethodInvocation *context, GVariant *new_settings) { - impl_settings_connection_update_helper (self, context, new_settings, TRUE); + settings_connection_update_helper (self, context, new_settings, TRUE); } static void @@ -1798,7 +1798,7 @@ impl_settings_connection_update_unsaved (NMSettingsConnection *self, GDBusMethodInvocation *context, GVariant *new_settings) { - impl_settings_connection_update_helper (self, context, new_settings, FALSE); + settings_connection_update_helper (self, context, new_settings, FALSE); } static void @@ -1807,7 +1807,7 @@ impl_settings_connection_save (NMSettingsConnection *self, { /* Do nothing if the connection is already synced with disk */ if (nm_settings_connection_get_unsaved (self)) - impl_settings_connection_update_helper (self, context, NULL, TRUE); + settings_connection_update_helper (self, context, NULL, TRUE); else g_dbus_method_invocation_return_value (context, NULL); } From b96a40c2ec9e4318e7d2a578396236f68e487710 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 11 Feb 2016 08:36:39 +0100 Subject: [PATCH 2/7] core: add version-id to NMActiveConnection This field will be later used by NMDevice's Reapply and GetAppliedConnection methods. The usecase is to first fetch the currently applied connection, adjust it and reapply it. Using the version-id, a concurrent modification can be detected and Reapply can reject the invocation. --- src/devices/nm-device.c | 17 +++++++++++++---- src/nm-active-connection.c | 39 +++++++++++++++++++++++++++++++++++++- src/nm-active-connection.h | 3 +++ 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 29ebe0e759..c33a19db65 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -7181,6 +7181,7 @@ reapply_connection (NMDevice *self, NMConnection *con_old, *con_new; NMSettingIPConfig *s_ip4_old, *s_ip4_new; NMSettingIPConfig *s_ip6_old, *s_ip6_new; + guint64 version_id; if (priv->state != NM_DEVICE_STATE_ACTIVATED) { g_set_error_literal (error, @@ -7212,12 +7213,17 @@ reapply_connection (NMDevice *self, NM_SETTING_CONNECTION_METERED)) return FALSE; - _LOGD (LOGD_DEVICE, "reapply"); - /************************************************************************** * Update applied connection *************************************************************************/ + if (diffs) + nm_active_connection_version_id_bump ((NMActiveConnection *) priv->act_request); + + _LOGD (LOGD_DEVICE, "reapply (version-id %llu%s)", + (long long unsigned) nm_active_connection_version_id_get (((NMActiveConnection *) priv->act_request)), + diffs ? "" : " (unmodified)"); + if (diffs) { con_old = applied_clone = nm_simple_connection_new_clone (applied); con_new = applied; @@ -9218,6 +9224,7 @@ nm_device_reapply_settings_immediately (NMDevice *self) NMSettingConnection *s_con_applied; const char *zone; NMMetered metered; + guint64 version_id; g_return_if_fail (NM_IS_DEVICE (self)); @@ -9240,7 +9247,8 @@ nm_device_reapply_settings_immediately (NMDevice *self) if (g_strcmp0 ((zone = nm_setting_connection_get_zone (s_con_settings)), nm_setting_connection_get_zone (s_con_applied)) != 0) { - _LOGD (LOGD_DEVICE, "reapply setting: zone = %s%s%s", NM_PRINT_FMT_QUOTE_STRING (zone)); + version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->priv->act_request); + _LOGD (LOGD_DEVICE, "reapply setting: zone = %s%s%s (version-id %llu)", NM_PRINT_FMT_QUOTE_STRING (zone), (long long unsigned) version_id); g_object_set (G_OBJECT (s_con_applied), NM_SETTING_CONNECTION_ZONE, zone, @@ -9251,7 +9259,8 @@ nm_device_reapply_settings_immediately (NMDevice *self) if ((metered = nm_setting_connection_get_metered (s_con_settings)) != nm_setting_connection_get_metered (s_con_applied)) { - _LOGD (LOGD_DEVICE, "reapply setting: metered = %d", (int) metered); + version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->priv->act_request); + _LOGD (LOGD_DEVICE, "reapply setting: metered = %d (version-id %llu)", (int) metered, (long long unsigned) version_id); g_object_set (G_OBJECT (s_con_applied), NM_SETTING_CONNECTION_METERED, metered, diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 91068e56a7..f7506022a1 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -46,6 +46,8 @@ typedef struct { char *specific_object; NMDevice *device; + guint64 version_id; + char *pending_activation_id; gboolean is_default; @@ -796,10 +798,45 @@ nm_active_connection_authorize (NMActiveConnection *self, /****************************************************************/ +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", (long long unsigned) priv->version_id); + return priv->version_id; +} + +/****************************************************************/ + static void nm_active_connection_init (NMActiveConnection *self) { + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + _LOGT ("creating"); + + priv->version_id = _version_id_new (); } static void @@ -810,7 +847,7 @@ constructed (GObject *object) G_OBJECT_CLASS (nm_active_connection_parent_class)->constructed (object); - _LOGD ("constructed (%s)", G_OBJECT_TYPE_NAME (self)); + _LOGD ("constructed (%s, version-id %llu)", G_OBJECT_TYPE_NAME (self), (long long unsigned) priv->version_id); g_return_if_fail (priv->subject); } diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index f57f2081f1..a7b3d0cd34 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -83,6 +83,9 @@ typedef struct { NMMetered new_value); } NMActiveConnectionClass; +guint64 nm_active_connection_version_id_get (NMActiveConnection *self); +guint64 nm_active_connection_version_id_bump (NMActiveConnection *self); + GType nm_active_connection_get_type (void); typedef void (*NMActiveConnectionAuthResultFunc) (NMActiveConnection *self, From 6898e2169e2fc2ca9d938208ad84a112ccb3f23e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 11 Feb 2016 09:04:58 +0100 Subject: [PATCH 3/7] all: add version-id argument to device's Reapply method This breaks API and ABI for the functions related to Reapply, which got introduced in the current 1.1 development phase. The version-id is here to allow users to error out if the connection on the device was changed by a concurrent action. https://bugzilla.gnome.org/show_bug.cgi?id=761714 --- clients/cli/devices.c | 2 +- introspection/nm-device.xml | 7 +++++++ libnm-core/nm-errors.h | 2 ++ libnm/nm-device.c | 12 +++++++++-- libnm/nm-device.h | 2 ++ src/devices/nm-device.c | 40 ++++++++++++++++++++++++++++++++++--- 6 files changed, 59 insertions(+), 6 deletions(-) diff --git a/clients/cli/devices.c b/clients/cli/devices.c index c960c54eb4..d2cb9fcba9 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -1928,7 +1928,7 @@ do_device_reapply (NmCli *nmc, int argc, char **argv) info->queue = g_slist_prepend (info->queue, g_object_ref (device)); /* Now reapply the connection to the device */ - nm_device_reapply_async (device, NULL, 0, NULL, reapply_device_cb, info); + nm_device_reapply_async (device, NULL, 0, 0, NULL, reapply_device_cb, info); } error: diff --git a/introspection/nm-device.xml b/introspection/nm-device.xml index 2930cf067e..eada289f28 100644 --- a/introspection/nm-device.xml +++ b/introspection/nm-device.xml @@ -176,6 +176,13 @@ settings from the connection that is active on the device will be used. + + + If non-zero, the current version id of the applied connection must match. + This optional argument allows to catch concurrent modifications when + reapplying the currently applied connection with modifications. + + Flags which would modify the behavior of the Reapply call. diff --git a/libnm-core/nm-errors.h b/libnm-core/nm-errors.h index a9857445b7..f5e08f9a6b 100644 --- a/libnm-core/nm-errors.h +++ b/libnm-core/nm-errors.h @@ -142,6 +142,7 @@ GQuark nm_crypto_error_quark (void); * @NM_DEVICE_ERROR_SPECIFIC_OBJECT_NOT_FOUND: the "specific object" in the * activation request (eg, the #NMAccessPoint or #NMWimaxNsp) was not * found. + * @NM_DEVICE_ERROR_VERSION_ID_MISMATCH: the version id did not match. * * Device-related errors. * @@ -158,6 +159,7 @@ typedef enum { NM_DEVICE_ERROR_NOT_SOFTWARE, /*< nick=NotSoftware >*/ NM_DEVICE_ERROR_NOT_ALLOWED, /*< nick=NotAllowed >*/ NM_DEVICE_ERROR_SPECIFIC_OBJECT_NOT_FOUND, /*< nick=SpecificObjectNotFound >*/ + NM_DEVICE_ERROR_VERSION_ID_MISMATCH, /*< nick=VersionIdMismatch >*/ } NMDeviceError; #define NM_DEVICE_ERROR nm_device_error_quark () diff --git a/libnm/nm-device.c b/libnm/nm-device.c index 49e1e5f7e9..e1e77efc58 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -2167,6 +2167,9 @@ nm_device_is_software (NMDevice *device) * nm_device_reapply: * @device: a #NMDevice * @connection: the #NMConnection to replace the applied settings with or %NULL to reuse existing + * @version_id: zero or the expected version id of the applied connection. If specified + * and the version id mismatches, the call fails without modification. This allows to + * catch concurrent accesses. * @flags: always set this to zero * @cancellable: a #GCancellable, or %NULL * @error: location for a #GError, or %NULL @@ -2181,6 +2184,7 @@ nm_device_is_software (NMDevice *device) gboolean nm_device_reapply (NMDevice *device, NMConnection *connection, + guint64 version_id, guint flags, GCancellable *cancellable, GError **error) @@ -2197,7 +2201,7 @@ nm_device_reapply (NMDevice *device, ret = nmdbus_device_call_reapply_sync (NM_DEVICE_GET_PRIVATE (device)->proxy, - dict, flags, cancellable, error); + dict, version_id, flags, cancellable, error); if (error && *error) g_dbus_error_strip_remote_error (*error); return ret; @@ -2226,6 +2230,9 @@ device_reapply_cb (GObject *proxy, * nm_device_reapply_async: * @device: a #NMDevice * @connection: the #NMConnection to replace the applied settings with or %NULL to reuse existing + * @version_id: zero or the expected version id of the applied connection. If specified + * and the version id mismatches, the call fails without modification. This allows to + * catch concurrent accesses. * @flags: always set this to zero * @cancellable: a #GCancellable, or %NULL * @callback: callback to be called when the reapply operation completes @@ -2239,6 +2246,7 @@ device_reapply_cb (GObject *proxy, void nm_device_reapply_async (NMDevice *device, NMConnection *connection, + guint64 version_id, guint flags, GCancellable *cancellable, GAsyncReadyCallback callback, @@ -2258,7 +2266,7 @@ nm_device_reapply_async (NMDevice *device, nm_device_reapply_async); nmdbus_device_call_reapply (NM_DEVICE_GET_PRIVATE (device)->proxy, - dict, flags, cancellable, + dict, version_id, flags, cancellable, device_reapply_cb, simple); } diff --git a/libnm/nm-device.h b/libnm/nm-device.h index bf845cebff..816acb7483 100644 --- a/libnm/nm-device.h +++ b/libnm/nm-device.h @@ -140,12 +140,14 @@ char ** nm_device_disambiguate_names (NMDevice **devices, NM_AVAILABLE_IN_1_2 gboolean nm_device_reapply (NMDevice *device, NMConnection *connection, + guint64 version_id, guint flags, GCancellable *cancellable, GError **error); NM_AVAILABLE_IN_1_2 void nm_device_reapply_async (NMDevice *device, NMConnection *connection, + guint64 version_id, guint flags, GCancellable *cancellable, GAsyncReadyCallback callback, diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index c33a19db65..5d9903dc91 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -7162,6 +7162,8 @@ nm_device_reactivate_ip6_config (NMDevice *self, /* reapply_connection: * @connection: the new connection settings to be applied or %NULL to reapply * the current settings connection + * @version_id: either zero, or the current version id for the applied + * connection. * @error: the error if %FALSE is returned * * Change configuration of an already configured device if possible. @@ -7172,6 +7174,7 @@ nm_device_reactivate_ip6_config (NMDevice *self, static gboolean reapply_connection (NMDevice *self, NMConnection *connection, + guint64 version_id, GError **error) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -7181,7 +7184,6 @@ reapply_connection (NMDevice *self, NMConnection *con_old, *con_new; NMSettingIPConfig *s_ip4_old, *s_ip4_new; NMSettingIPConfig *s_ip6_old, *s_ip6_new; - guint64 version_id; if (priv->state != NM_DEVICE_STATE_ACTIVATED) { g_set_error_literal (error, @@ -7213,6 +7215,15 @@ reapply_connection (NMDevice *self, NM_SETTING_CONNECTION_METERED)) return FALSE; + if ( version_id != 0 + && version_id != nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request)) { + g_set_error_literal (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_VERSION_ID_MISMATCH, + "Reapply failed because device changed in the meantime and the version-id mismatches"); + return FALSE; + } + /************************************************************************** * Update applied connection *************************************************************************/ @@ -7249,6 +7260,11 @@ reapply_connection (NMDevice *self, return TRUE; } +typedef struct { + NMConnection *connection; + guint64 version_id; +} ReapplyData; + static void reapply_cb (NMDevice *self, GDBusMethodInvocation *context, @@ -7256,9 +7272,17 @@ reapply_cb (NMDevice *self, GError *error, gpointer user_data) { - gs_unref_object NMConnection *connection = NM_CONNECTION (user_data); + ReapplyData *reapply_data = user_data; + guint64 version_id = 0; + gs_unref_object NMConnection *connection = NULL; GError *local = NULL; + if (reapply_data) { + connection = reapply_data->connection; + version_id = reapply_data->version_id; + g_slice_free (ReapplyData, reapply_data); + } + if (error) { nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, subject, error->message); g_dbus_method_invocation_return_gerror (context, error); @@ -7267,6 +7291,7 @@ reapply_cb (NMDevice *self, if (!reapply_connection (self, connection ? : (NMConnection *) nm_device_get_settings_connection (self), + version_id, &local)) { nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, subject, local->message); g_dbus_method_invocation_take_error (context, local); @@ -7281,12 +7306,14 @@ static void impl_device_reapply (NMDevice *self, GDBusMethodInvocation *context, GVariant *settings, + guint64 version_id, guint flags) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMSettingsConnection *settings_connection; NMConnection *connection = NULL; GError *error = NULL; + ReapplyData *reapply_data; /* No flags supported as of now. */ if (flags != 0) { @@ -7322,6 +7349,13 @@ impl_device_reapply (NMDevice *self, nm_connection_clear_secrets (connection); } + if (connection || version_id) { + reapply_data = g_slice_new (ReapplyData); + reapply_data->connection = connection; + reapply_data->version_id = version_id; + } else + reapply_data = NULL; + /* Ask the manager to authenticate this request for us */ g_signal_emit (self, signals[AUTH_REQUEST], 0, context, @@ -7329,7 +7363,7 @@ impl_device_reapply (NMDevice *self, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE, reapply_cb, - connection); + reapply_data); } static void From 62910d19d731a7cce0cf3acd9268720f74bb6e32 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 11 Feb 2016 09:18:35 +0100 Subject: [PATCH 4/7] core: add NMDevice's GetAppliedConnection D-Bus call Expose applied connection in D-Bus API. https://bugzilla.gnome.org/show_bug.cgi?id=760884 --- introspection/nm-device.xml | 65 +++++++++++++++++++++---- src/devices/nm-device.c | 95 +++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 9 deletions(-) diff --git a/introspection/nm-device.xml b/introspection/nm-device.xml index eada289f28..f1033c73f2 100644 --- a/introspection/nm-device.xml +++ b/introspection/nm-device.xml @@ -172,15 +172,18 @@ - The effective connection settings and properties to use. If empty, the connection - settings from the connection that is active on the device will be used. + The optional connection settings that will be reapplied on the device. If empty, the + currently active settings-connection will be used. The connection cannot arbitrarly + differ from the current applied-connection otherwise the call will fail. + Only certain changes are supported, like adding or removing IP addresses. - If non-zero, the current version id of the applied connection must match. - This optional argument allows to catch concurrent modifications when - reapplying the currently applied connection with modifications. + If non-zero, the current version id of the applied-connection must match. + The current version id can be retrieved via GetAppliedConnection. + This optional argument allows to catch concurrent modifications between + the GetAppliedConnection call and Reapply. @@ -190,10 +193,54 @@ - Attempts to update the configuration of a device without deactivating it. - You can either modify the configuration by passing the desired setup via "connection" - argument or just omit the argument to bring it in sync with the connection that - has been activated but could have been modified since. + Attempts to update the configuration of a device without deactivating it. NetworkManager + has the concept of connections, which are profiles that contain the configuration for + a networking device. Those connections are exposed via D-Bus as individual objects + that can be created, modified and deleted. When activating such a settings-connection + on a device, the settings-connection is cloned to become an applied-connection and used to + configure the device (see GetAppliedConnection). Subsequent modification of the + settings-connection don't propagate automatically to the device's applied-connection + (with exception of the firewall-zone and the metered property). For the changes to take + effect, you can either re-activate the settings-connection, or call Reapply. + The Reapply call allows you to directly update the applied-connection and reconfigure + the device. + Reapply can also be useful if the currently applied-connection is equal to the connection + that is about to be reapplied. This allows to reconfigure the device and revert external + changes like removing or adding an IP address (which NetworkManager doesn't revert + automatically because it is assumed that the user made these changes intentionally outside + of NetworkManager). + Reapply can make the applied-connection different from the settings-connection, + just like updating the settings-connection can make them different. + + + + + + + Flags which would modify the behavior of the GetAppliedConnection call. + There are no flags defined currently and the users should use the value of 0. + + + + + The effective connection settings that the connection has currently applied. + + + + + The version-id of the currently applied connection. This can be specified during + Reapply to avoid races where you first fetch the applied connection, modify it + and try to reapply it. If the applied connection is modified in the meantime, the + version_id gets incremented and Reapply will fail. + + + + Get the currently applied connection on the device. This is a snapshot of the last activated + connection on the device, that is the configuration that is currently applied on the device. + Usually this is the same as GetSettings of the referenced settings connection. However, it + can differ if the settings connection was subsequently modified or the applied connection was + modified by Reapply. The applied connection is set when activating a device or when calling + Reapply. diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 5d9903dc91..f20a0fc581 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -7366,6 +7366,100 @@ impl_device_reapply (NMDevice *self, reapply_data); } +/*****************************************************************************/ + +static void +get_applied_connection_cb (NMDevice *self, + GDBusMethodInvocation *context, + NMAuthSubject *subject, + GError *error, + gpointer user_data /* possibly dangling pointer */) +{ + NMDevicePrivate *priv; + NMConnection *applied_connection; + GVariant *settings; + + g_return_if_fail (NM_IS_DEVICE (self)); + + if (error) { + g_dbus_method_invocation_return_gerror (context, error); + return; + } + + priv = NM_DEVICE_GET_PRIVATE (self); + + applied_connection = nm_device_get_applied_connection (self); + + if (!applied_connection) { + error = g_error_new_literal (NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ACTIVE, + "Device is not activated"); + g_dbus_method_invocation_take_error (context, error); + return; + } + + if (applied_connection != user_data) { + /* The applied connection changed due to a race. Reauthenticate. */ + g_signal_emit (self, signals[AUTH_REQUEST], 0, + context, + applied_connection, + NM_AUTH_PERMISSION_NETWORK_CONTROL, + TRUE, + get_applied_connection_cb, + applied_connection /* no need take a ref. We will not dereference this pointer. */); + return; + } + + settings = nm_connection_to_dbus (applied_connection, NM_CONNECTION_SERIALIZE_NO_SECRETS); + if (!settings) + settings = g_variant_new_array (G_VARIANT_TYPE ("{sa{sv}}"), NULL, 0); + + g_dbus_method_invocation_return_value (context, + g_variant_new ("(@a{sa{sv}}t)", + settings, + nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request))); +} + +static void +impl_device_get_applied_connection (NMDevice *self, + GDBusMethodInvocation *context, + guint32 flags) +{ + NMConnection *applied_connection; + GError *error = NULL; + + g_return_if_fail (NM_IS_DEVICE (self)); + + /* No flags supported as of now. */ + if (flags != 0) { + error = g_error_new_literal (NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "Invalid flags specified"); + g_dbus_method_invocation_take_error (context, error); + return; + } + + applied_connection = nm_device_get_applied_connection (self); + if (!applied_connection) { + error = g_error_new_literal (NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ACTIVE, + "Device is not activated"); + g_dbus_method_invocation_take_error (context, error); + return; + } + + /* Ask the manager to authenticate this request for us */ + g_signal_emit (self, signals[AUTH_REQUEST], 0, + context, + applied_connection, + NM_AUTH_PERMISSION_NETWORK_CONTROL, + TRUE, + get_applied_connection_cb, + applied_connection /* no need take a ref. We will not dereference this pointer. */); +} + +/*****************************************************************************/ + static void disconnect_cb (NMDevice *self, GDBusMethodInvocation *context, @@ -11724,6 +11818,7 @@ nm_device_class_init (NMDeviceClass *klass) nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), NMDBUS_TYPE_DEVICE_SKELETON, "Reapply", impl_device_reapply, + "GetAppliedConnection", impl_device_get_applied_connection, "Disconnect", impl_device_disconnect, "Delete", impl_device_delete, NULL); From 4bd45b94588b42672dbf4c13e8cb574a3b8d5e2c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 11 Feb 2016 12:00:30 +0100 Subject: [PATCH 5/7] libnm: add nm_device_get_applied_connection() function --- libnm/libnm.ver | 3 + libnm/nm-device.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++ libnm/nm-device.h | 18 +++++ 3 files changed, 194 insertions(+) diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 3867c3df0e..944c49bef3 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -875,6 +875,9 @@ global: nm_connection_get_setting_vxlan; nm_connection_verify_secrets; nm_device_ethernet_get_s390_subchannels; + nm_device_get_applied_connection; + nm_device_get_applied_connection_async; + nm_device_get_applied_connection_finish; nm_device_get_lldp_neighbors; nm_device_get_metered; nm_device_get_nm_plugin_missing; diff --git a/libnm/nm-device.c b/libnm/nm-device.c index e1e77efc58..242fe7e197 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -2299,6 +2299,179 @@ nm_device_reapply_finish (NMDevice *device, return g_simple_async_result_get_op_res_gboolean (simple); } +/*****************************************************************************/ + +/** + * nm_device_get_applied_connection: + * @device: a #NMDevice + * @flags: the flags argument. Currently this value must always be zero. + * @version_id: (out): (allow-none): returns the current version id of + * the applied connection + * @cancellable: a #GCancellable, or %NULL + * @error: location for a #GError, or %NULL + * + * Fetch the currently applied connection on the device. + * + * Returns: (transfer-full): a %NMConnection with the currently applied settings + * or %NULL on error. + * + * Since: 1.2 + **/ +NMConnection * +nm_device_get_applied_connection (NMDevice *device, + guint32 flags, + guint64 *version_id, + GCancellable *cancellable, + GError **error) +{ + gs_unref_variant GVariant *dict = NULL; + guint64 my_version_id; + gboolean success; + NMConnection *connection; + + g_return_val_if_fail (NM_IS_DEVICE (device), NULL); + g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (!error || !*error, NULL); + + success = nmdbus_device_call_get_applied_connection_sync (NM_DEVICE_GET_PRIVATE (device)->proxy, + flags, &dict, &my_version_id, cancellable, error); + if (!success) { + if (error && *error) + g_dbus_error_strip_remote_error (*error); + return NULL; + } + + connection = nm_simple_connection_new_from_dbus (dict, error); + if (!connection) + return NULL; + + NM_SET_OUT (version_id, my_version_id); + return connection; +} + +typedef struct { + NMConnection *connection; + guint64 version_id; +} GetAppliedConnectionData; + +static void +device_get_applied_connection_data_free (gpointer user_data) +{ + GetAppliedConnectionData *data = user_data; + + g_return_if_fail (data); + + g_object_unref (data->connection); + g_slice_free (GetAppliedConnectionData, data); +} + +static void +device_get_applied_connection_cb (GObject *proxy, + GAsyncResult *result, + gpointer user_data) +{ + gs_unref_object GSimpleAsyncResult *simple = user_data; + gs_unref_variant GVariant *dict = NULL; + guint64 my_version_id; + GError *error = NULL; + NMConnection *connection; + GetAppliedConnectionData *data; + + if (!nmdbus_device_call_get_applied_connection_finish (NMDBUS_DEVICE (proxy), &dict, &my_version_id, result, &error)) { + g_dbus_error_strip_remote_error (error); + g_simple_async_result_take_error (simple, error); + goto out; + } + + connection = nm_simple_connection_new_from_dbus (dict, &error); + if (!connection) { + g_simple_async_result_take_error (simple, error); + goto out; + } + + data = g_slice_new (GetAppliedConnectionData); + data->connection = connection; + data->version_id = my_version_id; + g_simple_async_result_set_op_res_gpointer (simple, data, device_get_applied_connection_data_free); + +out: + g_simple_async_result_complete (simple); +} + +/** + * nm_device_get_applied_connection_async: + * @device: a #NMDevice + * @flags: the flags argument. Currently this value must always be zero. + * @cancellable: a #GCancellable, or %NULL + * @callback: callback to be called when the reapply operation completes + * @user_data: caller-specific data passed to @callback + * + * Asynchronously begins an get the a currently applied connection. + * + * Since: 1.2 + **/ +void +nm_device_get_applied_connection_async (NMDevice *device, + guint32 flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + + g_return_if_fail (NM_IS_DEVICE (device)); + g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); + + simple = g_simple_async_result_new (G_OBJECT (device), callback, user_data, + nm_device_get_applied_connection_async); + + nmdbus_device_call_get_applied_connection (NM_DEVICE_GET_PRIVATE (device)->proxy, + flags, cancellable, + device_get_applied_connection_cb, simple); +} + +/** + * nm_device_get_applied_connection_finish: + * @device: a #NMDevice + * @result: the result passed to the #GAsyncReadyCallback + * @version_id: (out): (allow-none): the current version id of the applied + * connection. + * @error: location for a #GError, or %NULL + * + * Gets the result of a call to nm_device_get_applied_connection_async(). + * + * Returns: (transfer-full): a currently applied %NMConnection or %NULL in case + * of error. + * + * Since: 1.2 + **/ +NMConnection * +nm_device_get_applied_connection_finish (NMDevice *device, + GAsyncResult *result, + guint64 *version_id, + GError **error) +{ + GSimpleAsyncResult *simple; + GetAppliedConnectionData *data; + + g_return_val_if_fail (NM_IS_DEVICE (device), NULL); + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (device), nm_device_get_applied_connection_async), NULL); + g_return_val_if_fail (!error || !*error, NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + data = g_simple_async_result_get_op_res_gpointer (simple); + g_return_val_if_fail (data, NULL); + g_return_val_if_fail (NM_IS_CONNECTION (data->connection), NULL); + + NM_SET_OUT (version_id, data->version_id); + return g_object_ref (data->connection); +} + +/*****************************************************************************/ + /** * nm_device_disconnect: * @device: a #NMDevice diff --git a/libnm/nm-device.h b/libnm/nm-device.h index 816acb7483..87fcb0335e 100644 --- a/libnm/nm-device.h +++ b/libnm/nm-device.h @@ -157,6 +157,24 @@ gboolean nm_device_reapply_finish (NMDevice *device, GAsyncResult *result, GError **error); +NM_AVAILABLE_IN_1_2 +NMConnection *nm_device_get_applied_connection (NMDevice *device, + guint32 flags, + guint64 *version_id, + GCancellable *cancellable, + GError **error); +NM_AVAILABLE_IN_1_2 +void nm_device_get_applied_connection_async (NMDevice *device, + guint32 flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +NM_AVAILABLE_IN_1_2 +NMConnection *nm_device_get_applied_connection_finish (NMDevice *device, + GAsyncResult *result, + guint64 *version_id, + GError **error); + gboolean nm_device_disconnect (NMDevice *device, GCancellable *cancellable, GError **error); From 54dc78931475cf4d25f562e39aa61745a7c4a2dd Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 12 Feb 2016 14:02:53 +0100 Subject: [PATCH 6/7] device: fix signature for @flags argument of impl_device_reapply() Thereby, also adjust the type for libnm's wrapper function -- as we already broke ABI. --- libnm/nm-device.c | 4 ++-- libnm/nm-device.h | 4 ++-- src/devices/nm-device.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libnm/nm-device.c b/libnm/nm-device.c index 242fe7e197..3e887f79ea 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -2185,7 +2185,7 @@ gboolean nm_device_reapply (NMDevice *device, NMConnection *connection, guint64 version_id, - guint flags, + guint32 flags, GCancellable *cancellable, GError **error) { @@ -2247,7 +2247,7 @@ void nm_device_reapply_async (NMDevice *device, NMConnection *connection, guint64 version_id, - guint flags, + guint32 flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) diff --git a/libnm/nm-device.h b/libnm/nm-device.h index 87fcb0335e..c16ead9ed2 100644 --- a/libnm/nm-device.h +++ b/libnm/nm-device.h @@ -141,14 +141,14 @@ NM_AVAILABLE_IN_1_2 gboolean nm_device_reapply (NMDevice *device, NMConnection *connection, guint64 version_id, - guint flags, + guint32 flags, GCancellable *cancellable, GError **error); NM_AVAILABLE_IN_1_2 void nm_device_reapply_async (NMDevice *device, NMConnection *connection, guint64 version_id, - guint flags, + guint32 flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index f20a0fc581..e5b5e63472 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -7307,7 +7307,7 @@ impl_device_reapply (NMDevice *self, GDBusMethodInvocation *context, GVariant *settings, guint64 version_id, - guint flags) + guint32 flags) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMSettingsConnection *settings_connection; @@ -7318,7 +7318,7 @@ impl_device_reapply (NMDevice *self, /* No flags supported as of now. */ if (flags != 0) { error = g_error_new_literal (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, + NM_DEVICE_ERROR_FAILED, "Invalid flags specified"); nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message); g_dbus_method_invocation_take_error (context, error); From f40c4798456d2e16b479e5c85424967124dc51b4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 13 Feb 2016 14:41:57 +0100 Subject: [PATCH 7/7] introspection: document the meaning of active connections --- introspection/nm-active-connection.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/introspection/nm-active-connection.xml b/introspection/nm-active-connection.xml index 4d5d15a1e5..203437b7cc 100644 --- a/introspection/nm-active-connection.xml +++ b/introspection/nm-active-connection.xml @@ -9,6 +9,15 @@ The Connection.Active object tracks the life-cycle of the connection attempt and if successful indicates whether the connected network is the "default" or preferred network for access. + NetworkManager has the concept of connections, which can be thought of as + settings, a profile or a configuration that can be applied on a networking + device. + Such settings-connections are exposed as D-Bus object and the active-connection + expresses this relationship between device and settings-connection. + At any time a settings-connection can only be activated on one device and vice + versa. However, during activation and deactivation multiple active-connections + can reference the same device or settings-connection as they are waiting to + be activated or to be deactivated.