diff options
author | Ben Chan <benchan@chromium.org> | 2013-09-18 01:46:20 -0700 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2013-09-18 11:37:19 +0200 |
commit | 2b2026421507df561fa329b3d480a7d6476221b9 (patch) | |
tree | 188c294f21048e9a7c729f54ed24c8da6821093b | |
parent | aa74ea1aa64470b2b4ec76dbc707f30fc22e3f83 (diff) |
huawei: handle disconnection via ^NDISSTAT unsolicited message
This patch changes MMBroadbandModemHuawei to use ^NDISSTAT unsolicited
messages to handle network-initiated disconnection. As a ^NDISSTAT
unsolicited message is similar to a ^NDISSTATQRY response, the patch
extends the ^NDISSTATQRY parser code to handle both ^NDISSTAT and
^NDISSTATQRY responses.
-rw-r--r-- | plugins/huawei/mm-broadband-bearer-huawei.c | 20 | ||||
-rw-r--r-- | plugins/huawei/mm-broadband-bearer-huawei.h | 3 | ||||
-rw-r--r-- | plugins/huawei/mm-broadband-modem-huawei.c | 83 | ||||
-rw-r--r-- | plugins/huawei/mm-modem-helpers-huawei.c | 18 | ||||
-rw-r--r-- | plugins/huawei/mm-modem-helpers-huawei.h | 2 | ||||
-rw-r--r-- | plugins/huawei/tests/test-modem-helpers-huawei.c | 34 |
6 files changed, 143 insertions, 17 deletions
diff --git a/plugins/huawei/mm-broadband-bearer-huawei.c b/plugins/huawei/mm-broadband-bearer-huawei.c index eec37f3d..233102f0 100644 --- a/plugins/huawei/mm-broadband-bearer-huawei.c +++ b/plugins/huawei/mm-broadband-bearer-huawei.c @@ -639,6 +639,26 @@ disconnect_3gpp (MMBroadbandBearer *self, /*****************************************************************************/ +void +mm_broadband_bearer_huawei_report_connection_status (MMBroadbandBearerHuawei *self, + gboolean connected) +{ + /* When a pending connection / disconnection attempt is in progress, we use + * ^NDISSTATQRY? to check the connection status and thus temporarily ignore + * ^NDISSTAT unsolicited messages */ + if (self->priv->connect_pending || self->priv->disconnect_pending) + return; + + /* 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_disconnection (MM_BEARER (self)); + } +} + +/*****************************************************************************/ + MMBearer * mm_broadband_bearer_huawei_new_finish (GAsyncResult *res, GError **error) diff --git a/plugins/huawei/mm-broadband-bearer-huawei.h b/plugins/huawei/mm-broadband-bearer-huawei.h index 4c87d9cc..3eb0efd6 100644 --- a/plugins/huawei/mm-broadband-bearer-huawei.h +++ b/plugins/huawei/mm-broadband-bearer-huawei.h @@ -56,4 +56,7 @@ void mm_broadband_bearer_huawei_new (MMBroadbandModemHuawei *modem, MMBearer *mm_broadband_bearer_huawei_new_finish (GAsyncResult *res, GError **error); +void mm_broadband_bearer_huawei_report_connection_status (MMBroadbandBearerHuawei *self, + gboolean connected); + #endif /* MM_BROADBAND_BEARER_HUAWEI_H */ diff --git a/plugins/huawei/mm-broadband-modem-huawei.c b/plugins/huawei/mm-broadband-modem-huawei.c index 73323e26..66ec62de 100644 --- a/plugins/huawei/mm-broadband-modem-huawei.c +++ b/plugins/huawei/mm-broadband-modem-huawei.c @@ -34,6 +34,7 @@ #include "mm-log.h" #include "mm-errors-types.h" #include "mm-modem-helpers.h" +#include "mm-modem-helpers-huawei.h" #include "mm-base-modem-at.h" #include "mm-iface-modem.h" #include "mm-iface-modem-3gpp.h" @@ -43,6 +44,7 @@ #include "mm-broadband-modem-huawei.h" #include "mm-broadband-bearer-huawei.h" #include "mm-broadband-bearer.h" +#include "mm-bearer-list.h" #include "mm-sim-huawei.h" static void iface_modem_init (MMIfaceModem *iface); @@ -85,6 +87,7 @@ struct _MMBroadbandModemHuaweiPrivate { /* Regex for connection status related notifications */ GRegex *dsflowrpt_regex; + GRegex *ndisstat_regex; /* Regex to ignore */ GRegex *boot_regex; @@ -97,7 +100,6 @@ struct _MMBroadbandModemHuaweiPrivate { GRegex *srvst_regex; GRegex *stin_regex; GRegex *hcsq_regex; - GRegex *ndisstat_regex; GRegex *pdpdeact_regex; GRegex *ndisend_regex; GRegex *rfswitch_regex; @@ -1510,6 +1512,68 @@ huawei_status_changed (MMAtSerialPort *port, g_free (str); } +typedef struct { + gboolean ipv4_available; + gboolean ipv4_connected; + gboolean ipv6_available; + gboolean ipv6_connected; +} NdisstatResult; + +static void +bearer_report_connection_status (MMBearer *bearer, + NdisstatResult *ndisstat_result) +{ + 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. */ + mm_broadband_bearer_huawei_report_connection_status (MM_BROADBAND_BEARER_HUAWEI (bearer), + ndisstat_result->ipv4_connected); + } +} + +static void +huawei_ndisstat_changed (MMAtSerialPort *port, + GMatchInfo *match_info, + MMBroadbandModemHuawei *self) +{ + gchar *str; + NdisstatResult ndisstat_result; + GError *error = NULL; + MMBearerList *list = NULL; + + str = g_match_info_fetch (match_info, 1); + if (!mm_huawei_parse_ndisstatqry_response (str, + &ndisstat_result.ipv4_available, + &ndisstat_result.ipv4_connected, + &ndisstat_result.ipv6_available, + &ndisstat_result.ipv6_connected, + &error)) { + mm_dbg ("Ignore invalid ^NDISSTAT unsolicited message: '%s' (error %s)", + str, error->message); + g_error_free (error); + return; + } + + mm_dbg ("NDIS status: IPv4 %s, IPv6 %s", + ndisstat_result.ipv4_available ? + (ndisstat_result.ipv4_connected ? "connected" : "disconnected") : "not available", + ndisstat_result.ipv6_available ? + (ndisstat_result.ipv6_connected ? "connected" : "disconnected") : "not available"); + + /* If empty bearer list, nothing else to do */ + g_object_get (self, + MM_IFACE_MODEM_BEARER_LIST, &list, + NULL); + if (!list) + return; + + mm_bearer_list_foreach (list, + (MMBearerListForeachFunc)bearer_report_connection_status, + &ndisstat_result); + + g_object_unref (list); +} + static void set_3gpp_unsolicited_events_handlers (MMBroadbandModemHuawei *self, gboolean enable) @@ -1548,6 +1612,13 @@ set_3gpp_unsolicited_events_handlers (MMBroadbandModemHuawei *self, enable ? (MMAtSerialUnsolicitedMsgFn)huawei_status_changed : NULL, enable ? self : NULL, NULL); + + mm_at_serial_port_add_unsolicited_msg_handler ( + ports[i], + self->priv->ndisstat_regex, + enable ? (MMAtSerialUnsolicitedMsgFn)huawei_ndisstat_changed : NULL, + enable ? self : NULL, + NULL); } } @@ -2992,10 +3063,6 @@ set_ignored_unsolicited_events_handlers (MMBroadbandModemHuawei *self) NULL, NULL, NULL); mm_at_serial_port_add_unsolicited_msg_handler ( ports[i], - self->priv->ndisstat_regex, - NULL, NULL, NULL); - mm_at_serial_port_add_unsolicited_msg_handler ( - ports[i], self->priv->pdpdeact_regex, NULL, NULL, NULL); mm_at_serial_port_add_unsolicited_msg_handler ( @@ -3063,6 +3130,8 @@ mm_broadband_modem_huawei_init (MMBroadbandModemHuawei *self) G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); self->priv->dsflowrpt_regex = g_regex_new ("\\r\\n\\^DSFLOWRPT:(.+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + self->priv->ndisstat_regex = g_regex_new ("\\r\\n(\\^NDISSTAT:.+)\\r+\\n", + G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); self->priv->boot_regex = g_regex_new ("\\r\\n\\^BOOT:.+\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); self->priv->connect_regex = g_regex_new ("\\r\\n\\^CONNECT .+\\r\\n", @@ -3083,8 +3152,6 @@ mm_broadband_modem_huawei_init (MMBroadbandModemHuawei *self) G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); self->priv->hcsq_regex = g_regex_new ("\\r\\n\\^HCSQ:.+\\r+\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - self->priv->ndisstat_regex = g_regex_new ("\\r\\n\\^NDISSTAT:.+\\r+\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); self->priv->pdpdeact_regex = g_regex_new ("\\r\\n\\^PDPDEACT:.+\\r+\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); self->priv->ndisend_regex = g_regex_new ("\\r\\n\\^NDISEND:.+\\r+\\n", @@ -3109,6 +3176,7 @@ finalize (GObject *object) g_regex_unref (self->priv->hrssilvl_regex); g_regex_unref (self->priv->mode_regex); g_regex_unref (self->priv->dsflowrpt_regex); + g_regex_unref (self->priv->ndisstat_regex); g_regex_unref (self->priv->boot_regex); g_regex_unref (self->priv->connect_regex); g_regex_unref (self->priv->csnr_regex); @@ -3119,7 +3187,6 @@ finalize (GObject *object) g_regex_unref (self->priv->srvst_regex); g_regex_unref (self->priv->stin_regex); g_regex_unref (self->priv->hcsq_regex); - g_regex_unref (self->priv->ndisstat_regex); g_regex_unref (self->priv->pdpdeact_regex); g_regex_unref (self->priv->ndisend_regex); g_regex_unref (self->priv->rfswitch_regex); diff --git a/plugins/huawei/mm-modem-helpers-huawei.c b/plugins/huawei/mm-modem-helpers-huawei.c index f5abe579..bb977c27 100644 --- a/plugins/huawei/mm-modem-helpers-huawei.c +++ b/plugins/huawei/mm-modem-helpers-huawei.c @@ -23,7 +23,7 @@ #include "mm-modem-helpers-huawei.h" /*****************************************************************************/ -/* ^NDISSTATQRY response parser */ +/* ^NDISSTAT / ^NDISSTATQRY response parser */ gboolean mm_huawei_parse_ndisstatqry_response (const gchar *response, @@ -37,8 +37,10 @@ mm_huawei_parse_ndisstatqry_response (const gchar *response, GMatchInfo *match_info; GError *inner_error = NULL; - if (!response || !g_str_has_prefix (response, "^NDISSTATQRY:")) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing ^NDISSTATQRY prefix"); + if (!response || + !(g_str_has_prefix (response, "^NDISSTAT:") || + g_str_has_prefix (response, "^NDISSTATQRY:"))) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing ^NDISSTAT / ^NDISSTATQRY prefix"); return FALSE; } @@ -46,6 +48,8 @@ mm_huawei_parse_ndisstatqry_response (const gchar *response, *ipv6_available = FALSE; /* The response maybe as: + * ^NDISSTAT: 1,,,IPV4 + * ^NDISSTAT: 0,33,,IPV6 * ^NDISSTATQRY: 1,,,IPV4 * ^NDISSTATQRY: 0,33,,IPV6 * OK @@ -54,8 +58,8 @@ mm_huawei_parse_ndisstatqry_response (const gchar *response, * ^NDISSTATQRY:0,,,"IPV4",0,,,"IPV6" * OK */ - r = g_regex_new ("\\^NDISSTATQRY:\\s*(\\d),([^,]*),([^,]*),([^,\\r\\n]*)(?:\\r\\n)?" - "(?:\\^NDISSTATQRY:)?\\s*,?(\\d)?,?([^,]*)?,?([^,]*)?,?([^,\\r\\n]*)?(?:\\r\\n)?", + r = g_regex_new ("\\^NDISSTAT(?:QRY)?:\\s*(\\d),([^,]*),([^,]*),([^,\\r\\n]*)(?:\\r\\n)?" + "(?:\\^NDISSTAT:|\\^NDISSTATQRY:)?\\s*,?(\\d)?,?([^,]*)?,?([^,]*)?,?([^,\\r\\n]*)?(?:\\r\\n)?", G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW, 0, NULL); g_assert (r != NULL); @@ -78,7 +82,7 @@ mm_huawei_parse_ndisstatqry_response (const gchar *response, (connected != 0 && connected != 1)) { inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't parse ^NDISSTATQRY fields"); + "Couldn't parse ^NDISSTAT / ^NDISSTATQRY fields"); } else if (g_ascii_strcasecmp (ip_type_str, "IPV4") == 0) { *ipv4_available = TRUE; *ipv4_connected = (gboolean)connected; @@ -98,7 +102,7 @@ mm_huawei_parse_ndisstatqry_response (const gchar *response, if (!ipv4_available && !ipv6_available) { inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't find IPv4 or IPv6 info in ^NDISSTATQRY response"); + "Couldn't find IPv4 or IPv6 info in ^NDISSTAT / ^NDISSTATQRY response"); } if (inner_error) { diff --git a/plugins/huawei/mm-modem-helpers-huawei.h b/plugins/huawei/mm-modem-helpers-huawei.h index cc32087d..4d15e8ae 100644 --- a/plugins/huawei/mm-modem-helpers-huawei.h +++ b/plugins/huawei/mm-modem-helpers-huawei.h @@ -19,7 +19,7 @@ #include "glib.h" -/* ^NDISSTATQRY response parser */ +/* ^NDISSTAT / ^NDISSTATQRY response parser */ gboolean mm_huawei_parse_ndisstatqry_response (const gchar *response, gboolean *ipv4_available, gboolean *ipv4_connected, diff --git a/plugins/huawei/tests/test-modem-helpers-huawei.c b/plugins/huawei/tests/test-modem-helpers-huawei.c index ea4cd956..8d99215e 100644 --- a/plugins/huawei/tests/test-modem-helpers-huawei.c +++ b/plugins/huawei/tests/test-modem-helpers-huawei.c @@ -20,7 +20,7 @@ #include "mm-modem-helpers-huawei.h" /*****************************************************************************/ -/* Test ^NDISSTATQRY responses */ +/* Test ^NDISSTAT / ^NDISSTATQRY responses */ typedef struct { const gchar *str; @@ -31,6 +31,38 @@ typedef struct { } NdisstatqryTest; static const NdisstatqryTest ndisstatqry_tests[] = { + { "^NDISSTAT: 1,,,IPV4\r\n", TRUE, TRUE, FALSE, FALSE }, + { "^NDISSTAT: 0,,,IPV4\r\n", TRUE, FALSE, FALSE, FALSE }, + { "^NDISSTAT: 1,,,IPV6\r\n", FALSE, FALSE, TRUE, TRUE }, + { "^NDISSTAT: 0,,,IPV6\r\n", FALSE, FALSE, TRUE, FALSE }, + { "^NDISSTAT: 1,,,IPV4\r\n" + "^NDISSTAT: 1,,,IPV6\r\n", TRUE, TRUE, TRUE, TRUE }, + { "^NDISSTAT: 1,,,IPV4\r\n" + "^NDISSTAT: 0,,,IPV6\r\n", TRUE, TRUE, TRUE, FALSE }, + { "^NDISSTAT: 0,,,IPV4\r\n" + "^NDISSTAT: 1,,,IPV6\r\n", TRUE, FALSE, TRUE, TRUE }, + { "^NDISSTAT: 0,,,IPV4\r\n" + "^NDISSTAT: 0,,,IPV6\r\n", TRUE, FALSE, TRUE, FALSE }, + { "^NDISSTAT: 1,,,IPV4", TRUE, TRUE, FALSE, FALSE }, + { "^NDISSTAT: 0,,,IPV4", TRUE, FALSE, FALSE, FALSE }, + { "^NDISSTAT: 1,,,IPV6", FALSE, FALSE, TRUE, TRUE }, + { "^NDISSTAT: 0,,,IPV6", FALSE, FALSE, TRUE, FALSE }, + { "^NDISSTAT: 1,,,IPV4\r\n" + "^NDISSTAT: 1,,,IPV6", TRUE, TRUE, TRUE, TRUE }, + { "^NDISSTAT: 1,,,IPV4\r\n" + "^NDISSTAT: 0,,,IPV6", TRUE, TRUE, TRUE, FALSE }, + { "^NDISSTAT: 0,,,IPV4\r\n" + "^NDISSTAT: 1,,,IPV6", TRUE, FALSE, TRUE, TRUE }, + { "^NDISSTAT: 0,,,IPV4\r\n" + "^NDISSTAT: 0,,,IPV6", TRUE, FALSE, TRUE, FALSE }, + { "^NDISSTAT: 1,,,\"IPV4\",1,,,\"IPV6\"", TRUE, TRUE, TRUE, TRUE }, + { "^NDISSTAT: 1,,,\"IPV4\",0,,,\"IPV6\"", TRUE, TRUE, TRUE, FALSE }, + { "^NDISSTAT: 0,,,\"IPV4\",1,,,\"IPV6\"", TRUE, FALSE, TRUE, TRUE }, + { "^NDISSTAT: 0,,,\"IPV4\",0,,,\"IPV6\"", TRUE, FALSE, TRUE, FALSE }, + { "^NDISSTAT: 1,,,\"IPV4\",1,,,\"IPV6\"\r\n", TRUE, TRUE, TRUE, TRUE }, + { "^NDISSTAT: 1,,,\"IPV4\",0,,,\"IPV6\"\r\n", TRUE, TRUE, TRUE, FALSE }, + { "^NDISSTAT: 0,,,\"IPV4\",1,,,\"IPV6\"\r\n", TRUE, FALSE, TRUE, TRUE }, + { "^NDISSTAT: 0,,,\"IPV4\",0,,,\"IPV6\"\r\n", TRUE, FALSE, TRUE, FALSE }, { "^NDISSTATQRY: 1,,,IPV4\r\n", TRUE, TRUE, FALSE, FALSE }, { "^NDISSTATQRY: 0,,,IPV4\r\n", TRUE, FALSE, FALSE, FALSE }, { "^NDISSTATQRY: 1,,,IPV6\r\n", FALSE, FALSE, TRUE, TRUE }, |