diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2013-09-20 19:29:38 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2013-09-23 08:29:21 +0200 |
commit | 21a5aaf4fe6934aad2e6c770aa4bdffa3ad29f9d (patch) | |
tree | fdbd5f0e84029773585572a6e8312f7069e35019 | |
parent | d818d9fe065b4baac979abf5c45e0d212ccf908d (diff) | |
download | ModemManager-21a5aaf4fe6934aad2e6c770aa4bdffa3ad29f9d.tar.gz |
huawei: delay processing of network-initiated disconnection
Originally developed by:
Prathmesh Prabhu <pprabhu@chromium.org>
Ben Chan <benchan@chromium.org>
Huawei MU736 prematurely fires a ^NDISSTAT unsolicited message upon a
network-initiated disconnection. The modem can go into a bad state if a
reconnect attempt happens before the disconnection completes. This patch works
around the issue by delaying the reporting of the disconnection.
-rw-r--r-- | plugins/huawei/mm-broadband-bearer-huawei.c | 56 | ||||
-rw-r--r-- | plugins/huawei/mm-broadband-modem-huawei.c | 7 | ||||
-rw-r--r-- | src/mm-bearer.h | 1 |
3 files changed, 61 insertions, 3 deletions
diff --git a/plugins/huawei/mm-broadband-bearer-huawei.c b/plugins/huawei/mm-broadband-bearer-huawei.c index 2d8f0cdd3..deb91caaa 100644 --- a/plugins/huawei/mm-broadband-bearer-huawei.c +++ b/plugins/huawei/mm-broadband-bearer-huawei.c @@ -37,6 +37,8 @@ G_DEFINE_TYPE (MMBroadbandBearerHuawei, mm_broadband_bearer_huawei, MM_TYPE_BROA struct _MMBroadbandBearerHuaweiPrivate { gpointer connect_pending; gpointer disconnect_pending; + /* Tag for the post task for network-initiated disconnect */ + guint network_disconnect_pending_id; }; /*****************************************************************************/ @@ -232,6 +234,11 @@ connect_3gpp_context_step (Connect3gppContext *ctx) return; } + /* Network-initiated disconnect should not be outstanding at this point, + * because it interferes with the connect attempt. + */ + g_assert (ctx->self->priv->network_disconnect_pending_id == 0); + switch (ctx->step) { case CONNECT_3GPP_CONTEXT_STEP_FIRST: { MMBearerIpFamily ip_family; @@ -598,6 +605,11 @@ disconnect_3gpp_context_step (Disconnect3gppContext *ctx) return; case DISCONNECT_3GPP_CONTEXT_STEP_LAST: + if (ctx->self->priv->network_disconnect_pending_id != 0) { + g_source_remove (ctx->self->priv->network_disconnect_pending_id); + ctx->self->priv->network_disconnect_pending_id = 0; + } + /* Clear context */ ctx->self->priv->disconnect_pending = NULL; /* Set data port as result */ @@ -640,6 +652,18 @@ disconnect_3gpp (MMBroadbandBearer *self, /*****************************************************************************/ +static gboolean +network_disconnect_3gpp_delayed (MMBroadbandBearerHuawei *self) +{ + mm_dbg ("Disconnect bearer '%s' on network request.", + mm_bearer_get_path (MM_BEARER (self))); + + self->priv->network_disconnect_pending_id = 0; + mm_bearer_report_connection_status (MM_BEARER (self), + MM_BEARER_CONNECTION_STATUS_DISCONNECTED); + return FALSE; +} + static void report_connection_status (MMBearer *bearer, MMBearerConnectionStatus status) @@ -647,6 +671,7 @@ report_connection_status (MMBearer *bearer, MMBroadbandBearerHuawei *self = MM_BROADBAND_BEARER_HUAWEI (bearer); g_assert (status == MM_BEARER_CONNECTION_STATUS_CONNECTED || + status == MM_BEARER_CONNECTION_STATUS_DISCONNECTING || status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED); /* When a pending connection / disconnection attempt is in progress, we use @@ -664,7 +689,22 @@ report_connection_status (MMBearer *bearer, /* We already use ^NDISSTATQRY? to poll the connection status, so only * handle network-initiated disconnection here. */ - mm_dbg ("Disconnect bearer '%s'", mm_bearer_get_path (MM_BEARER (self))); + if (status == MM_BEARER_CONNECTION_STATUS_DISCONNECTING) { + /* MM_BEARER_CONNECTION_STATUS_DISCONNECTING is used to indicate that the + * reporting of disconnection should be delayed. See MMBroadbandModemHuawei's + * bearer_report_connection_status for details. */ + if (self->priv->network_disconnect_pending_id == 0) { + mm_dbg ("Delay network-initiated disconnection of bearer '%s'", + mm_bearer_get_path (MM_BEARER (self))); + self->priv->network_disconnect_pending_id = (g_timeout_add_seconds ( + 4, + (GSourceFunc) network_disconnect_3gpp_delayed, + self)); + } + return; + } + + /* Report disconnected right away */ MM_BEARER_CLASS (mm_broadband_bearer_huawei_parent_class)->report_connection_status ( bearer, MM_BEARER_CONNECTION_STATUS_DISCONNECTED); @@ -692,6 +732,19 @@ mm_broadband_bearer_huawei_new_finish (GAsyncResult *res, return MM_BEARER (bearer); } +static void +dispose (GObject *object) +{ + MMBroadbandBearerHuawei *self = MM_BROADBAND_BEARER_HUAWEI (object); + + if (self->priv->network_disconnect_pending_id != 0) { + g_source_remove (self->priv->network_disconnect_pending_id); + self->priv->network_disconnect_pending_id = 0; + } + + G_OBJECT_CLASS (mm_broadband_bearer_huawei_parent_class)->dispose (object); +} + void mm_broadband_bearer_huawei_new (MMBroadbandModemHuawei *modem, MMBearerProperties *config, @@ -728,6 +781,7 @@ mm_broadband_bearer_huawei_class_init (MMBroadbandBearerHuaweiClass *klass) g_type_class_add_private (object_class, sizeof (MMBroadbandBearerHuaweiPrivate)); + object_class->dispose = dispose; bearer_class->report_connection_status = report_connection_status; broadband_bearer_class->connect_3gpp = connect_3gpp; broadband_bearer_class->connect_3gpp_finish = connect_3gpp_finish; diff --git a/plugins/huawei/mm-broadband-modem-huawei.c b/plugins/huawei/mm-broadband-modem-huawei.c index f93f5a1c4..4f231df82 100644 --- a/plugins/huawei/mm-broadband-modem-huawei.c +++ b/plugins/huawei/mm-broadband-modem-huawei.c @@ -1525,11 +1525,14 @@ bearer_report_connection_status (MMBearer *bearer, { if (ndisstat_result->ipv4_available) { /* TODO: MMBroadbandBearerHuawei does not currently support IPv6. - * When it does, we should check the IP family associated with each bearer. */ + * When it does, we should check the IP family associated with each bearer. + * + * Also, send DISCONNECTING so that we give some time before actually + * disconnecting the connection */ mm_bearer_report_connection_status (bearer, ndisstat_result->ipv4_connected ? MM_BEARER_CONNECTION_STATUS_CONNECTED : - MM_BEARER_CONNECTION_STATUS_DISCONNECTED); + MM_BEARER_CONNECTION_STATUS_DISCONNECTING); } } diff --git a/src/mm-bearer.h b/src/mm-bearer.h index dc217c505..c1bcaeee0 100644 --- a/src/mm-bearer.h +++ b/src/mm-bearer.h @@ -70,6 +70,7 @@ typedef enum { /*< underscore_name=mm_bearer_status >*/ typedef enum { /*< underscore_name=mm_bearer_connection_status >*/ MM_BEARER_CONNECTION_STATUS_UNKNOWN, MM_BEARER_CONNECTION_STATUS_DISCONNECTED, + MM_BEARER_CONNECTION_STATUS_DISCONNECTING, MM_BEARER_CONNECTION_STATUS_CONNECTED, MM_BEARER_CONNECTION_STATUS_CONNECTION_FAILED, } MMBearerConnectionStatus; |