summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-12-08 12:50:10 +0100
committerThomas Haller <thaller@redhat.com>2014-12-11 17:03:27 +0100
commit01a376011427671caf0acfad96be217a48d1a3a6 (patch)
tree1837a59772497019c69e6d3ac8e467bc5009c1ba
parent6a7257ab98c686bce727405eea546e20aa732509 (diff)
downloadNetworkManager-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.c100
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;