From 4cb97cf66f175857a1910ee926ea61dc507c08e8 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 3 Feb 2015 16:15:37 +0100 Subject: [PATCH] manager: remove a connection from device if we're activating it on another device The connection now might be being activated on another device. Defer the removal until we're sure the activation request will proceed and only add the active connection afterwards. https://bugzilla.gnome.org/show_bug.cgi?id=730492 --- src/devices/nm-device.c | 47 +++++++++++++++++++++++++++++++++-------- src/devices/nm-device.h | 2 ++ src/nm-manager.c | 29 +++++++------------------ 3 files changed, 48 insertions(+), 30 deletions(-) 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;