This patch updates the NDISDUP check handle for Huawei modem. For Huawei devices, which expose the standard ECM port, at command "^DHCP?" is used to query the IP and DNS address for the connection, At command "^NDISSTATQRY?" is used to query the connection status(connected or disconnected). They have some different. The response of DHCP does not exactly indicate the right connection status in that time. So it is better to send NDISSTATQRY to check the connection status after NDISDUP connect/disconnect, but not DHCP. diff -urpN mm-orig/plugins/huawei/mm-broadband-bearer-huawei.c mm/plugins/huawei/mm-broadband-bearer-huawei.c --- mm-orig/plugins/huawei/mm-broadband-bearer-huawei.c 2013-06-04 20:35:00.000000000 +0800 +++ mm/plugins/huawei/mm-broadband-bearer-huawei.c 2013-06-06 15:46:09.000000000 +0800 @@ -43,7 +43,7 @@ struct _MMBroadbandBearerHuaweiPrivate { typedef enum { CONNECT_3GPP_CONTEXT_STEP_FIRST = 0, CONNECT_3GPP_CONTEXT_STEP_NDISDUP, - CONNECT_3GPP_CONTEXT_STEP_DHCP, + CONNECT_3GPP_CONTEXT_STEP_NDISSTATQRY, CONNECT_3GPP_CONTEXT_STEP_LAST } Connect3gppContextStep; @@ -85,7 +85,7 @@ connect_3gpp_finish (MMBroadbandBearer * static void connect_3gpp_context_step (Connect3gppContext *ctx); static gboolean -connect_retry_dhcp_check_cb (MMBroadbandBearerHuawei *self) +connect_retry_ndisstatqry_check_cb (MMBroadbandBearerHuawei *self) { Connect3gppContext *ctx; @@ -103,44 +103,80 @@ connect_retry_dhcp_check_cb (MMBroadband } static void -connect_dhcp_check_ready (MMBaseModem *modem, +connect_ndisstatqry_check_ready (MMBaseModem *modem, GAsyncResult *res, MMBroadbandBearerHuawei *self) { Connect3gppContext *ctx; - GError *error = NULL; + const gchar *response; ctx = self->priv->connect_pending; g_assert (ctx != NULL); /* Balance refcount */ g_object_unref (self); - - if (!mm_base_modem_at_command_full_finish (modem, res, &error)) { - /* Only retry the DHCP check if we get a mobile equipment error, or if - * the command timed out. */ - if (error->domain == MM_MOBILE_EQUIPMENT_ERROR || - g_error_matches (error, - MM_SERIAL_ERROR, - MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) { - g_error_free (error); + + response = mm_base_modem_at_command_full_finish (modem, res, NULL); + if (!response) { + mm_dbg ("%s: modem doesn't support ndisstatqry command", __func__); + goto failed; + } else { + gchar **ndisstatqry; + gchar **ndisstate; + gchar *status; + guint connect_status; + guint index; + + ndisstatqry = g_strsplit (response, "^NDISSTATQRY:", 0); + if (!ndisstatqry) { + mm_dbg ("%s: No NDISSTATQRY found\n", __func__); + goto failed; + } + for (index = 0; ndisstatqry[index]; index++) { + if (!strstr (ndisstatqry[index], ",")) { + continue; + } + ndisstate = g_strsplit (ndisstatqry[index], ",", 0); + if (!ndisstate) { + mm_dbg ("%s: No state found\n", __func__); + g_strfreev (ndisstatqry); + goto failed; + } + status = g_strstrip (ndisstate[0]); + if (!mm_get_uint_from_str (status, &connect_status)) { + mm_dbg ("%s: Get connect status failed\n", __func__); + g_strfreev (ndisstate); + g_strfreev (ndisstatqry); + goto failed; + } + g_strfreev (ndisstate); + if (connect_status == 1) { + mm_dbg ("%s: connection successfully\n", __func__); + break; + } + } + g_strfreev (ndisstatqry); + if (connect_status != 1) { /* Connect failed */ /* Setup timeout to retry the same step */ g_timeout_add_seconds (1, - (GSourceFunc)connect_retry_dhcp_check_cb, + (GSourceFunc)connect_retry_ndisstatqry_check_cb, g_object_ref (self)); return; } - - /* Fatal error happened; e.g. modem unplugged */ - self->priv->connect_pending = NULL; - g_simple_async_result_take_error (ctx->result, error); - connect_3gpp_context_complete_and_free (ctx); - return; } - + /* Success! */ ctx->step++; connect_3gpp_context_step (ctx); + return; + +failed: + ctx->self->priv->connect_pending = NULL; + g_simple_async_result_set_error (ctx->result, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED, + "Connection attempt not supported"); + connect_3gpp_context_complete_and_free (ctx); } static void @@ -236,7 +272,6 @@ connect_3gpp_context_step (Connect3gppCo connect_3gpp_context_complete_and_free (ctx); return; } - /* Store the context */ ctx->self->priv->connect_pending = ctx; @@ -276,7 +311,7 @@ connect_3gpp_context_step (Connect3gppCo return; } - case CONNECT_3GPP_CONTEXT_STEP_DHCP: + case CONNECT_3GPP_CONTEXT_STEP_NDISSTATQRY: /* Wait for dial up timeout, retries for 60 times * (1s between the retries, so it means 1 minute). * If too many retries, failed @@ -296,12 +331,12 @@ connect_3gpp_context_step (Connect3gppCo ctx->check_count++; mm_base_modem_at_command_full (ctx->modem, ctx->primary, - "^DHCP?", + "^NDISSTATQRY?", 3, FALSE, FALSE, NULL, - (GAsyncReadyCallback)connect_dhcp_check_ready, + (GAsyncReadyCallback)connect_ndisstatqry_check_ready, g_object_ref (ctx->self)); return; @@ -378,7 +413,7 @@ connect_3gpp (MMBroadbandBearer *self, typedef enum { DISCONNECT_3GPP_CONTEXT_STEP_FIRST = 0, DISCONNECT_3GPP_CONTEXT_STEP_NDISDUP, - DISCONNECT_3GPP_CONTEXT_STEP_DHCP, + DISCONNECT_3GPP_CONTEXT_STEP_NDISSTATQRY, DISCONNECT_3GPP_CONTEXT_STEP_LAST } Disconnect3gppContextStep; @@ -413,7 +448,7 @@ disconnect_3gpp_finish (MMBroadbandBeare static void disconnect_3gpp_context_step (Disconnect3gppContext *ctx); static gboolean -disconnect_retry_dhcp_check_cb (MMBroadbandBearerHuawei *self) +disconnect_retry_ndisstatqry_check_cb (MMBroadbandBearerHuawei *self) { Disconnect3gppContext *ctx; @@ -430,11 +465,12 @@ disconnect_retry_dhcp_check_cb (MMBroadb } static void -disconnect_dhcp_check_ready (MMBaseModem *modem, +disconnect_ndisstatqry_check_ready (MMBaseModem *modem, GAsyncResult *res, MMBroadbandBearerHuawei *self) { Disconnect3gppContext *ctx; + const gchar *response; ctx = self->priv->disconnect_pending; g_assert (ctx != NULL); @@ -442,18 +478,68 @@ disconnect_dhcp_check_ready (MMBaseModem /* Balance refcount */ g_object_unref (self); - /* If any response give, we're still connected */ - if (mm_base_modem_at_command_full_finish (modem, res, NULL)) { - /* Setup timeout to retry the same step */ - g_timeout_add_seconds (1, - (GSourceFunc)disconnect_retry_dhcp_check_cb, - g_object_ref (self)); - return; + response = mm_base_modem_at_command_full_finish (modem, res, NULL); + if (!response) { + mm_dbg ("%s: modem doesn't support ndisstatqry command", __func__); + goto failed; + } else { + gchar **ndisstatqry; + gchar **ndisstate; + gchar *status; + guint connect_status; + guint index; + + ndisstatqry = g_strsplit (response, "^NDISSTATQRY:", 0); + if (!ndisstatqry) { + mm_dbg ("%s: No NDISSTATQRY found\n", __func__); + goto failed; + } + for (index = 0; ndisstatqry[index]; index++) { + if (!strstr (ndisstatqry[index], ",")) { + continue; + } + ndisstate = g_strsplit (ndisstatqry[index], ",", 0); + if (!ndisstate) { + mm_dbg ("%s: No state found\n", __func__); + g_strfreev (ndisstatqry); + goto failed; + } + status = g_strstrip (ndisstate[0]); + if (!mm_get_uint_from_str (status, &connect_status)) { + mm_dbg ("%s: Get connect status failed\n", __func__); + g_strfreev (ndisstate); + g_strfreev (ndisstatqry); + goto failed; + } + g_strfreev (ndisstate); + if (connect_status == 1) { + mm_dbg ("%s: connection is still connected\n", __func__); + break; + } + } + g_strfreev (ndisstatqry); + + if (connect_status != 0) { /* Still in connected */ + /* Setup timeout to retry the same step */ + g_timeout_add_seconds (1, + (GSourceFunc)disconnect_retry_ndisstatqry_check_cb, + g_object_ref (self)); + return; + } } /* Success! */ ctx->step++; disconnect_3gpp_context_step (ctx); + return; + +failed: + ctx->self->priv->disconnect_pending = NULL; + g_simple_async_result_set_error (ctx->result, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED, + "Disconnection attempt not supported"); + disconnect_3gpp_context_complete_and_free (ctx); } static void @@ -506,7 +592,7 @@ disconnect_3gpp_context_step (Disconnect g_object_ref (ctx->self)); return; - case DISCONNECT_3GPP_CONTEXT_STEP_DHCP: + case DISCONNECT_3GPP_CONTEXT_STEP_NDISSTATQRY: /* If too many retries (1s of wait between the retries), failed */ if (ctx->check_count > 10) { /* Clear context */ @@ -523,12 +609,12 @@ disconnect_3gpp_context_step (Disconnect ctx->check_count++; mm_base_modem_at_command_full (ctx->modem, ctx->primary, - "^DHCP?", + "^NDISSTATQRY?", 3, FALSE, FALSE, NULL, - (GAsyncReadyCallback)disconnect_dhcp_check_ready, + (GAsyncReadyCallback)disconnect_ndisstatqry_check_ready, g_object_ref (ctx->self)); return;
Attachment:
change_to_ndisstatqry.patch
Description: change_to_ndisstatqry.patch