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

Aleksander Morgado aleksander at lanedo.com
Wed Sep 18 02:39:29 PDT 2013


On 18/09/13 10:46, Ben Chan wrote:
> 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.
> ---

Looks good to me now, pushed.

BTW, we should probably define a more generic
"mm_bearer_report_connection_status()" method and let bearer subclasses
of different plugins implement it, in order to handle network-initiated
disconnections.


>  plugins/huawei/mm-broadband-bearer-huawei.c      | 20 ++++++
>  plugins/huawei/mm-broadband-bearer-huawei.h      |  3 +
>  plugins/huawei/mm-broadband-modem-huawei.c       | 83 +++++++++++++++++++++---
>  plugins/huawei/mm-modem-helpers-huawei.c         | 18 +++--
>  plugins/huawei/mm-modem-helpers-huawei.h         |  2 +-
>  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 eec37f3..233102f 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 4c87d9c..3eb0efd 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 73323e2..66ec62d 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 f5abe57..bb977c2 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 cc32087..4d15e8a 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 ea4cd95..8d99215 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  },
> 


-- 
Aleksander


More information about the ModemManager-devel mailing list