[PATCH] broadband-modem-icera: add IPv6 support

Dan Williams dcbw at redhat.com
Mon Feb 17 20:26:28 CET 2014


On Mon, 2014-02-17 at 13:19 -0600, Dan Williams wrote:
> Split out the %IPDPADDR parsing into a helper and add testcases for it,
> and add support for IPv6 handling.  It's likely that the returned IPv6
> address should only be used for neighbor discovery, and that clients
> should listen for IPv6 Router Advertisements to find their IPv6 prefix
> and RDNSS/DNSSD information.

Actually, scratch this, I'll do a v2 since this patch (and existing MM)
require an IPv4 context, but the modems don't care.

Dan

> ---
>  plugins/Makefile.am                            |  17 ++-
>  plugins/icera/mm-broadband-bearer-icera.c      | 164 ++++++---------------
>  plugins/icera/mm-modem-helpers-icera.c         | 196 +++++++++++++++++++++++++
>  plugins/icera/mm-modem-helpers-icera.h         |  28 ++++
>  plugins/icera/tests/test-modem-helpers-icera.c | 158 ++++++++++++++++++++
>  5 files changed, 439 insertions(+), 124 deletions(-)
>  create mode 100644 plugins/icera/mm-modem-helpers-icera.c
>  create mode 100644 plugins/icera/mm-modem-helpers-icera.h
>  create mode 100644 plugins/icera/tests/test-modem-helpers-icera.c
> 
> diff --git a/plugins/Makefile.am b/plugins/Makefile.am
> index 5041ea7..6f40bc2 100644
> --- a/plugins/Makefile.am
> +++ b/plugins/Makefile.am
> @@ -86,21 +86,36 @@ TEST_COMMON_LIBADD_FLAGS = \
>  
>  # Icera-specific support
>  noinst_LTLIBRARIES += libmm-utils-icera.la
>  libmm_utils_icera_la_SOURCES = \
>  	icera/mm-broadband-modem-icera.h \
>  	icera/mm-broadband-modem-icera.c \
>  	icera/mm-broadband-bearer-icera.h \
> -	icera/mm-broadband-bearer-icera.c
> +	icera/mm-broadband-bearer-icera.c \
> +	icera/mm-modem-helpers-icera.c \
> +	icera/mm-modem-helpers-icera.h
>  libmm_utils_icera_la_CPPFLAGS = $(PLUGIN_COMMON_COMPILER_FLAGS)
>  libmm_utils_icera_la_LIBADD = $(GUDEV_LIBS) $(MM_LIBS)
>  
>  ICERA_COMMON_COMPILER_FLAGS = -I$(top_srcdir)/plugins/icera
>  ICERA_COMMON_LIBADD_FLAGS = $(builddir)/libmm-utils-icera.la
>  
> +noinst_PROGRAMS += test-modem-helpers-icera
> +test_modem_helpers_icera_SOURCES = \
> +	icera/mm-modem-helpers-icera.c \
> +	icera/mm-modem-helpers-icera.h \
> +	icera/tests/test-modem-helpers-icera.c
> +test_modem_helpers_icera_CPPFLAGS = \
> +	-I$(top_srcdir)/plugins/icera \
> +	$(PLUGIN_COMMON_COMPILER_FLAGS)
> +test_modem_helpers_icera_LDADD = \
> +       $(top_builddir)/libmm-glib/libmm-glib.la \
> +       $(top_builddir)/src/libmodem-helpers.la
> +test_modem_helpers_icera_LDFLAGS = $(PLUGIN_COMMON_LINKER_FLAGS)
> +
>  ########################################
>  
>  pkglib_LTLIBRARIES = \
>  	libmm-plugin-generic.la \
>  	libmm-plugin-nokia.la \
>  	libmm-plugin-nokia-icera.la \
>  	libmm-plugin-cinterion.la \
> diff --git a/plugins/icera/mm-broadband-bearer-icera.c b/plugins/icera/mm-broadband-bearer-icera.c
> index ad7ca06..c0874d2 100644
> --- a/plugins/icera/mm-broadband-bearer-icera.c
> +++ b/plugins/icera/mm-broadband-bearer-icera.c
> @@ -29,14 +29,15 @@
>  
>  #include "mm-broadband-bearer-icera.h"
>  #include "mm-base-modem-at.h"
>  #include "mm-log.h"
>  #include "mm-modem-helpers.h"
>  #include "mm-error-helpers.h"
>  #include "mm-daemon-enums-types.h"
> +#include "mm-modem-helpers-icera.h"
>  
>  G_DEFINE_TYPE (MMBroadbandBearerIcera, mm_broadband_bearer_icera, MM_TYPE_BROADBAND_BEARER);
>  
>  enum {
>      PROP_0,
>      PROP_DEFAULT_IP_METHOD,
>      PROP_LAST
> @@ -98,172 +99,89 @@ get_ip_config_context_complete_and_free (GetIpConfig3gppContext *ctx)
>      g_object_unref (ctx->result);
>      g_object_unref (ctx->primary);
>      g_object_unref (ctx->modem);
>      g_object_unref (ctx->self);
>      g_free (ctx);
>  }
>  
> +typedef struct {
> +    MMBearerIpConfig *ipv4;
> +    MMBearerIpConfig *ipv6;
> +} IpConfigs;
> +
> +static void
> +ip_configs_free (IpConfigs *configs)
> +{
> +    g_clear_object (&configs->ipv4);
> +    g_clear_object (&configs->ipv6);
> +    g_free (configs);
> +}
> +
>  static gboolean
>  get_ip_config_3gpp_finish (MMBroadbandBearer *self,
>                             GAsyncResult *res,
>                             MMBearerIpConfig **ipv4_config,
>                             MMBearerIpConfig **ipv6_config,
>                             GError **error)
>  {
> -    MMBearerIpConfig *ip_config;
> +    IpConfigs *configs;
>  
>      if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
>          return FALSE;
>  
> -    /* No IPv6 for now */
> -    ip_config = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
> -    *ipv4_config = g_object_ref (ip_config);
> -    *ipv6_config = NULL;
> +    configs = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
> +    *ipv4_config = g_object_ref (configs->ipv4);
> +    *ipv6_config = g_object_ref (configs->ipv6);
>      return TRUE;
>  }
>  
> -#define IPDPADDR_TAG "%IPDPADDR: "
> -
>  static void
>  ip_config_ready (MMBaseModem *modem,
>                   GAsyncResult *res,
>                   GetIpConfig3gppContext *ctx)
>  {
> -    MMBearerIpConfig *ip_config = NULL;
> +    MMBearerIpConfig *ip4_config = NULL;
> +    MMBearerIpConfig *ip6_config = NULL;
>      const gchar *response;
>      GError *error = NULL;
> -    gchar **items;
> -    gchar *dns[3] = { 0 };
> -    guint i;
> -    guint dns_i;
> +    IpConfigs *configs;
>  
>      response = mm_base_modem_at_command_full_finish (MM_BASE_MODEM (modem), res, &error);
>      if (error) {
>          g_simple_async_result_take_error (ctx->result, error);
> -        get_ip_config_context_complete_and_free (ctx);
> -        return;
> +        goto out;
>      }
>  
> -    /* TODO: use a regex to parse this */
> +    if (!mm_icera_parse_ipdpaddr_response (response,
> +                                           ctx->cid,
> +                                           &ip4_config,
> +                                           &ip6_config,
> +                                           &error)) {
> +        g_simple_async_result_take_error (ctx->result, error);
> +        goto out;
> +    }
>  
> -    /* Check result */
> -    if (!g_str_has_prefix (response, IPDPADDR_TAG)) {
> +    if (!ip4_config) {
>          g_simple_async_result_set_error (ctx->result,
>                                           MM_CORE_ERROR,
>                                           MM_CORE_ERROR_FAILED,
> -                                         "Couldn't get IP config: invalid response '%s'",
> +                                         "Couldn't get IP config: couldn't parse response '%s'",
>                                           response);
> -        get_ip_config_context_complete_and_free (ctx);
> -        return;
> +        goto out;
>      }
>  
> -    /* %IPDPADDR: <cid>,<ip>,<gw>,<dns1>,<dns2>[,<nbns1>,<nbns2>[,<??>,<netmask>,<gw>]]
> -     *
> -     * Sierra USB305: %IPDPADDR: 2, 21.93.217.11, 21.93.217.10, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0
> -     * K3805-Z: %IPDPADDR: 2, 21.93.217.11, 21.93.217.10, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0, 255.0.0.0, 255.255.255.0, 21.93.217.10,
> -     */
> -    response = mm_strip_tag (response, IPDPADDR_TAG);
> -    items = g_strsplit (response, ", ", 0);
> -
> -    ip_config = mm_bearer_ip_config_new ();
> -
> -    for (i = 0, dns_i = 0; items[i]; i++) {
> -        if (i == 0) { /* CID */
> -            gint num;
> -
> -            if (!mm_get_int_from_str (items[i], &num) ||
> -                num != ctx->cid) {
> -                error = g_error_new (MM_CORE_ERROR,
> -                                     MM_CORE_ERROR_FAILED,
> -                                     "Unknown CID in IPDPADDR response ("
> -                                     "got %d, expected %d)",
> -                                     (guint) num,
> -                                     ctx->cid);
> -                break;
> -            }
> -        } else if (i == 1) { /* IP address */
> -            guint32 tmp = 0;
> -
> -            if (!inet_pton (AF_INET, items[i], &tmp)) {
> -                mm_warn ("Couldn't parse IP address '%s'", items[i]);
> -                g_clear_object (&ip_config);
> -                break;
> -            }
> -
> -            mm_bearer_ip_config_set_method (ip_config, MM_BEARER_IP_METHOD_STATIC);
> -            mm_bearer_ip_config_set_address (ip_config,  items[i]);
> -        } else if (i == 2) { /* Gateway */
> -            guint32 tmp = 0;
> -
> -            if (!inet_pton (AF_INET, items[i], &tmp)) {
> -                mm_warn ("Couldn't parse gateway address '%s'", items[i]);
> -                g_clear_object (&ip_config);
> -                break;
> -            }
> -
> -            if (tmp)
> -                mm_bearer_ip_config_set_gateway (ip_config, items[i]);
> -        } else if (i == 3 || i == 4) { /* DNS entries */
> -            guint32 tmp = 0;
> -
> -            if (!inet_pton (AF_INET, items[i], &tmp)) {
> -                mm_warn ("Couldn't parse DNS address '%s'", items[i]);
> -                g_clear_object (&ip_config);
> -                break;
> -            }
> -
> -            if (tmp)
> -                dns[dns_i++] = items[i];
> -        } else if (i == 8) { /* Netmask */
> -            guint32 tmp = 0;
> -
> -            if (!inet_pton (AF_INET, items[i], &tmp)) {
> -                mm_warn ("Couldn't parse netmask '%s'", items[i]);
> -                g_clear_object (&ip_config);
> -                break;
> -            }
> -
> -            mm_bearer_ip_config_set_prefix (ip_config, mm_netmask_to_cidr (items[i]));
> -        } else if (i == 9) { /* Duplicate Gateway */
> -            if (!mm_bearer_ip_config_get_gateway (ip_config)) {
> -                guint32 tmp = 0;
> -
> -                if (!inet_pton (AF_INET, items[i], &tmp)) {
> -                    mm_warn ("Couldn't parse (duplicate) gateway address '%s'", items[i]);
> -                    g_clear_object (&ip_config);
> -                    break;
> -                }
> -
> -                if (tmp)
> -                    mm_bearer_ip_config_set_gateway (ip_config, items[i]);
> -            }
> -        }
> -    }
> -
> -    if (!ip_config) {
> -        if (error)
> -            g_simple_async_result_take_error (ctx->result, error);
> -        else
> -            g_simple_async_result_set_error (ctx->result,
> -                                             MM_CORE_ERROR,
> -                                             MM_CORE_ERROR_FAILED,
> -                                             "Couldn't get IP config: couldn't parse response '%s'",
> -                                             response);
> -    } else {
> -        /* If we got DNS entries, set them in the IP config */
> -        if (dns[0])
> -            mm_bearer_ip_config_set_dns (ip_config, (const gchar **)dns);
> -
> -        g_simple_async_result_set_op_res_gpointer (ctx->result,
> -                                                   ip_config,
> -                                                   (GDestroyNotify)g_object_unref);
> -    }
> +    configs = g_new0 (IpConfigs, 1);
> +    configs->ipv4 = ip4_config;
> +    configs->ipv6 = ip6_config;
> +    g_simple_async_result_set_op_res_gpointer (ctx->result,
> +                                               configs,
> +                                               (GDestroyNotify)ip_configs_free);
>  
> +out:
>      get_ip_config_context_complete_and_free (ctx);
> -    g_strfreev (items);
>  }
>  
>  static void
>  get_ip_config_3gpp (MMBroadbandBearer *self,
>                      MMBroadbandModem *modem,
>                      MMPortSerialAt *primary,
>                      MMPortSerialAt *secondary,
> @@ -280,15 +198,15 @@ get_ip_config_3gpp (MMBroadbandBearer *self,
>                                            cid,
>                                            callback,
>                                            user_data);
>  
>      if (ctx->self->priv->default_ip_method == MM_BEARER_IP_METHOD_STATIC) {
>          gchar *command;
>  
> -        command = g_strdup_printf ("%%IPDPADDR=%d", cid);
> +        command = g_strdup_printf ("%%IPDPADDR=%u", cid);
>          mm_base_modem_at_command_full (MM_BASE_MODEM (modem),
>                                         primary,
>                                         command,
>                                         3,
>                                         FALSE,
>                                         FALSE, /* raw */
>                                         NULL, /* cancellable */
> diff --git a/plugins/icera/mm-modem-helpers-icera.c b/plugins/icera/mm-modem-helpers-icera.c
> new file mode 100644
> index 0000000..ef1511f
> --- /dev/null
> +++ b/plugins/icera/mm-modem-helpers-icera.c
> @@ -0,0 +1,196 @@
> +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details:
> + *
> + * Copyright (C) 2012 Google, Inc.
> + * Copyright (C) 2012 - 2013 Aleksander Morgado <aleksander at gnu.org>
> + * Copyright (C) 2014 Dan Williams <dcbw at redhat.com>
> + */
> +
> +#include <string.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <arpa/inet.h>
> +
> +#include <ModemManager.h>
> +#define _LIBMM_INSIDE_MM
> +#include <libmm-glib.h>
> +
> +#include "mm-log.h"
> +#include "mm-modem-helpers.h"
> +#include "mm-modem-helpers-icera.h"
> +
> +/*****************************************************************************/
> +/* %IPDPADDR response parser */
> +
> +#define IPDPADDR_TAG "%IPDPADDR: "
> +
> +gboolean
> +mm_icera_parse_ipdpaddr_response (const gchar *response,
> +                                  guint expected_cid,
> +                                  MMBearerIpConfig **out_ip4_config,
> +                                  MMBearerIpConfig **out_ip6_config,
> +                                  GError **error)
> +{
> +    MMBearerIpConfig *ip4_config = NULL;
> +    MMBearerIpConfig *ip6_config = NULL;
> +    gboolean success;
> +    char **items;
> +    gchar *dns[3] = { 0 };
> +    guint dns_i = 0, num_items;
> +    gint num;
> +    guint32 tmp;
> +
> +    g_return_val_if_fail (out_ip4_config, FALSE);
> +    g_return_val_if_fail (out_ip6_config, FALSE);
> +
> +    if (!response || !g_str_has_prefix (response, "%IPDPADDR:")) {
> +        g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing %%IPDPADDR prefix");
> +        return FALSE;
> +    }
> +
> +    /* %IPDPADDR: <cid>,<ip>,<gw>,<dns1>,<dns2>[,<nbns1>,<nbns2>[,<??>,<netmask>,<gw>]]
> +     * %IPDPADDR: <cid>,<ip>,<gw>,<dns1>,<dns2>,<nbns1>,<nbns2>,<netmask>,<gw>
> +     * %IPDPADDR: <cid>,<ip>,<gw>,<dns1>,<dns2>,<nbns1>,<nbns2>,<??>,<gw>,<ip6>,::,<ip6_dns1>,::,::,::,::,::
> +     *
> +     * Sierra USB305: %IPDPADDR: 2, 21.93.217.11, 21.93.217.10, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0
> +     * K3805-Z: %IPDPADDR: 2, 21.93.217.11, 21.93.217.10, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0, 255.0.0.0, 255.255.255.0, 21.93.217.10,
> +     * Nokia 21M:     %IPDPADDR: 2, 33.196.7.127, 33.196.7.128, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0, 255.0.0.0, 33.196.7.128, fe80::f:9135:5901, ::, fd00:976a::9, ::, ::, ::, ::, ::
> +     */
> +    response = mm_strip_tag (response, IPDPADDR_TAG);
> +    items = g_strsplit (response, ", ", 0);
> +    num_items = g_strv_length (items);
> +
> +    if (num_items < 7) {
> +        g_set_error_literal (error,
> +                             MM_CORE_ERROR,
> +                             MM_CORE_ERROR_FAILED,
> +                             "Malformed IPDPADDR response (not enough items)");
> +        goto out;
> +    }
> +
> +    /* Validate context ID */
> +    if (!mm_get_int_from_str (items[0], &num) ||
> +        num != expected_cid) {
> +        g_set_error (error,
> +                     MM_CORE_ERROR,
> +                     MM_CORE_ERROR_FAILED,
> +                     "Unknown CID in IPDPADDR response (got %d, expected %d)",
> +                     (guint) num,
> +                     expected_cid);
> +        goto out;
> +    }
> +
> +    ip4_config = mm_bearer_ip_config_new ();
> +    mm_bearer_ip_config_set_method (ip4_config, MM_BEARER_IP_METHOD_STATIC);
> +
> +    /* IP address and prefix */
> +    tmp = 0;
> +    if (!inet_pton (AF_INET, items[1], &tmp)) {
> +        mm_warn ("Couldn't parse IPv4 address '%s'", items[1]);
> +        goto out;
> +    }
> +    mm_bearer_ip_config_set_address (ip4_config, items[1]);
> +    /* Default prefix */
> +    mm_bearer_ip_config_set_prefix (ip4_config, 32);
> +
> +    /* Gateway */
> +    tmp = 0;
> +    if (inet_pton (AF_INET, items[2], &tmp) && tmp)
> +        mm_bearer_ip_config_set_gateway (ip4_config, items[2]);
> +    else {
> +        mm_warn ("Couldn't parse gateway address '%s'", items[2]);
> +        goto out;
> +    }
> +
> +    /* DNS */
> +    tmp = 0;
> +    if (inet_pton (AF_INET, items[3], &tmp) && tmp)
> +        dns[dns_i++] = items[3];
> +    else {
> +        mm_warn ("Couldn't parse DNS address '%s'", items[3]);
> +        goto out;
> +    }
> +    tmp = 0;
> +    if (inet_pton (AF_INET, items[4], &tmp) && tmp)
> +        dns[dns_i++] = items[4];
> +    else {
> +        mm_warn ("Couldn't parse DNS address '%s'", items[4]);
> +        goto out;
> +    }
> +    if (dns_i > 0)
> +        mm_bearer_ip_config_set_dns (ip4_config, (const gchar **) dns);
> +
> +    /* Secondary gateway */
> +    if ((num_items >= 9) && !mm_bearer_ip_config_get_gateway (ip4_config)) {
> +        const gchar *gw2 = NULL;
> +
> +        /* Sometimes at position 9 (index 8).  Other times, some subnet-type
> +         * stuff is at position 9 and the gateway is position 10.
> +         */
> +        if (items[8] && !strstr (items[8], "255."))
> +            gw2 = items[8];
> +        else if (items[9] && !strstr (items[9], "255."))
> +            gw2 = items[9];
> +
> +        if (gw2 && inet_pton (AF_INET, gw2, &tmp) && tmp)
> +            mm_bearer_ip_config_set_gateway (ip4_config, gw2);
> +        else {
> +            mm_warn ("Couldn't parse secondary gateway address '%s'",
> +                     gw2 ? gw2 : "(unknown)");
> +            goto out;
> +        }
> +    }
> +
> +    if (num_items >= 12) {
> +        struct in6_addr tmp6 = IN6ADDR_ANY_INIT;
> +
> +        /* It appears that for IPv6 %IPDPADDR returns only the expected
> +         * link-local address and a DNS address, and that to retrieve the
> +         * IPv6 prefix, extra DNS, and search domains, the host must listen
> +         * for IPv6 Router Advertisements on the net port.
> +         */
> +
> +        ip6_config = mm_bearer_ip_config_new ();
> +        mm_bearer_ip_config_set_method (ip6_config, MM_BEARER_IP_METHOD_STATIC);
> +
> +        /* IP address and prefix */
> +        if (!inet_pton (AF_INET6, items[9], &tmp6) &&
> +                !IN6_IS_ADDR_UNSPECIFIED (&tmp6)) {
> +            mm_warn ("Couldn't parse IPv6 address '%s'", items[9]);
> +            goto out;
> +        }
> +        mm_bearer_ip_config_set_address (ip6_config, items[9]);
> +        mm_bearer_ip_config_set_prefix (ip6_config, 128);
> +
> +        /* DNS server */
> +        memset (&tmp6, 0, sizeof (tmp6));
> +        if (inet_pton (AF_INET6, items[11], &tmp6) &&
> +                !IN6_IS_ADDR_UNSPECIFIED (&tmp6)) {
> +            dns[0] = items[11];
> +            dns[1] = NULL;
> +            mm_bearer_ip_config_set_dns (ip6_config, (const gchar **) dns);
> +        } else {
> +            mm_warn ("Couldn't parse DNS address '%s'", items[11]);
> +            goto out;
> +        }
> +    }
> +
> +    success = TRUE;
> +
> +out:
> +    g_strfreev (items);
> +
> +    *out_ip4_config = ip4_config;
> +    *out_ip6_config = ip6_config;
> +    return success;
> +}
> +
> diff --git a/plugins/icera/mm-modem-helpers-icera.h b/plugins/icera/mm-modem-helpers-icera.h
> new file mode 100644
> index 0000000..8a7a87a
> --- /dev/null
> +++ b/plugins/icera/mm-modem-helpers-icera.h
> @@ -0,0 +1,28 @@
> +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details:
> + *
> + * Copyright (C) 2014 Dan Williams <dcbw at redhat.com>
> + */
> +
> +#ifndef MM_MODEM_HELPERS_ICERA_H
> +#define MM_MODEM_HELPERS_ICERA_H
> +
> +#include "glib.h"
> +
> +/* %IPDPADDR response parser */
> +gboolean mm_icera_parse_ipdpaddr_response (const gchar *response,
> +                                           guint expected_cid,
> +                                           MMBearerIpConfig **out_ip4_config,
> +                                           MMBearerIpConfig **out_ip6_config,
> +                                           GError **error);
> +
> +#endif  /* MM_MODEM_HELPERS_HUAWEI_H */
> diff --git a/plugins/icera/tests/test-modem-helpers-icera.c b/plugins/icera/tests/test-modem-helpers-icera.c
> new file mode 100644
> index 0000000..f704c5f
> --- /dev/null
> +++ b/plugins/icera/tests/test-modem-helpers-icera.c
> @@ -0,0 +1,158 @@
> +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details:
> + *
> + * Copyright (C) 2013 Aleksander Morgado <aleksander at gnu.org>
> + * Copyright (C) 2014 Dan Williams <dcbw at redhat.com>
> + */
> +
> +#include <glib.h>
> +#include <glib-object.h>
> +#include <locale.h>
> +
> +#include <ModemManager.h>
> +#define _LIBMM_INSIDE_MM
> +#include <libmm-glib.h>
> +
> +#include "mm-log.h"
> +#include "mm-modem-helpers.h"
> +#include "mm-modem-helpers-icera.h"
> +
> +/*****************************************************************************/
> +/* Test %IPDPADDR responses */
> +
> +typedef struct {
> +    const gchar *str;
> +    const guint expected_cid;
> +
> +    /* IPv4 */
> +    const gchar *ipv4_addr;
> +    const gchar *ipv4_gw;
> +    const gchar *ipv4_dns1;
> +    const gchar *ipv4_dns2;
> +
> +    /* IPv6 */
> +    const gchar *ipv6_addr;
> +    const gchar *ipv6_dns1;
> +} IpdpaddrTest;
> +
> +static const IpdpaddrTest ipdpaddr_tests[] = {
> +    /* Sierra USB305 */
> +    { "%IPDPADDR: 2, 21.93.217.11, 21.93.217.10, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0\r\n", 
> +        2, "21.93.217.11", "21.93.217.10", "10.177.0.34", "10.161.171.220",
> +        NULL, NULL },
> +
> +    /* ZTE/Vodafone K3805-Z */
> +    { "%IPDPADDR: 5, 21.93.217.11, 21.93.217.10, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0, 255.0.0.0, 255.255.255.0, 21.93.217.10,\r\n",
> +        5, "21.93.217.11", "21.93.217.10", "10.177.0.34", "10.161.171.220",
> +        NULL, NULL },
> +
> +    /* Nokia 21M */
> +    { "%IPDPADDR: 1, 33.196.7.127, 33.196.7.128, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0, 255.0.0.0, 33.196.7.128, fe80::f:9135:5901, ::, fd00:976a::9, ::, ::, ::, ::, ::\r\n",
> +        1, "33.196.7.127", "33.196.7.128", "10.177.0.34", "10.161.171.220",
> +        "fe80::f:9135:5901", "fd00:976a::9" },
> +
> +    /* Some development chip (cnsbg.p1001.rev2, CL477342) */
> +    { "%IPDPADDR: 5, 27.107.96.189, 27.107.96.188, 121.242.190.210, 121.242.190.181, 0.0.0.0, 0.0.0.0, 255.255.255.254, 27.107.96.188\r\n",
> +        5, "27.107.96.189", "27.107.96.188", "121.242.190.210", "121.242.190.181",
> +        NULL, NULL },
> +
> +    { NULL }
> +};
> +
> +static void
> +test_ipdpaddr (void)
> +{
> +    guint i;
> +
> +    for (i = 0; ipdpaddr_tests[i].str; i++) {
> +        gboolean success;
> +        GError *error = NULL;
> +        MMBearerIpConfig *ipv4 = NULL;
> +        MMBearerIpConfig *ipv6 = NULL;
> +        const gchar **dns;
> +        guint dnslen;
> +
> +        success = mm_icera_parse_ipdpaddr_response (
> +                        ipdpaddr_tests[i].str,
> +                        ipdpaddr_tests[i].expected_cid,
> +                        &ipv4,
> +                        &ipv6,
> +                        &error);
> +        g_assert_no_error (error);
> +        g_assert (success);
> +
> +        /* IPv4 */
> +        g_assert (ipv4);
> +        g_assert_cmpint (mm_bearer_ip_config_get_method (ipv4), ==, MM_BEARER_IP_METHOD_STATIC);
> +        g_assert_cmpstr (mm_bearer_ip_config_get_address (ipv4), ==, ipdpaddr_tests[i].ipv4_addr);
> +        g_assert_cmpint (mm_bearer_ip_config_get_prefix (ipv4), ==, 32);
> +        g_assert_cmpstr (mm_bearer_ip_config_get_gateway (ipv4), ==, ipdpaddr_tests[i].ipv4_gw);
> +
> +        dns = mm_bearer_ip_config_get_dns (ipv4);
> +        g_assert (dns);
> +        dnslen = g_strv_length ((gchar **) dns);
> +        g_assert_cmpint (dnslen, ==, 2);
> +        g_assert_cmpstr (dns[0], ==, ipdpaddr_tests[i].ipv4_dns1);
> +        g_assert_cmpstr (dns[1], ==, ipdpaddr_tests[i].ipv4_dns2);
> +
> +        /* IPv6 */
> +        if (ipdpaddr_tests[i].ipv6_addr) {
> +            g_assert (ipv6);
> +
> +            g_assert_cmpint (mm_bearer_ip_config_get_method (ipv6), ==, MM_BEARER_IP_METHOD_STATIC);
> +            g_assert_cmpstr (mm_bearer_ip_config_get_address (ipv6), ==, ipdpaddr_tests[i].ipv6_addr);
> +            g_assert_cmpint (mm_bearer_ip_config_get_prefix (ipv6), ==, 128);
> +
> +            dns = mm_bearer_ip_config_get_dns (ipv6);
> +            g_assert (dns);
> +            dnslen = g_strv_length ((gchar **) dns);
> +            g_assert_cmpint (dnslen, ==, 1);
> +            g_assert_cmpstr (dns[0], ==, ipdpaddr_tests[i].ipv6_dns1);
> +        } else {
> +            g_assert (ipv6 == NULL);
> +        }
> +    }
> +}
> +
> +/*****************************************************************************/
> +
> +void
> +_mm_log (const char *loc,
> +         const char *func,
> +         guint32 level,
> +         const char *fmt,
> +         ...)
> +{
> +#if defined ENABLE_TEST_MESSAGE_TRACES
> +    /* Dummy log function */
> +    va_list args;
> +    gchar *msg;
> +
> +    va_start (args, fmt);
> +    msg = g_strdup_vprintf (fmt, args);
> +    va_end (args);
> +    g_print ("%s\n", msg);
> +    g_free (msg);
> +#endif
> +}
> +
> +int main (int argc, char **argv)
> +{
> +    setlocale (LC_ALL, "");
> +
> +    g_type_init ();
> +    g_test_init (&argc, &argv, NULL);
> +
> +    g_test_add_func ("/MM/icera/ipdpaddr", test_ipdpaddr);
> +
> +    return g_test_run ();
> +}




More information about the ModemManager-devel mailing list