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 {
|
struct _MMBroadbandBearerHuaweiPrivate {
|
||||||
gpointer connect_pending;
|
gpointer connect_pending;
|
||||||
gpointer disconnect_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;
|
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) {
|
switch (ctx->step) {
|
||||||
case CONNECT_3GPP_CONTEXT_STEP_FIRST: {
|
case CONNECT_3GPP_CONTEXT_STEP_FIRST: {
|
||||||
MMBearerIpFamily ip_family;
|
MMBearerIpFamily ip_family;
|
||||||
@@ -598,6 +605,11 @@ disconnect_3gpp_context_step (Disconnect3gppContext *ctx)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case DISCONNECT_3GPP_CONTEXT_STEP_LAST:
|
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 */
|
/* Clear context */
|
||||||
ctx->self->priv->disconnect_pending = NULL;
|
ctx->self->priv->disconnect_pending = NULL;
|
||||||
/* Set data port as result */
|
/* 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
|
static void
|
||||||
report_connection_status (MMBearer *bearer,
|
report_connection_status (MMBearer *bearer,
|
||||||
MMBearerConnectionStatus status)
|
MMBearerConnectionStatus status)
|
||||||
@@ -647,6 +671,7 @@ report_connection_status (MMBearer *bearer,
|
|||||||
MMBroadbandBearerHuawei *self = MM_BROADBAND_BEARER_HUAWEI (bearer);
|
MMBroadbandBearerHuawei *self = MM_BROADBAND_BEARER_HUAWEI (bearer);
|
||||||
|
|
||||||
g_assert (status == MM_BEARER_CONNECTION_STATUS_CONNECTED ||
|
g_assert (status == MM_BEARER_CONNECTION_STATUS_CONNECTED ||
|
||||||
|
status == MM_BEARER_CONNECTION_STATUS_DISCONNECTING ||
|
||||||
status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED);
|
status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED);
|
||||||
|
|
||||||
/* When a pending connection / disconnection attempt is in progress, we use
|
/* 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
|
/* We already use ^NDISSTATQRY? to poll the connection status, so only
|
||||||
* handle network-initiated disconnection here. */
|
* 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 (
|
MM_BEARER_CLASS (mm_broadband_bearer_huawei_parent_class)->report_connection_status (
|
||||||
bearer,
|
bearer,
|
||||||
MM_BEARER_CONNECTION_STATUS_DISCONNECTED);
|
MM_BEARER_CONNECTION_STATUS_DISCONNECTED);
|
||||||
@@ -692,6 +732,19 @@ mm_broadband_bearer_huawei_new_finish (GAsyncResult *res,
|
|||||||
return MM_BEARER (bearer);
|
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
|
void
|
||||||
mm_broadband_bearer_huawei_new (MMBroadbandModemHuawei *modem,
|
mm_broadband_bearer_huawei_new (MMBroadbandModemHuawei *modem,
|
||||||
MMBearerProperties *config,
|
MMBearerProperties *config,
|
||||||
@@ -728,6 +781,7 @@ mm_broadband_bearer_huawei_class_init (MMBroadbandBearerHuaweiClass *klass)
|
|||||||
|
|
||||||
g_type_class_add_private (object_class, sizeof (MMBroadbandBearerHuaweiPrivate));
|
g_type_class_add_private (object_class, sizeof (MMBroadbandBearerHuaweiPrivate));
|
||||||
|
|
||||||
|
object_class->dispose = dispose;
|
||||||
bearer_class->report_connection_status = report_connection_status;
|
bearer_class->report_connection_status = report_connection_status;
|
||||||
broadband_bearer_class->connect_3gpp = connect_3gpp;
|
broadband_bearer_class->connect_3gpp = connect_3gpp;
|
||||||
broadband_bearer_class->connect_3gpp_finish = connect_3gpp_finish;
|
broadband_bearer_class->connect_3gpp_finish = connect_3gpp_finish;
|
||||||
|
@@ -1525,11 +1525,14 @@ bearer_report_connection_status (MMBearer *bearer,
|
|||||||
{
|
{
|
||||||
if (ndisstat_result->ipv4_available) {
|
if (ndisstat_result->ipv4_available) {
|
||||||
/* TODO: MMBroadbandBearerHuawei does not currently support IPv6.
|
/* 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,
|
mm_bearer_report_connection_status (bearer,
|
||||||
ndisstat_result->ipv4_connected ?
|
ndisstat_result->ipv4_connected ?
|
||||||
MM_BEARER_CONNECTION_STATUS_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 >*/
|
typedef enum { /*< underscore_name=mm_bearer_connection_status >*/
|
||||||
MM_BEARER_CONNECTION_STATUS_UNKNOWN,
|
MM_BEARER_CONNECTION_STATUS_UNKNOWN,
|
||||||
MM_BEARER_CONNECTION_STATUS_DISCONNECTED,
|
MM_BEARER_CONNECTION_STATUS_DISCONNECTED,
|
||||||
|
MM_BEARER_CONNECTION_STATUS_DISCONNECTING,
|
||||||
MM_BEARER_CONNECTION_STATUS_CONNECTED,
|
MM_BEARER_CONNECTION_STATUS_CONNECTED,
|
||||||
MM_BEARER_CONNECTION_STATUS_CONNECTION_FAILED,
|
MM_BEARER_CONNECTION_STATUS_CONNECTION_FAILED,
|
||||||
} MMBearerConnectionStatus;
|
} MMBearerConnectionStatus;
|
||||||
|
Reference in New Issue
Block a user