diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2019-11-25 10:40:10 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2019-12-03 08:56:47 +0000 |
commit | 991e615736c1b467d7ab7041f0475297e6ef86d2 (patch) | |
tree | 4f0c7d3d8aa1c51dd3ed9bcfd39efc6d8f4f6cbf | |
parent | ae53b0458bd5ca110c04aef42069e9e7b4cd2af5 (diff) |
bearer-qmi: handle disconnection indications during connection attempts
If a WDS indication is received telling us that the modem is no longer
connected, abort the ongoing connection attempt right away with an
error and cleanup all allocated clients (implicitly disconnecting them
if required)..
Fixes https://gitlab.freedesktop.org/mobile-broadband/ModemManager/issues/155
-rw-r--r-- | src/mm-bearer-qmi.c | 97 |
1 files changed, 75 insertions, 22 deletions
diff --git a/src/mm-bearer-qmi.c b/src/mm-bearer-qmi.c index 295b14fe..1bcb8a0a 100644 --- a/src/mm-bearer-qmi.c +++ b/src/mm-bearer-qmi.c @@ -39,6 +39,10 @@ G_DEFINE_TYPE (MMBearerQmi, mm_bearer_qmi, MM_TYPE_BASE_BEARER) #define GLOBAL_PACKET_DATA_HANDLE 0xFFFFFFFF struct _MMBearerQmiPrivate { + /* Cancellables available during a connection attempt */ + GCancellable *ongoing_connect_user_cancellable; + GCancellable *ongoing_connect_network_cancellable; + /* State kept while connected */ MMPortQmi *qmi; gboolean explicit_qmi_open; @@ -504,9 +508,15 @@ complete_connect (GTask *task, MMBearerConnectResult *result, GError *error) { + ConnectContext *ctx; + g_assert (result || error); g_assert (!(result && error)); + ctx = g_task_get_task_data (task); + g_clear_object (&ctx->self->priv->ongoing_connect_user_cancellable); + g_clear_object (&ctx->self->priv->ongoing_connect_network_cancellable); + if (error) g_task_return_error (task, error); else @@ -1231,12 +1241,13 @@ qmi_port_open_ready (MMPortQmi *qmi, static void connect_context_step (GTask *task) { + MMBearerQmi *self; ConnectContext *ctx; - GCancellable *cancellable; - cancellable = g_task_get_cancellable (task); + self = g_task_get_source_object (task); - if (g_cancellable_is_cancelled (cancellable)) { + g_assert (self->priv->ongoing_connect_user_cancellable); + if (g_cancellable_is_cancelled (self->priv->ongoing_connect_user_cancellable)) { complete_connect (task, NULL, g_error_new (G_IO_ERROR, @@ -1245,6 +1256,16 @@ connect_context_step (GTask *task) return; } + g_assert (self->priv->ongoing_connect_network_cancellable); + if (g_cancellable_is_cancelled (self->priv->ongoing_connect_network_cancellable)) { + complete_connect (task, + NULL, + g_error_new (MM_CORE_ERROR, + MM_CORE_ERROR_ABORTED, + "aborted by the network")); + return; + } + ctx = g_task_get_task_data (task); switch (ctx->step) { @@ -1263,7 +1284,7 @@ connect_context_step (GTask *task) if (!mm_port_qmi_is_open (ctx->qmi)) { mm_port_qmi_open (ctx->qmi, TRUE, - cancellable, + g_task_get_cancellable (task), (GAsyncReadyCallback)qmi_port_open_ready, task); return; @@ -1313,7 +1334,7 @@ connect_context_step (GTask *task) mm_port_qmi_allocate_client (ctx->qmi, QMI_SERVICE_WDS, MM_PORT_QMI_FLAG_WDS_IPV4, - cancellable, + g_task_get_cancellable (task), (GAsyncReadyCallback)qmi_port_allocate_client_ready, task); return; @@ -1336,7 +1357,7 @@ connect_context_step (GTask *task) qmi_client_wds_set_ip_family (ctx->client_ipv4, input, 10, - cancellable, + g_task_get_cancellable (task), (GAsyncReadyCallback)set_ip_family_ready, task); qmi_message_wds_set_ip_family_input_unref (input); @@ -1355,7 +1376,7 @@ connect_context_step (GTask *task) &ctx->packet_service_status_ipv4_indication_id); setup_event_report_unsolicited_events (ctx->self, ctx->client_ipv4, - cancellable, + g_task_get_cancellable (task), (GAsyncReadyCallback) connect_enable_indications_ipv4_ready, task); return; @@ -1368,7 +1389,7 @@ connect_context_step (GTask *task) qmi_client_wds_start_network (ctx->client_ipv4, input, 45, - cancellable, + g_task_get_cancellable (task), (GAsyncReadyCallback)start_network_ready, task); qmi_message_wds_start_network_input_unref (input); @@ -1412,7 +1433,7 @@ connect_context_step (GTask *task) mm_port_qmi_allocate_client (ctx->qmi, QMI_SERVICE_WDS, MM_PORT_QMI_FLAG_WDS_IPV6, - cancellable, + g_task_get_cancellable (task), (GAsyncReadyCallback)qmi_port_allocate_client_ready, task); return; @@ -1437,7 +1458,7 @@ connect_context_step (GTask *task) qmi_client_wds_set_ip_family (ctx->client_ipv6, input, 10, - cancellable, + g_task_get_cancellable (task), (GAsyncReadyCallback)set_ip_family_ready, task); qmi_message_wds_set_ip_family_input_unref (input); @@ -1456,7 +1477,7 @@ connect_context_step (GTask *task) &ctx->packet_service_status_ipv6_indication_id); setup_event_report_unsolicited_events (ctx->self, ctx->client_ipv6, - cancellable, + g_task_get_cancellable (task), (GAsyncReadyCallback) connect_enable_indications_ipv6_ready, task); return; @@ -1469,7 +1490,7 @@ connect_context_step (GTask *task) qmi_client_wds_start_network (ctx->client_ipv6, input, 45, - cancellable, + g_task_get_cancellable (task), (GAsyncReadyCallback)start_network_ready, task); qmi_message_wds_start_network_input_unref (input); @@ -1552,11 +1573,19 @@ connect_context_step (GTask *task) } static void -_connect (MMBaseBearer *self, +cancel_operation_cancellable (GCancellable *cancellable, + GCancellable *operation_cancellable) +{ + g_cancellable_cancel (operation_cancellable); +} + +static void +_connect (MMBaseBearer *_self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { + MMBearerQmi *self = MM_BEARER_QMI (_self); MMBearerProperties *properties = NULL; ConnectContext *ctx; MMBaseModem *modem = NULL; @@ -1565,6 +1594,7 @@ _connect (MMBaseBearer *self, GError *error = NULL; const gchar *apn; GTask *task; + GCancellable *operation_cancellable = NULL; g_object_get (self, MM_BASE_BEARER_MODEM, &modem, @@ -1598,7 +1628,7 @@ _connect (MMBaseBearer *self, } /* Check whether we have an APN */ - apn = mm_bearer_properties_get_apn (mm_base_bearer_peek_config (MM_BASE_BEARER (self))); + apn = mm_bearer_properties_get_apn (mm_base_bearer_peek_config (_self)); /* Is this a 3GPP only modem and no APN was given? If so, error */ if (mm_iface_modem_is_3gpp_only (MM_IFACE_MODEM (modem)) && !apn) { @@ -1643,7 +1673,9 @@ _connect (MMBaseBearer *self, MM_BASE_BEARER_CONFIG, &properties, NULL); - task = g_task_new (self, cancellable, callback, user_data); + operation_cancellable = g_cancellable_new (); + task = g_task_new (self, operation_cancellable, callback, user_data); + g_task_set_check_cancellable (task, FALSE); g_task_set_task_data (task, ctx, (GDestroyNotify)connect_context_free); if (properties) { @@ -1659,7 +1691,7 @@ _connect (MMBaseBearer *self, ip_family == MM_BEARER_IP_FAMILY_ANY) { gchar *ip_family_str; - ip_family = mm_base_bearer_get_default_ip_family (self); + ip_family = mm_base_bearer_get_default_ip_family (_self); ip_family_str = mm_bearer_ip_family_build_string_from_mask (ip_family); mm_dbg ("No specific IP family requested, defaulting to %s", ip_family_str); @@ -1718,10 +1750,27 @@ _connect (MMBaseBearer *self, } } + /* setup network cancellable */ + g_assert (!self->priv->ongoing_connect_network_cancellable); + self->priv->ongoing_connect_network_cancellable = g_cancellable_new (); + g_cancellable_connect (self->priv->ongoing_connect_network_cancellable, + G_CALLBACK (cancel_operation_cancellable), + g_object_ref (operation_cancellable), + g_object_unref); + + /* setup user cancellable */ + g_assert (!self->priv->ongoing_connect_user_cancellable); + self->priv->ongoing_connect_user_cancellable = g_object_ref (cancellable); + g_cancellable_connect (self->priv->ongoing_connect_user_cancellable, + G_CALLBACK (cancel_operation_cancellable), + g_object_ref (operation_cancellable), + g_object_unref); + /* Run! */ connect_context_step (task); out: + g_clear_object (&operation_cancellable); g_clear_object (&qmi); g_clear_object (&data); g_clear_object (&modem); @@ -2004,7 +2053,6 @@ disconnect (MMBaseBearer *_self, ctx->packet_data_handle_ipv6 = self->priv->packet_data_handle_ipv6; ctx->step = DISCONNECT_STEP_FIRST; - task = g_task_new (self, NULL, callback, user_data); g_task_set_task_data (task, ctx, (GDestroyNotify)disconnect_context_free); /* Run! */ @@ -2014,15 +2062,20 @@ disconnect (MMBaseBearer *_self, /*****************************************************************************/ static void -report_connection_status (MMBaseBearer *self, - MMBearerConnectionStatus status) +report_connection_status (MMBaseBearer *_self, + MMBearerConnectionStatus status) { - if (status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED) + MMBearerQmi *self = MM_BEARER_QMI (_self); + + if (status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED) { + /* Cancel any ongoing connection attempt */ + g_cancellable_cancel (self->priv->ongoing_connect_network_cancellable); /* Cleanup all connection related data */ - reset_bearer_connection (MM_BEARER_QMI (self), TRUE, TRUE); + reset_bearer_connection (self, TRUE, TRUE); + } /* Chain up parent's report_connection_status() */ - MM_BASE_BEARER_CLASS (mm_bearer_qmi_parent_class)->report_connection_status (self, status); + MM_BASE_BEARER_CLASS (mm_bearer_qmi_parent_class)->report_connection_status (_self, status); } /*****************************************************************************/ |