diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index 8dae02e0b..24bb0b336 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -97,5 +97,6 @@ void nm_device_master_check_slave_physical_port (NMDevice *dev, NMDevice *slave, void nm_device_set_carrier (NMDevice *device, gboolean carrier); void nm_device_emit_recheck_auto_activate (NMDevice *device); +void nm_device_queue_recheck_assume (NMDevice *device); #endif /* NM_DEVICE_PRIVATE_H */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index f91667519..5dea3971e 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -105,6 +105,7 @@ enum { IP6_CONFIG_CHANGED, REMOVED, RECHECK_AUTO_ACTIVATE, + RECHECK_ASSUME, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -237,6 +238,7 @@ typedef struct { gpointer act_source_func; guint act_source6_id; gpointer act_source6_func; + guint recheck_assume_id; /* Link stuff */ guint link_connected_id; @@ -2016,6 +2018,26 @@ nm_device_can_assume_connections (NMDevice *device) return !!NM_DEVICE_GET_CLASS (device)->update_connection; } +static gboolean +nm_device_emit_recheck_assume (gpointer self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + priv->recheck_assume_id = 0; + if (!nm_device_get_act_request (self) && (priv->ip4_config || priv->ip6_config)) + g_signal_emit (self, signals[RECHECK_ASSUME], 0); + return G_SOURCE_REMOVE; +} + +void +nm_device_queue_recheck_assume (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (nm_device_can_assume_connections (self) && !priv->recheck_assume_id) + priv->recheck_assume_id = g_idle_add (nm_device_emit_recheck_assume, self); +} + void nm_device_emit_recheck_auto_activate (NMDevice *self) { @@ -5243,6 +5265,8 @@ nm_device_set_ip4_config (NMDevice *self, nm_connection_add_setting (connection, s_ip4); g_object_thaw_notify (G_OBJECT (connection)); } + + nm_device_queue_recheck_assume (self); } if (reason) @@ -5345,6 +5369,8 @@ nm_device_set_ip6_config (NMDevice *self, nm_connection_add_setting (connection, s_ip6); g_object_thaw_notify (G_OBJECT (connection)); } + + nm_device_queue_recheck_assume (self); } if (reason) @@ -5789,6 +5815,11 @@ dispose (GObject *object) g_clear_pointer (&priv->ip6_saved_properties, g_hash_table_unref); + if (priv->recheck_assume_id) { + g_source_remove (priv->recheck_assume_id); + priv->recheck_assume_id = 0; + } + link_disconnect_action_cancel (self); if (priv->con_provider) { @@ -6437,6 +6468,13 @@ nm_device_class_init (NMDeviceClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + signals[RECHECK_ASSUME] = + g_signal_new (NM_DEVICE_RECHECK_ASSUME, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), G_TYPE_FROM_CLASS (klass), &dbus_glib_nm_device_object_info); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 9193264c9..503837281 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -76,6 +76,7 @@ #define NM_DEVICE_IP6_CONFIG_CHANGED "ip6-config-changed" #define NM_DEVICE_REMOVED "removed" #define NM_DEVICE_RECHECK_AUTO_ACTIVATE "recheck-auto-activate" +#define NM_DEVICE_RECHECK_ASSUME "recheck-assume" G_BEGIN_DECLS diff --git a/src/nm-manager.c b/src/nm-manager.c index 92ea164e9..681de94ac 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1586,6 +1586,89 @@ get_existing_connection (NMManager *manager, NMDevice *device) return added ? NM_CONNECTION (added) : NULL; } +static gboolean +assume_connection (NMManager *self, NMDevice *device, NMConnection *connection) +{ + NMActiveConnection *active, *master_ac; + NMAuthSubject *subject; + GError *error = NULL; + + nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume connection", + nm_device_get_iface (device)); + + /* Move device to DISCONNECTED to activate the connection */ + if (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE) { + nm_device_state_changed (device, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + } + g_return_if_fail (nm_device_get_state (device) >= NM_DEVICE_STATE_DISCONNECTED); + + subject = nm_auth_subject_new_internal (); + active = _new_active_connection (self, connection, NULL, device, subject, &error); + g_object_unref (subject); + + if (!active) { + nm_log_warn (LOGD_DEVICE, "assumed connection %s failed to activate: (%d) %s", + nm_connection_get_path (connection), + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_error_free (error); + return FALSE; + } + + /* If the device is a slave or VLAN, find the master ActiveConnection */ + master_ac = NULL; + if (find_master (self, connection, device, NULL, NULL, &master_ac, NULL) && master_ac) + nm_active_connection_set_master (active, master_ac); + + nm_active_connection_set_assumed (active, TRUE); + nm_active_connection_export (active); + active_connection_add (self, active); + nm_device_queue_activation (device, NM_ACT_REQUEST (active)); + g_object_unref (active); + + return TRUE; +} + +static void +recheck_assume_connection (NMDevice *device, gpointer user_data) +{ + NMManager *self = user_data; + NMConnection *connection; + gboolean was_unmanaged = FALSE; + + if (manager_sleeping (self)) + return; + if (nm_device_get_unmanaged_flag (device, NM_UNMANAGED_USER)) + return; + + connection = get_existing_connection (self, device); + if (!connection) { + nm_log_dbg (LOGD_DEVICE, "(%s): can't assume; no connection", + nm_device_get_iface (device)); + return; + } + + if (nm_device_get_state (device) == NM_DEVICE_STATE_UNMANAGED) { + was_unmanaged = TRUE; + nm_device_state_changed (device, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + } + + if (!assume_connection (self, device, connection)) { + if (was_unmanaged) { + nm_device_state_changed (device, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_CONFIG_FAILED); + nm_device_state_changed (device, + NM_DEVICE_STATE_UNMANAGED, + NM_DEVICE_STATE_REASON_CONFIG_FAILED); + } + } +} + /** * add_device: * @self: the #NMManager @@ -1708,42 +1791,14 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con) */ system_create_virtual_devices (self); - /* If the device has a connection it can assume, do that now */ - if (connection) { - NMActiveConnection *active; - NMAuthSubject *subject; - GError *error = NULL; - - nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume connection", - nm_device_get_iface (device)); - - /* Move device to DISCONNECTED to activate the connection */ - nm_device_state_changed (device, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - - subject = nm_auth_subject_new_internal (); - active = _new_active_connection (self, connection, NULL, device, subject, &error); - if (active) { - NMActiveConnection *master_ac = NULL; - - /* If the device is a slave or VLAN, find the master ActiveConnection */ - if (find_master (self, connection, device, NULL, NULL, &master_ac, NULL) && master_ac) - nm_active_connection_set_master (active, master_ac); - - nm_active_connection_set_assumed (active, TRUE); - nm_active_connection_export (active); - active_connection_add (self, active); - nm_device_queue_activation (device, NM_ACT_REQUEST (active)); - g_object_unref (active); - } else { - nm_log_warn (LOGD_DEVICE, "assumed connection %s failed to activate: (%d) %s", - nm_connection_get_path (connection), - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_error_free (error); - } - g_object_unref (subject); + /* If the device has a connection it can assume, do that now. If it's a + * device that we might ever want to assume a connection on, then set that up. + */ + if (connection) + assume_connection (self, device, connection); + if (generate_con) { + g_signal_connect (device, NM_DEVICE_RECHECK_ASSUME, + G_CALLBACK (recheck_assume_connection), self); } }