[PATCH v3 2/2] huawei: delay processing of network-initiated disconnection
Ben Chan
benchan at chromium.org
Thu Sep 19 22:14:49 PDT 2013
From: Prathmesh Prabhu <pprabhu at 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.
---
plugins/huawei/mm-broadband-bearer-huawei.c | 59 ++++++++++++++++++++++++++++-
plugins/huawei/mm-broadband-modem-huawei.c | 15 ++++++--
2 files changed, 69 insertions(+), 5 deletions(-)
diff --git a/plugins/huawei/mm-broadband-bearer-huawei.c b/plugins/huawei/mm-broadband-bearer-huawei.c
index c9d9001..5f4612c 100644
--- a/plugins/huawei/mm-broadband-bearer-huawei.c
+++ b/plugins/huawei/mm-broadband-bearer-huawei.c
@@ -36,6 +36,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;
};
/*****************************************************************************/
@@ -231,6 +233,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;
@@ -597,6 +604,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 */
@@ -639,6 +651,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)
@@ -653,11 +677,28 @@ report_connection_status (MMBearer *bearer,
/* We already use ^NDISSTATQRY? to poll the connection status, so only
* handle network-initiated disconnection here. */
- if (status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED) {
- mm_dbg ("Disconnect bearer '%s'", mm_bearer_get_path (MM_BEARER (self)));
+ switch (status) {
+ case 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. */
+ mm_dbg ("Delay network-initiated disconnection of bearer '%s'",
+ mm_bearer_get_path (MM_BEARER (self)));
+ if (self->priv->network_disconnect_pending_id == 0)
+ self->priv->network_disconnect_pending_id = g_timeout_add_seconds (
+ 4,
+ (GSourceFunc) network_disconnect_3gpp_delayed,
+ self);
+ break;
+
+ case MM_BEARER_CONNECTION_STATUS_DISCONNECTED:
MM_BEARER_CLASS (mm_broadband_bearer_huawei_parent_class)->report_connection_status (
bearer,
status);
+ break;
+
+ default:
+ break;
}
}
@@ -683,6 +724,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,
@@ -719,6 +773,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 f93f5a1..8115440 100644
--- a/plugins/huawei/mm-broadband-modem-huawei.c
+++ b/plugins/huawei/mm-broadband-modem-huawei.c
@@ -1523,13 +1523,22 @@ static void
bearer_report_connection_status (MMBearer *bearer,
NdisstatResult *ndisstat_result)
{
+ /* TODO: MMBroadbandBearerHuawei does not currently support IPv6.
+ * When it does, we should check the IP family associated with each 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. */
+ /* A firmware bug in Huawei MU736 causes a ^NDISSTAT unsolicited message
+ * to fire prematurely upon a network-initiated disconnection. The modem
+ * may go into a bad state if we try to reconnect too soon. As a workaround,
+ * we report MM_BEARER_CONNECTION_STATUS_DISCONNECTING instead of
+ * MM_BEARER_CONNECTION_STATUS_DISCONNECTED such that MMBroadbandBearerHuawei's
+ * report_connection_status() will delay the reporting of the connection
+ * status by a few seconds, which is sufficient to ensure that the modem
+ * actually disconnects from the network. Since it is a small delay, we do
+ * this for all Huawei modems. */
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);
}
}
--
1.8.4
More information about the ModemManager-devel
mailing list