huawei: delay processing of network-initiated disconnection
Originally developed by: Prathmesh Prabhu <pprabhu@chromium.org> Ben Chan <benchan@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.
This commit is contained in:
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user