about summary refs log tree commit diff
path: root/src/core/nm-manager.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2024-05-05 00:07:30 +0200
committerMichael Biebl <biebl@debian.org>2024-05-05 00:07:30 +0200
commit34bb501be08aa2b313d88e67d6e0a7e0a3f9cfa6 (patch)
tree4e6220877828be4c6f261de09ec0cb2d80e32389 /src/core/nm-manager.c
parentbba2e4b4de668db525cbfdfc35292e5a0b51671a (diff)
New upstream version 1.47.90 upstream/1.47.90
Diffstat (limited to 'src/core/nm-manager.c')
-rw-r--r--src/core/nm-manager.c171
1 files changed, 123 insertions, 48 deletions
diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c
index 730ba476..b2a827e3 100644
--- a/src/core/nm-manager.c
+++ b/src/core/nm-manager.c
@@ -46,7 +46,7 @@
 #include "nm-priv-helper-call.h"
 #include "nm-rfkill-manager.h"
 #include "nm-session-monitor.h"
-#include "nm-sleep-monitor.h"
+#include "nm-power-monitor.h"
 #include "settings/nm-settings-connection.h"
 #include "settings/nm-settings.h"
 #include "vpn/nm-vpn-manager.h"
@@ -214,7 +214,7 @@ typedef struct {
 
     NMVpnManager *vpn_manager;
 
-    NMSleepMonitor *sleep_monitor;
+    NMPowerMonitor *power_monitor;
 
     NMAuthManager *auth_mgr;
 
@@ -1914,7 +1914,8 @@ find_device_by_ip_iface(NMManager *self, const char *iface)
  * is given, this function will only return master devices and will ensure
  * @slave, when activated, can be a slave of the returned master device.  If
  * @connection is given, this function will only consider devices that are
- * compatible with @connection.
+ * compatible with @connection. If @child is given, this function will only
+ * return parent device.
  *
  * Returns: the matching #NMDevice
  */
@@ -1922,7 +1923,8 @@ static NMDevice *
 find_device_by_iface(NMManager    *self,
                      const char   *iface,
                      NMConnection *connection,
-                     NMConnection *slave)
+                     NMConnection *slave,
+                     NMConnection *child)
 {
     NMManagerPrivate *priv     = NM_MANAGER_GET_PRIVATE(self);
     NMDevice         *fallback = NULL;
@@ -1936,11 +1938,13 @@ find_device_by_iface(NMManager    *self,
         if (connection && !nm_device_check_connection_compatible(candidate, connection, TRUE, NULL))
             continue;
         if (slave) {
-            if (!nm_device_is_master(candidate))
+            if (!nm_device_is_controller(candidate))
                 continue;
             if (!nm_device_check_slave_connection_compatible(candidate, slave))
                 continue;
         }
+        if (child && !nm_device_can_be_parent(candidate))
+            continue;
 
         if (nm_device_is_real(candidate))
             return candidate;
@@ -2405,7 +2409,7 @@ find_parent_device_for_connection(NMManager       *self,
     NM_SET_OUT(out_parent_spec, parent_name);
 
     /* Try as an interface name of a parent device */
-    parent = find_device_by_iface(self, parent_name, NULL, NULL);
+    parent = find_device_by_iface(self, parent_name, NULL, NULL, connection);
     if (parent)
         return parent;
 
@@ -3777,7 +3781,7 @@ recheck_assume_connection(NMManager *self, NMDevice *device)
                         &master_ac,
                         NULL)
             && master_ac)
-            nm_active_connection_set_master(active, master_ac);
+            nm_active_connection_set_controller(active, master_ac);
 
         active_connection_add(self, active);
         nm_device_queue_activation(device, NM_ACT_REQUEST(active));
@@ -4434,10 +4438,25 @@ platform_query_devices(NMManager *self)
     links        = nm_platform_link_get_all(priv->platform);
     if (!links)
         return;
+
     for (i = 0; i < links->len; i++) {
-        const NMPlatformLink          *link = NMP_OBJECT_CAST_LINK(links->pdata[i]);
+        const NMPlatformLink          *elem = NMP_OBJECT_CAST_LINK(links->pdata[i]);
+        const NMPlatformLink          *link;
         const NMConfigDeviceStateData *dev_state;
 
+        /*
+         * @links is an immutable snapshot of the platform links captured before
+         * the loop was started. It's possible that in the meantime, while
+         * processing netlink events in platform_link_added(), a link was
+         * renamed.  If that happens, we have 2 different views of the same
+         * ifindex: the one from @links and the one from platform. This can
+         * cause race conditions; make sure to use the latest known version of
+         * the link.
+         */
+        link = nm_platform_link_get(priv->platform, elem->ifindex);
+        if (!link)
+            continue;
+
         dev_state = nm_config_device_state_get(priv->config, link->ifindex);
         platform_link_added(self,
                             link->ifindex,
@@ -4921,7 +4940,7 @@ find_master(NMManager             *self,
     nm_assert(!out_master_ac || !*out_master_ac);
 
     s_con  = nm_connection_get_setting_connection(connection);
-    master = nm_setting_connection_get_master(s_con);
+    master = nm_setting_connection_get_controller(s_con);
 
     if (master == NULL)
         return TRUE; /* success, but no master */
@@ -5003,7 +5022,7 @@ find_master(NMManager             *self,
     }
 
     if (!master_connection) {
-        master_device = find_device_by_iface(self, master, NULL, connection);
+        master_device = find_device_by_iface(self, master, NULL, connection, NULL);
         if (!master_device) {
             g_set_error(error,
                         NM_MANAGER_ERROR,
@@ -5924,7 +5943,7 @@ _internal_activate_device(NMManager *self, NMActiveConnection *active, GError **
                                              NM_DEVICE_STATE_REASON_USER_REQUESTED);
         }
 
-        nm_active_connection_set_master(active, master_ac);
+        nm_active_connection_set_controller(active, master_ac);
         _LOGD(LOGD_CORE,
               "Activation of '%s' depends on active connection %p %s",
               nm_settings_connection_get_id(sett_conn),
@@ -6445,7 +6464,7 @@ validate_activation_request(NMManager             *self,
             if (!iface)
                 return NULL;
 
-            device = find_device_by_iface(self, iface, connection, NULL);
+            device = find_device_by_iface(self, iface, connection, NULL, NULL);
             if (!device) {
                 g_set_error_literal(error,
                                     NM_MANAGER_ERROR,
@@ -7128,7 +7147,7 @@ static gboolean
 sleep_devices_add(NMManager *self, NMDevice *device, gboolean suspending)
 {
     NMManagerPrivate              *priv   = NM_MANAGER_GET_PRIVATE(self);
-    NMSleepMonitorInhibitorHandle *handle = NULL;
+    NMPowerMonitorInhibitorHandle *handle = NULL;
 
     if (g_hash_table_lookup_extended(priv->sleep_devices, device, NULL, (gpointer *) &handle)) {
         if (suspending) {
@@ -7136,16 +7155,16 @@ sleep_devices_add(NMManager *self, NMDevice *device, gboolean suspending)
              * Even if we had an old handle, it might be stale by now. */
             g_hash_table_insert(priv->sleep_devices,
                                 device,
-                                nm_sleep_monitor_inhibit_take(priv->sleep_monitor));
+                                nm_power_monitor_inhibit_take(priv->power_monitor));
             if (handle)
-                nm_sleep_monitor_inhibit_release(priv->sleep_monitor, handle);
+                nm_power_monitor_inhibit_release(priv->power_monitor, handle);
         }
         return FALSE;
     }
 
     g_hash_table_insert(priv->sleep_devices,
                         g_object_ref(device),
-                        suspending ? nm_sleep_monitor_inhibit_take(priv->sleep_monitor) : NULL);
+                        suspending ? nm_power_monitor_inhibit_take(priv->power_monitor) : NULL);
     g_signal_connect(device, "notify::" NM_DEVICE_STATE, G_CALLBACK(device_sleep_cb), self);
     return TRUE;
 }
@@ -7154,13 +7173,13 @@ static gboolean
 sleep_devices_remove(NMManager *self, NMDevice *device)
 {
     NMManagerPrivate              *priv = NM_MANAGER_GET_PRIVATE(self);
-    NMSleepMonitorInhibitorHandle *handle;
+    NMPowerMonitorInhibitorHandle *handle;
 
     if (!g_hash_table_lookup_extended(priv->sleep_devices, device, NULL, (gpointer *) &handle))
         return FALSE;
 
     if (handle)
-        nm_sleep_monitor_inhibit_release(priv->sleep_monitor, handle);
+        nm_power_monitor_inhibit_release(priv->power_monitor, handle);
 
     /* Remove device from hash */
     g_signal_handlers_disconnect_by_func(device, device_sleep_cb, self);
@@ -7177,14 +7196,14 @@ sleep_devices_clear(NMManager *self)
 {
     NMManagerPrivate              *priv = NM_MANAGER_GET_PRIVATE(self);
     NMDevice                      *device;
-    NMSleepMonitorInhibitorHandle *handle;
+    NMPowerMonitorInhibitorHandle *handle;
     GHashTableIter                 iter;
 
     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);
         if (handle)
-            nm_sleep_monitor_inhibit_release(priv->sleep_monitor, handle);
+            nm_power_monitor_inhibit_release(priv->power_monitor, handle);
         g_object_unref(device);
         g_hash_table_iter_remove(&iter);
     }
@@ -7216,6 +7235,33 @@ device_sleep_cb(NMDevice *device, GParamSpec *pspec, NMManager *self)
 }
 
 static void
+_handle_device_takedown(NMManager *self,
+                        NMDevice  *device,
+                        gboolean   suspending,
+                        gboolean   is_shutdown)
+{
+    nm_device_notify_sleeping(device);
+
+    if (nm_device_is_activating(device)
+        || nm_device_get_state(device) == NM_DEVICE_STATE_ACTIVATED) {
+        _LOGD(LOGD_SUSPEND,
+              "%s: wait disconnection of device %s",
+              is_shutdown ? "shutdown" : "sleep",
+              nm_device_get_ip_iface(device));
+
+        if (sleep_devices_add(self, device, suspending))
+            nm_device_queue_state(device,
+                                  NM_DEVICE_STATE_DEACTIVATING,
+                                  NM_DEVICE_STATE_REASON_SLEEPING);
+    } else {
+        nm_device_set_unmanaged_by_flags(device,
+                                         NM_UNMANAGED_SLEEPING,
+                                         NM_UNMAN_FLAG_OP_SET_UNMANAGED,
+                                         NM_DEVICE_STATE_REASON_SLEEPING);
+    }
+}
+
+static void
 do_sleep_wake(NMManager *self, gboolean sleeping_changed)
 {
     NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
@@ -7249,24 +7295,7 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
                 continue;
             }
 
-            nm_device_notify_sleeping(device);
-
-            if (nm_device_is_activating(device)
-                || nm_device_get_state(device) == NM_DEVICE_STATE_ACTIVATED) {
-                _LOGD(LOGD_SUSPEND,
-                      "sleep: wait disconnection of device %s",
-                      nm_device_get_ip_iface(device));
-
-                if (sleep_devices_add(self, device, suspending))
-                    nm_device_queue_state(device,
-                                          NM_DEVICE_STATE_DEACTIVATING,
-                                          NM_DEVICE_STATE_REASON_SLEEPING);
-            } else {
-                nm_device_set_unmanaged_by_flags(device,
-                                                 NM_UNMANAGED_SLEEPING,
-                                                 NM_UNMAN_FLAG_OP_SET_UNMANAGED,
-                                                 NM_DEVICE_STATE_REASON_SLEEPING);
-            }
+            _handle_device_takedown(self, device, suspending, FALSE);
         }
     } else {
         _LOGD(LOGD_SUSPEND, "sleep: %s...", waking_from_suspend ? "waking up" : "re-enabling");
@@ -7438,7 +7467,7 @@ impl_manager_sleep(NMDBusObject                      *obj,
 }
 
 static void
-sleeping_cb(NMSleepMonitor *monitor, gboolean is_about_to_suspend, gpointer user_data)
+sleeping_cb(NMPowerMonitor *monitor, gboolean is_about_to_suspend, gpointer user_data)
 {
     NMManager *self = user_data;
 
@@ -7447,6 +7476,41 @@ sleeping_cb(NMSleepMonitor *monitor, gboolean is_about_to_suspend, gpointer user
 }
 
 static void
+shutdown_cb(NMPowerMonitor *monitor, gpointer user_data)
+{
+    NMManager        *self = user_data;
+    NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
+    NMDevice         *device;
+
+    _LOGT(LOGD_SUSPEND, "shutdown: received shutdown signal");
+
+    c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
+        NMSettingConnection *s_con;
+        gboolean             take_down = FALSE;
+
+        s_con = nm_device_get_applied_setting(device, NM_TYPE_SETTING_CONNECTION);
+        if (!s_con)
+            continue;
+
+        if (nm_setting_connection_get_down_on_poweroff(s_con)
+            == NM_SETTING_CONNECTION_DOWN_ON_POWEROFF_YES)
+            take_down = TRUE;
+        else if (nm_setting_connection_get_down_on_poweroff(s_con)
+                 == NM_SETTING_CONNECTION_DOWN_ON_POWEROFF_DEFAULT)
+            take_down = nm_config_data_get_connection_default_int64(
+                NM_CONFIG_GET_DATA,
+                NM_CON_DEFAULT("connection.down-on-poweroff"),
+                device,
+                NM_SETTING_CONNECTION_DOWN_ON_POWEROFF_NO,
+                NM_SETTING_CONNECTION_DOWN_ON_POWEROFF_YES,
+                NM_SETTING_CONNECTION_DOWN_ON_POWEROFF_NO);
+
+        if (take_down)
+            _handle_device_takedown(self, device, FALSE, TRUE);
+    }
+}
+
+static void
 _internal_enable(NMManager *self, gboolean enable)
 {
     NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
@@ -8458,7 +8522,8 @@ impl_manager_checkpoint_create(NMDBusObject                      *obj,
                                      | NM_CHECKPOINT_CREATE_FLAG_DELETE_NEW_CONNECTIONS
                                      | NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES
                                      | NM_CHECKPOINT_CREATE_FLAG_ALLOW_OVERLAPPING
-                                     | NM_CHECKPOINT_CREATE_FLAG_NO_PRESERVE_EXTERNAL_PORTS)))) {
+                                     | NM_CHECKPOINT_CREATE_FLAG_NO_PRESERVE_EXTERNAL_PORTS
+                                     | NM_CHECKPOINT_CREATE_FLAG_TRACK_INTERNAL_GLOBAL_DNS)))) {
         g_dbus_method_invocation_return_error_literal(invocation,
                                                       NM_MANAGER_ERROR,
                                                       NM_MANAGER_ERROR_INVALID_ARGUMENTS,
@@ -8834,8 +8899,9 @@ nm_manager_init(NMManager *self)
     priv->devcon_data_dict = g_hash_table_new(_devcon_data_hash, _devcon_data_equal);
 
     /* sleep/wake handling */
-    priv->sleep_monitor = nm_sleep_monitor_new();
-    g_signal_connect(priv->sleep_monitor, NM_SLEEP_MONITOR_SLEEPING, G_CALLBACK(sleeping_cb), self);
+    priv->power_monitor = nm_power_monitor_new();
+    g_signal_connect(priv->power_monitor, NM_POWER_MONITOR_SLEEPING, G_CALLBACK(sleeping_cb), self);
+    g_signal_connect(priv->power_monitor, NM_POWER_MONITOR_SHUTDOWN, G_CALLBACK(shutdown_cb), self);
 
     /* Listen for authorization changes */
     priv->auth_mgr = g_object_ref(nm_auth_manager_get());
@@ -8979,9 +9045,10 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
     case PROP_CHECKPOINTS:
         g_value_take_boxed(
             value,
-            priv->checkpoint_mgr ? nm_strv_make_deep_copied(
-                nm_checkpoint_manager_get_checkpoint_paths(priv->checkpoint_mgr, NULL))
-                                 : NULL);
+            priv->checkpoint_mgr
+                ? nm_strv_make_deep_copied(
+                      nm_checkpoint_manager_get_checkpoint_paths(priv->checkpoint_mgr, NULL))
+                : NULL);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -9134,9 +9201,9 @@ dispose(GObject *object)
         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);
-        g_clear_object(&priv->sleep_monitor);
+    if (priv->power_monitor) {
+        g_signal_handlers_disconnect_by_func(priv->power_monitor, sleeping_cb, self);
+        g_clear_object(&priv->power_monitor);
     }
 
     if (priv->fw_monitor) {
@@ -9765,3 +9832,11 @@ nm_manager_class_init(NMManagerClass *manager_class)
                                                    1,
                                                    NM_TYPE_DEVICE);
 }
+
+NMConfig *
+nm_manager_get_config(NMManager *self)
+{
+    NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
+
+    return priv->config;
+}