device: add O.FD.NM.Device.Reapply() call
authorLubomir Rintel <lkundrak@v3.sk>
Mon, 2 Nov 2015 14:32:38 +0000 (15:32 +0100)
committerLubomir Rintel <lkundrak@v3.sk>
Sun, 10 Jan 2016 22:13:34 +0000 (23:13 +0100)
The introspection data and daemon stub. There's no settings that can be
reapplied at the moment.

introspection/nm-device.xml
src/devices/nm-device.c

index cf04ac8..2930cf0 100644 (file)
       </tp:docstring>
     </property>
 
+    <method name="Reapply">
+      <arg name="connection" type="a{sa{sv}}" direction="in">
+        <tp:docstring>
+          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.
+        </tp:docstring>
+      </arg>
+      <arg name="flags" type="u" direction="in">
+        <tp:docstring>
+          Flags which would modify the behavior of the Reapply call.
+          There are no flags defined currently and the users should use the value of 0.
+        </tp:docstring>
+      </arg>
+      <tp:docstring>
+        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.
+      </tp:docstring>
+    </method>
+
     <method name="Disconnect">
       <tp:docstring>
         Disconnects a device and prevents the device from automatically activating further connections without user intervention.
index f77f576..49b3261 100644 (file)
@@ -6829,6 +6829,175 @@ _cleanup_ip6_pre (NMDevice *self, CleanupType cleanup_type)
        addrconf6_cleanup (self);
 }
 
+/* reapply_connection:
+ * @connection: the new connection settings to be applied
+ * @flags: always zero
+ * @reconfigure: %FALSE if this is a dry-run, %TRUE for an actual action
+ * @error: the error if %FALSE is returned
+ *
+ * Change configuration of an already configured device if possible.
+ * Updates the device's applied connection upon success.
+ *
+ * Return: %FALSE if the new configuration can not be reapplied.
+ */
+static gboolean
+reapply_connection (NMDevice *self,
+                    NMConnection *connection,
+                    guint flags,
+                    gboolean reconfigure,
+                    GError **error)
+{
+       NMConnection *applied = nm_device_get_applied_connection (self);
+       NMConnection *old;
+       GHashTable *diffs = NULL;
+       GHashTableIter iter;
+       const char *setting;
+
+       /* No flags supported as of now. */
+       if (flags != 0) {
+               g_set_error (error,
+                            NM_DEVICE_ERROR,
+                            NM_DEVICE_ERROR_FAILED,
+                            "Invalid flags specified");
+               return FALSE;
+       }
+
+       nm_connection_diff (connection,
+                           applied,
+                           NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP |
+                           NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS,
+                           &diffs);
+
+       /* Everything set. */
+       if (!diffs)
+               return TRUE;
+
+       old  = nm_simple_connection_new_clone (applied);
+       if (reconfigure)
+               nm_connection_replace_settings_from_connection (applied, connection);
+
+       g_hash_table_iter_init (&iter, diffs);
+       while (g_hash_table_iter_next (&iter, (gpointer *)&setting, NULL)) {
+               g_set_error (error,
+                            NM_DEVICE_ERROR,
+                            NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
+                            "Can't reapply changes to '%s' settings",
+                            setting);
+               return FALSE;
+       }
+
+       if (reconfigure)
+               nm_connection_replace_settings_from_connection (applied, NM_CONNECTION (connection));
+
+       return TRUE;
+}
+
+typedef struct {
+       NMConnection *connection;
+       guint flags;
+} ReapplyInfo;
+
+static void
+reapply_cb (NMDevice *self,
+            GDBusMethodInvocation *context,
+            NMAuthSubject *subject,
+            GError *error,
+            gpointer user_data)
+{
+       ReapplyInfo *info = (ReapplyInfo *)user_data;
+       NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+       GError *local = NULL;
+
+       if (error) {
+               g_dbus_method_invocation_return_gerror (context, error);
+               goto out;
+       }
+
+       /* Authorized */
+       if (priv->state != NM_DEVICE_STATE_ACTIVATED) {
+               local = g_error_new_literal (NM_DEVICE_ERROR,
+                                            NM_DEVICE_ERROR_NOT_ACTIVE,
+                                            "Device is not activated");
+               g_dbus_method_invocation_return_gerror (context, local);
+               g_error_free (local);
+               goto out;
+       }
+
+       if (!reapply_connection (self,
+                                info->connection,
+                                info->flags,
+                                FALSE,
+                                &local)) {
+               /* The dry-run check failed, pityfully. */
+               g_dbus_method_invocation_return_gerror (context, local);
+               g_error_free (local);
+               goto out;
+       }
+
+       reapply_connection (self,
+                           info->connection,
+                           info->flags,
+                           TRUE,
+                           &local);
+       g_dbus_method_invocation_return_value (context, NULL);
+
+out:
+       g_object_unref (info->connection);
+       g_slice_free (ReapplyInfo, info);
+}
+
+static void
+impl_device_reapply (NMDevice *self,
+                     GDBusMethodInvocation *context,
+                     GVariant *settings,
+                     guint flags)
+{
+       NMSettingsConnection *settings_connection;
+       NMConnection *connection;
+       GError *error = NULL;
+       ReapplyInfo *info;
+
+       if (NM_DEVICE_GET_PRIVATE (self)->act_request == NULL) {
+               error = g_error_new_literal (NM_DEVICE_ERROR,
+                                            NM_DEVICE_ERROR_NOT_ACTIVE,
+                                            "This device is not active");
+               g_dbus_method_invocation_return_gerror (context, error);
+               g_error_free (error);
+               return;
+       }
+
+       settings_connection = nm_device_get_settings_connection (self);
+       g_return_if_fail (settings_connection);
+
+       if (settings && g_variant_n_children (settings)) {
+               /* New settings specified inline. */
+               connection = nm_simple_connection_new_from_dbus (settings, &error);
+               if (!connection) {
+                       g_prefix_error (&error, "The settings specified are invalid: ");
+                       g_dbus_method_invocation_return_gerror (context, error);
+                       g_error_free (error);
+                       return;
+               }
+               nm_connection_clear_secrets (connection);
+       } else {
+               /* Just reuse whatever is active already. */
+               connection = NM_CONNECTION (g_object_ref (settings_connection));
+       }
+
+       info = g_slice_new0 (ReapplyInfo);
+       info->connection = connection;
+       info->flags = flags;
+
+       /* Ask the manager to authenticate this request for us */
+       g_signal_emit (self, signals[AUTH_REQUEST], 0,
+                      context,
+                      nm_device_get_applied_connection (self),
+                      NM_AUTH_PERMISSION_NETWORK_CONTROL,
+                      TRUE,
+                      reapply_cb,
+                      info);
+}
+
 static void
 disconnect_cb (NMDevice *self,
                GDBusMethodInvocation *context,
@@ -10924,6 +11093,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,
                                                "Disconnect", impl_device_disconnect,
                                                "Delete", impl_device_delete,
                                                NULL);