diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 4edbe84503..1083274df8 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -5908,6 +5908,26 @@ _carrier_wait_check_act_request_must_queue (NMDevice *self, NMActRequest *req) return TRUE; } +void +nm_device_steal_connection (NMDevice *self, NMConnection *connection) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + _LOGW (LOGD_DEVICE, "disconnecting connection '%s' for new activation request.", + nm_connection_get_id (connection)); + + if ( priv->queued_act_request + && connection == nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (priv->queued_act_request))) + _clear_queued_act_request (priv); + + if ( priv->act_request + && connection == nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (priv->act_request)) + && priv->state < NM_DEVICE_STATE_DEACTIVATING) + nm_device_state_changed (self, + NM_DEVICE_STATE_DEACTIVATING, + NM_DEVICE_STATE_REASON_USER_REQUESTED); +} + void nm_device_queue_activation (NMDevice *self, NMActRequest *req) { @@ -5929,8 +5949,8 @@ nm_device_queue_activation (NMDevice *self, NMActRequest *req) _LOGD (LOGD_DEVICE, "queue activation request waiting for %s", must_queue ? "carrier" : "currently active connection to disconnect"); + /* Deactivate existing activation request first */ if (priv->act_request) { - /* Deactivate existing activation request first */ _LOGI (LOGD_DEVICE, "disconnecting for new activation request."); nm_device_state_changed (self, NM_DEVICE_STATE_DEACTIVATING, @@ -7390,10 +7410,9 @@ _cleanup_ip_pre (NMDevice *self, gboolean deconfigure) } static void -_cleanup_generic_pre (NMDevice *self, gboolean deconfigure) +_cancel_activation (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; /* Clean up when device was deactivated during call to firewall */ if (priv->fw_call) { @@ -7401,6 +7420,20 @@ _cleanup_generic_pre (NMDevice *self, gboolean deconfigure) priv->fw_call = NULL; } + ip_check_gw_ping_cleanup (self); + + /* Break the activation chain */ + activation_source_clear (self, TRUE, AF_INET); + activation_source_clear (self, TRUE, AF_INET6); +} + +static void +_cleanup_generic_pre (NMDevice *self, gboolean deconfigure) +{ + NMConnection *connection; + + _cancel_activation (self); + connection = nm_device_get_connection (self); if ( deconfigure && connection @@ -7410,12 +7443,6 @@ _cleanup_generic_pre (NMDevice *self, gboolean deconfigure) NULL); } - ip_check_gw_ping_cleanup (self); - - /* Break the activation chain */ - activation_source_clear (self, TRUE, AF_INET); - activation_source_clear (self, TRUE, AF_INET6); - /* Clear any queued transitions */ nm_device_queued_state_clear (self); @@ -7951,6 +7978,8 @@ _set_state_full (NMDevice *self, } break; case NM_DEVICE_STATE_DEACTIVATING: + _cancel_activation (self); + if (quitting) { nm_dispatcher_call_sync (DISPATCHER_ACTION_PRE_DOWN, nm_act_request_get_connection (req), diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 479c9bf299..a204bc134f 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -387,6 +387,8 @@ void nm_device_queue_state (NMDevice *self, gboolean nm_device_get_firmware_missing (NMDevice *self); +void nm_device_steal_connection (NMDevice *device, NMConnection *connection); + void nm_device_queue_activation (NMDevice *device, NMActRequest *req); gboolean nm_device_supports_vlans (NMDevice *device); diff --git a/src/nm-manager.c b/src/nm-manager.c index 71e4b4a0fe..6e78dbe6d2 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -2684,7 +2684,7 @@ _internal_activate_vpn (NMManager *self, NMActiveConnection *active, GError **er static gboolean _internal_activate_device (NMManager *self, NMActiveConnection *active, GError **error) { - NMDevice *device, *master_device = NULL; + NMDevice *device, *existing, *master_device = NULL; NMConnection *connection; NMConnection *master_connection = NULL; NMActiveConnection *master_ac = NULL; @@ -2836,6 +2836,11 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * nm_active_connection_get_path (master_ac)); } + /* Disconnect the connection if connected or queued on another device */ + existing = nm_manager_get_connection_device (self, connection); + if (existing) + nm_device_steal_connection (existing, connection); + /* Export the new ActiveConnection to clients and start it on the device */ nm_active_connection_export (active); g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS); @@ -2873,6 +2878,7 @@ _internal_activate_generic (NMManager *self, NMActiveConnection *active, GError * is exported, make sure the manager's activating-connection property * is up-to-date. */ + active_connection_add (self, active); policy_activating_device_changed (G_OBJECT (priv->policy), NULL, self); } @@ -2942,18 +2948,6 @@ _new_active_connection (NMManager *self, return NULL; } - if (existing_ac) { - NMDevice *existing_device = nm_active_connection_get_device (existing_ac); - - if (existing_device != device) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_ALREADY_ACTIVE, - "Connection '%s' is already active on %s", - nm_connection_get_id (connection), - nm_device_get_iface (existing_device)); - return NULL; - } - } - /* Normalize the specific object */ if (specific_object && g_strcmp0 (specific_object, "/") == 0) specific_object = NULL; @@ -2985,7 +2979,6 @@ _internal_activation_failed (NMManager *self, nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING); nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED); } - active_connection_remove (self, active); } static void @@ -3063,10 +3056,8 @@ nm_manager_activate_connection (NMManager *self, device, subject, error); - if (active) { + if (active) nm_active_connection_authorize (active, _internal_activation_auth_done, self, NULL); - active_connection_add (self, active); - } return active; } @@ -3313,7 +3304,6 @@ impl_manager_activate_connection (NMManager *self, goto error; nm_active_connection_authorize (active, _activation_auth_done, self, context); - active_connection_add (self, active); g_clear_object (&subject); return; @@ -3391,8 +3381,6 @@ _add_and_activate_auth_done (NMActiveConnection *active, activation_add_done, info); } else { - active_connection_remove (self, active); - g_assert (error_desc); error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, @@ -3499,7 +3487,6 @@ impl_manager_add_and_activate_connection (NMManager *self, goto error; nm_active_connection_authorize (active, _add_and_activate_auth_done, self, context); - active_connection_add (self, active); g_object_unref (connection); g_object_unref (subject); return;