<div dir="ltr"><div>Thanks Aleksander,</div><div><br></div>Verified that the final patch here on top of <div><br></div><div>[PATCH v4 1/2] bearer: consolidate unsolicited connection status reports</div><div><br></div><div>

work correctly w.r.t. Huawei MU736, i.e., connect/disconnect/network initiated disconnect operations all work correctly.</div>
<div class="gmail_extra"><br><br><div class="gmail_quote">On Fri, Sep 20, 2013 at 10:29 AM, Aleksander Morgado <span dir="ltr"><<a href="mailto:aleksander@lanedo.com" target="_blank">aleksander@lanedo.com</a>></span> wrote:<br>


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