summary refs log tree commit diff
path: root/src/core/nm-policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/nm-policy.c')
-rw-r--r--src/core/nm-policy.c143
1 files changed, 129 insertions, 14 deletions
diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c
index 16b0211f..518fc596 100644
--- a/src/core/nm-policy.c
+++ b/src/core/nm-policy.c
@@ -797,6 +797,20 @@ device_dns_lookup_done(NMDevice *device, gpointer user_data)
 }
 
 static void
+device_carrier_changed(NMDevice *device, GParamSpec *pspec, gpointer user_data)
+{
+    NMPolicyPrivate *priv = user_data;
+    NMPolicy        *self = _PRIV_TO_SELF(priv);
+    gs_free char    *msg  = NULL;
+
+    if (nm_device_has_carrier(device)) {
+        g_signal_handlers_disconnect_by_func(device, device_carrier_changed, priv);
+        msg = g_strdup_printf("device '%s' got carrier", nm_device_get_iface(device));
+        update_system_hostname(self, msg);
+    }
+}
+
+static void
 update_system_hostname(NMPolicy *self, const char *msg)
 {
     NMPolicyPrivate       *priv = NM_POLICY_GET_PRIVATE(self);
@@ -880,6 +894,7 @@ update_system_hostname(NMPolicy *self, const char *msg)
         info        = &g_array_index(infos, DeviceHostnameInfo, i);
         addr_family = info->IS_IPv4 ? AF_INET : AF_INET6;
         g_signal_handlers_disconnect_by_func(info->device, device_dns_lookup_done, self);
+        g_signal_handlers_disconnect_by_func(info->device, device_carrier_changed, priv);
 
         if (info->from_dhcp) {
             dhcp_config = nm_device_get_dhcp_config(info->device, addr_family);
@@ -905,10 +920,18 @@ update_system_hostname(NMPolicy *self, const char *msg)
 
         if (priv->hostname_mode != NM_POLICY_HOSTNAME_MODE_DHCP) {
             if (info->from_dns) {
-                const char *result;
-                gboolean    wait = FALSE;
+                const char *result = NULL;
+                gboolean    wait   = FALSE;
 
-                result = nm_device_get_hostname_from_dns_lookup(info->device, addr_family, &wait);
+                if (nm_device_has_carrier(info->device)) {
+                    result =
+                        nm_device_get_hostname_from_dns_lookup(info->device, addr_family, &wait);
+                } else {
+                    g_signal_connect(info->device,
+                                     "notify::" NM_DEVICE_CARRIER,
+                                     G_CALLBACK(device_carrier_changed),
+                                     priv);
+                }
                 if (result) {
                     _set_hostname(self, result, "from address lookup");
                     return;
@@ -1556,6 +1579,7 @@ nm_policy_unblock_failed_ovs_interfaces(NMPolicy *self)
     NMPolicyPrivate             *priv        = NM_POLICY_GET_PRIVATE(self);
     NMSettingsConnection *const *connections = NULL;
     guint                        i;
+    gboolean                     multiconnect = FALSE;
 
     _LOGT(LOGD_DEVICE, "unblocking failed OVS interfaces");
 
@@ -1563,6 +1587,13 @@ nm_policy_unblock_failed_ovs_interfaces(NMPolicy *self)
     for (i = 0; connections[i]; i++) {
         NMSettingsConnection *sett_conn  = connections[i];
         NMConnection         *connection = nm_settings_connection_get_connection(sett_conn);
+        NMSettingConnection  *s_con      = nm_connection_get_setting_connection(connection);
+
+        /* Check if any connection is connect multiple */
+        if (s_con
+            && nm_setting_connection_get_multi_connect(s_con)
+                   == NM_CONNECTION_MULTI_CONNECT_MULTIPLE)
+            multiconnect = TRUE;
 
         if (nm_connection_get_setting_ovs_interface(connection)) {
             nm_settings_connection_autoconnect_retries_reset(sett_conn);
@@ -1572,6 +1603,18 @@ nm_policy_unblock_failed_ovs_interfaces(NMPolicy *self)
                 FALSE);
         }
     }
+
+    /* There is, at least, one multiconnect connection with an OVS setting.
+     * Let's check the OVS devices retries */
+    if (multiconnect) {
+        NMDevice      *device;
+        GHashTableIter h_iter;
+        g_hash_table_iter_init(&h_iter, priv->devices);
+        while (g_hash_table_iter_next(&h_iter, (gpointer *) &device, NULL)) {
+            if (nm_device_get_device_type(device) == NM_DEVICE_TYPE_OVS_INTERFACE)
+                nm_device_autoconnect_retries_reset(device);
+        }
+    }
 }
 
 static gboolean
@@ -1583,7 +1626,8 @@ reset_autoconnect_all(
     NMPolicyPrivate             *priv        = NM_POLICY_GET_PRIVATE(self);
     NMSettingsConnection *const *connections = NULL;
     guint                        i;
-    gboolean                     changed = FALSE;
+    gboolean                     changed      = FALSE;
+    gboolean                     multiconnect = FALSE;
 
     _LOGD(LOGD_DEVICE,
           "re-enabling autoconnect for all connections%s%s%s",
@@ -1594,6 +1638,8 @@ reset_autoconnect_all(
     connections = nm_settings_get_connections(priv->settings, NULL);
     for (i = 0; connections[i]; i++) {
         NMSettingsConnection *sett_conn = connections[i];
+        NMSettingConnection  *s_con =
+            nm_connection_get_setting_connection(nm_settings_connection_get_connection(sett_conn));
 
         if (device
             && !nm_device_check_connection_compatible(
@@ -1602,6 +1648,11 @@ reset_autoconnect_all(
                 NULL))
             continue;
 
+        if (s_con
+            && nm_setting_connection_get_multi_connect(s_con)
+                   == NM_CONNECTION_MULTI_CONNECT_MULTIPLE)
+            multiconnect = TRUE;
+
         if (only_no_secrets) {
             /* we only reset the no-secrets blocked flag. */
             if (nm_settings_connection_autoconnect_blocked_reason_set(
@@ -1630,6 +1681,20 @@ reset_autoconnect_all(
             }
         }
     }
+
+    /* There is, at least, one multiconnect connection. Let's check the devices retries */
+    if (multiconnect) {
+        NMDevice      *device_iter;
+        GHashTableIter h_iter;
+        g_hash_table_iter_init(&h_iter, priv->devices);
+        while (g_hash_table_iter_next(&h_iter, (gpointer *) &device_iter, NULL)) {
+            if (nm_device_get_autoconnect_retries(device_iter) != -2) {
+                nm_device_autoconnect_retries_reset(device_iter);
+                changed = TRUE;
+            }
+        }
+    }
+
     return changed;
 }
 
@@ -1687,7 +1752,8 @@ reset_connections_retries(gpointer user_data)
     NMSettingsConnection *const *connections = NULL;
     guint                        i;
     gint32                       con_stamp, min_stamp, now;
-    gboolean                     changed = FALSE;
+    gboolean                     changed      = FALSE;
+    gboolean                     multiconnect = FALSE;
 
     priv->reset_retries_id = 0;
 
@@ -1696,6 +1762,14 @@ reset_connections_retries(gpointer user_data)
     connections = nm_settings_get_connections(priv->settings, NULL);
     for (i = 0; connections[i]; i++) {
         NMSettingsConnection *connection = connections[i];
+        NMSettingConnection  *s_con =
+            nm_connection_get_setting_connection(nm_settings_connection_get_connection(connection));
+
+        /* Check if any connection is connect multiple */
+        if (s_con
+            && nm_setting_connection_get_multi_connect(s_con)
+                   == NM_CONNECTION_MULTI_CONNECT_MULTIPLE)
+            multiconnect = TRUE;
 
         con_stamp = nm_settings_connection_autoconnect_retries_blocked_until(connection);
         if (con_stamp == 0)
@@ -1708,6 +1782,25 @@ reset_connections_retries(gpointer user_data)
             min_stamp = con_stamp;
     }
 
+    /* There is, at least, one multiconnect connection. Let's check the devices retries */
+    if (multiconnect) {
+        NMDevice      *device;
+        GHashTableIter h_iter;
+        g_hash_table_iter_init(&h_iter, priv->devices);
+        while (g_hash_table_iter_next(&h_iter, (gpointer *) &device, NULL)) {
+            con_stamp = nm_device_autoconnect_retries_blocked_until(device);
+
+            /* default value in device is -2, which means, we do not care */
+            if (con_stamp <= 0)
+                continue;
+            if (con_stamp <= now) {
+                nm_device_autoconnect_retries_reset(device);
+                changed = TRUE;
+            } else if (min_stamp == 0 || min_stamp > con_stamp)
+                min_stamp = con_stamp;
+        }
+    }
+
     /* Schedule the handler again if there are some stamps left */
     if (min_stamp != 0)
         priv->reset_retries_id =
@@ -1721,21 +1814,31 @@ reset_connections_retries(gpointer user_data)
 }
 
 static void
-_connection_autoconnect_retries_set(NMPolicy *self, NMSettingsConnection *connection, int tries)
+_connection_autoconnect_retries_set(NMPolicy             *self,
+                                    NMSettingsConnection *connection,
+                                    NMDevice             *device,
+                                    int                   tries)
 {
-    NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self);
+    NMPolicyPrivate     *priv = NM_POLICY_GET_PRIVATE(self);
+    NMSettingConnection *s_con;
+    gint32               retry_time;
 
     nm_assert(NM_IS_SETTINGS_CONNECTION(connection));
     nm_assert(tries >= 0);
 
-    nm_settings_connection_autoconnect_retries_set(connection, tries);
+    s_con = nm_connection_get_setting_connection(nm_settings_connection_get_connection(connection));
+    if (s_con
+        && nm_setting_connection_get_multi_connect(s_con) == NM_CONNECTION_MULTI_CONNECT_MULTIPLE) {
+        nm_device_set_autoconnect_retries(device, tries);
+        retry_time = nm_device_autoconnect_retries_blocked_until(device);
+    } else {
+        nm_settings_connection_autoconnect_retries_set(connection, tries);
+        retry_time = nm_settings_connection_autoconnect_retries_blocked_until(connection);
+    }
 
     if (tries == 0) {
         /* Schedule a handler to reset retries count */
         if (!priv->reset_retries_id) {
-            gint32 retry_time =
-                nm_settings_connection_autoconnect_retries_blocked_until(connection);
-
             g_warn_if_fail(retry_time != 0);
             priv->reset_retries_id =
                 g_timeout_add_seconds(MAX(0, retry_time - nm_utils_get_monotonic_timestamp_sec()),
@@ -1997,13 +2100,25 @@ device_state_changed(NMDevice           *device,
             }
 
             if (!blocked) {
-                tries = nm_settings_connection_autoconnect_retries_get(sett_conn);
+                s_con = nm_connection_get_setting_connection(
+                    nm_settings_connection_get_connection(sett_conn));
+                if (s_con
+                    && nm_setting_connection_get_multi_connect(s_con)
+                           == NM_CONNECTION_MULTI_CONNECT_MULTIPLE) {
+                    if (nm_device_get_autoconnect_retries(device) == -2)
+                        nm_device_set_autoconnect_retries(
+                            device,
+                            nm_settings_connection_autoconnect_retries_get(sett_conn));
+
+                    tries = nm_device_get_autoconnect_retries(device);
+                } else
+                    tries = nm_settings_connection_autoconnect_retries_get(sett_conn);
                 if (tries > 0) {
                     _LOGD(LOGD_DEVICE,
                           "connection '%s' failed to autoconnect; %d tries left",
                           nm_settings_connection_get_id(sett_conn),
                           tries - 1);
-                    _connection_autoconnect_retries_set(self, sett_conn, tries - 1);
+                    _connection_autoconnect_retries_set(self, sett_conn, device, tries - 1);
                 } else if (tries != 0) {
                     _LOGD(LOGD_DEVICE,
                           "connection '%s' failed to autoconnect; infinite tries left",
@@ -2893,7 +3008,7 @@ dispose(GObject *object)
     }
 
     g_hash_table_iter_init(&h_iter, priv->devices);
-    if (g_hash_table_iter_next(&h_iter, (gpointer *) &device, NULL)) {
+    while (g_hash_table_iter_next(&h_iter, (gpointer *) &device, NULL)) {
         g_hash_table_iter_remove(&h_iter);
         devices_list_unregister(self, device);
     }