[PATCH v5 2/2] huawei: delay processing of network-initiated disconnection

Aleksander Morgado aleksander at lanedo.com
Fri Sep 20 10:29:38 PDT 2013


Originally developed by:
  Prathmesh Prabhu <pprabhu at chromium.org>
  Ben Chan <benchan 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 | 56 ++++++++++++++++++++++++++++-
 plugins/huawei/mm-broadband-modem-huawei.c  |  7 ++--
 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 2d8f0cd..deb91ca 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 f93f5a1..4f231df 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 dc217c5..c1bcaee 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;
--
1.8.3.1


More information about the ModemManager-devel mailing list