[PATCH v2 2/2] huawei: delay processing of network initiated bearer disconnection
Ben Chan
benchan at chromium.org
Thu Sep 19 01:12:32 PDT 2013
From: Prathmesh Prabhu <pprabhu at chromium.org>
Network initiated bearer disconnection is notified by MU736 through the
NDISTAT unsolicited event. Due to a firmware bug, this event is created
prematurely. This patch 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 | 59 +++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 4 deletions(-)
diff --git a/plugins/huawei/mm-broadband-bearer-huawei.c b/plugins/huawei/mm-broadband-bearer-huawei.c
index 9251622..c6bd8cc 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_status (MM_BEARER (self), MM_BEARER_STATUS_DISCONNECTED);
+ self->priv->network_disconnect_pending_id = 0;
+ return FALSE;
+}
void
mm_broadband_bearer_huawei_report_connection_status (MMBroadbandBearerHuawei *self,
@@ -651,10 +673,25 @@ 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_status (MM_BEARER (self), MM_BEARER_STATUS_DISCONNECTED);
- }
+ if (connected)
+ return;
+
+ /* 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.
+ */
+ mm_bearer_report_status (MM_BEARER (self), MM_BEARER_STATUS_DISCONNECTING);
+ self->priv->network_disconnect_pending_id = g_timeout_add_seconds (4,
+ (GSourceFunc) network_disconnect_3gpp_delayed,
+ self);
}
/*****************************************************************************/
@@ -679,6 +716,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 +765,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