device: accept user activation request while waiting for carrier

https://bugzilla.redhat.com/show_bug.cgi?id=1079353
(cherry picked from commit 0bfe635119)
This commit is contained in:
Thomas Haller 2014-12-08 12:50:10 +01:00
parent b6495b5000
commit b8f40f969b
3 changed files with 110 additions and 13 deletions

View file

@ -209,6 +209,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;
@ -337,6 +338,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 _carrier_wait_check_queued_act_request (NMDevice *self);
static gboolean nm_device_get_default_unmanaged (NMDevice *self);
static void _set_state_full (NMDevice *self,
@ -1137,6 +1140,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);
_carrier_wait_check_queued_act_request (self);
}
} else if (state <= NM_DEVICE_STATE_DISCONNECTED) {
_LOGI (LOGD_DEVICE, "link disconnected");
@ -5697,12 +5701,78 @@ _device_activate (NMDevice *self, NMActRequest *req)
nm_device_activate_schedule_stage1_device_prepare (self);
}
static void
_carrier_wait_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;
priv->queued_act_request_is_waiting_for_carrier = FALSE;
if (!priv->carrier) {
_LOGD (LOGD_DEVICE, "Cancel queued activation request as we have no carrier after timeout");
g_clear_object (&priv->queued_act_request);
} else {
_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
_carrier_wait_check_act_request_must_queue (NMDevice *self, NMActRequest *req)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
/* If we have carrier or if we are not waiting for it, the activation
* request is not blocked waiting for carrier. */
if (priv->carrier)
return FALSE;
if (priv->carrier_wait_id == 0)
return FALSE;
connection = nm_act_request_get_connection (req);
if (!nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL, NULL)) {
/* We passed all @flags we have, and no @specific_object.
* This equals maximal availability, if a connection is not available
* in this case, it is not waiting for carrier.
*
* Actually, why are we even trying to activate it? Strange, but whatever
* the reason, don't wait for carrier.
*/
return FALSE;
}
if (nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL & ~_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER, NULL)) {
/* The connection was available with flags ALL, and it is still available
* if we pretend not to wait for carrier. That means that the
* connection is available now, and does not wait for carrier.
*
* Since the flags increase the availability of a connection, when checking
* ALL&~WAITING_CARRIER, it means that we certainly would wait for carrier. */
return FALSE;
}
/* The activation request must wait for carrier. */
return TRUE;
}
void
nm_device_queue_activation (NMDevice *self, NMActRequest *req)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gboolean must_queue;
if (!priv->act_request) {
must_queue = _carrier_wait_check_act_request_must_queue (self, req);
if (!priv->act_request && !must_queue) {
/* Just activate immediately */
_device_activate (self, req);
return;
@ -5711,12 +5781,17 @@ nm_device_queue_activation (NMDevice *self, NMActRequest *req)
/* supercede any already-queued request */
_clear_queued_act_request (priv);
priv->queued_act_request = g_object_ref (req);
priv->queued_act_request_is_waiting_for_carrier = must_queue;
/* 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);
_LOGD (LOGD_DEVICE, "queue activation request waiting for %s", must_queue ? "carrier" : "currently active connection to disconnect");
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);
}
}
/*
@ -6258,6 +6333,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);
_carrier_wait_check_queued_act_request (self);
return G_SOURCE_REMOVE;
}
@ -6843,7 +6921,10 @@ nm_device_check_connection_available (NMDevice *self,
&& nm_device_get_unmanaged_flag (self, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT))
return FALSE;
if ( state < NM_DEVICE_STATE_DISCONNECTED
&& !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE))
&& ( ( !NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)
&& !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE))
|| ( NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)
&& !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER))))
return FALSE;
if (!nm_device_check_connection_compatible (self, connection))
@ -6889,13 +6970,25 @@ check_connection_available (NMDevice *self,
NMDeviceCheckConAvailableFlags flags,
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 ( NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)
&& priv->carrier_wait_id != 0) {
/* The device has no carrier though the connection requires it.
*
* If we are still waiting for carrier, the connection is available
* for an explicit user-request. */
return TRUE;
}
return FALSE;
}
void
@ -7620,7 +7713,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;

View file

@ -93,7 +93,10 @@ typedef enum NMActStageReturn NMActStageReturn;
typedef enum {
NM_DEVICE_CHECK_CON_AVAILABLE_NONE = 0,
NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST = (1L << 0),
_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER = (1L << 0),
_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP = (1L << 1),
NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST = _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER
| _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP,
__NM_DEVICE_CHECK_CON_AVAILABLE_ALL,
NM_DEVICE_CHECK_CON_AVAILABLE_ALL = (((__NM_DEVICE_CHECK_CON_AVAILABLE_ALL - 1) << 1) - 1),

View file

@ -902,7 +902,7 @@ check_connection_available (NMDevice *device,
* activating but the network isn't available let the device recheck
* availability.
*/
if (nm_setting_wireless_get_hidden (s_wifi) || NM_FLAGS_HAS (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST))
if (nm_setting_wireless_get_hidden (s_wifi) || NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP))
return TRUE;
/* check if its visible */