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:
settings from the connection that is active on the device will be used.
</tp:docstring>
</arg>
+ <arg name="version_id" type="t" direction="in">
+ <tp:docstring>
+ 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.
+ </tp:docstring>
+ </arg>
<arg name="flags" type="u" direction="in">
<tp:docstring>
Flags which would modify the behavior of the Reapply call.
* @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.
*
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 ()
* 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
gboolean
nm_device_reapply (NMDevice *device,
NMConnection *connection,
+ guint64 version_id,
guint flags,
GCancellable *cancellable,
GError **error)
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;
* 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
void
nm_device_reapply_async (NMDevice *device,
NMConnection *connection,
+ guint64 version_id,
guint flags,
GCancellable *cancellable,
GAsyncReadyCallback callback,
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);
}
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,
/* 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.
static gboolean
reapply_connection (NMDevice *self,
NMConnection *connection,
+ guint64 version_id,
GError **error)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (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,
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
*************************************************************************/
return TRUE;
}
+typedef struct {
+ NMConnection *connection;
+ guint64 version_id;
+} ReapplyData;
+
static void
reapply_cb (NMDevice *self,
GDBusMethodInvocation *context,
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);
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);
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) {
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,
NM_AUTH_PERMISSION_NETWORK_CONTROL,
TRUE,
reapply_cb,
- connection);
+ reapply_data);
}
static void