<div dir="ltr">Attached is the patch, gmail is the culprit.</div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Aug 29, 2016 at 9:36 AM, Dan Williams <span dir="ltr"><<a href="mailto:dcbw@redhat.com" target="_blank">dcbw@redhat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Sat, 2016-08-27 at 21:36 -0600, matthew stanger wrote:<br>
> Hi,<br>
><br>
> This is my first open source commit! The patch is mainly to support<br>
> the<br>
> PLS8 modems via a SWWAN connection. Please give it a good look over<br>
> and<br>
> give me feedback on what needs to be changed. It's my first time<br>
> using glib<br>
> so please call me out on stupid things I may have done :). This was<br>
> branched off 59f57befa4be81b562f9adfbac39fb<wbr>e19d88c111. Patch is<br>
> below:<br>
<br>
</span>Thanks for the patch!  One issue though, the patch got linewrapped by<br>
your mail client :(  If there's a way to mark all the lines of inline<br>
patch as "preformatted" or something so it doesn't wrap at 80 chars try<br>
that, otherwise you could attach the patch.<br>
<br>
Inline patches are easier to review and make comments on, but if your<br>
email client can't cooperate with linewrapping then an attachment works<br>
too.<br>
<br>
Thanks!<br>
Dan<br>
<div><div class="h5"><br>
> From 281c7c38d1edbf85d2a318b7a5eb7b<wbr>f8d56e2269 Mon Sep 17 00:00:00<br>
> 2001<br>
> From: Matthew Stanger <<a href="mailto:matthew_stanger@trimble.com">matthew_stanger@trimble.com</a>><br>
> Date: Fri, 26 Aug 2016 16:35:49 -0600<br>
> Subject: [PATCH] Features:  Added SWWAN support in Cinterion plugin.<br>
> Updated<br>
>  GPS support for Cinterion modems that use new SGPSC commands.  Added<br>
> LTE<br>
>  status for Cinterion plugin.  Made general Cinterion plugin<br>
> improvements to<br>
>  better support PLS8-X & PLS8-E modems.<br>
><br>
> Known issues:<br>
>  SWWAN connection not tied into mmcli status updates.<br>
>  Unknown logic flow for APN's which require User & Password.<br>
>  No support for IP version.<br>
>  Does not pull IP address from SWWAN into mmcli.<br>
>  Does not auto preform DHCP for SWWAN connection.<br>
>  Dual pdp context connections not yet supported.<br>
>  Simple connect/disconnect does not clean up bearer.<br>
> ---<br>
>  plugins/Makefile.am          <wbr>                      |    2 +<br>
>  plugins/cinterion/77-mm-<wbr>cinterion-port-types.rules |    2 +-<br>
>  plugins/cinterion/mm-<wbr>broadband-bearer-cinterion.c  <wbr>| 1126<br>
> ++++++++++++++++++++<br>
>  plugins/cinterion/mm-<wbr>broadband-bearer-cinterion.h  <wbr>|   56 +<br>
>  plugins/cinterion/mm-<wbr>broadband-modem-cinterion.c   <wbr>|  281 ++++-<br>
>  plugins/cinterion/mm-<wbr>broadband-modem-cinterion.h   <wbr>|    3 +<br>
>  plugins/cinterion/mm-common-<wbr>cinterion.c            |  402 ++++++-<br>
>  plugins/cinterion/mm-modem-<wbr>helpers-cinterion.c     |  188 ++++<br>
>  plugins/cinterion/mm-modem-<wbr>helpers-cinterion.h     |   17 +<br>
>  plugins/cinterion/mm-plugin-<wbr>cinterion.c            |  141 ++-<br>
>  src/mm-base-modem.c          <wbr>                      |   20 +<br>
>  src/mm-base-modem.h          <wbr>                      |    1 +<br>
>  12 files changed, 2183 insertions(+), 56 deletions(-)<br>
>  create mode 100644 plugins/cinterion/mm-<wbr>broadband-bearer-cinterion.c<br>
>  create mode 100644 plugins/cinterion/mm-<wbr>broadband-bearer-cinterion.h<br>
><br>
> diff --git a/plugins/Makefile.am b/plugins/Makefile.am<br>
> index 018b696..744fd18 100644<br>
> --- a/plugins/Makefile.am<br>
> +++ b/plugins/Makefile.am<br>
> @@ -565,6 +565,8 @@ libmm_plugin_cinterion_la_<wbr>SOURCES = \<br>
>   cinterion/mm-common-cinterion.<wbr>h \<br>
>   cinterion/mm-broadband-modem-<wbr>cinterion.c \<br>
>   cinterion/mm-broadband-modem-<wbr>cinterion.h \<br>
> + cinterion/mm-broadband-bearer-<wbr>cinterion.c \<br>
> + cinterion/mm-broadband-bearer-<wbr>cinterion.h \<br>
>   $(NULL)<br>
>  if WITH_QMI<br>
>  libmm_plugin_cinterion_la_<wbr>SOURCES += \<br>
> diff --git a/plugins/cinterion/77-mm-<wbr>cinterion-port-types.rules<br>
> b/plugins/cinterion/77-mm-<wbr>cinterion-port-types.rules<br>
> index 09de742..ee386f0 100644<br>
> --- a/plugins/cinterion/77-mm-<wbr>cinterion-port-types.rules<br>
> +++ b/plugins/cinterion/77-mm-<wbr>cinterion-port-types.rules<br>
> @@ -8,4 +8,4 @@ SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*",<br>
> ENV{.MM_USBIFNUM}="$attr{bInte<br>
><br>
>  ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0053",<br>
> ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_CINTERION_PORT_TYPE_<wbr>GPS}="1"<br>
><br>
> -LABEL="mm_cinterion_port_<wbr>types_end"<br>
> +LABEL="mm_cinterion_port_<wbr>types_end"<br>
> \ No newline at end of file<br>
> diff --git a/plugins/cinterion/mm-<wbr>broadband-bearer-cinterion.c<br>
> b/plugins/cinterion/mm-<wbr>broadband-bearer-cinterion.c<br>
> new file mode 100644<br>
> index 0000000..eb73cf5<br>
> --- /dev/null<br>
> +++ b/plugins/cinterion/mm-<wbr>broadband-bearer-cinterion.c<br>
> @@ -0,0 +1,1126 @@<br>
> +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset:<br>
> 4 -*-<br>
> */<br>
> +/*<br>
> + * This program is free software; you can redistribute it and/or<br>
> modify<br>
> + * it under the terms of the GNU General Public License as published<br>
> by<br>
> + * the Free Software Foundation; either version 2 of the License, or<br>
> + * (at your option) any later version.<br>
> + *<br>
> + * This program is distributed in the hope that it will be useful,<br>
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the<br>
> + * GNU General Public License for more details:<br>
> + *<br>
> + * Copyright (C) 2016 Trimble Navigation Limited<br>
> + * Author: Matthew Stanger <<a href="mailto:matthew_stanger@trimble.com">matthew_stanger@trimble.com</a>><br>
> + */<br>
> +<br>
> +#include <config.h><br>
> +#include <stdio.h><br>
> +#include <stdlib.h><br>
> +#include <unistd.h><br>
> +#include <string.h><br>
> +#include <ctype.h><br>
> +#include <arpa/inet.h><br>
> +#include <ModemManager.h><br>
> +#include "mm-base-modem-at.h"<br>
> +#include "mm-broadband-bearer-<wbr>cinterion.h"<br>
> +#include "mm-log.h"<br>
> +#include "mm-modem-helpers.h"<br>
> +#include "mm-modem-helpers-cinterion.h"<br>
> +#include "mm-daemon-enums-types.h"<br>
> +<br>
> +G_DEFINE_TYPE (MMBroadbandBearerCinterion,<br>
> mm_broadband_bearer_cinterion,<br>
> MM_TYPE_BROADBAND_BEARER);<br>
> +<br>
> +/****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
> +/* Common enums and structs */<br>
> +<br>
> +typedef enum {<br>
> +    MM_BEARER_CINTERION_AUTH_<wbr>UNKNOWN   = -1,<br>
> +    MM_BEARER_CINTERION_AUTH_<wbr>NONE      =  0,<br>
> +    MM_BEARER_CINTERION_AUTH_<wbr>PAP       =  1,<br>
> +    MM_BEARER_CINTERION_AUTH_<wbr>CHAP      =  2,<br>
> +    MM_BEARER_CINTERION_AUTH_<wbr>MSCHAPV2  =  3,<br>
> +} MMBearerCinterionAuthPref;<br>
> +<br>
> +typedef enum {<br>
> +    CONNECTION_UNKNOWN = 0,<br>
> +    CONNECTION_ACTIVE,<br>
> +    CONNECTION_INACTIVE,<br>
> +} SWWAN_USB_CONNECTION_STATE;<br>
> +<br>
> +typedef enum {<br>
> +    CONNECT_3GPP_CONTEXT_<wbr>STEP_INIT = 0,<br>
> +    CONNECT_3GPP_CONTEXT_<wbr>STEP_VERIFY_SWWAN,<br>
> +    CONNECT_3GPP_CONTEXT_<wbr>STEP_BEARER_PROPERTIES,<br>
> +    CONNECT_3GPP_CONTEXT_<wbr>STEP_SET_SWWAN,<br>
> +    CONNECT_3GPP_CONTEXT_<wbr>STEP_CONNECTION_STATUS,<br>
> +    CONNECT_3GPP_CONTEXT_<wbr>STEP_DONE,<br>
> +} Connect3gppContextStep;<br>
> +<br>
> +typedef enum {<br>
> +    DISCONNECT_3GPP_CONTEXT_<wbr>STEP_INIT = 0,<br>
> +    DISCONNECT_3GPP_CONTEXT_<wbr>STEP_SWWAN_DETACH,<br>
> +    DISCONNECT_3GPP_CONTEXT_<wbr>STEP_CONNECTION_STATUS,<br>
> +    DISCONNECT_3GPP_CONTEXT_<wbr>STEP_DONE<br>
> +} Disconnect3gppContextStep;<br>
> +<br>
> +typedef struct {<br>
> +    <wbr>MMBroadbandBearerCinterion *self;<br>
> +    MMBaseModem *modem;<br>
> +    MMPortSerialAt *primary;<br>
> +    MMPort *data;<br>
> +    Connect3gppContextStep connect;<br>
> +    Disconnect3gppContextStep disconnect;<br>
> +    SWWAN_USB_CONNECTION_<wbr>STATE usb0_state;<br>
> +    SWWAN_USB_CONNECTION_<wbr>STATE usb1_state;<br>
> +    MMBearerIpConfig *ipv4_config;<br>
> +    GCancellable *cancellable;<br>
> +    GSimpleAsyncResult *result;<br>
> +} Control3gppContext;<br>
> +<br>
> +struct _<wbr>MMBroadbandBearerCinterionPriv<wbr>ate {<br>
> +    gpointer connect_pending;<br>
> +    gpointer disconnect_pending;<br>
> +    guint network_disconnect_pending_id;<wbr>/* Tag for the post task for<br>
> network-initiated disconnect */<br>
> +    const gchar *bearer_interface;<br>
> +    const gchar *pdp_cid;<br>
> +    guint retry_count;<br>
> +    guint swwan_read_write;<br>
> +};<br>
> +<br>
> +/****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
> +/* Common 3GPP Function Declarations */<br>
> +static void connect_3gpp_context_step (Control3gppContext *ctx);<br>
> +static void disconnect_3gpp_context_step (Control3gppContext *ctx);<br>
> +static void connect_3gpp_context_complete_<wbr>and_free<br>
> (Control3gppContext<br>
> *ctx);<br>
> +static void disconnect_3gpp_context_<wbr>complete_and_free<br>
> (Control3gppContext<br>
> *ctx);<br>
> +<br>
> +/****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
> +/* Common 3GPP */<br>
> +<br>
> +static MMPortSerialAt *<br>
> +get_dial_port (MMBroadbandModemCinterion *modem,<br>
> +               MMPort        <wbr>         *data,<br>
> +               <wbr>MMPortSerialAt         *<wbr>primary)<br>
> +{<br>
> +   //Use only the primary port for sending AT commands.<br>
> +    return g_object_ref (primary);<br>
> +}<br>
> +<br>
> +static void<br>
> +cinterion_3gpp_state_machine_<wbr>logic (MMBroadbandBearerCinterion<br>
> *self)<br>
> +{<br>
> +    Control3gppContext *ctx;<br>
> +<br>
> +    //For connecting flows.<br>
> +    if (self->priv->connect_pending != NULL)<br>
> +    {<br>
> +        ctx = self->priv->connect_pending;<br>
> +<br>
> +        switch (ctx->connect) {<br>
> +<br>
> +        //Always go from INIT to VERIFY_SWWAN.<br>
> +        case CONNECT_3GPP_CONTEXT_STEP_<wbr>INIT: {<br>
> +            ctx->connect = CONNECT_3GPP_CONTEXT_STEP_<wbr>VERIFY_SWWAN;<br>
> +            break;<br>
> +        }<br>
> +<br>
> +        //Always go from VERIFY_SWWAN to BEARER_PROPERTIES.<br>
> +        case CONNECT_3GPP_CONTEXT_STEP_<wbr>VERIFY_SWWAN: {<br>
> +            //Only try 5 times to check the connection then give up.<br>
> +            if (self->priv->retry_count > 5)<br>
> +            {<br>
> +                g_simple_<wbr>async_result_set_error (ctx->result,<br>
> +                             <wbr>                    MM_CORE_<wbr>ERROR,<br>
> +                             <wbr>                    MM_CORE_<wbr>ERROR_TOO_M<br>
> ANY,<br>
> +                             <wbr>                    "Unknown bearer<br>
> state<br>
> during connection attempt.");<br>
> +<br>
> +                connect_3gpp_<wbr>context_complete_and_free (ctx);<br>
> +                return;<br>
> +            }<br>
> +            self->priv-><wbr>retry_count++;<br>
> +            ctx->connect =<br>
> CONNECT_3GPP_CONTEXT_STEP_<wbr>BEARER_PROPERTIES;<br>
> +            break;<br>
> +        }<br>
> +<br>
> +        //When in this state we can be setting up a brand new<br>
> connection<br>
> or,<br>
> +        //have just torn down a connection to setup a new one.<br>
> +        case CONNECT_3GPP_CONTEXT_STEP_<wbr>BEARER_PROPERTIES: {<br>
> +            //We were connected (flags still set) & just issued<br>
> SWWAN<br>
> disconnect.<br>
> +            //Now refresh our usb connection state & retry.<br>
> +            //TODO: Rework for dual sim connections.<br>
> +            if (ctx->usb0_state == CONNECTION_ACTIVE || ctx-<br>
> >usb1_state ==<br>
> CONNECTION_ACTIVE)<br>
> +            {<br>
> +                ctx->connect =<br>
> CONNECT_3GPP_CONTEXT_STEP_<wbr>VERIFY_SWWAN;<br>
> +            }<br>
> +            //There is no active connection and we set the context<br>
> correctly so continue to active SWWAN.<br>
> +            else if (ctx->usb0_state == CONNECTION_INACTIVE ||<br>
> ctx->usb1_state == CONNECTION_INACTIVE)<br>
> +                ctx->connect = CONNECT_3GPP_CONTEXT_STEP_SET_<wbr>SWWAN;<br>
> +            else<br>
> +            {<br>
> +                //Error, should be impossible to get here. State<br>
> machine<br>
> broken.<br>
> +                ctx->self-><wbr>priv->connect_pending = NULL;<br>
> +                g_simple_<wbr>async_result_set_error (ctx->result,<br>
> +                             <wbr>                    MM_CORE_<wbr>ERROR,<br>
> +                             <wbr>                    MM_CORE_<wbr>ERROR_WRONG<br>
> _STATE,<br>
> +                             <wbr>                    "Unknown bearer<br>
> state<br>
> during connection attempt.");<br>
> +<br>
> +                connect_3gpp_<wbr>context_complete_and_free (ctx);<br>
> +                return;<br>
> +            }<br>
> +<br>
> +            break;<br>
> +        }<br>
> +<br>
> +        //Always verify that the SWWAN connection is active after<br>
> trying<br>
> to set it up.<br>
> +        //Same step as CONNECT_3GPP_CONTEXT_STEP_<wbr>VERIFY_SWWAN but<br>
> makes it<br>
> easy to detect<br>
> +        //if we just came from a new or old connection.<br>
> +        case CONNECT_3GPP_CONTEXT_STEP_SET_<wbr>SWWAN: {<br>
> +            ctx->connect =<br>
> CONNECT_3GPP_CONTEXT_STEP_<wbr>CONNECTION_STATUS;<br>
> +            break;<br>
> +        }<br>
> +<br>
> +        //If SWWAN was just set, we expect it should be on.<br>
> +        case CONNECT_3GPP_CONTEXT_STEP_<wbr>CONNECTION_STATUS: {<br>
> +            if ((g_ascii_strncasecmp(ctx-><wbr>self->priv-<br>
> >bearer_interface,<br>
> "usb0", 4)==0 && ctx->usb0_state == CONNECTION_ACTIVE) ||<br>
> +                (g_ascii_<wbr>strncasecmp(ctx->self->priv-<br>
> >bearer_interface,<br>
> "usb1", 4)==0 && ctx->usb1_state == CONNECTION_ACTIVE))<br>
> +                ctx->connect = CONNECT_3GPP_CONTEXT_STEP_<wbr>DONE;<br>
> +            else<br>
> +            {<br>
> +                g_simple_<wbr>async_result_set_error (ctx->result,<br>
> +                             <wbr>                    MM_CORE_<wbr>ERROR,<br>
> +                             <wbr>                    MM_CORE_<wbr>ERROR_WRONG<br>
> _STATE,<br>
> +                             <wbr>                    "Unknown bearer<br>
> state<br>
> during connection attempt.");<br>
> +<br>
> +                connect_3gpp_<wbr>context_complete_and_free (ctx);<br>
> +                return;<br>
> +            }<br>
> +<br>
> +            break;<br>
> +        }<br>
> +<br>
> +        case CONNECT_3GPP_CONTEXT_STEP_<wbr>DONE: {<br>
> +            //Place holder, nothing should call this. Fall into<br>
> defualt<br>
> error.<br>
> +        }<br>
> +<br>
> +        default: {<br>
> +            mm_err ("Unexpected SWWAN connect state. Unable to<br>
> advance.");<br>
> +            ctx->self->priv-><wbr>connect_pending = NULL;<br>
> +            g_simple_async_<wbr>result_set_error (ctx->result,<br>
> +                             <wbr>                MM_CORE_ERROR,<br>
> +                             <wbr>                MM_CORE_ERROR_<wbr>WRONG_STA<br>
> TE,<br>
> +                             <wbr>                "Unexpected SWWAN<br>
> connect<br>
> state. Unable to advance.");<br>
> +<br>
> +            connect_3gpp_<wbr>context_complete_and_free (ctx);<br>
> +            return;<br>
> +        }<br>
> +<br>
> +<br>
> +        }<br>
> +<br>
> +        connect_3gpp_context_<wbr>step (ctx);<br>
> +    }<br>
> +    //Assume disconnecting flow, assert protects assumption.<br>
> +    else<br>
> +    {<br>
> +        g_assert (self->priv->disconnect_<wbr>pending != NULL);<br>
> +        ctx = self->priv->disconnect_<wbr>pending;<br>
> +<br>
> +        switch (ctx->disconnect) {<br>
> +<br>
> +        case DISCONNECT_3GPP_CONTEXT_STEP_<wbr>INIT: {<br>
> +            ctx->disconnect =<br>
> DISCONNECT_3GPP_CONTEXT_STEP_<wbr>SWWAN_DETACH;<br>
> +            break;<br>
> +        }<br>
> +<br>
> +        case DISCONNECT_3GPP_CONTEXT_STEP_<wbr>SWWAN_DETACH: {<br>
> +            ctx->disconnect =<br>
> DISCONNECT_3GPP_CONTEXT_STEP_<wbr>CONNECTION_STATUS;<br>
> +            break;<br>
> +        }<br>
> +<br>
> +        case DISCONNECT_3GPP_CONTEXT_STEP_<wbr>CONNECTION_STATUS: {<br>
> +            //We expect the bearer to be disconnected now. If it's<br>
> not try<br>
> again.<br>
> +            //TODO: Rework for dual sim connections.<br>
> +            if ((g_ascii_strncasecmp(ctx-><wbr>self->priv-<br>
> >bearer_interface,<br>
> "usb0", 4)==0 && ctx->usb0_state == CONNECTION_INACTIVE) ||<br>
> +                (g_ascii_<wbr>strncasecmp(ctx->self->priv-<br>
> >bearer_interface,<br>
> "usb1", 4)==0 && ctx->usb1_state == CONNECTION_INACTIVE))<br>
> +                ctx-><wbr>disconnect = DISCONNECT_3GPP_CONTEXT_STEP_<wbr>DONE;<br>
> +            else<br>
> +            {<br>
> +                ctx-><wbr>disconnect =<br>
> DISCONNECT_3GPP_CONTEXT_STEP_<wbr>SWWAN_DETACH;<br>
> +                sleep (1); //Wait a second on disconnect retry's.<br>
> +            }<br>
> +            break;<br>
> +        }<br>
> +<br>
> +        case DISCONNECT_3GPP_CONTEXT_STEP_<wbr>DONE: {<br>
> +            //Place holder, nothing should call this. Fall into<br>
> defualt<br>
> error.<br>
> +        }<br>
> +<br>
> +        default: {<br>
> +            mm_err ("Unexpected SWWAN disconnect state. Unable to<br>
> advance.");<br>
> +            ctx->self->priv-><wbr>connect_pending = NULL;<br>
> +            g_simple_async_<wbr>result_set_error (ctx->result,<br>
> +                             <wbr>                MM_CORE_ERROR,<br>
> +                             <wbr>                MM_CORE_ERROR_<wbr>WRONG_STA<br>
> TE,<br>
> +                             <wbr>                "Unexpected SWWAN<br>
> disconnect<br>
> state. Unable to advance.");<br>
> +<br>
> +            connect_3gpp_<wbr>context_complete_and_free (ctx);<br>
> +<br>
> +            return;<br>
> +        }<br>
> +<br>
> +        }<br>
> +<br>
> +        disconnect_3gpp_<wbr>context_step (ctx);<br>
> +    }<br>
> +}<br>
> +<br>
> +static gboolean<br>
> +proccess_swwan_response(<wbr>MMBroadbandBearerCinterion *self, GList<br>
> *result)<br>
> +{<br>
> +    Control3gppContext *ctx;<br>
> +<br>
> +    if (self->priv->connect_pending != NULL)<br>
> +        ctx = self->priv->connect_pending;<br>
> +    else<br>
> +    {<br>
> +        g_assert (self->priv->disconnect_<wbr>pending != NULL);<br>
> +        ctx = self->priv->disconnect_<wbr>pending;<br>
> +    }<br>
> +<br>
> +<br>
> +    if (g_list_length(result) != 0) {<br>
> +        int first_result = GPOINTER_TO_INT(result->data);<br>
> +<br>
> +        //mm_serial_parser_<wbr>v1_parse will catch CME Error. Parent<br>
> function<br>
> will then send<br>
> +        //that error to dbus out.<br>
> +        if(first_result == -1)<br>
> +            return FALSE;<br>
> +        //Recived an 'OK' response from a write command, place<br>
> holder so<br>
> we don't error below.<br>
> +       if (first_result == 0 && ctx->self->priv->swwan_read_<wbr>write ==<br>
> 1)<br>
> +            NULL;<br>
> +        //Recived an 'OK'(0) response from an swwwan read command.<br>
> +        else if (first_result == 0 && ctx->self->priv-<br>
> >swwan_read_write ==<br>
> 0)<br>
> +        {<br>
> +            ctx->usb0_state = CONNECTION_INACTIVE;<br>
> +            ctx->usb1_state = CONNECTION_INACTIVE;<br>
> +        }<br>
> +        //1 || 3 result is the CID, given when that context is<br>
> activated.<br>
> +       //TODO: Rework for dual sim connections.<br>
> +        else if (first_result == 1 && ctx->self->priv-<br>
> >swwan_read_write ==<br>
> 0)<br>
> +            ctx->usb1_state = CONNECTION_ACTIVE;<br>
> +        else if (first_result == 3 && ctx->self->priv-<br>
> >swwan_read_write ==<br>
> 0)<br>
> +            ctx->usb0_state = CONNECTION_ACTIVE;<br>
> +        else<br>
> +        {<br>
> +            for (; result; result = g_list_next (result))<br>
> +                mm_err ("Unknown SWWAN response data:%i",<br>
> GPOINTER_TO_INT(result->data))<wbr>;<br>
> +<br>
> +            g_simple_async_<wbr>result_set_error (ctx->result,<br>
> +                             <wbr>                MM_CORE_ERROR,<br>
> +                             <wbr>                MM_CORE_ERROR_<wbr>FAILED,<br>
> +                             <wbr>                "Internal error while<br>
> processing SWWAN response.");<br>
> +<br>
> +            return FALSE;<br>
> +        }<br>
> +     }<br>
> +     else {<br>
> +        mm_err ("Unable to parse zero length SWWAN response.");<br>
> +        return FALSE;<br>
> +     }<br>
> +<br>
> +     return TRUE;<br>
> +}<br>
> +<br>
> +static void<br>
> +get_swwan_response (MMBaseModem *modem,<br>
> +                          <wbr>GAsyncResult *res,<br>
> +                          <wbr>MMBroadbandBearerCinterion *self)<br>
> +{<br>
> +    Control3gppContext *ctx;<br>
> +    const gchar *response;<br>
> +    GError *error = NULL;<br>
> +    GList *response_parsed = NULL;<br>
> +<br>
> +    if (self->priv->connect_pending != NULL)<br>
> +        ctx = self->priv->connect_pending;<br>
> +    else<br>
> +    {<br>
> +        g_assert (self->priv->disconnect_<wbr>pending != NULL);<br>
> +        ctx = self->priv->disconnect_<wbr>pending;<br>
> +    }<br>
> +<br>
> +    // Balance refcount<br>
> +    g_object_unref (self);<br>
> +<br>
> +    //Parse the swwan response.<br>
> +    response = mm_base_modem_at_command_<wbr>finish (modem, res, &error);<br>
> +<br>
> +    //1st elem of response_parsed will be:<br>
> +    //1 or 3 for an active swwan, -1 for a valid error, 0 for<br>
> assumed 'OK'<br>
> (no conection)<br>
> +    if (error == NULL && !mm_cinterion_parse_swwan_<wbr>response<br>
> (response,<br>
> &response_parsed, &error))<br>
> +            NULL;<br>
> +<br>
> +<br>
> +    if (error != NULL || !proccess_swwan_response(ctx-><wbr>self,<br>
> response_parsed)) {<br>
> +        ctx->self->priv-><wbr>connect_pending = NULL;<br>
> +        ctx->self->priv-><wbr>disconnect_pending = NULL;<br>
> +<br>
> +        g_simple_async_<wbr>result_take_error (ctx->result, error);<br>
> +<br>
> +        if (ctx->connect)<br>
> +            connect_3gpp_<wbr>context_complete_and_free (ctx);<br>
> +        else<br>
> +            disconnect_3gpp_<wbr>context_complete_and_free (ctx);<br>
> +<br>
> +        return;<br>
> +<br>
> +    }<br>
> +<br>
> +    mm_dbg ("usb0-state:%i usb1-state:%i", ctx->usb0_state,<br>
> ctx->usb1_state);<br>
> +<br>
> +    g_list_free(response_<wbr>parsed);<br>
> +    g_clear_error (&error);<br>
> +<br>
> +    cinterion_3gpp_state_<wbr>machine_logic(ctx->self);<br>
> +<br>
> +    return;<br>
> +}<br>
> +<br>
> +/****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
> +/* Cinterion AT Command Wrappers */<br>
> +<br>
> +static void<br>
> +send_swwan_read_command(<wbr>Control3gppContext *ctx)<br>
> +{<br>
> +    ctx->self->priv->swwan_<wbr>read_write = 0;<br>
> +<br>
> +    //Check for swwan connection. The next state will be preformed<br>
> by the<br>
> callback.<br>
> +    mm_base_modem_at_command_<wbr>full (ctx->modem,<br>
> +                             <wbr>      ctx->primary,<br>
> +                             <wbr>      "^SWWAN?",<br>
> +                             <wbr>      5,<br>
> +                             <wbr>      FALSE,<br>
> +                             <wbr>      FALSE,<br>
> +                             <wbr>      NULL,<br>
> +                             <wbr>      (GAsyncReadyCallback)<wbr>get_swwan_re<br>
> sponse,<br>
> +                             <wbr>      g_object_ref (ctx->self));<br>
> +}<br>
> +<br>
> +static void<br>
> +send_swwan_connect_command(<wbr>Control3gppContext *ctx)<br>
> +{<br>
> +    //USB0(1st wwan adapt) -> 3rd context, USB1(2nd wwan adapt) -><br>
> 1st<br>
> context<br>
> +    gchar               *<wbr>command;<br>
> +    command = g_strdup_printf ("^SWWAN=%s,%s,%s",<br>
> +                             <wbr>  "1",<br>
> +                             <wbr>  ctx->self->priv->pdp_cid, //Expect 1<br>
> or 3<br>
> +<br>
> g_ascii_strncasecmp(ctx->self-<wbr>>priv->pdp_cid, "3", 1)==0  ? "1" :<br>
> "2");<br>
> +<br>
> +    ctx->self->priv->swwan_<wbr>read_write = 1;<br>
> +<br>
> +    //Start the swwan connection. The next state will be preformed<br>
> by the<br>
> callback.<br>
> +    mm_base_modem_at_command_<wbr>full (ctx->modem,<br>
> +                             <wbr>      ctx->primary,<br>
> +                             <wbr>      command,<br>
> +                             <wbr>      10,/*Seen it take 5 seconds :0 */<br>
> +                             <wbr>      FALSE,<br>
> +                             <wbr>      FALSE,<br>
> +                             <wbr>      NULL,<br>
> +                             <wbr>      (GAsyncReadyCallback)<wbr>get_swwan_re<br>
> sponse,<br>
> +                             <wbr>      g_object_ref (ctx->self));<br>
> +<br>
> +    g_free (command);<br>
> +}<br>
> +<br>
> +static void<br>
> +send_swwan_disconnect_<wbr>command(Control3gppContext *ctx)<br>
> +{<br>
> +    gchar               *<wbr>command;<br>
> +    command = g_strdup_printf ("^SWWAN=%s,%s,%s",<br>
> +                             <wbr>  "0",<br>
> +                             <wbr>  ctx->self->priv->pdp_cid,<br>
> +<br>
> g_ascii_strncasecmp(ctx->self-<wbr>>priv->pdp_cid, "3", 1)==0  ? "1" :<br>
> "2");<br>
> +<br>
> +    ctx->self->priv->swwan_<wbr>read_write = 1;<br>
> +<br>
> +    //Check for swwan connection. The next state will be preformed<br>
> by the<br>
> callback.<br>
> +    mm_base_modem_at_command_<wbr>full (ctx->modem,<br>
> +                             <wbr>      ctx->primary,<br>
> +                             <wbr>      command,<br>
> +                             <wbr>      10,<br>
> +                             <wbr>      FALSE,<br>
> +                             <wbr>      FALSE,<br>
> +                             <wbr>      NULL,<br>
> +                             <wbr>      (GAsyncReadyCallback)<wbr>get_swwan_re<br>
> sponse,<br>
> +                             <wbr>      g_object_ref (ctx->self));<br>
> +<br>
> +    g_free (command);<br>
> +}<br>
> +<br>
> +<br>
> +<br>
> +<br>
> +/****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
> +/* Connect 3GPP */<br>
> +<br>
> +static gint<br>
> +cinterion_parse_auth_type (MMBearerAllowedAuth mm_auth)<br>
> +{<br>
> +    switch (mm_auth) {<br>
> +    case MM_BEARER_ALLOWED_AUTH_NONE:<br>
> +        return MM_BEARER_CINTERION_AUTH_NONE;<br>
> +    case MM_BEARER_ALLOWED_AUTH_PAP:<br>
> +        return MM_BEARER_CINTERION_AUTH_PAP;<br>
> +    case MM_BEARER_ALLOWED_AUTH_CHAP:<br>
> +        return MM_BEARER_CINTERION_AUTH_CHAP;<br>
> +    case MM_BEARER_ALLOWED_AUTH_<wbr>MSCHAPV2:<br>
> +        return MM_BEARER_CINTERION_AUTH_<wbr>MSCHAPV2;<br>
> +    default:<br>
> +        return MM_BEARER_CINTERION_AUTH_<wbr>UNKNOWN;<br>
> +    }<br>
> +}<br>
> +<br>
> +static void<br>
> +connect_3gpp_context_<wbr>complete_and_free (Control3gppContext *ctx)<br>
> +{<br>
> +    g_simple_async_result_<wbr>complete_in_idle (ctx->result);<br>
> +    g_object_unref (ctx->cancellable);<br>
> +    g_object_unref (ctx->result);<br>
> +    g_object_unref (ctx->modem);<br>
> +    g_object_unref (ctx->self);<br>
> +    g_clear_object (&ctx->ipv4_config);<br>
> +    g_clear_object (&ctx->data);<br>
> +    g_clear_object (&ctx->primary);<br>
> +<br>
> +    g_slice_free (Control3gppContext, ctx);<br>
> +}<br>
> +<br>
> +static MMBearerConnectResult *<br>
> +connect_3gpp_finish (MMBroadbandBearer *self,<br>
> +                     <wbr>GAsyncResult *res,<br>
> +                     GError **error)<br>
> +{<br>
> +    if (g_simple_async_result_<wbr>propagate_error (G_SIMPLE_ASYNC_RESULT<br>
> (res), error))<br>
> +        return NULL;<br>
> +<br>
> +    return mm_bearer_connect_result_ref<br>
> (g_simple_async_result_get_op_<wbr>res_gpointer (G_SIMPLE_ASYNC_RESULT<br>
> (res)));<br>
> +}<br>
> +<br>
> +static gchar *<br>
> +build_cinterion_pdp_context_<wbr>string(Control3gppContext *ctx)<br>
> +{<br>
> +    const gchar         *apn = NULL;<br>
> +    const gchar         *user = NULL;<br>
> +    const gchar         *passwd = NULL;<br>
> +    MMBearerAllowedAuth  <wbr>auth;<br>
> +    gint                 <wbr>encoded_auth =<br>
> MM_BEARER_CINTERION_AUTH_<wbr>UNKNOWN;<br>
> +    gchar               *<wbr>command;<br>
> +<br>
> +    apn = mm_bearer_properties_get_apn (mm_base_bearer_peek_config<br>
> (MM_BASE_BEARER (ctx->self)));<br>
> +    user = mm_bearer_properties_get_user (mm_base_bearer_peek_config<br>
> (MM_BASE_BEARER (ctx->self)));<br>
> +    passwd = mm_bearer_properties_get_<wbr>password<br>
> (mm_base_bearer_peek_config<br>
> (MM_BASE_BEARER (ctx->self)));<br>
> +    auth = mm_bearer_properties_get_<wbr>allowed_auth<br>
> (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self)));<br>
> +    encoded_auth = cinterion_parse_auth_type (auth);<br>
> +<br>
> +    /* Default to no authentication if not specified */<br>
> +    if (encoded_auth == MM_BEARER_CINTERION_AUTH_<wbr>UNKNOWN) {<br>
> +        encoded_auth = MM_BEARER_CINTERION_AUTH_NONE;<br>
> +        mm_dbg ("Unable to detect authentication type. Defaulting<br>
> to:%i",<br>
> encoded_auth);<br>
> +    }<br>
> +<br>
> +    //TODO: Get IP type if specific protocol was specified.<br>
> Hardcoded to<br>
> IPV4 for now.<br>
> +<br>
> +    if (!user && !passwd)<br>
> +        command = g_strdup_printf<br>
> ("+CGDCONT=%s,\"IP\",\"%s\",\"<wbr>0.0.0.0\",0,0",<br>
> +                             <wbr>      ctx->self->priv->pdp_<wbr>cid,<br>
> +                             <wbr>      apn == NULL ? "" : apn);<br>
> +<br>
> +    /*TODO: Can't test this as we can't get a hold of a SIM w/ this<br>
> feature atm. This is a place<br>
> +    * holder. When we can test this then it should be refactored &<br>
> split<br>
> into another state so we<br>
> +    * can tell independently if the SGAUTH fails.<br>
> +    * Write Command<br>
> +    * AT^SGAUTH=<cid>[, <auth_type>[, <passwd>, <user>]]<br>
> +    * Response(s) <br>
> +    * OK<br>
> +    * ERROR<br>
> +    * +CME ERROR: <err><br>
> +    */<br>
> +    else<br>
> +        command = g_strdup_printf ("^SGAUTH=%s,%i,%s,%s;<br>
> +CGDCONT=%s,\"IP\",\"%s\",\"0.<wbr>0.0.0\",0,0 ",<br>
> +                             <wbr>      ctx->self->priv->pdp_<wbr>cid,<br>
> +                             <wbr>      encoded_auth,<br>
> +                             <wbr>      passwd == NULL ? "" : passwd,<br>
> +                             <wbr>      user == NULL ? "" : user,<br>
> +                             <wbr>      ctx->self->priv->pdp_<wbr>cid,<br>
> +                             <wbr>      apn == NULL ? "" : apn);<br>
> +    return command;<br>
> +}<br>
> +<br>
> +static gboolean<br>
> +set_pdp_cid(<wbr>Control3gppContext *ctx)<br>
> +{<br>
> +    GUdevClient         *<wbr>client;<br>
> +    GUdevDevice         *<wbr>data_device;<br>
> +<br>
> +    //Need the data port to figure out what context to activate.<br>
> +    client = g_udev_client_new (NULL);<br>
> +    data_device = (g_udev_client_query_by_<wbr>subsystem_and_name (<br>
> +                       <wbr>client,<br>
> +                       "net",<br>
> +                       mm_<wbr>port_get_device (ctx->data)));<br>
> +    ctx->self->priv->bearer_<wbr>interface =<br>
> g_udev_device_get_name(data_<wbr>device);<br>
> +<br>
> +    //Map PDP context from the current Bearer. USB0 -> 3rd context,<br>
> USB1<br>
> -> 1st context<br>
> +    if (g_ascii_strncasecmp(ctx-><wbr>self->priv->bearer_interface,<br>
> "usb0", 4)<br>
> == 0)<br>
> +        ctx->self->priv->  <wbr>pdp_cid = "3";<br>
> +    else if (g_ascii_strncasecmp(ctx-><wbr>self->priv->bearer_interface,<br>
> "usb1", 4) == 0)<br>
> +        ctx->self->priv->pdp_<wbr>cid = "1";<br>
> +    else<br>
> +    {<br>
> +        mm_err ("Unable to map usb interface:(%s) to context",<br>
> ctx->self->priv->bearer_<wbr>interface);<br>
> +<br>
> +        g_simple_async_<wbr>result_set_error (ctx->result,<br>
> +                             <wbr>            MM_CORE_ERROR,<br>
> +                             <wbr>            MM_CORE_ERROR_<wbr>FAILED,<br>
> +                             <wbr>            "Internal error while<br>
> mapping USB<br>
> network interface.");<br>
> +<br>
> +        ctx->self->priv-><wbr>connect_pending = NULL;<br>
> +        ctx->self->priv-><wbr>disconnect_pending = NULL;<br>
> +<br>
> +        if (ctx->connect)<br>
> +            connect_3gpp_<wbr>context_complete_and_free (ctx);<br>
> +        else<br>
> +            disconnect_3gpp_<wbr>context_complete_and_free (ctx);<br>
> +<br>
> +        return FALSE;<br>
> +    }<br>
> +<br>
> +    return TRUE;<br>
> +}<br>
> +<br>
> +static void<br>
> +handle_cancel_connect(<wbr>Control3gppContext *ctx)<br>
> +{<br>
> +    gchar               *<wbr>command;<br>
> +<br>
> +    // Clear context<br>
> +    ctx->self->priv->connect_<wbr>pending = NULL;<br>
> +<br>
> +    command = g_strdup_printf ("^SWWAN=%s,%s,%s",<br>
> +                             <wbr>  "0",<br>
> +                             <wbr>  ctx->self->priv->pdp_cid, //Expect 1<br>
> or 3,<br>
> +<br>
> g_ascii_strncasecmp(ctx->self-<wbr>>priv->pdp_cid, "3", 1)==0  ? "1" :<br>
> "2");<br>
> +<br>
> +    //Disconnect, may not succeed. Will not check response on<br>
> cancel.<br>
> +    mm_base_modem_at_command_<wbr>full (ctx->modem,<br>
> +                             <wbr>      ctx->primary,<br>
> +                             <wbr>      command,<br>
> +                             <wbr>      3,<br>
> +                             <wbr>      FALSE,<br>
> +                             <wbr>      FALSE,<br>
> +                             <wbr>      NULL,<br>
> +                             <wbr>      NULL, // Do not care the AT<br>
> response<br>
> +                             <wbr>      NULL);<br>
> +<br>
> +    g_simple_async_result_<wbr>set_error (ctx->result,<br>
> +                             <wbr>        MM_CORE_ERROR,<br>
> +                             <wbr>        MM_CORE_ERROR_<wbr>CANCELLED,<br>
> +                             <wbr>        "Cinterion connection operation<br>
> has<br>
> been cancelled");<br>
> +    connect_3gpp_context_<wbr>complete_and_free (ctx);<br>
> +<br>
> +}<br>
> +<br>
> +static void<br>
> +context_ready (MMBaseModem *modem,<br>
> +                       <wbr>GAsyncResult *res,<br>
> +                       <wbr>MMBroadbandBearerCinterion *self)<br>
> +{<br>
> +    Control3gppContext  *ctx;<br>
> +    GError              *<wbr>error = NULL;<br>
> +    const gchar         *response;<br>
> +<br>
> +    ctx = self->priv->connect_pending;<br>
> +    g_assert (ctx != NULL);<br>
> +<br>
> +    /* Balance refcount */<br>
> +    g_object_unref (self);<br>
> +<br>
> +    //Get the cgdcont write response. We expect: 'OK'<br>
> +    //Responses: OK, ERROR<br>
> +    response = mm_base_modem_at_command_<wbr>finish (modem, res, &error);<br>
> +<br>
> +    if (!response || error != NULL) {<br>
> +        mm_err ("CGDCONT read- Error:%d response:%s", error->code,<br>
> response);<br>
> +<br>
> +        self->priv->connect_<wbr>pending = NULL;<br>
> +        g_simple_async_<wbr>result_take_error (ctx->result, error);<br>
> +        connect_3gpp_context_<wbr>complete_and_free (ctx);<br>
> +<br>
> +        return;<br>
> +    }<br>
> +<br>
> +    /* Go to next step */<br>
> +    //ctx->connect = CONNECT_3GPP_CONTEXT_STEP_SET_<wbr>SWWAN;<br>
> +    cinterion_3gpp_state_<wbr>machine_logic(ctx->self);<br>
> +}<br>
> +<br>
> +static void<br>
> +connect_3gpp_context_step (Control3gppContext *ctx)<br>
> +{<br>
> +    /* Check for cancellation */<br>
> +    if (g_cancellable_is_cancelled (ctx->cancellable)) {<br>
> +        //Init the current context if not done already.<br>
> +        if (g_ascii_strncasecmp(ctx-><wbr>self->priv->pdp_cid, "0",<br>
> 1)==0)<br>
> +            if(set_pdp_cid(<wbr>ctx)) //Don't care about failure case for<br>
> cancel.<br>
> +<br>
> +        handle_cancel_<wbr>connect(ctx);<br>
> +        return;<br>
> +    }<br>
> +<br>
> +    // Network-initiated disconnect should not be outstanding at<br>
> this<br>
> point,<br>
> +    // because it interferes with the connect attempt.<br>
> +    g_assert (ctx->self->priv->network_<wbr>disconnect_pending_id == 0);<br>
> +    g_assert (ctx->self->priv->disconnect_<wbr>pending == NULL);<br>
> +<br>
> +<br>
> +    switch (ctx->connect) {<br>
> +    case CONNECT_3GPP_CONTEXT_STEP_<wbr>INIT: {<br>
> +        MMBearerIpFamily ip_family;<br>
> +<br>
> +        //Initialize variables, reminder!<br>
> +        ctx->usb0_state = CONNECTION_UNKNOWN;<br>
> +        ctx->usb1_state = CONNECTION_UNKNOWN;<br>
> +        ctx->self->priv->pdp_<wbr>cid = "0"; //Cinterion doesn't have cid<br>
> == 0<br>
> +        ctx->self->priv-><wbr>swwan_read_write = -1;<br>
> +        ctx->self->priv-><wbr>retry_count = 0;<br>
> +<br>
> +        if(!set_pdp_cid(ctx))<br>
> +            return;<br>
> +<br>
> +        ip_family = mm_bearer_properties_get_ip_<wbr>type<br>
> (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self)));<br>
> +<br>
> +        //TODO: Fix so more than IPV4 can be used.<br>
> +        if (ip_family == MM_BEARER_IP_FAMILY_NONE ||<br>
> +            ip_family == MM_BEARER_IP_FAMILY_ANY) {<br>
> +            gchar *ip_family_str;<br>
> +<br>
> +            ip_family = mm_base_bearer_get_default_ip_<wbr>family<br>
> (MM_BASE_BEARER (ctx->self));<br>
> +            ip_family_str =<br>
> mm_bearer_ip_family_build_<wbr>string_from_mask<br>
> (ip_family);<br>
> +            mm_dbg ("No specific IP family requested, defaulting to<br>
> %s",<br>
> +                    ip_<wbr>family_str);<br>
> +            g_free (ip_family_str);<br>
> +        }<br>
> +<br>
> +        /* Default to automatic/DHCP addressing */<br>
> +        ctx->ipv4_config = mm_bearer_ip_config_new ();<br>
> +        mm_bearer_ip_config_<wbr>set_method (ctx->ipv4_config,<br>
> MM_BEARER_IP_METHOD_DHCP);<br>
> +<br>
> +        /* Store the context */<br>
> +        ctx->self->priv-><wbr>connect_pending = ctx;<br>
> +<br>
> +        cinterion_3gpp_state_<wbr>machine_logic(ctx->self);<br>
> +        return;<br>
> +    }<br>
> +    case CONNECT_3GPP_CONTEXT_STEP_<wbr>VERIFY_SWWAN: {<br>
> +        send_swwan_read_<wbr>command(ctx);<br>
> +        return;<br>
> +    }<br>
> +<br>
> +    case CONNECT_3GPP_CONTEXT_STEP_<wbr>BEARER_PROPERTIES: {<br>
> +        gchar               *<wbr>command = NULL;<br>
> +<br>
> +        //TODO: Rework for dual sim connections, don't disconnect<br>
> the<br>
> wrong one.<br>
> +        //If there is already an active SWWAN connection disconnect<br>
> before<br>
> trying to set it's context.<br>
> +        if ((ctx->usb0_state == CONNECTION_ACTIVE &&<br>
> g_ascii_strncasecmp(ctx->self-<wbr>>priv->pdp_cid, "3", 1)) || ctx-<br>
> >usb0_state<br>
> == CONNECTION_UNKNOWN ||<br>
> +            (ctx->usb1_state == CONNECTION_ACTIVE &&<br>
> g_ascii_strncasecmp(ctx->self-<wbr>>priv->pdp_cid, "1", 1)) || ctx-<br>
> >usb1_state<br>
> == CONNECTION_UNKNOWN)<br>
> +        {<br>
> +            send_swwan_<wbr>disconnect_command(ctx);<br>
> +            g_free (command);<br>
> +            return;<br>
> +        }<br>
> +<br>
> +        command = build_cinterion_pdp_context_<wbr>string(ctx);<br>
> +<br>
> +        //Set the PDP context with cgdcont.<br>
> +        mm_base_modem_at_<wbr>command_full (ctx->modem,<br>
> +                             <wbr>          ctx->primary,<br>
> +                             <wbr>          command,<br>
> +                             <wbr>          3,<br>
> +                             <wbr>          FALSE,<br>
> +                             <wbr>          FALSE,<br>
> +                             <wbr>          NULL,<br>
> +                             <wbr>          (<wbr>GAsyncReadyCallback)context_<br>
> ready,<br>
> +                             <wbr>          g_object_ref (ctx->self));<br>
> +<br>
> +        g_free (command);<br>
> +        return;<br>
> +    }<br>
> +    case CONNECT_3GPP_CONTEXT_STEP_SET_<wbr>SWWAN: {<br>
> +        send_swwan_connect_<wbr>command(ctx);<br>
> +        return;<br>
> +    }<br>
> +    case CONNECT_3GPP_CONTEXT_STEP_<wbr>CONNECTION_STATUS: {<br>
> +        send_swwan_read_<wbr>command(ctx);<br>
> +        return;<br>
> +    }<br>
> +<br>
> +    case CONNECT_3GPP_CONTEXT_STEP_<wbr>DONE: {<br>
> +        /* Clear context */<br>
> +        ctx->self->priv-><wbr>connect_pending = NULL;<br>
> +        ctx->self->priv-><wbr>bearer_interface = NULL;<br>
> +        ctx->self->priv->pdp_<wbr>cid = NULL;<br>
> +        ctx->self->priv-><wbr>swwan_read_write = -1;<br>
> +<br>
> +        /* Setup result */<br>
> +        {<br>
> +            if (ctx->ipv4_config) {<br>
> +                g_simple_<wbr>async_result_set_op_res_<wbr>gpointer (<br>
> +                    ctx-><wbr>result,<br>
> +                    mm_<wbr>bearer_connect_result_new (ctx->data,<br>
> ctx->ipv4_config, NULL),<br>
> +                    (<wbr>GDestroyNotify)mm_bearer_<wbr>connect_result_unref);<br>
> +            }<br>
> +            else {<br>
> +                g_simple_<wbr>async_result_set_error (ctx->result,<br>
> +                             <wbr>                    MM_CORE_<wbr>ERROR,<br>
> +                             <wbr>                    MM_CORE_<wbr>ERROR_WRONG<br>
> _STATE,<br>
> +                             <wbr>                    "Cinterion<br>
> connection<br>
> failed to set IP protocol");<br>
> +            }<br>
> +        }<br>
> +<br>
> +        connect_3gpp_context_<wbr>complete_and_free (ctx);<br>
> +        return;<br>
> +    }<br>
> +    }<br>
> +}<br>
> +<br>
> +static void<br>
> +connect_3gpp (MMBroadbandBearer *self,<br>
> +              <wbr>MMBroadbandModem *modem,<br>
> +              MMPortSerialAt *primary,<br>
> +              MMPortSerialAt *secondary,<br>
> +              GCancellable *cancellable,<br>
> +              <wbr>GAsyncReadyCallback callback,<br>
> +              gpointer user_data)<br>
> +{<br>
> +    Control3gppContext  *ctx;<br>
> +    MMPort *port;<br>
> +<br>
> +    g_assert (primary != NULL);<br>
> +<br>
> +    // We need a net port<br>
> +    port = mm_base_modem_peek_best_data_<wbr>port (MM_BASE_MODEM (modem),<br>
> MM_PORT_TYPE_NET);<br>
> +    if (!port) {<br>
> +        g_simple_async_<wbr>report_error_in_idle (G_OBJECT (self),<br>
> +                             <wbr>                callback,<br>
> +                             <wbr>                user_data,<br>
> +                             <wbr>                MM_CORE_ERROR,<br>
> +                             <wbr>                MM_CORE_ERROR_<wbr>NOT_FOUND<br>
> ,<br>
> +                             <wbr>                "No valid data port<br>
> found to<br>
> launch connection");<br>
> +        return;<br>
> +    }<br>
> +<br>
> +<br>
> +    /* Setup connection context */<br>
> +    ctx = g_slice_new0 (Control3gppContext);<br>
> +    ctx->self = g_object_ref (self);<br>
> +    ctx->modem = g_object_ref (modem);<br>
> +    ctx->data = g_object_ref (port);<br>
> +    ctx->result = g_simple_async_result_new (G_OBJECT (self),<br>
> +                             <wbr>                callback,<br>
> +                             <wbr>                user_data,<br>
> +                             <wbr>                connect_3gpp);<br>
> +    ctx->cancellable = g_object_ref (cancellable);<br>
> +    ctx->connect = CONNECT_3GPP_CONTEXT_STEP_<wbr>INIT;<br>
> +<br>
> +    g_assert (ctx->self->priv->connect_<wbr>pending == NULL);<br>
> +    g_assert (ctx->self->priv->disconnect_<wbr>pending == NULL);<br>
> +<br>
> +    ctx->primary = get_dial_port (MM_BROADBAND_MODEM_CINTERION<br>
> (ctx->modem), ctx->data, primary);<br>
> +<br>
> +    /* Run! */<br>
> +    connect_3gpp_context_step (ctx);<br>
> +}<br>
> +<br>
> +/****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
> +/* Disconnect 3GPP */<br>
> +<br>
> +static void<br>
> +disconnect_3gpp_context_<wbr>complete_and_free (Control3gppContext *ctx)<br>
> +{<br>
> +    g_simple_async_result_<wbr>complete_in_idle (ctx->result);<br>
> +    g_object_unref (ctx->result);<br>
> +    g_object_unref (ctx->primary);<br>
> +    g_object_unref (ctx->self);<br>
> +    g_object_unref (ctx->modem);<br>
> +    g_slice_free (Control3gppContext, ctx);<br>
> +}<br>
> +<br>
> +static gboolean<br>
> +disconnect_3gpp_finish (MMBroadbandBearer *self,<br>
> +                        <wbr>GAsyncResult *res,<br>
> +                        <wbr>GError **error)<br>
> +{<br>
> +    return !g_simple_async_result_<wbr>propagate_error<br>
> (G_SIMPLE_ASYNC_RESULT<br>
> (res), error);<br>
> +}<br>
> +<br>
> +static void<br>
> +disconnect_3gpp_context_step (Control3gppContext *ctx)<br>
> +{<br>
> +    //There is no cancel handling b/c the only thing we could do<br>
> would<br>
> +    //be disconnect, which is already happening and bad things can<br>
> happen<br>
> +    //if we abandon the modem in an unknown state.<br>
> +<br>
> +    //Don't allow disconnect while connect in progress.<br>
> +    g_assert (ctx->self->priv->connect_<wbr>pending == NULL);<br>
> +<br>
> +    switch (ctx->disconnect) {<br>
> +    case DISCONNECT_3GPP_CONTEXT_STEP_<wbr>INIT:<br>
> +        /* Store the context */<br>
> +        ctx->self->priv-><wbr>disconnect_pending = ctx;<br>
> +<br>
> +        //Initialize variables, reminder!<br>
> +        ctx->self->priv->pdp_<wbr>cid = "0";<br>
> +        ctx->self->priv-><wbr>retry_count = 0;<br>
> +        ctx->self->priv-><wbr>swwan_read_write = -1;<br>
> +<br>
> +        // We ignore any pending network-initiated disconnection in<br>
> order<br>
> to prevent it<br>
> +        // from interfering with the client-initiated disconnection,<br>
> as we<br>
> would like to<br>
> +        // proceed with the latter anyway.<br>
> +        if (ctx->self->priv->network_<wbr>disconnect_pending_id != 0) {<br>
> +            g_source_remove<br>
> (ctx->self->priv->network_<wbr>disconnect_pending_id);<br>
> +            ctx->self->priv-><wbr>network_disconnect_pending_id = 0;<br>
> +        }<br>
> +<br>
> +        if(!set_pdp_cid(ctx))<br>
> +            return;<br>
> +<br>
> +        cinterion_3gpp_state_<wbr>machine_logic(ctx->self);<br>
> +        return;<br>
> +<br>
> +    case DISCONNECT_3GPP_CONTEXT_STEP_<wbr>SWWAN_DETACH:<br>
> +        // If too many retries (1s of wait between the retries),<br>
> failed<br>
> +        if ( ctx->self->priv->retry_count > 5) {<br>
> +            // Clear context<br>
> +            ctx->self->priv-><wbr>disconnect_pending = NULL;<br>
> +            g_simple_async_<wbr>result_set_error (ctx->result,<br>
> +                             <wbr>                MM_CORE_ERROR,<br>
> +                             <wbr>                MM_CORE_ERROR_<wbr>TOO_MANY,<br>
> +                             <wbr>                "Disconnection attempt<br>
> timed<br>
> out");<br>
> +<br>
> +            disconnect_3gpp_<wbr>context_complete_and_free (ctx);<br>
> +            return;<br>
> +        }<br>
> +<br>
> +        //Has call back to next state.<br>
> +        send_swwan_<wbr>disconnect_command(ctx);<br>
> +<br>
> +        //Only try to detach so many times.<br>
> +        ctx->self->priv-><wbr>retry_count++;<br>
> +<br>
> +        return;<br>
> +    case DISCONNECT_3GPP_CONTEXT_STEP_<wbr>CONNECTION_STATUS:<br>
> +         //Has call back to next state.<br>
> +         send_swwan_read_<wbr>command(ctx);<br>
> +         return;<br>
> +<br>
> +    case DISCONNECT_3GPP_CONTEXT_STEP_<wbr>DONE:<br>
> +        // Clear context<br>
> +        ctx->self->priv-><wbr>disconnect_pending = NULL;<br>
> +        ctx->self->priv->pdp_<wbr>cid = NULL;<br>
> +        ctx->self->priv-><wbr>swwan_read_write = -1;<br>
> +        // Set data port as result<br>
> +        g_simple_async_<wbr>result_set_op_res_gboolean (ctx->result,<br>
> TRUE);<br>
> +        disconnect_3gpp_<wbr>context_complete_and_free (ctx);<br>
> +<br>
> +        return;<br>
> +    }<br>
> +}<br>
> +<br>
> +static void<br>
> +disconnect_3gpp (MMBroadbandBearer *self,<br>
> +                 <wbr>MMBroadbandModem *modem,<br>
> +                 <wbr>MMPortSerialAt *primary,<br>
> +                 <wbr>MMPortSerialAt *secondary,<br>
> +                 MMPort *data,<br>
> +                 guint cid,<br>
> +                 <wbr>GAsyncReadyCallback callback,<br>
> +                 gpointer user_data)<br>
> +{<br>
> +    Control3gppContext *ctx;<br>
> +    MMPort *port;<br>
> +<br>
> +    g_assert (primary != NULL);<br>
> +<br>
> +    ctx = g_slice_new0 (Control3gppContext);<br>
> +    ctx->self = g_object_ref (self);<br>
> +    ctx->modem = MM_BASE_MODEM (g_object_ref (modem));<br>
> +    ctx->result = g_simple_async_result_new (G_OBJECT (self),<br>
> +                             <wbr>                callback,<br>
> +                             <wbr>                user_data,<br>
> +                             <wbr>                disconnect_<wbr>3gpp);<br>
> +    ctx->disconnect = DISCONNECT_3GPP_CONTEXT_STEP_<wbr>INIT;<br>
> +<br>
> +    g_assert (ctx->self->priv->connect_<wbr>pending == NULL);<br>
> +    g_assert (ctx->self->priv->disconnect_<wbr>pending == NULL);<br>
> +<br>
> +    //TODO: Not sure how else to get active data port? Can this be<br>
> done<br>
> without adding this<br>
> +    //function to mm-base-modem.c?<br>
> +    //TODO: Dual SIM how do we know which interface to<br>
> grab/disconnect if<br>
> two are active?<br>
> +    port = mm_base_modem_peek_current_<wbr>data_port (MM_BASE_MODEM<br>
> (modem),<br>
> MM_PORT_TYPE_NET);<br>
> +    if (!port) {<br>
> +        g_simple_async_<wbr>report_error_in_idle (G_OBJECT (self),<br>
> +                             <wbr>                callback,<br>
> +                             <wbr>                user_data,<br>
> +                             <wbr>                MM_CORE_ERROR,<br>
> +                             <wbr>                MM_CORE_ERROR_<wbr>NOT_FOUND<br>
> ,<br>
> +                             <wbr>                "No valid data port<br>
> found to<br>
> tear down.");<br>
> +        return;<br>
> +    }<br>
> +<br>
> +    ctx->data = g_object_ref (port);<br>
> +<br>
> +    ctx->primary = get_dial_port (MM_BROADBAND_MODEM_CINTERION<br>
> (ctx->modem), data, primary);<br>
> +<br>
> +    /* Start! */<br>
> +    disconnect_3gpp_context_<wbr>step (ctx);<br>
> +}<br>
> +<br>
> +/****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
> +<br>
> +static gboolean<br>
> +network_disconnect_3gpp_<wbr>delayed (MMBroadbandBearerCinterion *self)<br>
> +{<br>
> +    mm_dbg ("Disconnect bearer '%s' on network request.",<br>
> +            mm_base_bearer_<wbr>get_path (MM_BASE_BEARER (self)));<br>
> +<br>
> +    self->priv->network_<wbr>disconnect_pending_id = 0;<br>
> +    mm_base_bearer_report_<wbr>connection_status (MM_BASE_BEARER (self),<br>
> +<br>
> MM_BEARER_CONNECTION_STATUS_<wbr>DISCONNECTED);<br>
> +    return G_SOURCE_REMOVE;<br>
> +}<br>
> +<br>
> +//TODO: Test this.<br>
> +static void<br>
> +report_connection_status (MMBaseBearer *bearer,<br>
> +                          <wbr>MMBearerConnectionStatus status)<br>
> +{<br>
> +    <wbr>MMBroadbandBearerCinterion *self = MM_BROADBAND_BEARER_CINTERION<br>
> (bearer);<br>
> +<br>
> +    g_assert (status == MM_BEARER_CONNECTION_STATUS_<wbr>CONNECTED ||<br>
> +              status == MM_BEARER_CONNECTION_STATUS_<wbr>DISCONNECTING ||<br>
> +              status == MM_BEARER_CONNECTION_STATUS_<wbr>DISCONNECTED);<br>
> +<br>
> +    /* When a pending connection / disconnection attempt is in<br>
> progress,<br>
> we use<br>
> +     * ^SWWAN? to check the connection status and thus temporarily<br>
> ignore<br>
> +     * unsolicited messages */<br>
> +    if (self->priv->connect_pending || self->priv-<br>
> >disconnect_pending)<br>
> +        return;<br>
> +<br>
> +    /* Ignore 'CONNECTED' */<br>
> +    if (status == MM_BEARER_CONNECTION_STATUS_<wbr>CONNECTED)<br>
> +        return;<br>
> +<br>
> +    /* We already use ^SWWAN? to poll the connection status, so only<br>
> +     * handle network-initiated disconnection here. */<br>
> +    if (status == MM_BEARER_CONNECTION_STATUS_<wbr>DISCONNECTING) {<br>
> +        /* MM_BEARER_CONNECTION_STATUS_<wbr>DISCONNECTING is used to<br>
> indicate<br>
> that the<br>
> +         * reporting of disconnection should be delayed. See<br>
> MMBroadbandModemCinterion's<br>
> +         * bearer_report_connection_<wbr>status for details. */<br>
> +        if (mm_base_bearer_get_status (bearer) ==<br>
> MM_BEARER_STATUS_CONNECTED &&<br>
> +            self->priv-><wbr>network_disconnect_pending_id == 0) {<br>
> +            mm_dbg ("Delay network-initiated disconnection of bearer<br>
> '%s'",<br>
> +                    mm_base_<wbr>bearer_get_path (MM_BASE_BEARER<br>
> (self)));<br>
> +            self->priv-><wbr>network_disconnect_pending_id =<br>
> (g_timeout_add_seconds (<br>
> +                             <wbr>                              <wbr>  4,<br>
> +                             <wbr>                              <wbr>  (GSourc<br>
> eFunc)<br>
> network_disconnect_3gpp_<wbr>delayed,<br>
> +                             <wbr>                              <wbr>  self));<br>
> +        }<br>
> +        return;<br>
> +    }<br>
> +<br>
> +    /* Report disconnected right away */<br>
> +    MM_BASE_BEARER_CLASS<br>
> (mm_broadband_bearer_<wbr>cinterion_parent_class)-<br>
> >report_connection_status (<br>
> +        bearer,<br>
> +        MM_BEARER_CONNECTION_<wbr>STATUS_DISCONNECTED);<br>
> +}<br>
> +<br>
> +/****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
> +<br>
> +MMBaseBearer *<br>
> +mm_broadband_bearer_<wbr>cinterion_new_finish (GAsyncResult *res,<br>
> +                             <wbr>          GError **error)<br>
> +{<br>
> +    GObject *bearer;<br>
> +    GObject *source;<br>
> +<br>
> +    source = g_async_result_get_source_<wbr>object (res);<br>
> +    bearer = g_async_initable_new_finish (G_ASYNC_INITABLE (source),<br>
> res,<br>
> error);<br>
> +    g_object_unref (source);<br>
> +<br>
> +    if (!bearer)<br>
> +        return NULL;<br>
> +<br>
> +    /* Only export valid bearers */<br>
> +    mm_base_bearer_export (MM_BASE_BEARER (bearer));<br>
> +<br>
> +    return MM_BASE_BEARER (bearer);<br>
> +}<br>
> +<br>
> +static void<br>
> +dispose (GObject *object)<br>
> +{<br>
> +    <wbr>MMBroadbandBearerCinterion *self = MM_BROADBAND_BEARER_CINTERION<br>
> (object);<br>
> +<br>
> +    if (self->priv->network_<wbr>disconnect_pending_id != 0) {<br>
> +        g_source_remove (self->priv->network_<wbr>disconnect_pending_id);<br>
> +        self->priv->network_<wbr>disconnect_pending_id = 0;<br>
> +    }<br>
> +<br>
> +    G_OBJECT_CLASS (mm_broadband_bearer_<wbr>cinterion_parent_class)-<br>
> >dispose<br>
> (object);<br>
> +}<br>
> +<br>
> +void<br>
> +mm_broadband_bearer_<wbr>cinterion_new (MMBroadbandModemCinterion *modem,<br>
> +                             <wbr>   MMBearerProperties *config,<br>
> +                             <wbr>   GCancellable *cancellable,<br>
> +                             <wbr>   GAsyncReadyCallback callback,<br>
> +                             <wbr>   gpointer user_data)<br>
> +{<br>
> +    g_async_initable_new_<wbr>async (<br>
> +        MM_TYPE_BROADBAND_<wbr>BEARER_CINTERION,<br>
> +        G_PRIORITY_DEFAULT,<br>
> +        cancellable,<br>
> +        callback,<br>
> +        user_data,<br>
> +        MM_BASE_BEARER_MODEM, modem,<br>
> +        MM_BASE_BEARER_<wbr>CONFIG, config,<br>
> +        NULL);<br>
> +}<br>
> +<br>
> +static void<br>
> +mm_broadband_bearer_<wbr>cinterion_init (MMBroadbandBearerCinterion<br>
> *self)<br>
> +{<br>
> +    // Initialize private data<br>
> +    self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,<br>
> +<br>
>  MM_TYPE_BROADBAND_BEARER_<wbr>CINTERION,<br>
> +<br>
>  <wbr>MMBroadbandBearerCinterionPriv<wbr>ate);<br>
> +}<br>
> +<br>
> +static void<br>
> +mm_broadband_bearer_<wbr>cinterion_class_init<br>
> (<wbr>MMBroadbandBearerCinterionClas<wbr>s<br>
> *klass)<br>
> +{<br>
> +    GObjectClass *object_class = G_OBJECT_CLASS (klass);<br>
> +    MMBaseBearerClass *base_bearer_class = MM_BASE_BEARER_CLASS<br>
> (klass);<br>
> +    MMBroadbandBearerClass *broadband_bearer_class =<br>
> MM_BROADBAND_BEARER_CLASS (klass);<br>
> +<br>
> +    g_type_class_add_private (object_class, sizeof<br>
> (<wbr>MMBroadbandBearerCinterionPriv<wbr>ate));<br>
> +<br>
> +    object_class->dispose = dispose;<br>
> +    base_bearer_class-><wbr>report_connection_status =<br>
> report_connection_status; //TODO:What triggers this?<br>
> +<br>
> +    broadband_bearer_class-><wbr>connect_3gpp = connect_3gpp;<br>
> +    broadband_bearer_class-><wbr>connect_3gpp_finish =<br>
> connect_3gpp_finish;<br>
> +    broadband_bearer_class-><wbr>disconnect_3gpp = disconnect_3gpp;<br>
> +    broadband_bearer_class-><wbr>disconnect_3gpp_finish =<br>
> disconnect_3gpp_finish;<br>
> +}<br>
> diff --git a/plugins/cinterion/mm-<wbr>broadband-bearer-cinterion.h<br>
> b/plugins/cinterion/mm-<wbr>broadband-bearer-cinterion.h<br>
> new file mode 100644<br>
> index 0000000..8f315db<br>
> --- /dev/null<br>
> +++ b/plugins/cinterion/mm-<wbr>broadband-bearer-cinterion.h<br>
> @@ -0,0 +1,56 @@<br>
> +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset:<br>
> 4 -*-<br>
> */<br>
> +/*<br>
> + * This program is free software; you can redistribute it and/or<br>
> modify<br>
> + * it under the terms of the GNU General Public License as published<br>
> by<br>
> + * the Free Software Foundation; either version 2 of the License, or<br>
> + * (at your option) any later version.<br>
> + *<br>
> + * This program is distributed in the hope that it will be useful,<br>
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the<br>
> + * GNU General Public License for more details:<br>
> + *<br>
> + * Copyright (C) 2016 Trimble Navigation Limited<br>
> + * Author: Matthew Stanger <<a href="mailto:Matthew_Stanger@trimble.com">Matthew_Stanger@trimble.com</a>><br>
> + */<br>
> +<br>
> +#ifndef MM_BROADBAND_BEARER_CINTERION_<wbr>H<br>
> +#define MM_BROADBAND_BEARER_CINTERION_<wbr>H<br>
> +<br>
> +#include <glib.h><br>
> +#include <glib-object.h><br>
> +<br>
> +#include "mm-broadband-bearer.h"<br>
> +#include "mm-broadband-modem-cinterion.<wbr>h"<br>
> +<br>
> +#define MM_TYPE_BROADBAND_BEARER_<wbr>CINTERION<br>
>  (mm_broadband_bearer_<wbr>cinterion_get_type ())<br>
> +#define MM_BROADBAND_BEARER_CINTERION(<wbr>obj)<br>
>  (G_TYPE_CHECK_INSTANCE_CAST ((obj),<br>
> MM_TYPE_BROADBAND_BEARER_<wbr>CINTERION,<br>
> MMBroadbandBearerCinterion))<br>
> +#define MM_BROADBAND_BEARER_CINTERION_<wbr>CLASS(klass)<br>
>  (G_TYPE_CHECK_CLASS_CAST<br>
> ((klass),  MM_TYPE_BROADBAND_<wbr>BEARER_CINTERION,<br>
> MMBroadbandBearerCinterionClas<wbr>s))<br>
> +#define MM_IS_BROADBAND_BEARER_<wbr>CINTERION(obj)<br>
> (G_TYPE_CHECK_INSTANCE_TYPE ((obj),<br>
> MM_TYPE_BROADBAND_BEARER_<wbr>CINTERION))<br>
> +#define MM_IS_BROADBAND_BEARER_<wbr>CINTERION_CLASS(klass)<br>
> (G_TYPE_CHECK_CLASS_TYPE<br>
> ((klass),  MM_TYPE_BROADBAND_<wbr>BEARER_CINTERION))<br>
> +#define MM_BROADBAND_BEARER_CINTERION_<wbr>GET_CLASS(obj)<br>
>  (G_TYPE_INSTANCE_GET_CLASS<br>
> ((obj),  MM_TYPE_BROADBAND_<wbr>BEARER_CINTERION,<br>
> MMBroadbandBearerCinterionClas<wbr>s))<br>
> +<br>
> +typedef struct _MMBroadbandBearerCinterion<br>
> MMBroadbandBearerCinterion;<br>
> +typedef struct _<wbr>MMBroadbandBearerCinterionClas<wbr>s<br>
> MMBroadbandBearerCinterionClas<wbr>s;<br>
> +typedef struct _<wbr>MMBroadbandBearerCinterionPriv<wbr>ate<br>
> MMBroadbandBearerCinterionPriv<wbr>ate;<br>
> +<br>
> +struct _MMBroadbandBearerCinterion {<br>
> +    MMBroadbandBearer parent;<br>
> +    <wbr>MMBroadbandBearerCinterionPriv<wbr>ate *priv;<br>
> +};<br>
> +<br>
> +struct _<wbr>MMBroadbandBearerCinterionClas<wbr>s {<br>
> +    MMBroadbandBearerClass parent;<br>
> +};<br>
> +<br>
> +GType mm_broadband_bearer_cinterion_<wbr>get_type (void);<br>
> +<br>
> +void          mm_broadband_<wbr>bearer_cinterion_new<br>
>  (MMBroadbandModemCinterion *modem,<br>
> +                             <wbr>                        <wbr>MMBearerPropert<br>
> ies<br>
> *config,<br>
> +                             <wbr>                        <wbr>GCancellable<br>
> *cancellable,<br>
> +                             <wbr>                        <wbr>GAsyncReadyCall<br>
> back<br>
</div></div><div><div class="h5">> callback,<br>
> +                             <wbr>                        <wbr>gpointer<br>
> user_data);<br>
> +MMBaseBearer *mm_broadband_bearer_<wbr>cinterion_new_finish (GAsyncResult<br>
> *res,<br>
> +                             <wbr>                        GError<br>
> **error);<br>
> +<br>
> +#endif /* MM_BROADBAND_BEARER_CINTERION_<wbr>H */<br>
> diff --git a/plugins/cinterion/mm-<wbr>broadband-modem-cinterion.c<br>
> b/plugins/cinterion/mm-<wbr>broadband-modem-cinterion.c<br>
> index 4882a41..ac1c5f5 100644<br>
> --- a/plugins/cinterion/mm-<wbr>broadband-modem-cinterion.c<br>
> +++ b/plugins/cinterion/mm-<wbr>broadband-modem-cinterion.c<br>
> @@ -12,7 +12,9 @@<br>
>   *<br>
>   * Copyright (C) 2011 Ammonit Measurement GmbH<br>
>   * Copyright (C) 2011 Google Inc.<br>
> + * Copyright (C) 2016 Trimble Navigation Limited<br>
>   * Author: Aleksander Morgado <<a href="mailto:aleksander@lanedo.com">aleksander@lanedo.com</a>><br>
> + * Contributor: Matthew Stanger <<a href="mailto:matthew_stanger@trimble.com">matthew_stanger@trimble.com</a>><br>
>   */<br>
><br>
>  #include <config.h><br>
> @@ -22,6 +24,8 @@<br>
>  #include <string.h><br>
>  #include <unistd.h><br>
>  #include <ctype.h><br>
> +#include <gudev/gudev.h><br>
> +<br>
><br>
>  #include "ModemManager.h"<br>
>  #include "mm-modem-helpers.h"<br>
> @@ -36,6 +40,7 @@<br>
>  #include "mm-broadband-modem-cinterion.<wbr>h"<br>
>  #include "mm-modem-helpers-cinterion.h"<br>
>  #include "mm-common-cinterion.h"<br>
> +#include "mm-broadband-bearer-<wbr>cinterion.h"<br>
><br>
>  static void iface_modem_init      (<wbr>MMIfaceModem *iface);<br>
>  static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);<br>
> @@ -50,6 +55,12 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemCinterion,<br>
> mm_broadband_modem_cinterion,<br>
>                          G_<wbr>IMPLEMENT_INTERFACE<br>
> (MM_TYPE_IFACE_MODEM_<wbr>MESSAGING, iface_modem_messaging_init)<br>
>                          G_<wbr>IMPLEMENT_INTERFACE<br>
> (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init))<br>
><br>
> +typedef enum {<br>
> +    FEATURE_SUPPORT_UNKNOWN,<br>
> +    FEATURE_NOT_SUPPORTED,<br>
> +    FEATURE_SUPPORTED<br>
> +} FeatureSupport;<br>
> +<br>
>  struct _<wbr>MMBroadbandModemCinterionPriva<wbr>te {<br>
>      /* Flag to know if we should try AT^SIND or not to get psinfo */<br>
>      gboolean sind_psinfo;<br>
> @@ -69,6 +80,9 @@ struct _<wbr>MMBroadbandModemCinterionPriva<wbr>te {<br>
>      GArray *cnmi_supported_bm;<br>
>      GArray *cnmi_supported_ds;<br>
>      GArray *cnmi_supported_bfr;<br>
> +<br>
> +    FeatureSupport swwan_support;<br>
> +<br>
>  };<br>
><br>
>  /****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
> @@ -117,7 +131,7 @@ cnmi_test_ready (MMBaseModem *self,<br>
>  {<br>
>      GError *error = NULL;<br>
><br>
> -    mm_base_modem_at_command_<wbr>finish (MM_BASE_MODEM (self), res,<br>
> &error);<br>
> +     mm_base_modem_at_<wbr>command_finish (MM_BASE_MODEM (self), res,<br>
> &error);<br>
>      if (error)<br>
>          g_simple_async_<wbr>result_take_error (simple, error);<br>
>      else<br>
> @@ -727,10 +741,16 @@ get_access_technology_from_<wbr>psinfo (const gchar<br>
> *psinfo,<br>
>          case 9:<br>
>          case 10:<br>
>              return (MM_MODEM_ACCESS_TECHNOLOGY_<wbr>HSDPA |<br>
> MM_MODEM_ACCESS_TECHNOLOGY_<wbr>HSUPA);<br>
> +        case 16:<br>
> +        case 17:<br>
> +            return MM_MODEM_ACCESS_TECHNOLOGY_<wbr>LTE;<br>
>          default:<br>
> +            mm_dbg ("Unable to identify access technology in<br>
> case:%i",<br>
> psinfoval);<br>
>              break;<br>
>          }<br>
>      }<br>
> +    else<br>
> +        mm_err ("FAILED get_access_technology_from_<wbr>psinfo-int");<br>
><br>
>      g_set_error (error,<br>
>                   MM_CORE_<wbr>ERROR,<br>
> @@ -1648,6 +1668,259 @@ setup_ports (MMBroadbandModem *self)<br>
>  }<br>
><br>
>  /****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
> +/* Create Bearer (Modem interface) */<br>
> +<br>
> +typedef struct {<br>
> +    MMBroadbandModemCinterion *self;<br>
> +    GSimpleAsyncResult *result;<br>
> +    MMBearerProperties *properties;<br>
> +} CreateBearerContext;<br>
> +<br>
> +static void<br>
> +create_bearer_context_<wbr>complete_and_free (CreateBearerContext *ctx)<br>
> +{<br>
> +    g_simple_async_result_<wbr>complete (ctx->result);<br>
> +    g_object_unref (ctx->result);<br>
> +    g_object_unref (ctx->self);<br>
> +    g_object_unref (ctx->properties);<br>
> +    g_slice_free (CreateBearerContext, ctx);<br>
> +}<br>
> +<br>
> +static MMBaseBearer *<br>
> +cinterion_modem_create_<wbr>bearer_finish (MMIfaceModem *self,<br>
> +                             <wbr>      GAsyncResult *res,<br>
> +                             <wbr>      GError **error)<br>
> +{<br>
> +    MMBaseBearer *bearer;<br>
> +<br>
> +    if (g_simple_async_result_<wbr>propagate_error (G_SIMPLE_ASYNC_RESULT<br>
> (res), error))<br>
> +        return NULL;<br>
> +<br>
> +    bearer = g_simple_async_result_get_op_<wbr>res_gpointer<br>
> (G_SIMPLE_ASYNC_RESULT (res));<br>
> +    mm_dbg ("New cinterion bearer created at DBus path '%s'",<br>
> mm_base_bearer_get_path (bearer));<br>
> +    return g_object_ref (bearer);<br>
> +}<br>
> +<br>
> +static void<br>
> +broadband_bearer_cinterion_<wbr>new_ready (GObject *source,<br>
> +                             <wbr>      GAsyncResult *res,<br>
> +                             <wbr>      CreateBearerContext *ctx)<br>
> +{<br>
> +    MMBaseBearer *bearer;<br>
> +    GError *error = NULL;<br>
> +<br>
> +    bearer = mm_broadband_bearer_cinterion_<wbr>new_finish (res, &error);<br>
> +    if (!bearer)<br>
> +        g_simple_async_<wbr>result_take_error (ctx->result, error);<br>
> +    else<br>
> +        g_simple_async_<wbr>result_set_op_res_gpointer (ctx->result,<br>
> bearer,<br>
> (GDestroyNotify)g_object_<wbr>unref);<br>
> +    create_bearer_context_<wbr>complete_and_free (ctx);<br>
> +}<br>
> +<br>
> +static void<br>
> +broadband_bearer_new_ready (GObject *source,<br>
> +                            <wbr>GAsyncResult *res,<br>
> +                            <wbr>CreateBearerContext *ctx)<br>
> +{<br>
> +    MMBaseBearer *bearer;<br>
> +    GError *error = NULL;<br>
> +<br>
> +    bearer = mm_broadband_bearer_new_finish (res, &error);<br>
> +    if (!bearer)<br>
> +        g_simple_async_<wbr>result_take_error (ctx->result, error);<br>
> +    else<br>
> +        g_simple_async_<wbr>result_set_op_res_gpointer (ctx->result,<br>
> bearer,<br>
> (GDestroyNotify)g_object_<wbr>unref);<br>
> +    create_bearer_context_<wbr>complete_and_free (ctx);<br>
> +}<br>
> +<br>
> +static void<br>
> +create_bearer_for_net_port (CreateBearerContext *ctx)<br>
> +{<br>
> +    switch (ctx->self->priv->swwan_<wbr>support) {<br>
> +    case FEATURE_SUPPORT_UNKNOWN:<br>
> +        g_assert_not_reached ();<br>
> +    case FEATURE_NOT_SUPPORTED:<br>
> +        mm_dbg ("^SWWAN not supported, creating default bearer...");<br>
> +        mm_broadband_bearer_<wbr>new (MM_BROADBAND_MODEM (ctx->self),<br>
> +                             <wbr>    ctx->properties,<br>
> +                             <wbr>    NULL, /* cancellable */<br>
> +<br>
> (GAsyncReadyCallback)<wbr>broadband_bearer_new_ready,<br>
> +                             <wbr>    ctx);<br>
> +        return;<br>
> +    case FEATURE_SUPPORTED:<br>
> +        mm_dbg ("^SWWAN supported, creating cinterion bearer...");<br>
> +        mm_broadband_bearer_<wbr>cinterion_new<br>
> (MM_BROADBAND_MODEM_CINTERION<br>
> (ctx->self),<br>
> +                             <wbr>           ctx->properties,<br>
> +                             <wbr>           NULL, /* cancellable */<br>
> +<br>
>  (GAsyncReadyCallback)<wbr>broadband_bearer_cinterion_<wbr>new_ready,<br>
> +                             <wbr>           ctx);<br>
> +        return;<br>
> +    }<br>
> +}<br>
> +<br>
> +static MMPortSerialAt *<br>
> +peek_port_at_for_data (MMBroadbandModemCinterion *self,<br>
> +                       MMPort *port)<br>
> +{<br>
> +    GList *cdc_wdm_at_ports, *l;<br>
> +    const gchar *net_port_parent_path;<br>
> +<br>
> +    g_warn_if_fail (mm_port_get_subsys (port) ==<br>
> MM_PORT_SUBSYS_NET);<br>
> +    net_port_parent_path = mm_port_get_parent_path (port);<br>
> +<br>
> +    if (!net_port_parent_path) {<br>
> +        g_warning ("(%s) no parent path for net port",<br>
> mm_port_get_device<br>
> (port));<br>
> +        return NULL;<br>
> +    }<br>
> +<br>
> +    //Find the port to send AT commands on...<br>
> +    cdc_wdm_at_ports = mm_base_modem_find_ports (MM_BASE_MODEM<br>
> (self),<br>
> +                             <wbr>                    MM_PORT_<wbr>SUBSYS_USB,<br>
> +                             <wbr>                    MM_PORT_<wbr>TYPE_NET,<br>
> +                             <wbr>                    NULL);<br>
> +<br>
> +<br>
> +    for (l = cdc_wdm_at_ports; l; l = l->next) {<br>
> +        const gchar  *wdm_port_parent_path;<br>
> +<br>
> +        g_assert (MM_IS_PORT_SERIAL_AT (l->data));<br>
> +        wdm_port_parent_path = mm_port_get_parent_path (MM_PORT (l-<br>
> >data));<br>
> +<br>
> +        if (wdm_port_parent_path && g_str_equal<br>
> (wdm_port_parent_path,<br>
> net_port_parent_path))<br>
> +           return MM_PORT_SERIAL_AT (l->data);<br>
> +    }<br>
> +<br>
> +    return NULL;<br>
> +}<br>
> +<br>
> +MMPortSerialAt *<br>
> +mm_broadband_modem_cinterion_<wbr>peek_port_at_for_data<br>
> (MMBroadbandModemCinterion *self,<br>
> +                             <wbr>                    MMPort *port)<br>
> +{<br>
> +    MMPortSerialAt *found;<br>
> +<br>
> +    g_assert (self->priv->swwan_support == FEATURE_SUPPORTED);<br>
> +<br>
> +    found = peek_port_at_for_data (self, port);<br>
> +    if (!found)<br>
> +        mm_warn ("Couldn't find associated cdc-wdm port for<br>
> 'net/%s'",<br>
> +                 mm_port_get_<wbr>device (port));<br>
> +    return found;<br>
> +}<br>
> +<br>
> +static void<br>
> +ensure_swwan_support_checked (MMBroadbandModemCinterion *self,<br>
> +                             <wbr>   MMPort *port)<br>
> +{<br>
> +    GUdevClient *client;<br>
> +    GUdevDevice *data_device;<br>
> +<br>
> +    /* Initialize the swwan feature */<br>
> +    if (self->priv->swwan_support != FEATURE_SUPPORT_UNKNOWN)<br>
> +        return;<br>
> +<br>
> +    /* First, check for devices which could support SWWAN. They<br>
> +     * will be tagged by udev as net devices. */<br>
> +    client = g_udev_client_new (NULL);<br>
> +    data_device = (g_udev_client_query_by_<wbr>subsystem_and_name (<br>
> +                       <wbr>client,<br>
> +                       "net",<br>
> +                       mm_<wbr>port_get_device (port)));<br>
> +<br>
> +    /* udevadm info for Cinterion PLS8-X v3.017 Modem<br>
> +        P: /devices/pci0000:00/0000:00:<wbr>14.0/usb3/3-2/3-<br>
> 2:1.10/net/usb0<br>
> +        E:<br>
> DEVPATH=/devices/pci0000:00/<wbr>0000:00:14.0/usb3/3-2/3-2:1.<wbr>10/net/usb0<br>
> +        E: ID_BUS=usb<br>
> +        E: ID_MM_CANDIDATE=1<br>
> +        E: ID_MODEL=LTE_Modem<br>
> +        E: ID_MODEL_ENC=LTE\x20Modem<br>
> +        E: ID_MODEL_FROM_DATABASE=2.0 root hub<br>
> +        E: ID_MODEL_ID=0061<br>
> +        E: ID_NET_NAME_MAC=<wbr>enxdeadbeef0000<br>
> +        E: ID_NET_NAME_PATH=enp0s20u2i10<br>
> +        E: ID_REVISION=0232<br>
> +        E: ID_SERIAL=Cinterion_LTE_Modem<br>
> +        E: ID_TYPE=generic<br>
> +            E: ID_USB_DRIVER=cdc_ether<br>
> +        E: ID_USB_INTERFACES=:020201:<wbr>0a0000:020600:<br>
> +        E: ID_USB_INTERFACE_NUM=0a<br>
> +        E: ID_VENDOR=Cinterion<br>
> +        E: ID_VENDOR_ENC=Cinterion<br>
> +        E: ID_VENDOR_FROM_DATABASE=Linux Foundation<br>
> +        E: ID_VENDOR_ID=1e2d<br>
> +        E: IFINDEX=11<br>
> +        E: INTERFACE=usb0<br>
> +        E: SUBSYSTEM=net<br>
> +        E: USEC_INITIALIZED=4142603761<br>
> +<br>
> +        P: /devices/pci0000:00/0000:00:<wbr>14.0/usb3/3-2/3-2:1.11<br>
> +        E: DEVPATH=/devices/pci0000:00/<wbr>0000:00:14.0/usb3/3-2/3-<br>
> 2:1.11<br>
> +        E: DEVTYPE=usb_interface<br>
> +        E: DRIVER=cdc_ether<br>
> +        E: ID_MODEL_FROM_DATABASE=2.0 root hub<br>
> +        E: ID_VENDOR_FROM_DATABASE=Linux Foundation<br>
> +        E: INTERFACE=10/0/0<br>
> +        E:<br>
> MODALIAS=usb:<wbr>v1E2Dp0061d0232dc00dsc00dp00ic<wbr>0Aisc00ip00in0B<br>
> +        E: PRODUCT=1e2d/61/232<br>
> +        E: SUBSYSTEM=usb<br>
> +        E: TYPE=0/0/0<br>
> +        E: USEC_INITIALIZED=604142604196<br>
> +    */<br>
> +<br>
> +    //Assumption - Cinterion modems that use cdc_ether will support<br>
> the<br>
> swwan via usb ethernet.<br>
> +    //Cinterion alluded to this idea when I spoke with their<br>
> engineering<br>
> support but stopped short<br>
> +    //of being able to confirm if all future/current models will be<br>
> this<br>
> way.<br>
> +    if (data_device &&<br>
> g_str_equal(g_udev_device_get_<wbr>property(data_device,<br>
> "ID_USB_DRIVER"),"cdc_ether")) {<br>
> +        mm_dbg ("This device (%s) can support swwan feature",<br>
> mm_port_get_device (port));<br>
> +        self->priv->swwan_<wbr>support = FEATURE_SUPPORTED;<br>
> +    }<br>
> +    else<br>
> +    {<br>
> +        self->priv->swwan_<wbr>support = FEATURE_NOT_SUPPORTED;<br>
> +        mm_dbg ("This device (%s) can not support swwan feature",<br>
> mm_port_get_device (port));<br>
> +    }<br>
> +<br>
> +    /* Free the g_object*/<br>
> +    if (data_device)<br>
> +        g_object_unref (data_device);<br>
> +    if (client)<br>
> +        g_object_unref (client);<br>
> +}<br>
> +<br>
> +static void<br>
> +cinterion_modem_create_bearer (MMIfaceModem *self,<br>
> +                            <wbr>MMBearerProperties *properties,<br>
> +                            <wbr>GAsyncReadyCallback callback,<br>
> +                            <wbr>gpointer user_data)<br>
> +{<br>
> +    CreateBearerContext *ctx;<br>
> +    MMPort *port;<br>
> +<br>
> +    ctx = g_slice_new0 (CreateBearerContext);<br>
> +    ctx->self = g_object_ref (self);<br>
> +    ctx->properties = g_object_ref (properties);<br>
> +    ctx->result = g_simple_async_result_new (G_OBJECT (self),<br>
> +                             <wbr>                callback,<br>
> +                             <wbr>                user_data,<br>
> +<br>
> cinterion_modem_create_bearer)<wbr>;<br>
> +<br>
> +    port = mm_base_modem_peek_best_data_<wbr>port (MM_BASE_MODEM (self),<br>
> MM_PORT_TYPE_NET);<br>
> +<br>
> +    if (port) {<br>
> +        ensure_swwan_support_<wbr>checked (ctx->self, port);<br>
> +        create_bearer_for_<wbr>net_port (ctx);<br>
> +        return;<br>
> +    }<br>
> +<br>
> +    mm_dbg ("Creating default bearer...");<br>
> +    mm_broadband_bearer_new (MM_BROADBAND_MODEM (self),<br>
> +                             <wbr>properties,<br>
> +                             <wbr>NULL, /* cancellable */<br>
> +<br>
> (GAsyncReadyCallback)<wbr>broadband_bearer_new_ready,<br>
> +                             <wbr>ctx);<br>
> +}<br>
> +<br>
> +/****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
><br>
>  MMBroadbandModemCinterion *<br>
>  mm_broadband_modem_cinterion_<wbr>new (const gchar *device,<br>
> @@ -1675,6 +1948,7 @@ mm_broadband_modem_cinterion_<wbr>init<br>
> (MMBroadbandModemCinterion *self)<br>
><br>
>      /* Set defaults */<br>
>      self->priv->sind_psinfo = TRUE; /* Initially, always try to get<br>
> psinfo<br>
> */<br>
> +    self->priv->swwan_support = FEATURE_SUPPORT_UNKNOWN;<br>
>  }<br>
><br>
>  static void<br>
> @@ -1683,7 +1957,7 @@ finalize (GObject *object)<br>
>      MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION<br>
> (object);<br>
><br>
>      g_free (self->priv->sleep_mode_cmd);<br>
> -    g_free (self->priv->manual_operator_<wbr>id);<br>
> +    g_free (self->priv->manual_operator_<wbr>id);<br>
><br>
>      if (self->priv->cnmi_supported_<wbr>mode)<br>
>          g_array_unref (self->priv->cnmi_supported_<wbr>mode);<br>
> @@ -1704,6 +1978,8 @@ iface_modem_init (MMIfaceModem *iface)<br>
>  {<br>
>      iface_modem_parent = g_type_interface_peek_parent (iface);<br>
><br>
> +    iface->create_bearer = cinterion_modem_create_bearer;<br>
> +    iface->create_bearer_<wbr>finish =<br>
> cinterion_modem_create_bearer_<wbr>finish;<br>
>      iface->load_supported_<wbr>modes = load_supported_modes;<br>
>      iface->load_supported_<wbr>modes_finish =<br>
> load_supported_modes_finish;<br>
>      iface->set_current_modes = set_current_modes;<br>
> @@ -1764,7 +2040,6 @@ mm_broadband_modem_cinterion_<wbr>class_init<br>
> (<wbr>MMBroadbandModemCinterionClass *klass)<br>
>  {<br>
>      GObjectClass *object_class = G_OBJECT_CLASS (klass);<br>
>      MMBroadbandModemClass *broadband_modem_class =<br>
> MM_BROADBAND_MODEM_CLASS (klass);<br>
> -<br>
>      g_type_class_add_private (object_class, sizeof<br>
> (<wbr>MMBroadbandModemCinterionPriva<wbr>te));<br>
><br>
>      /* Virtual methods */<br>
> diff --git a/plugins/cinterion/mm-<wbr>broadband-modem-cinterion.h<br>
> b/plugins/cinterion/mm-<wbr>broadband-modem-cinterion.h<br>
> index 47f0dcb..b675f3d 100644<br>
> --- a/plugins/cinterion/mm-<wbr>broadband-modem-cinterion.h<br>
> +++ b/plugins/cinterion/mm-<wbr>broadband-modem-cinterion.h<br>
> @@ -48,4 +48,7 @@ MMBroadbandModemCinterion<br>
> *mm_broadband_modem_cinterion_<wbr>new (const gchar *device<br>
>                               <wbr>                              <wbr>  guint16<br>
> vendor_id,<br>
>                               <wbr>                              <wbr>  guint16<br>
> product_id);<br>
><br>
> +MMPortSerialAt *mm_broadband_modem_cinterion_<wbr>peek_port_at_for_data<br>
> (MMBroadbandModemCinterion *self,<br>
> +                             <wbr>                              <wbr>      MMP<br>
> ort<br>
> *port);<br>
> +<br>
>  #endif /* MM_BROADBAND_MODEM_CINTERION_H */<br>
> diff --git a/plugins/cinterion/mm-common-<wbr>cinterion.c<br>
> b/plugins/cinterion/mm-common-<wbr>cinterion.c<br>
> index 6e4da70..79f8384 100644<br>
> --- a/plugins/cinterion/mm-common-<wbr>cinterion.c<br>
> +++ b/plugins/cinterion/mm-common-<wbr>cinterion.c<br>
> @@ -11,13 +11,15 @@<br>
>   * GNU General Public License for more details:<br>
>   *<br>
>   * Copyright (C) 2014 Ammonit Measurement GmbH<br>
> + * Copyright (C) 2016 Trimble Navigation Limited<br>
>   * Author: Aleksander Morgado <<a href="mailto:aleksander@aleksander.es">aleksander@aleksander.es</a>><br>
> + * Contributor: Matthew Stanger <<a href="mailto:matthew_stanger@trimble.com">matthew_stanger@trimble.com</a>><br>
>   */<br>
><br>
>  #include "mm-common-cinterion.h"<br>
>  #include "mm-base-modem-at.h"<br>
> +#include "mm-log.h"<br>
><br>
> -static MMIfaceModemLocation *iface_modem_location_parent;<br>
><br>
>  /****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
><br>
> @@ -25,11 +27,40 @@ static MMIfaceModemLocation<br>
> *iface_modem_location_parent;<br>
>  static GQuark cinterion_location_context_<wbr>quark;<br>
><br>
>  /****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
> +/* Def's and Enum's */<br>
> +<br>
> +typedef enum {<br>
> +    GPS_CONTEXT_STEP_SGPSS = 0,<br>
> +    GPS_CONTEXT_STEP_SGPSC_<wbr>ANTENNA,<br>
> +    GPS_CONTEXT_STEP_SGPSC_<wbr>ENGINE,<br>
> +    GPS_CONTEXT_STEP_SGPSC_<wbr>OUTPUT,<br>
> +    GPS_CONTEXT_STEP_DONE,<br>
> +} ConnectGpsContextStep;<br>
> +<br>
> +typedef struct {<br>
> +    MMBaseModem *self;<br>
> +    GSimpleAsyncResult *result;<br>
> +    MMModemLocationSource source;<br>
> +    ConnectGpsContextStep enable_state;<br>
> +    ConnectGpsContextStep disable_state;<br>
> +    gpointer connect_pending;<br>
> +    gpointer disconnect_pending;<br>
> +    gint gps_retry;<br>
> +} LocationGatheringContext;<br>
><br>
>  typedef struct {<br>
>      MMModemLocationSource enabled_sources;<br>
>  } LocationContext;<br>
><br>
> +static MMIfaceModemLocation *iface_modem_location_parent;<br>
> +static void try_gps_enable (MMIfaceModemLocation *self,<br>
> +                <wbr>LocationGatheringContext *ctx);<br>
> +static void try_gps_disable (MMIfaceModemLocation *self,<br>
> +                <wbr>LocationGatheringContext *ctx);<br>
> +static void send_gps_command (MMIfaceModemLocation *self,<br>
> +                             <wbr> LocationGatheringContext *ctx,<br>
> +                             <wbr> gchar **command);<br>
> +<br>
>  static void<br>
>  location_context_free (LocationContext *ctx)<br>
>  {<br>
> @@ -127,13 +158,7 @@ mm_common_cinterion_location_<wbr>load_capabilities<br>
> (MMIfaceModemLocation *self,<br>
>  }<br>
><br>
>  /****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
> -/* Enable/Disable location gathering (Location interface) */<br>
> -<br>
> -typedef struct {<br>
> -    MMBaseModem *self;<br>
> -    GSimpleAsyncResult *result;<br>
> -    MMModemLocationSource source;<br>
> -} LocationGatheringContext;<br>
> +/* Common location gathering (Location interface) */<br>
><br>
>  static void<br>
>  location_gathering_context_<wbr>complete_and_free<br>
> (LocationGatheringContext<br>
> *ctx)<br>
> @@ -144,6 +169,145 @@ location_gathering_context_<wbr>complete_and_free<br>
> (LocationGatheringContext *ctx)<br>
>      g_slice_free (LocationGatheringContext, ctx);<br>
>  }<br>
><br>
> +static void<br>
> +location_gathering_context_<wbr>complete_and_free_full<br>
> (LocationGatheringContext *ctx)<br>
> +{<br>
> +    //It's importiant that this parent function remains protected by<br>
> calls<br>
> where<br>
> +    //both context '*_pending' pointers could be active.<br>
> +    if (ctx->connect_pending != NULL)<br>
> +        ctx->connect_pending = NULL;<br>
> +    else<br>
> +        ctx->disconnect_<wbr>pending = NULL;<br>
> +<br>
> +    location_gathering_<wbr>context_complete_and_free(ctx)<wbr>;<br>
> +}<br>
> +<br>
> +static void<br>
> +promote_gps_state_from_<wbr>response (MMBaseModem *self,<br>
> +                       <wbr>GAsyncResult *res,<br>
> +                       <wbr>LocationGatheringContext *ctx)<br>
> +{<br>
> +    GError *error = NULL;<br>
> +    ConnectGpsContextStep state;<br>
> +    gchar *result;<br>
> +<br>
> +    //Adjust for whether we're dis/en-ableing<br>
> +    if (ctx->connect_pending != NULL)<br>
> +        state = ctx->enable_state;<br>
> +    else<br>
> +    {<br>
> +        g_assert(ctx-><wbr>disconnect_pending != NULL);<br>
> +        state = ctx->disable_state;<br>
> +    }<br>
> +<br>
> +    //We see that the 'Engine,1' command (PLS8) fails for no<br>
> apparent<br>
> reason<br>
> +    //on ATMEL AT91SAM9263 ARM & not x86. See<br>
> 'mm_common_cinterion_setup_<wbr>gps_port'<br>
> +    //comments.<br>
> +    result = g_strdup (mm_base_modem_at_command_<wbr>full_finish (self,<br>
> res,<br>
> &error));<br>
> +<br>
> +    //If we get an error don't progress at first, try the same state<br>
> again.<br>
> +    if ((!result && state != GPS_CONTEXT_STEP_SGPSS && ctx-><br>
> gps_retry <<br>
> 3))<br>
> +    {<br>
> +        state = GPS_CONTEXT_STEP_SGPSS;<br>
> +        ctx->gps_retry++;<br>
> +    }<br>
> +    else {<br>
> +<br>
> +<br>
> +    switch (state) {<br>
> +<br>
> +    //First step try's the legacy SGPSS command. If it fails don't<br>
> error<br>
> out<br>
> +    //continue on to send new Cinterion GPS commands and see if they<br>
> work.<br>
> +    case GPS_CONTEXT_STEP_SGPSS: {<br>
> +        if (!result) {<br>
> +            mm_info ("SGPSS command failed, will try another<br>
> Cinterion GPS<br>
> command.");<br>
> +            state = GPS_CONTEXT_STEP_SGPSC_<wbr>ANTENNA;<br>
> +        }<br>
> +        else<br>
> +            state = GPS_CONTEXT_STEP_DONE;<br>
> +<br>
> +        break;<br>
> +    }<br>
> +    //If the new GPS enable comand fails then exit we are out of<br>
> things to<br>
> try.<br>
> +    //Only connect flow cares about errors.<br>
> +    case GPS_CONTEXT_STEP_SGPSC_<wbr>ANTENNA: {<br>
> +        if (!result && ctx->disconnect_pending == NULL) {<br>
> +            mm_info ("SGPSC command failed, we are out of things to<br>
> try.");<br>
> +            g_simple_async_<wbr>result_take_error (ctx->result, error);<br>
> +            location_<wbr>gathering_context_complete_<wbr>and_free_full (ctx);<br>
> +            return;<br>
> +        }<br>
> +        else<br>
> +             state = GPS_CONTEXT_STEP_SGPSC_ENGINE;<br>
> +<br>
> +        break;<br>
> +    }<br>
> +    case GPS_CONTEXT_STEP_SGPSC_ENGINE: {<br>
> +        if (!result && ctx->disconnect_pending == NULL) {<br>
> +            g_simple_async_<wbr>result_take_error (ctx->result, error);<br>
> +            location_<wbr>gathering_context_complete_<wbr>and_free_full (ctx);<br>
> +            return;<br>
> +        }<br>
> +        else<br>
> +            state = GPS_CONTEXT_STEP_SGPSC_OUTPUT;<br>
> +<br>
> +        break;<br>
> +    }<br>
> +    case GPS_CONTEXT_STEP_SGPSC_OUTPUT: {<br>
> +        if (!result && ctx->disconnect_pending == NULL) {<br>
> +            g_simple_async_<wbr>result_take_error (ctx->result, error);<br>
> +            location_<wbr>gathering_context_complete_<wbr>and_free_full (ctx);<br>
> +            return;<br>
> +        }<br>
> +        else<br>
> +            state = GPS_CONTEXT_STEP_DONE;<br>
> +<br>
> +        break;<br>
> +    }<br>
> +    case GPS_CONTEXT_STEP_DONE: {<br>
> +        //Shouldn't get here, fall into default error.<br>
> +    }<br>
> +    default: {<br>
> +        g_simple_async_<wbr>result_set_error (ctx->result,<br>
> +                             <wbr>            MM_CORE_ERROR,<br>
> +                             <wbr>            MM_CORE_ERROR_<wbr>WRONG_STATE,<br>
> +                             <wbr>            "Unknown gps state during<br>
> setup.");<br>
> +<br>
> +        location_gathering_<wbr>context_complete_and_free_full (ctx);<br>
> +        g_free(result);<br>
> +        return;<br>
> +    }<br>
> +    }<br>
> +    }<br>
> +<br>
> +    //Save state and go back to dis/en-ableing<br>
> +    if (ctx->connect_pending != NULL) {<br>
> +        ctx->enable_state = state;<br>
> +        try_gps_enable(ctx-><wbr>connect_pending, ctx);<br>
> +    }<br>
> +    else {<br>
> +        ctx->disable_state = state;<br>
> +        try_gps_disable(ctx-><wbr>disconnect_pending, ctx);<br>
> +    }<br>
> +    g_free(result);<br>
> +}<br>
> +<br>
> +static void<br>
> +send_gps_command (MMIfaceModemLocation *self,<br>
> +                  <wbr>LocationGatheringContext *ctx,<br>
> +                  gchar **command)<br>
> +{<br>
> +    mm_base_modem_at_command_<wbr>full (MM_BASE_MODEM (self),<br>
> +                             <wbr>      mm_base_modem_peek_best_<wbr>at_port<br>
> (MM_BASE_MODEM (self), NULL),<br>
> +                             <wbr>      *command,<br>
> +                             <wbr>      5,<br>
> +                             <wbr>      FALSE,<br>
> +                             <wbr>      FALSE, /* raw */<br>
> +                             <wbr>      NULL, /* cancellable */<br>
> +<br>
> (GAsyncReadyCallback)promote_<wbr>gps_state_from_response,<br>
> +                             <wbr>      ctx);<br>
> +}<br>
> +<br>
>  /****************************<wbr>**/<br>
>  /* Disable location gathering */<br>
><br>
> @@ -157,15 +321,9 @@<br>
> mm_common_cinterion_disable_<wbr>location_gathering_finish<br>
> (MMIfaceModemLocation *sel<br>
><br>
>  static void<br>
>  gps_disabled_ready (MMBaseModem *self,<br>
> -                    <wbr>GAsyncResult *res,<br>
>                      <wbr>LocationGatheringContext *ctx)<br>
>  {<br>
> -    GError *error = NULL;<br>
> -<br>
> -    if (!mm_base_modem_at_command_<wbr>full_finish (self, res, &error))<br>
> -        g_simple_async_<wbr>result_take_error (ctx->result, error);<br>
> -    else<br>
> -        g_simple_async_<wbr>result_set_op_res_gboolean (ctx->result,<br>
> TRUE);<br>
> +    g_simple_async_result_<wbr>set_op_res_gboolean (ctx->result, TRUE);<br>
><br>
>      /* Only use the GPS port in NMEA/RAW setups */<br>
>      if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_<wbr>NMEA |<br>
> @@ -178,11 +336,57 @@ gps_disabled_ready (MMBaseModem *self,<br>
>              mm_port_serial_<wbr>close (MM_PORT_SERIAL (gps_port));<br>
>      }<br>
><br>
> -    location_gathering_<wbr>context_complete_and_free (ctx);<br>
> +    location_gathering_<wbr>context_complete_and_free_full (ctx);<br>
> +}<br>
> +<br>
> +static void<br>
> +try_gps_disable (MMIfaceModemLocation *self,<br>
> +                <wbr>LocationGatheringContext *ctx)<br>
> +{<br>
> +    gchar *gps_command;<br>
> +<br>
> +    switch (ctx->disable_state) {<br>
> +<br>
> +    //The old command to enable GPS, works on at least PSX8<br>
> +    case GPS_CONTEXT_STEP_SGPSS: {<br>
> +        gps_command = "^SGPSS=0";<br>
> +        break;<br>
> +    }<br>
> +    //Commands Power/Ant, Engine & Output w/ sgpsc are<br>
> +    //used by PLS8-X & E. Since around versions 2.0+<br>
> +    case GPS_CONTEXT_STEP_SGPSC_<wbr>ANTENNA: {<br>
> +        gps_command = "^SGPSC=\"Power/Antenna\",\"<wbr>off\"";<br>
> +        break;<br>
> +    }<br>
> +    case GPS_CONTEXT_STEP_SGPSC_ENGINE: {<br>
> +        gps_command = "^SGPSC=\"Engine\",\"0\"";<br>
> +        break;<br>
> +    }<br>
> +    case GPS_CONTEXT_STEP_SGPSC_OUTPUT: {<br>
> +        gps_command = "^SGPSC=\"NMEA/Output\",\"off\<wbr>"";<br>
> +        break;<br>
> +    }<br>
> +    case GPS_CONTEXT_STEP_DONE: {<br>
> +        gps_disabled_ready(<wbr>MM_BASE_MODEM (self), ctx);<br>
> +        return;<br>
> +    }<br>
> +    default: {<br>
> +        g_simple_async_<wbr>result_set_error (ctx->result,<br>
> +                             <wbr>            MM_CORE_ERROR,<br>
> +                             <wbr>            MM_CORE_ERROR_<wbr>WRONG_STATE,<br>
> +                             <wbr>            "Unknown gps state during<br>
</div></div>> tear<br>
> down.");<br>
> +<br>
> +        location_gathering_<wbr>context_complete_and_free_full (ctx);<br>
> +        return;<br>
> +    }<br>
> +    }<br>
> +<br>
> +    send_gps_command(self, ctx, &gps_command);<br>
<span class="">> +    return;<br>
>  }<br>
><br>
>  static void<br>
> -internal_disable_location_<wbr>gathering (LocationGatheringContext *ctx)<br>
> +internal_disable_location_<wbr>gathering (MMIfaceModemLocation *self,<br>
> LocationGatheringContext *ctx)<br>
>  {<br>
>      LocationContext *location_ctx;<br>
>      gboolean stop_gps = FALSE;<br>
> @@ -202,21 +406,30 @@ internal_disable_location_<wbr>gathering<br>
> (LocationGatheringContext *ctx)<br>
>      }<br>
><br>
>      if (stop_gps) {<br>
> -        /* We disable continuous GPS fixes */<br>
> -        mm_base_modem_at_<wbr>command_full (MM_BASE_MODEM (ctx->self),<br>
> -                             <wbr>          mm_base_modem_peek_<wbr>best_at_po<br>
> rt<br>
> (MM_BASE_MODEM (ctx->self), NULL),<br>
> -                             <wbr>          "AT^SGPSS=0",<br>
> -                             <wbr>          3,<br>
> -                             <wbr>          FALSE,<br>
> -                             <wbr>          FALSE, /* raw */<br>
> -                             <wbr>          NULL, /* cancellable */<br>
> -<br>
> (GAsyncReadyCallback)gps_<wbr>disabled_ready,<br>
> -                             <wbr>          ctx);<br>
> +        //Don't allow disconnects while trying to connect.<br>
</span><span class="">> +        if (ctx->connect_pending != NULL)<br>
</span>> +        {<br>
<span class="">> +            g_simple_async_<wbr>result_set_error (ctx->result,<br>
> +                             <wbr>                MM_CORE_ERROR,<br>
</span>> +                             <wbr>                MM_CORE_ERROR_<wbr>IN_PROGRE<br>
<span class="">> SS,<br>
> +                             <wbr>                "Can't disconnect GPS<br>
> while<br>
> another process is trying to connect it.");<br>
> +<br>
> +            //*_complete_and_<wbr>free_full is safe to use for the<br>
> disconnect<br>
> flow after this point.<br>
</span><span class="">> +            ctx->disconnect_<wbr>pending = NULL;<br>
</span>> +            location_<wbr>gathering_context_complete_<wbr>and_free (ctx);<br>
> +            return;<br>
> +        }<br>
> +<br>
> +        ctx->disable_state = GPS_CONTEXT_STEP_SGPSS;<br>
<span class="">> +        ctx->disconnect_<wbr>pending = self;<br>
> +        try_gps_disable(self, ctx);<br>
> +<br>
>          return;<br>
>      }<br>
><br>
>      /* For any other location (e.g. 3GPP), or if still some GPS<br>
> needed,<br>
> just return */<br>
</span>>      g_simple_async_result_<wbr>set_op_res_gboolean (ctx->result, TRUE);<br>
> +    ctx->disconnect_pending = NULL;<br>
<span class="">>      location_gathering_<wbr>context_complete_and_free (ctx);<br>
>  }<br>
><br>
> @@ -236,12 +449,13 @@ parent_disable_location_<wbr>gathering_ready<br>
> (MMIfaceModemLocation *self,<br>
>          } else {<br>
>              /* Fatal */<br>
</span>>              g_simple_async_<wbr>result_take_error (ctx->result, error);<br>
> +            ctx->disconnect_<wbr>pending = NULL;<br>
<span class="">>              location_<wbr>gathering_context_complete_<wbr>and_free (ctx);<br>
>              return;<br>
>          }<br>
>      }<br>
><br>
> -    internal_disable_<wbr>location_gathering (ctx);<br>
> +    internal_disable_<wbr>location_gathering (self, ctx);<br>
>  }<br>
><br>
>  void<br>
> @@ -259,6 +473,9 @@ mm_common_cinterion_disable_<wbr>location_gathering<br>
> (MMIfaceModemLocation *self,<br>
>                               <wbr>                user_data,<br>
><br>
> mm_common_cinterion_disable_<wbr>location_gathering);<br>
>      ctx->source = source;<br>
</span><span class="">> +    ctx->connect_pending = NULL;<br>
</span>> +    ctx->disconnect_pending = NULL;<br>
> +    ctx->gps_retry = 0;<br>
<span class="">><br>
>      /* Chain up parent's gathering enable */<br>
>      if (iface_modem_location_parent-><wbr>disable_location_gathering) {<br>
> @@ -270,7 +487,7 @@ mm_common_cinterion_disable_<wbr>location_gathering<br>
> (MMIfaceModemLocation *self,<br>
>          return;<br>
>      }<br>
><br>
> -    internal_disable_<wbr>location_gathering (ctx);<br>
> +    internal_disable_<wbr>location_gathering (self, ctx);<br>
>  }<br>
><br>
>  /****************************<wbr>******************************<wbr>*********<br>
> **********/<br>
> @@ -286,16 +503,10 @@<br>
> mm_common_cinterion_enable_<wbr>location_gathering_finish<br>
> (MMIfaceModemLocation *self<br>
><br>
>  static void<br>
</span>>  gps_enabled_ready (MMBaseModem *self,<br>
<span class="">> -                   <wbr>GAsyncResult *res,<br>
>                     <wbr>LocationGatheringContext *ctx)<br>
>  {<br>
</span>>      GError *error = NULL;<br>
><br>
> -    if (!mm_base_modem_at_command_<wbr>full_finish (self, res, &error)) {<br>
<span class="">> -        g_simple_async_<wbr>result_take_error (ctx->result, error);<br>
</span>> -        location_gathering_<wbr>context_complete_and_free (ctx);<br>
> -        return;<br>
> -    }<br>
><br>
<span class="">>      /* Only use the GPS port in NMEA/RAW setups */<br>
>      if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_<wbr>NMEA |<br>
</span><span class="">> @@ -312,12 +523,60 @@ gps_enabled_ready (MMBaseModem *self,<br>
>                               <wbr>                    MM_CORE_<wbr>ERROR,<br>
>                               <wbr>                    MM_CORE_<wbr>ERROR_FAILE<br>
> D,<br>
>                               <wbr>                    "Couldn't open raw<br>
> GPS<br>
> serial port");<br>
> -        } else<br>
> +        }<br>
> +        else<br>
>              g_simple_async_<wbr>result_set_op_res_gboolean (ctx->result,<br>
> TRUE);<br>
> -    } else<br>
> +<br>
> +    }<br>
> +    else<br>
>          g_simple_async_<wbr>result_set_op_res_gboolean (ctx->result,<br>
> TRUE);<br>
><br>
</span><span class="">> -    location_gathering_<wbr>context_complete_and_free (ctx);<br>
> +    location_gathering_<wbr>context_complete_and_free_full (ctx);<br>
> +}<br>
> +<br>
> +static void<br>
</span>> +try_gps_enable (MMIfaceModemLocation *self,<br>
<span class="">> +                <wbr>LocationGatheringContext *ctx)<br>
> +{<br>
> +    gchar *gps_command;<br>
> +<br>
</span>> +    switch (ctx->enable_state) {<br>
<span class="">> +<br>
> +    //The old command to enable GPS, works on at least PSX8<br>
> +    case GPS_CONTEXT_STEP_SGPSS: {<br>
</span>> +        gps_command = "^SGPSS=4";<br>
<span class="">> +        break;<br>
> +    }<br>
> +    //Commands Power/Ant, Engine & Output w/ sgpsc are<br>
</span>> +    //used by PLS8-X & E. Since versions 2.0+<br>
> +    case GPS_CONTEXT_STEP_SGPSC_<wbr>ANTENNA: {<br>
> +        gps_command = "^SGPSC=\"Power/Antenna\",\"<wbr>on\"";<br>
<span class="">> +        break;<br>
> +    }<br>
> +    case GPS_CONTEXT_STEP_SGPSC_ENGINE: {<br>
</span>> +        gps_command = "^SGPSC=\"Engine\",\"1\"";<br>
<span class="">> +        break;<br>
> +    }<br>
> +    case GPS_CONTEXT_STEP_SGPSC_OUTPUT: {<br>
</span>> +        gps_command = "^SGPSC=\"NMEA/Output\",\"on\"<wbr>";<br>
<span class="">> +        break;<br>
> +    }<br>
> +    case GPS_CONTEXT_STEP_DONE: {<br>
</span>> +        gps_enabled_ready(MM_<wbr>BASE_MODEM (self), ctx);<br>
<span class="">> +        return;<br>
> +    }<br>
> +    default: {<br>
> +        g_simple_async_<wbr>result_set_error (ctx->result,<br>
> +                             <wbr>            MM_CORE_ERROR,<br>
> +                             <wbr>            MM_CORE_ERROR_<wbr>WRONG_STATE,<br>
</span><span class="">> +                             <wbr>            "Unknown gps state during<br>
> setup.");<br>
</span>> +        location_gathering_<wbr>context_complete_and_free_full (ctx);<br>
> +        return;<br>
> +    }<br>
> +    }<br>
<span class="">> +<br>
> +    send_gps_command(self, ctx, &gps_command);<br>
> +    return;<br>
>  }<br>
><br>
>  static void<br>
> @@ -338,13 +597,13 @@ parent_enable_location_<wbr>gathering_ready<br>
> (MMIfaceModemLocation *self,<br>
>          } else {<br>
>              /* Fatal */<br>
</span>>              g_simple_async_<wbr>result_take_error (ctx->result, error);<br>
> +            ctx->connect_<wbr>pending = NULL;<br>
<div><div class="h5">>              location_<wbr>gathering_context_complete_<wbr>and_free (ctx);<br>
>              return;<br>
>          }<br>
>      }<br>
><br>
>      /* Now our own enabling */<br>
> -<br>
>      location_ctx = get_location_context (MM_BASE_MODEM (self));<br>
><br>
>      /* NMEA and RAW are both enabled in the same way */<br>
> @@ -359,22 +618,33 @@ parent_enable_location_<wbr>gathering_ready<br>
> (MMIfaceModemLocation *self,<br>
>          location_ctx-><wbr>enabled_sources |= ctx->source;<br>
>      }<br>
><br>
> +<br>
>      if (start_gps) {<br>
> -        /* We enable continuous GPS fixes */<br>
> -        mm_base_modem_at_<wbr>command_full (MM_BASE_MODEM (self),<br>
> -                             <wbr>          mm_base_modem_peek_<wbr>best_at_po<br>
> rt<br>
> (MM_BASE_MODEM (self), NULL),<br>
> -                             <wbr>          "AT^SGPSS=4",<br>
> -                             <wbr>          3,<br>
> -                             <wbr>          FALSE,<br>
> -                             <wbr>          FALSE, /* raw */<br>
> -                             <wbr>          NULL, /* cancellable */<br>
> -<br>
> (GAsyncReadyCallback)gps_<wbr>enabled_ready,<br>
> -                             <wbr>          ctx);<br>
> +        //Can only setup/tear down one thing at a time.<br>
</div></div>> +        if (ctx->disconnect_pending != NULL)<br>
<div class="HOEnZb"><div class="h5">> +        {<br>
> +            g_simple_async_<wbr>result_set_error (ctx->result,<br>
> +                             <wbr>                MM_CORE_ERROR,<br>
> +                             <wbr>              </div></div>...<br><br>[Message clipped]  </blockquote></div><br></div>