about summary refs log tree commit diff
path: root/src/core/nm-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/nm-manager.c')
-rw-r--r--src/core/nm-manager.c152
1 files changed, 117 insertions, 35 deletions
diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c
index 52153697..822df7ad 100644
--- a/src/core/nm-manager.c
+++ b/src/core/nm-manager.c
@@ -20,6 +20,7 @@
 #include "devices/nm-device-factory.h"
 #include "devices/nm-device-generic.h"
 #include "devices/nm-device.h"
+#include "dns/nm-dns-manager.h"
 #include "dhcp/nm-dhcp-manager.h"
 #include "libnm-core-aux-intern/nm-common-macros.h"
 #include "libnm-core-intern/nm-core-internal.h"
@@ -144,6 +145,9 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMManager,
 typedef struct {
     NMPlatform *platform;
 
+    NMDnsManager *dns_mgr;
+    gulong        dns_mgr_update_pending_signal_id;
+
     GArray *capabilities;
 
     CList               active_connections_lst_head; /* Oldest ACs at the beginning */
@@ -209,6 +213,10 @@ typedef struct {
 
     unsigned connectivity_check_enabled_last : 2;
 
+    /* List of GDBusMethodInvocation of in progress Sleep() and Enable()
+     * calls. They return only if all in-flight deactivations finished. */
+    GSList *sleep_invocations;
+
     guint delete_volatile_connection_idle_id;
     CList delete_volatile_connection_lst_head;
 } NMManagerPrivate;
@@ -346,6 +354,9 @@ static NMActiveConnection *_new_active_connection(NMManager             *self,
 
 static void policy_activating_ac_changed(GObject *object, GParamSpec *pspec, gpointer user_data);
 
+static void device_has_pending_action_changed(NMDevice *device, GParamSpec *pspec, NMManager *self);
+static void check_if_startup_complete(NMManager *self);
+
 static gboolean find_master(NMManager             *self,
                             NMConnection          *connection,
                             NMDevice              *device,
@@ -1601,7 +1612,11 @@ manager_device_state_changed(NMDevice           *device,
         nm_settings_device_added(priv->settings, device);
 }
 
-static void device_has_pending_action_changed(NMDevice *device, GParamSpec *pspec, NMManager *self);
+static void
+_dns_mgr_update_pending_cb(NMDevice *device, GParamSpec *pspec, NMManager *self)
+{
+    check_if_startup_complete(self);
+}
 
 static void
 check_if_startup_complete(NMManager *self)
@@ -1616,6 +1631,20 @@ check_if_startup_complete(NMManager *self)
     if (!priv->devices_inited)
         return;
 
+    if (nm_dns_manager_get_update_pending(nm_manager_get_dns_manager(self))) {
+        if (priv->dns_mgr_update_pending_signal_id == 0) {
+            priv->dns_mgr_update_pending_signal_id =
+                g_signal_connect(nm_manager_get_dns_manager(self),
+                                 "notify::" NM_DNS_MANAGER_UPDATE_PENDING,
+                                 G_CALLBACK(_dns_mgr_update_pending_cb),
+                                 self);
+        }
+        return;
+    }
+
+    nm_clear_g_signal_handler(nm_manager_get_dns_manager(self),
+                              &priv->dns_mgr_update_pending_signal_id);
+
     c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
         reason = nm_device_has_pending_action_reason(device);
         if (reason) {
@@ -2221,6 +2250,18 @@ connection_updated_cb(NMSettings           *settings,
     connection_changed(self, sett_conn);
 }
 
+static void
+connections_changed(NMManager *self)
+{
+    NMManagerPrivate            *priv = NM_MANAGER_GET_PRIVATE(self);
+    NMSettingsConnection *const *connections;
+    guint                        i;
+
+    connections = nm_settings_get_connections_sorted_by_autoconnect_priority(priv->settings, NULL);
+    for (i = 0; connections[i]; i++)
+        connection_changed(self, connections[i]);
+}
+
 /*****************************************************************************/
 
 static void
@@ -6336,6 +6377,22 @@ done:
     g_clear_object(&subject);
 }
 
+static void
+sleep_devices_check_empty(NMManager *self)
+{
+    NMManagerPrivate      *priv = NM_MANAGER_GET_PRIVATE(self);
+    GDBusMethodInvocation *invocation;
+
+    if (g_hash_table_size(priv->sleep_devices) > 0)
+        return;
+
+    while (priv->sleep_invocations) {
+        invocation = priv->sleep_invocations->data;
+        g_dbus_method_invocation_return_value(invocation, NULL);
+        priv->sleep_invocations = g_slist_remove(priv->sleep_invocations, invocation);
+    }
+}
+
 static gboolean
 sleep_devices_add(NMManager *self, NMDevice *device, gboolean suspending)
 {
@@ -6378,6 +6435,9 @@ sleep_devices_remove(NMManager *self, NMDevice *device)
     g_signal_handlers_disconnect_by_func(device, device_sleep_cb, self);
     g_hash_table_remove(priv->sleep_devices, device);
     g_object_unref(device);
+
+    sleep_devices_check_empty(self);
+
     return TRUE;
 }
 
@@ -6389,9 +6449,6 @@ sleep_devices_clear(NMManager *self)
     NMSleepMonitorInhibitorHandle *handle;
     GHashTableIter                 iter;
 
-    if (!priv->sleep_devices)
-        return;
-
     g_hash_table_iter_init(&iter, priv->sleep_devices);
     while (g_hash_table_iter_next(&iter, (gpointer *) &device, (gpointer *) &handle)) {
         g_signal_handlers_disconnect_by_func(device, device_sleep_cb, self);
@@ -6400,6 +6457,8 @@ sleep_devices_clear(NMManager *self)
         g_object_unref(device);
         g_hash_table_iter_remove(&iter);
     }
+
+    sleep_devices_check_empty(self);
 }
 
 static void
@@ -6521,7 +6580,7 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
                 && !nm_device_get_unmanaged_flags(device, NM_UNMANAGED_SLEEPING)) {
                 /* DHCP leases of software devices could have gone stale
                  * so we need to renew them. */
-                nm_device_update_dynamic_ip_setup(device);
+                nm_device_update_dynamic_ip_setup(device, "wake up");
                 continue;
             }
 
@@ -6551,6 +6610,10 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
                                              FALSE,
                                              NM_DEVICE_STATE_REASON_NOW_MANAGED);
         }
+
+        /* Give the connections a chance to recreate the virtual devices.
+	 * We've torn them down on sleep. */
+        connections_changed(self);
     }
 
     nm_manager_update_state(self);
@@ -6628,7 +6691,10 @@ impl_manager_sleep(NMDBusObject                      *obj,
                             TRUE,
                             subject,
                             NULL);
-    g_dbus_method_invocation_return_value(invocation, NULL);
+
+    priv->sleep_invocations = g_slist_prepend(priv->sleep_invocations, invocation);
+    sleep_devices_check_empty(self);
+
     return;
 }
 
@@ -6668,10 +6734,11 @@ _internal_enable(NMManager *self, gboolean enable)
 static void
 enable_net_done_cb(NMAuthChain *chain, GDBusMethodInvocation *context, gpointer user_data)
 {
-    NMManager       *self = NM_MANAGER(user_data);
-    NMAuthCallResult result;
-    gboolean         enable;
-    NMAuthSubject   *subject;
+    NMManager        *self = NM_MANAGER(user_data);
+    NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
+    NMAuthCallResult  result;
+    gboolean          enable;
+    NMAuthSubject    *subject;
 
     nm_assert(G_IS_DBUS_METHOD_INVOCATION(context));
 
@@ -6696,8 +6763,10 @@ enable_net_done_cb(NMAuthChain *chain, GDBusMethodInvocation *context, gpointer
     }
 
     _internal_enable(self, enable);
-    g_dbus_method_invocation_return_value(context, NULL);
     nm_audit_log_control_op(NM_AUDIT_OP_NET_CONTROL, enable ? "on" : "off", TRUE, subject, NULL);
+
+    priv->sleep_invocations = g_slist_prepend(priv->sleep_invocations, context);
+    sleep_devices_check_empty(self);
 }
 
 static void
@@ -7014,10 +7083,6 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde
     guint32                        route_metric_default_aspired;
     guint32                        route_metric_default_effective;
     NMTernary                      nm_owned;
-    NMDhcpConfig                  *dhcp_config;
-    const char                    *next_server   = NULL;
-    const char                    *root_path     = NULL;
-    const char                    *dhcp_bootfile = NULL;
 
     NM_SET_OUT(out_ifindex, 0);
 
@@ -7059,15 +7124,6 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde
                                                               TRUE,
                                                               &route_metric_default_aspired);
 
-    dhcp_config = nm_device_get_dhcp_config(device, AF_INET);
-    if (dhcp_config) {
-        root_path     = nm_dhcp_config_get_option(dhcp_config, "root_path");
-        next_server   = nm_dhcp_config_get_option(dhcp_config, "next_server");
-        dhcp_bootfile = nm_dhcp_config_get_option(dhcp_config, "filename");
-        if (!dhcp_bootfile)
-            dhcp_bootfile = nm_dhcp_config_get_option(dhcp_config, "bootfile_name");
-    }
-
     if (!nm_config_device_state_write(ifindex,
                                       managed_type,
                                       perm_hw_addr_fake,
@@ -7075,9 +7131,8 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde
                                       nm_owned,
                                       route_metric_default_aspired,
                                       route_metric_default_effective,
-                                      next_server,
-                                      root_path,
-                                      dhcp_bootfile))
+                                      nm_device_get_dhcp_config(device, AF_INET),
+                                      nm_device_get_dhcp_config(device, AF_INET6)))
         return FALSE;
 
     NM_SET_OUT(out_ifindex, ifindex);
@@ -7119,9 +7174,8 @@ devices_inited_cb(gpointer user_data)
 gboolean
 nm_manager_start(NMManager *self, GError **error)
 {
-    NMManagerPrivate            *priv = NM_MANAGER_GET_PRIVATE(self);
-    NMSettingsConnection *const *connections;
-    guint                        i;
+    NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
+    guint             i;
 
     nm_device_factory_manager_load_factories(_register_device_factory, self);
 
@@ -7175,9 +7229,10 @@ nm_manager_start(NMManager *self, GError **error)
                      NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,
                      G_CALLBACK(connection_updated_cb),
                      self);
-    connections = nm_settings_get_connections_sorted_by_autoconnect_priority(priv->settings, NULL);
-    for (i = 0; connections[i]; i++)
-        connection_changed(self, connections[i]);
+
+    /* Make sure virtual devices for all connections are created so
+     * that they could be autoconnected.  */
+    connections_changed(self);
 
     nm_clear_g_source(&priv->devices_inited_id);
     priv->devices_inited_id = g_idle_add_full(G_PRIORITY_LOW + 10, devices_inited_cb, self, NULL);
@@ -7790,6 +7845,28 @@ impl_manager_checkpoint_adjust_rollback_timeout(NMDBusObject
 
 /*****************************************************************************/
 
+NMDnsManager *
+nm_manager_get_dns_manager(NMManager *self)
+{
+    NMManagerPrivate *priv;
+
+    g_return_val_if_fail(NM_IS_MANAGER(self), NULL);
+
+    priv = NM_MANAGER_GET_PRIVATE(self);
+
+    if (G_UNLIKELY(!priv->dns_mgr)) {
+        /* Initialize lazily on first use.
+         *
+         * But keep a reference. This is to ensure proper lifetimes between
+         * singleton instances (i.e. nm_dns_manager_get() outlives NMManager). */
+        priv->dns_mgr = g_object_ref(nm_dns_manager_get());
+    }
+
+    return priv->dns_mgr;
+}
+
+/*****************************************************************************/
+
 static void
 auth_mgr_changed(NMAuthManager *auth_manager, gpointer user_data)
 {
@@ -8250,6 +8327,9 @@ dispose(GObject *object)
         g_clear_object(&priv->concheck_mgr);
     }
 
+    nm_clear_g_signal_handler(priv->dns_mgr, &priv->dns_mgr_update_pending_signal_id);
+    g_clear_object(&priv->dns_mgr);
+
     if (priv->auth_mgr) {
         g_signal_handlers_disconnect_by_func(priv->auth_mgr, G_CALLBACK(auth_mgr_changed), self);
         g_clear_object(&priv->auth_mgr);
@@ -8300,8 +8380,10 @@ dispose(GObject *object)
 
     g_clear_object(&priv->vpn_manager);
 
-    sleep_devices_clear(self);
-    nm_clear_pointer(&priv->sleep_devices, g_hash_table_unref);
+    if (priv->sleep_devices) {
+        sleep_devices_clear(self);
+        nm_clear_pointer(&priv->sleep_devices, g_hash_table_unref);
+    }
 
     if (priv->sleep_monitor) {
         g_signal_handlers_disconnect_by_func(priv->sleep_monitor, sleeping_cb, self);