summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2013-09-20 19:29:38 +0200
committerAleksander Morgado <aleksander@lanedo.com>2013-09-23 08:29:21 +0200
commit21a5aaf4fe6934aad2e6c770aa4bdffa3ad29f9d (patch)
treefdbd5f0e84029773585572a6e8312f7069e35019
parentd818d9fe065b4baac979abf5c45e0d212ccf908d (diff)
downloadModemManager-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.c56
-rw-r--r--plugins/huawei/mm-broadband-modem-huawei.c7
-rw-r--r--src/mm-bearer.h1
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;