diff options
author | Thomas Haller <thaller@redhat.com> | 2014-12-08 12:50:10 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2014-12-11 17:03:27 +0100 |
commit | 01a376011427671caf0acfad96be217a48d1a3a6 (patch) | |
tree | 1837a59772497019c69e6d3ac8e467bc5009c1ba | |
parent | 6a7257ab98c686bce727405eea546e20aa732509 (diff) | |
download | NetworkManager-rh/queue_act_request_no_carrier_rh1079353.tar.gz |
device: accept user activation request while waiting for carrierrh/queue_act_request_no_carrier_rh1079353
-rw-r--r-- | src/devices/nm-device.c | 100 |
1 files changed, 90 insertions, 10 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index dd07d6722e..edd647f3f1 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -208,6 +208,7 @@ typedef struct { guint32 ip4_address; NMActRequest * queued_act_request; + gboolean queued_act_request_is_waiting_for_carrier; NMActRequest * act_request; guint act_source_id; gpointer act_source_func; @@ -335,6 +336,8 @@ static gboolean addrconf6_start_with_link_ready (NMDevice *self); static gboolean dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection); static NMActStageReturn linklocal6_start (NMDevice *self); +static void _wait_carrier_check_queued_act_request (NMDevice *self); + static gboolean nm_device_get_default_unmanaged (NMDevice *self); static void _set_state_full (NMDevice *self, @@ -1109,6 +1112,7 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) g_source_remove (priv->carrier_wait_id); priv->carrier_wait_id = 0; nm_device_remove_pending_action (self, "carrier wait", TRUE); + _wait_carrier_check_queued_act_request (self); } } else if (state <= NM_DEVICE_STATE_DISCONNECTED) { _LOGI (LOGD_DEVICE, "link disconnected"); @@ -5593,12 +5597,71 @@ _device_activate (NMDevice *self, NMActRequest *req) nm_device_activate_schedule_stage1_device_prepare (self); } +static void +_wait_carrier_check_queued_act_request (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMActRequest *queued_req; + + if ( !priv->queued_act_request + || !priv->queued_act_request_is_waiting_for_carrier) + return; + + if (!priv->carrier) { + _LOGD (LOGD_DEVICE, "Cancel queued activation request as we have no carrier after timeout"); + g_clear_object (&priv->queued_act_request); + return; + } + + _LOGD (LOGD_DEVICE, "Activate queued activation request as we now have carrier"); + queued_req = priv->queued_act_request; + priv->queued_act_request = NULL; + _device_activate (self, queued_req); + g_object_unref (queued_req); +} + +static gboolean +_wait_carrier_is_waiting (NMDevice *self, NMActRequest *req) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMConnection *connection; + guint carrier_wait_id; + gboolean is_available_without_wait; + + if (priv->carrier) + return FALSE; + if (priv->carrier_wait_id == 0) + return FALSE; + + connection = nm_act_request_get_connection (req); + + if (!nm_device_connection_is_available (self, connection, TRUE)) { + /* We don't have carrier and are still waiting for it. However, + * device is not available for user-request. That means + * that the activation comes from internal, which only succeeds + * if we have carrier -- or carrier is not required. + * We don't wait. */ + return FALSE; + } + + /* See if we the connection is no longer available, if we fake not to wait. */ + carrier_wait_id = priv->carrier_wait_id; + priv->carrier_wait_id = 0; + is_available_without_wait = nm_device_connection_is_available (self, connection, TRUE); + priv->carrier_wait_id = carrier_wait_id; + + return is_available_without_wait ? FALSE : TRUE; +} + void nm_device_queue_activation (NMDevice *self, NMActRequest *req) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean is_waiting; + + is_waiting = _wait_carrier_is_waiting (self, req); - if (!priv->act_request) { + if (!priv->act_request && !is_waiting) { /* Just activate immediately */ _device_activate (self, req); return; @@ -5607,12 +5670,15 @@ nm_device_queue_activation (NMDevice *self, NMActRequest *req) /* supercede any already-queued request */ g_clear_object (&priv->queued_act_request); priv->queued_act_request = g_object_ref (req); + priv->queued_act_request_is_waiting_for_carrier = is_waiting; - /* Deactivate existing activation request first */ - _LOGI (LOGD_DEVICE, "disconnecting for new activation request."); - nm_device_state_changed (self, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_NONE); + 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, + NM_DEVICE_STATE_REASON_NONE); + } } /* @@ -6154,6 +6220,9 @@ carrier_wait_timeout (gpointer user_data) NM_DEVICE_GET_PRIVATE (self)->carrier_wait_id = 0; nm_device_remove_pending_action (self, "carrier wait", TRUE); + + _wait_carrier_check_queued_act_request (self); + return G_SOURCE_REMOVE; } @@ -6813,13 +6882,23 @@ check_connection_available (NMDevice *self, gboolean for_user_activation_request, const char *specific_object) { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + /* Connections which require a network connection are not available when * the device has no carrier, even with ignore-carrer=TRUE. */ - if (NM_DEVICE_GET_PRIVATE (self)->carrier == FALSE) - return connection_requires_carrier (connection) ? FALSE : TRUE; + if ( priv->carrier + || !connection_requires_carrier (connection)) + return TRUE; - return TRUE; + if ( for_user_activation_request + && priv->carrier_wait_id != 0) { + /* We just upped the interface and still waiting for carrier. + * Accept the external user activation request and queue it. */ + return TRUE; + } + + return FALSE; } void @@ -7530,7 +7609,8 @@ _set_state_full (NMDevice *self, } break; case NM_DEVICE_STATE_DISCONNECTED: - if (priv->queued_act_request) { + if ( priv->queued_act_request + && !priv->queued_act_request_is_waiting_for_carrier) { NMActRequest *queued_req; queued_req = priv->queued_act_request; |