[PATCH] huawei: delay processing of network initiated bearer disconnection

Prathmesh Prabhu pprabhu at chromium.org
Wed Sep 18 18:53:17 PDT 2013


Network initiated bearer disconnection is notified by MU736 through the NDISTAT
unsolicited event. Due to a firmware bug, this event is created prematurely.
This CL delays processing of this event. If the event is handled before the
modem actually disconnects the bearer, a reconnect attempt can leave the modem
in a broken state.
---
 plugins/huawei/mm-broadband-bearer-huawei.c | 53 +++++++++++++++++++++++++++--
 1 file changed, 51 insertions(+), 2 deletions(-)

diff --git a/plugins/huawei/mm-broadband-bearer-huawei.c b/plugins/huawei/mm-broadband-bearer-huawei.c
index 233102f..9207a58 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 */
@@ -638,6 +650,16 @@ disconnect_3gpp (MMBroadbandBearer *self,
 }
 
 /*****************************************************************************/
+/* Disconnect 3GPP on network initiated request */
+
+static gboolean
+network_disconnect_3gpp_delayed (MMBroadbandBearerHuawei *self)
+{
+    mm_dbg ("Disconnect bearer '%s' on network request.", mm_bearer_get_path (MM_BEARER (self)));
+    mm_bearer_report_disconnection (MM_BEARER (self));
+    self->priv->network_disconnect_pending_id = 0;
+    return FALSE;
+}
 
 void
 mm_broadband_bearer_huawei_report_connection_status (MMBroadbandBearerHuawei *self,
@@ -652,8 +674,21 @@ mm_broadband_bearer_huawei_report_connection_status (MMBroadbandBearerHuawei *se
     /* We already use ^NDISSTATQRY? to poll the connection status, so only
      * handle network-initiated disconnection here. */
     if (!connected) {
-        mm_dbg ("Disconnect bearer '%s'", mm_bearer_get_path (MM_BEARER (self)));
-        mm_bearer_report_disconnection (MM_BEARER (self));
+        /* Ignore multiple disconnect signals, while we're still processing one */
+        if (self->priv->network_disconnect_pending_id != 0)
+          return;
+
+        mm_dbg ("Post delayed task to disconnect bearer '%s'", mm_bearer_get_path (MM_BEARER (self)));
+        /* A firmware bug in MU736 causes the network initiated network
+         * disconnect signal to fire prematurely. We must give modem a little
+         * time to actually disconnect the bearer. Otherwise, it is possible to
+         * confuse the modem if a reconnect is attempted too soon.
+         *
+         * Since this is a small timeout, we currently do this for all Huawei modems.
+         */
+        self->priv->network_disconnect_pending_id = g_timeout_add_seconds (4,
+                                                                           (GSourceFunc) network_disconnect_3gpp_delayed,
+                                                                           self);
     }
 }
 
@@ -679,6 +714,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,
@@ -715,6 +763,7 @@ mm_broadband_bearer_huawei_class_init (MMBroadbandBearerHuaweiClass *klass)
 
     g_type_class_add_private (object_class, sizeof (MMBroadbandBearerHuaweiPrivate));
 
+    object_class->dispose = dispose;
     broadband_bearer_class->connect_3gpp = connect_3gpp;
     broadband_bearer_class->connect_3gpp_finish = connect_3gpp_finish;
     broadband_bearer_class->disconnect_3gpp = disconnect_3gpp;
-- 
1.8.4



More information about the ModemManager-devel mailing list