From 2fe5ebe21cd34bd97b76319496b66fb7be2ef4b7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 26 Feb 2014 13:18:16 -0600 Subject: [PATCH] core: correctly handle pre-activation dependency failure (rh #1069695) Dependencies may fail before the activation actually starts, like when a software device gets removed while the activation is scheduled but before it has started. In these cases, the activation request should fail. --- src/nm-activation-request.c | 25 +++++++++++++++++-------- src/nm-manager.c | 23 ++++++++++++++++++++++- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index 41f1cbf63f..9f9ee0f940 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -308,18 +308,27 @@ device_state_changed (NMActiveConnection *active, NMActiveConnectionState cur_ac_state = nm_active_connection_get_state (active); NMActiveConnectionState ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; - /* Ignore state changes when this activation request is not yet active, but - * handle the DISCONNECTED state correctly. The device clears the - * activation request before sending the state change signal so this - * must be special-cased to ensure the activation request is deactivated. + /* Decide which device state changes to handle when this active connection + * is not the device's current request. Two cases here: (a) the AC is + * pending and not yet active, and (b) the AC was active but the device is + * entering DISCONNECTED state (which clears the device's current AC before + * emitting the state change signal). */ if (NM_ACTIVE_CONNECTION (nm_device_get_act_request (device)) != active) { - if (new_state != NM_DEVICE_STATE_DISCONNECTED) - return; - if (cur_ac_state < NM_ACTIVE_CONNECTION_STATE_ACTIVATING) + /* Some other request is activating; this one must be pending */ + if (new_state >= NM_DEVICE_STATE_PREPARE) return; + else if (new_state == NM_DEVICE_STATE_DISCONNECTED) { + /* This request hasn't started activating yet; the device is + * disconnecting and cleaning up a previous activation request. + */ + if (cur_ac_state < NM_ACTIVE_CONNECTION_STATE_ACTIVATING) + return; - /* Catch device disconnections after this request has been active */ + /* Catch device disconnections after this request has been active */ + } + + /* All states < DISCONNECTED are fatal and handled */ } /* Set NMActiveConnection state based on the device's state */ diff --git a/src/nm-manager.c b/src/nm-manager.c index ee1eea6682..264f8e2a71 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -2611,7 +2611,17 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * device = nm_active_connection_get_device (active); if (!device) { - g_assert (connection_needs_virtual_device (connection)); + if (!connection_needs_virtual_device (connection)) { + NMSettingConnection *s_con = nm_connection_get_setting_connection (connection); + + g_assert (s_con); + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "Unsupported virtual interface type '%s'", + nm_setting_connection_get_connection_type (s_con)); + return FALSE; + } device = system_create_virtual_device (self, connection); if (!device) { @@ -2721,6 +2731,17 @@ _internal_activate_generic (NMManager *self, NMActiveConnection *active, GError NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); gboolean success = FALSE; + /* Ensure activation request is still valid, eg that its device hasn't gone + * away or that some other dependency has not failed. + */ + if (nm_active_connection_get_state (active) >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_DEPENDENCY_FAILED, + "Activation failed because dependencies failed."); + return FALSE; + } + if (NM_IS_VPN_CONNECTION (active)) success = _internal_activate_vpn (self, active, error); else