[RFC PATCH] huawei: handle disconnection via ^NDISSTAT unsolicited message

Ben Chan benchan at chromium.org
Mon Sep 16 16:17:37 PDT 2013


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
refactors and reuses the ^NDISSTATQRY parser code to handle both
^NDISSTAT and ^NDISSTATQRY responses.
---
Hey Aleksander and Dan,

This follows up the discussion on
http://lists.freedesktop.org/archives/modemmanager-devel/2013-September/000236.html

We're not entirely sure whether the ^NDISSTAT unsolicited message can replace
the ^NDISSTATQRY poll for obtaining connection status, so this patch doesn't
particularly address that.

This patch may miss a few corner cases, but it's better to get some feedback
from you at this stage.

There is also one outstanding issue we observe from MU736 that we may need to
delay the invocation of mm_bearer_report_disconnection upon receiving
^NDISSTAT by seconds to tens of second. Otherwise, the modem may run into a
weird state if we try to reconnect too soon.

Thanks,
Ben



 plugins/huawei/mm-broadband-bearer-huawei.c      |  12 +++
 plugins/huawei/mm-broadband-modem-huawei.c       | 100 +++++++++++++++++--
 plugins/huawei/mm-broadband-modem-huawei.h       |   3 +
 plugins/huawei/mm-modem-helpers-huawei.c         |  74 +++++++++++---
 plugins/huawei/mm-modem-helpers-huawei.h         |   8 ++
 plugins/huawei/tests/test-modem-helpers-huawei.c | 120 ++++++++++++++---------
 6 files changed, 245 insertions(+), 72 deletions(-)

diff --git a/plugins/huawei/mm-broadband-bearer-huawei.c b/plugins/huawei/mm-broadband-bearer-huawei.c
index eec37f3..4d79fac 100644
--- a/plugins/huawei/mm-broadband-bearer-huawei.c
+++ b/plugins/huawei/mm-broadband-bearer-huawei.c
@@ -63,6 +63,9 @@ typedef struct {
 static void
 connect_3gpp_context_complete_and_free (Connect3gppContext *ctx)
 {
+    mm_broadband_modem_huawei_ignore_ndisstat_unsolicited_msg (MM_BROADBAND_MODEM_HUAWEI (ctx->modem),
+                                                               FALSE /* ignore */);
+
     g_simple_async_result_complete_in_idle (ctx->result);
     g_object_unref (ctx->cancellable);
     g_object_unref (ctx->result);
@@ -399,6 +402,9 @@ connect_3gpp (MMBroadbandBearer *self,
         return;
     }
 
+    mm_broadband_modem_huawei_ignore_ndisstat_unsolicited_msg (MM_BROADBAND_MODEM_HUAWEI (ctx->modem),
+                                                               TRUE /* ignore */);
+
     /* Run! */
     connect_3gpp_context_step (ctx);
 }
@@ -426,6 +432,9 @@ typedef struct {
 static void
 disconnect_3gpp_context_complete_and_free (Disconnect3gppContext *ctx)
 {
+    mm_broadband_modem_huawei_ignore_ndisstat_unsolicited_msg (MM_BROADBAND_MODEM_HUAWEI (ctx->modem),
+                                                               FALSE /* ignore */);
+
     g_simple_async_result_complete (ctx->result);
     g_object_unref (ctx->result);
     g_object_unref (ctx->primary);
@@ -633,6 +642,9 @@ disconnect_3gpp (MMBroadbandBearer *self,
     g_assert (ctx->self->priv->connect_pending == NULL);
     g_assert (ctx->self->priv->disconnect_pending == NULL);
 
+    mm_broadband_modem_huawei_ignore_ndisstat_unsolicited_msg (MM_BROADBAND_MODEM_HUAWEI (ctx->modem),
+                                                               TRUE /* ignore */);
+
     /* Start! */
     disconnect_3gpp_context_step (ctx);
 }
diff --git a/plugins/huawei/mm-broadband-modem-huawei.c b/plugins/huawei/mm-broadband-modem-huawei.c
index 45bc806..870103b 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;
@@ -96,7 +99,6 @@ struct _MMBroadbandModemHuaweiPrivate {
     GRegex *srvst_regex;
     GRegex *stin_regex;
     GRegex *hcsq_regex;
-    GRegex *ndisstat_regex;
     GRegex *pdpdeact_regex;
     GRegex *ndisend_regex;
     GRegex *rfswitch_regex;
@@ -106,6 +108,8 @@ struct _MMBroadbandModemHuaweiPrivate {
 
     gboolean sysinfoex_supported;
     gboolean sysinfoex_support_checked;
+
+    gboolean ignore_ndisstat_msg;
 };
 
 /*****************************************************************************/
@@ -1509,6 +1513,83 @@ 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)
+{
+    /* We already use ^NDISSTATQRY? to poll the connection status, so we only
+     * handle network-initiated disconnection here. */
+    if (ndisstat_result->ipv4_available && !ndisstat_result->ipv4_connected) {
+        /* TODO: MMBroadbandBearerHuawei does not currently support IPv6.
+         * When it does, we should check the IP family associated with each bearer. */
+        mm_dbg ("Disconnect bearer '%s'", mm_bearer_get_path (bearer));
+        mm_bearer_report_disconnection (bearer);
+    }
+}
+
+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_ndisstat_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");
+
+    /* 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->ignore_ndisstat_msg)
+        return;
+
+    /* 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);
+}
+
+void
+mm_broadband_modem_huawei_ignore_ndisstat_unsolicited_msg (MMBroadbandModemHuawei *self,
+                                                           gboolean ignore)
+{
+    self->priv->ignore_ndisstat_msg = ignore;
+}
+
 static void
 set_3gpp_unsolicited_events_handlers (MMBroadbandModemHuawei *self,
                                       gboolean enable)
@@ -1547,6 +1628,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);
     }
 }
 
@@ -2987,10 +3075,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 (
@@ -3058,6 +3142,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->csnr_regex = g_regex_new ("\\r\\n\\^CSNR:.+\\r\\n",
@@ -3076,8 +3162,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",
@@ -3102,6 +3186,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->csnr_regex);
     g_regex_unref (self->priv->cusatp_regex);
@@ -3111,7 +3196,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-broadband-modem-huawei.h b/plugins/huawei/mm-broadband-modem-huawei.h
index 06874bc..615bbac 100644
--- a/plugins/huawei/mm-broadband-modem-huawei.h
+++ b/plugins/huawei/mm-broadband-modem-huawei.h
@@ -48,4 +48,7 @@ MMBroadbandModemHuawei *mm_broadband_modem_huawei_new (const gchar *device,
                                                        guint16 vendor_id,
                                                        guint16 product_id);
 
+void mm_broadband_modem_huawei_ignore_ndisstat_unsolicited_msg (MMBroadbandModemHuawei *self,
+                                                                gboolean ignore);
+
 #endif /* MM_BROADBAND_MODEM_HUAWEI_H */
diff --git a/plugins/huawei/mm-modem-helpers-huawei.c b/plugins/huawei/mm-modem-helpers-huawei.c
index f5abe57..92812d8 100644
--- a/plugins/huawei/mm-modem-helpers-huawei.c
+++ b/plugins/huawei/mm-modem-helpers-huawei.c
@@ -25,22 +25,28 @@
 /*****************************************************************************/
 /* ^NDISSTATQRY response parser */
 
-gboolean
-mm_huawei_parse_ndisstatqry_response (const gchar *response,
-                                      gboolean *ipv4_available,
-                                      gboolean *ipv4_connected,
-                                      gboolean *ipv6_available,
-                                      gboolean *ipv6_connected,
-                                      GError **error)
+static gboolean
+parse_ndisstat_response (const gchar *response,
+                         const gchar *ndisstat_type,
+                         gboolean *ipv4_available,
+                         gboolean *ipv4_connected,
+                         gboolean *ipv6_available,
+                         gboolean *ipv6_connected,
+                         GError **error)
 {
     GRegex *r;
     GMatchInfo *match_info;
     GError *inner_error = NULL;
+    gchar *prefix;
+    gchar *regex_str;
 
-    if (!response || !g_str_has_prefix (response, "^NDISSTATQRY:")) {
-        g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing ^NDISSTATQRY prefix");
+    prefix = g_strdup_printf ("^%s:", ndisstat_type);
+    if (!response || !g_str_has_prefix (response, prefix)) {
+        g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing %s prefix", prefix);
+        g_free (prefix);
         return FALSE;
     }
+    g_free (prefix);
 
     *ipv4_available = FALSE;
     *ipv6_available = FALSE;
@@ -54,10 +60,12 @@ 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)?",
-                     G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW,
-                     0, NULL);
+    regex_str = g_strdup_printf ("\\^%s:\\s*(\\d),([^,]*),([^,]*),([^,\\r\\n]*)(?:\\r\\n)?"
+                                 "(?:\\^%s:)?\\s*,?(\\d)?,?([^,]*)?,?([^,]*)?,?([^,\\r\\n]*)?(?:\\r\\n)?",
+                                 ndisstat_type,
+                                 ndisstat_type);
+    r = g_regex_new (regex_str, G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW, 0, NULL);
+    g_free (regex_str);
     g_assert (r != NULL);
 
     g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
@@ -78,7 +86,8 @@ 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 ^%s fields",
+                                           ndisstat_type);
             } else if (g_ascii_strcasecmp (ip_type_str, "IPV4") == 0) {
                 *ipv4_available = TRUE;
                 *ipv4_connected = (gboolean)connected;
@@ -98,7 +107,8 @@ 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 ^%s response",
+                                   ndisstat_type);
     }
 
     if (inner_error) {
@@ -108,3 +118,37 @@ mm_huawei_parse_ndisstatqry_response (const gchar *response,
 
     return TRUE;
 }
+
+gboolean
+mm_huawei_parse_ndisstat_response (const gchar *response,
+                                   gboolean *ipv4_available,
+                                   gboolean *ipv4_connected,
+                                   gboolean *ipv6_available,
+                                   gboolean *ipv6_connected,
+                                   GError **error)
+{
+    return parse_ndisstat_response (response,
+                                    "NDISSTAT",
+                                    ipv4_available,
+                                    ipv4_connected,
+                                    ipv6_available,
+                                    ipv6_connected,
+                                    error);
+}
+
+gboolean
+mm_huawei_parse_ndisstatqry_response (const gchar *response,
+                                      gboolean *ipv4_available,
+                                      gboolean *ipv4_connected,
+                                      gboolean *ipv6_available,
+                                      gboolean *ipv6_connected,
+                                      GError **error)
+{
+    return parse_ndisstat_response (response,
+                                    "NDISSTATQRY",
+                                    ipv4_available,
+                                    ipv4_connected,
+                                    ipv6_available,
+                                    ipv6_connected,
+                                    error);
+}
diff --git a/plugins/huawei/mm-modem-helpers-huawei.h b/plugins/huawei/mm-modem-helpers-huawei.h
index cc32087..2e8148b 100644
--- a/plugins/huawei/mm-modem-helpers-huawei.h
+++ b/plugins/huawei/mm-modem-helpers-huawei.h
@@ -19,6 +19,14 @@
 
 #include "glib.h"
 
+/* ^NDISSTAT response parser */
+gboolean mm_huawei_parse_ndisstat_response (const gchar *response,
+                                            gboolean *ipv4_available,
+                                            gboolean *ipv4_connected,
+                                            gboolean *ipv6_available,
+                                            gboolean *ipv6_connected,
+                                            GError **error);
+
 /* ^NDISSTATQRY response parser */
 gboolean mm_huawei_parse_ndisstatqry_response (const gchar *response,
                                                gboolean *ipv4_available,
diff --git a/plugins/huawei/tests/test-modem-helpers-huawei.c b/plugins/huawei/tests/test-modem-helpers-huawei.c
index ea4cd95..3b3d035 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;
@@ -28,74 +28,95 @@ typedef struct {
     gboolean expected_ipv4_connected;
     gboolean expected_ipv6_available;
     gboolean expected_ipv6_connected;
-} NdisstatqryTest;
-
-static const NdisstatqryTest ndisstatqry_tests[] = {
-    { "^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  },
-    { "^NDISSTATQRY: 0,,,IPV6\r\n", FALSE, FALSE, TRUE,  FALSE },
-    { "^NDISSTATQRY: 1,,,IPV4\r\n"
-      "^NDISSTATQRY: 1,,,IPV6\r\n", TRUE,  TRUE,  TRUE,  TRUE  },
-    { "^NDISSTATQRY: 1,,,IPV4\r\n"
-      "^NDISSTATQRY: 0,,,IPV6\r\n", TRUE,  TRUE,  TRUE,  FALSE },
-    { "^NDISSTATQRY: 0,,,IPV4\r\n"
-      "^NDISSTATQRY: 1,,,IPV6\r\n", TRUE,  FALSE, TRUE,  TRUE  },
-    { "^NDISSTATQRY: 0,,,IPV4\r\n"
-      "^NDISSTATQRY: 0,,,IPV6\r\n", TRUE,  FALSE, TRUE,  FALSE },
-    { "^NDISSTATQRY: 1,,,IPV4",     TRUE,  TRUE,  FALSE, FALSE },
-    { "^NDISSTATQRY: 0,,,IPV4",     TRUE,  FALSE, FALSE, FALSE },
-    { "^NDISSTATQRY: 1,,,IPV6",     FALSE, FALSE, TRUE,  TRUE  },
-    { "^NDISSTATQRY: 0,,,IPV6",     FALSE, FALSE, TRUE,  FALSE },
-    { "^NDISSTATQRY: 1,,,IPV4\r\n"
-      "^NDISSTATQRY: 1,,,IPV6",     TRUE,  TRUE,  TRUE,  TRUE  },
-    { "^NDISSTATQRY: 1,,,IPV4\r\n"
-      "^NDISSTATQRY: 0,,,IPV6",     TRUE,  TRUE,  TRUE,  FALSE },
-    { "^NDISSTATQRY: 0,,,IPV4\r\n"
-      "^NDISSTATQRY: 1,,,IPV6",     TRUE,  FALSE, TRUE,  TRUE  },
-    { "^NDISSTATQRY: 0,,,IPV4\r\n"
-      "^NDISSTATQRY: 0,,,IPV6",     TRUE,  FALSE, TRUE,  FALSE },
-    { "^NDISSTATQRY: 1,,,\"IPV4\",1,,,\"IPV6\"",     TRUE,  TRUE,  TRUE,  TRUE  },
-    { "^NDISSTATQRY: 1,,,\"IPV4\",0,,,\"IPV6\"",     TRUE,  TRUE,  TRUE,  FALSE },
-    { "^NDISSTATQRY: 0,,,\"IPV4\",1,,,\"IPV6\"",     TRUE,  FALSE, TRUE,  TRUE  },
-    { "^NDISSTATQRY: 0,,,\"IPV4\",0,,,\"IPV6\"",     TRUE,  FALSE, TRUE,  FALSE },
-    { "^NDISSTATQRY: 1,,,\"IPV4\",1,,,\"IPV6\"\r\n", TRUE,  TRUE,  TRUE,  TRUE  },
-    { "^NDISSTATQRY: 1,,,\"IPV4\",0,,,\"IPV6\"\r\n", TRUE,  TRUE,  TRUE,  FALSE },
-    { "^NDISSTATQRY: 0,,,\"IPV4\",1,,,\"IPV6\"\r\n", TRUE,  FALSE, TRUE,  TRUE  },
-    { "^NDISSTATQRY: 0,,,\"IPV4\",0,,,\"IPV6\"\r\n", TRUE,  FALSE, TRUE,  FALSE },
+} NdisstatTest;
+
+static const NdisstatTest ndisstat_tests[] = {
+    { "1,,,IPV4\r\n", TRUE,  TRUE,  FALSE, FALSE },
+    { "0,,,IPV4\r\n", TRUE,  FALSE, FALSE, FALSE },
+    { "1,,,IPV6\r\n", FALSE, FALSE, TRUE,  TRUE  },
+    { "0,,,IPV6\r\n", FALSE, FALSE, TRUE,  FALSE },
+    { "1,,,IPV4\r\n"
+      "1,,,IPV6\r\n", TRUE,  TRUE,  TRUE,  TRUE  },
+    { "1,,,IPV4\r\n"
+      "0,,,IPV6\r\n", TRUE,  TRUE,  TRUE,  FALSE },
+    { "0,,,IPV4\r\n"
+      "1,,,IPV6\r\n", TRUE,  FALSE, TRUE,  TRUE  },
+    { "0,,,IPV4\r\n"
+      "0,,,IPV6\r\n", TRUE,  FALSE, TRUE,  FALSE },
+    { "1,,,IPV4",     TRUE,  TRUE,  FALSE, FALSE },
+    { "0,,,IPV4",     TRUE,  FALSE, FALSE, FALSE },
+    { "1,,,IPV6",     FALSE, FALSE, TRUE,  TRUE  },
+    { "0,,,IPV6",     FALSE, FALSE, TRUE,  FALSE },
+    { "1,,,IPV4\r\n"
+      "1,,,IPV6",     TRUE,  TRUE,  TRUE,  TRUE  },
+    { "1,,,IPV4\r\n"
+      "0,,,IPV6",     TRUE,  TRUE,  TRUE,  FALSE },
+    { "0,,,IPV4\r\n"
+      "1,,,IPV6",     TRUE,  FALSE, TRUE,  TRUE  },
+    { "0,,,IPV4\r\n"
+      "0,,,IPV6",     TRUE,  FALSE, TRUE,  FALSE },
+    { "1,,,\"IPV4\",1,,,\"IPV6\"",     TRUE,  TRUE,  TRUE,  TRUE  },
+    { "1,,,\"IPV4\",0,,,\"IPV6\"",     TRUE,  TRUE,  TRUE,  FALSE },
+    { "0,,,\"IPV4\",1,,,\"IPV6\"",     TRUE,  FALSE, TRUE,  TRUE  },
+    { "0,,,\"IPV4\",0,,,\"IPV6\"",     TRUE,  FALSE, TRUE,  FALSE },
+    { "1,,,\"IPV4\",1,,,\"IPV6\"\r\n", TRUE,  TRUE,  TRUE,  TRUE  },
+    { "1,,,\"IPV4\",0,,,\"IPV6\"\r\n", TRUE,  TRUE,  TRUE,  FALSE },
+    { "0,,,\"IPV4\",1,,,\"IPV6\"\r\n", TRUE,  FALSE, TRUE,  TRUE  },
+    { "0,,,\"IPV4\",0,,,\"IPV6\"\r\n", TRUE,  FALSE, TRUE,  FALSE },
     { NULL, FALSE, FALSE, FALSE, FALSE }
 };
 
+typedef gboolean (*ParseNdisstatResponseFn) (const gchar *response,
+                                             gboolean *ipv4_available,
+                                             gboolean *ipv4_connected,
+                                             gboolean *ipv6_available,
+                                             gboolean *ipv6_connected,
+                                             GError **error);
+
 static void
-test_ndisstatqry (void)
+test_ndisstat_common (const gchar *ndisstat_type, ParseNdisstatResponseFn parser)
 {
+    gchar *response;
     guint i;
 
-    for (i = 0; ndisstatqry_tests[i].str; i++) {
+    for (i = 0; ndisstat_tests[i].str; i++) {
         GError *error = NULL;
         gboolean ipv4_available;
         gboolean ipv4_connected;
         gboolean ipv6_available;
         gboolean ipv6_connected;
 
-        g_assert (mm_huawei_parse_ndisstatqry_response (
-                      ndisstatqry_tests[i].str,
-                      &ipv4_available,
-                      &ipv4_connected,
-                      &ipv6_available,
-                      &ipv6_connected,
-                      &error) == TRUE);
+        response = g_strdup_printf ("^%s: %s", ndisstat_type, ndisstat_tests[i].str);
+        g_assert (parser (response,
+                          &ipv4_available,
+                          &ipv4_connected,
+                          &ipv6_available,
+                          &ipv6_connected,
+                          &error) == TRUE);
+        g_free (response);
         g_assert_no_error (error);
 
-        g_assert (ipv4_available == ndisstatqry_tests[i].expected_ipv4_available);
+        g_assert (ipv4_available == ndisstat_tests[i].expected_ipv4_available);
         if (ipv4_available)
-            g_assert (ipv4_connected == ndisstatqry_tests[i].expected_ipv4_connected);
-        g_assert (ipv6_available == ndisstatqry_tests[i].expected_ipv6_available);
+            g_assert (ipv4_connected == ndisstat_tests[i].expected_ipv4_connected);
+        g_assert (ipv6_available == ndisstat_tests[i].expected_ipv6_available);
         if (ipv6_available)
-            g_assert (ipv6_connected == ndisstatqry_tests[i].expected_ipv6_connected);
+            g_assert (ipv6_connected == ndisstat_tests[i].expected_ipv6_connected);
     }
 }
 
+static void
+test_ndisstat (void)
+{
+    test_ndisstat_common ("NDISSTAT", mm_huawei_parse_ndisstat_response);
+}
+
+static void
+test_ndisstatqry (void)
+{
+    test_ndisstat_common ("NDISSTATQRY", mm_huawei_parse_ndisstatqry_response);
+}
+
 /*****************************************************************************/
 
 int main (int argc, char **argv)
@@ -105,6 +126,7 @@ int main (int argc, char **argv)
     g_type_init ();
     g_test_init (&argc, &argv, NULL);
 
+    g_test_add_func ("/MM/huawei/ndisstat", test_ndisstat);
     g_test_add_func ("/MM/huawei/ndisstatqry", test_ndisstatqry);
 
     return g_test_run ();
-- 
1.8.4



More information about the ModemManager-devel mailing list