diff options
author | Aleksander Morgado <aleksandermj@chromium.org> | 2022-12-08 13:37:55 +0000 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2023-01-03 13:56:25 +0000 |
commit | e14b904cbd6816cb0227d519d308ae71ddaf6e07 (patch) | |
tree | 4997ab68cc606fdf4d72a571e821cec0c8df42ef /plugins/mbm | |
parent | 072d7ac9065f444e83b390a1e2af5471ac0d48f6 (diff) |
build: move plugins directory to src/plugins
We are going to allow including the plugin sources built within the
ModemManager daemon binary; moving the sources within the daemon
sources directory makes it easier.
Diffstat (limited to 'plugins/mbm')
-rw-r--r-- | plugins/mbm/77-mm-ericsson-mbm.rules | 174 | ||||
-rw-r--r-- | plugins/mbm/mm-broadband-bearer-mbm.c | 911 | ||||
-rw-r--r-- | plugins/mbm/mm-broadband-bearer-mbm.h | 68 | ||||
-rw-r--r-- | plugins/mbm/mm-broadband-modem-mbm.c | 1583 | ||||
-rw-r--r-- | plugins/mbm/mm-broadband-modem-mbm.h | 58 | ||||
-rw-r--r-- | plugins/mbm/mm-modem-helpers-mbm.c | 337 | ||||
-rw-r--r-- | plugins/mbm/mm-modem-helpers-mbm.h | 51 | ||||
-rw-r--r-- | plugins/mbm/mm-plugin-mbm.c | 101 | ||||
-rw-r--r-- | plugins/mbm/mm-plugin-mbm.h | 43 | ||||
-rw-r--r-- | plugins/mbm/mm-sim-mbm.c | 242 | ||||
-rw-r--r-- | plugins/mbm/mm-sim-mbm.h | 51 | ||||
-rw-r--r-- | plugins/mbm/tests/test-modem-helpers-mbm.c | 268 |
12 files changed, 0 insertions, 3887 deletions
diff --git a/plugins/mbm/77-mm-ericsson-mbm.rules b/plugins/mbm/77-mm-ericsson-mbm.rules deleted file mode 100644 index 73e08692..00000000 --- a/plugins/mbm/77-mm-ericsson-mbm.rules +++ /dev/null @@ -1,174 +0,0 @@ -# do not edit this file, it will be overwritten on update - -ACTION!="add|change|move|bind", GOTO="mm_mbm_end" -SUBSYSTEMS=="usb", ATTRS{idVendor}=="0bdb", GOTO="mm_mbm_ericsson_vendorcheck" -SUBSYSTEMS=="usb", ATTRS{idVendor}=="0fce", GOTO="mm_mbm_sony_vendorcheck" -SUBSYSTEMS=="usb", ATTRS{idVendor}=="413c", GOTO="mm_mbm_dell_vendorcheck" -SUBSYSTEMS=="usb", ATTRS{idVendor}=="03f0", GOTO="mm_mbm_hp_vendorcheck" -SUBSYSTEMS=="usb", ATTRS{idVendor}=="0930", GOTO="mm_mbm_toshiba_vendorcheck" -GOTO="mm_mbm_end" - -LABEL="mm_mbm_ericsson_vendorcheck" -SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}" - -# Ericsson F3507g -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1900", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1900", ENV{ID_MM_ERICSSON_MBM}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1902", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1902", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson F3607gw -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1904", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1904", ENV{ID_MM_ERICSSON_MBM}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1905", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1905", ENV{ID_MM_ERICSSON_MBM}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1906", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1906", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson F3307 -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="190a", ENV{ID_MM_ERICSSON_MBM}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1909", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson F3307 R2 -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1914", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson C3607w -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1049", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson C3607w v2 -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="190b", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson F5521gw -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="190d", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="190d", ENV{ID_MM_ERICSSON_MBM}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1911", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1911", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson H5321gw -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1919", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson H5321w -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="191d", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson F5321gw -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1917", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson F5321w -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="191b", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson C5621gw -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="191f", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson C5621w -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1921", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson H5321gw -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1926", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1926", ENV{ID_MM_ERICSSON_MBM}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1927", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1927", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson C3304w -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1928", ENV{ID_MM_ERICSSON_MBM}="1" - -# Ericsson C5621 TFF -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1936", ENV{ID_MM_ERICSSON_MBM}="1" - -# Lenovo N5321gw -ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="193e", ENV{ID_MM_ERICSSON_MBM}="1" - -GOTO="mm_mbm_end" - -LABEL="mm_mbm_sony_vendorcheck" - -# Sony-Ericsson MD300 -ATTRS{idVendor}=="0fce", ATTRS{idProduct}=="d0cf", ENV{ID_MM_ERICSSON_MBM}="1" - -# Sony-Ericsson MD400 -ATTRS{idVendor}=="0fce", ATTRS{idProduct}=="d0e1", ENV{ID_MM_ERICSSON_MBM}="1" - -# Sony-Ericsson MD400G -ATTRS{idVendor}=="0fce", ATTRS{idProduct}=="d103", ENV{ID_MM_ERICSSON_MBM}="1" - -GOTO="mm_mbm_end" - -LABEL="mm_mbm_dell_vendorcheck" -SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}" - -# Dell 5560 -ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818e", ENV{ID_MM_ERICSSON_MBM}="1" -ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818e", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" - -# Dell 5550 -ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818d", ENV{ID_MM_ERICSSON_MBM}="1" - -# Dell 5530 HSDPA -ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8147", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8147", ENV{ID_MM_ERICSSON_MBM}="1" - -# Dell F3607gw -ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8183", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8183", ENV{ID_MM_ERICSSON_MBM}="1" -ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8184", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8184", ENV{ID_MM_ERICSSON_MBM}="1" - -# Dell F3307 -ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818b", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818b", ENV{ID_MM_ERICSSON_MBM}="1" -ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818c", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818c", ENV{ID_MM_ERICSSON_MBM}="1" - -GOTO="mm_mbm_end" - -LABEL="mm_mbm_hp_vendorcheck" -SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}" - -# HP hs2330 Mobile Broadband Module -ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="271d", ENV{ID_MM_ERICSSON_MBM}="1" - -# HP hs2320 Mobile Broadband Module -ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="261d", ENV{ID_MM_ERICSSON_MBM}="1" - -# HP hs2340 Mobile Broadband Module -ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="3a1d", ENV{ID_MM_ERICSSON_MBM}="1" - -# HP hs2350 Mobile Broadband Module -ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="3d1d", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="3d1d", ENV{ID_MM_ERICSSON_MBM}="1" - -# HP lc2000 Mobile Broadband Module -ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="301d", ENV{ID_MM_ERICSSON_MBM}="1" - -# HP lc2010 Mobile Broadband Module -ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="2f1d", ENV{ID_MM_ERICSSON_MBM}="1" - -GOTO="mm_mbm_end" - -LABEL="mm_mbm_toshiba_vendorcheck" -SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}" - -# Toshiba -ATTRS{idVendor}=="0930", ATTRS{idProduct}=="130b", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="0930", ATTRS{idProduct}=="130b", ENV{ID_MM_ERICSSON_MBM}="1" - -# Toshiba F3607gw -ATTRS{idVendor}=="0930", ATTRS{idProduct}=="130c", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="0930", ATTRS{idProduct}=="130c", ENV{ID_MM_ERICSSON_MBM}="1" -ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1311", ENV{.MM_USBIFNUM}=="09", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1311", ENV{ID_MM_ERICSSON_MBM}="1" - -# Toshiba F3307 -ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1315", ENV{ID_MM_ERICSSON_MBM}="1" -ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1316", ENV{ID_MM_ERICSSON_MBM}="1" -ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1317", ENV{ID_MM_ERICSSON_MBM}="1" - -# Toshiba F5521gw -ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1313", ENV{ID_MM_ERICSSON_MBM}="1" -ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1314", ENV{ID_MM_ERICSSON_MBM}="1" - -# Toshiba H5321gw -ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1319", ENV{ID_MM_ERICSSON_MBM}="1" - -GOTO="mm_mbm_end" - -LABEL="mm_mbm_end" diff --git a/plugins/mbm/mm-broadband-bearer-mbm.c b/plugins/mbm/mm-broadband-bearer-mbm.c deleted file mode 100644 index c1407ab4..00000000 --- a/plugins/mbm/mm-broadband-bearer-mbm.c +++ /dev/null @@ -1,911 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details: - * - * Copyright (C) 2008 - 2010 Ericsson AB - * Copyright (C) 2009 - 2012 Red Hat, Inc. - * Copyright (C) 2012 Lanedo GmbH - * Copyright (C) 2017 Aleksander Morgado <aleksander@aleksander.es> - * - * Author: Per Hallsmark <per.hallsmark@ericsson.com> - * Bjorn Runaker <bjorn.runaker@ericsson.com> - * Torgny Johansson <torgny.johansson@ericsson.com> - * Jonas Sjöquist <jonas.sjoquist@ericsson.com> - * Dan Williams <dcbw@redhat.com> - * Aleksander Morgado <aleksander@aleksander.es> - */ - -#include <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <ctype.h> -#include <arpa/inet.h> - -#include <ModemManager.h> -#define _LIBMM_INSIDE_MM -#include <libmm-glib.h> - -#include "mm-base-modem-at.h" -#include "mm-broadband-bearer-mbm.h" -#include "mm-log-object.h" -#include "mm-modem-helpers.h" -#include "mm-modem-helpers-mbm.h" -#include "mm-daemon-enums-types.h" - -G_DEFINE_TYPE (MMBroadbandBearerMbm, mm_broadband_bearer_mbm, MM_TYPE_BROADBAND_BEARER) - -struct _MMBroadbandBearerMbmPrivate { - GTask *connect_pending; - GTask *disconnect_pending; -}; - -/*****************************************************************************/ -/* 3GPP Dialing (sub-step of the 3GPP Connection sequence) */ - -typedef struct { - MMBaseModem *modem; - MMPortSerialAt *primary; - guint cid; - MMPort *data; - guint poll_count; - guint poll_id; - GError *saved_error; -} Dial3gppContext; - -static void -dial_3gpp_context_free (Dial3gppContext *ctx) -{ - g_assert (!ctx->poll_id); - g_assert (!ctx->saved_error); - g_clear_object (&ctx->data); - g_clear_object (&ctx->primary); - g_clear_object (&ctx->modem); - g_slice_free (Dial3gppContext, ctx); -} - -static MMPort * -dial_3gpp_finish (MMBroadbandBearer *self, - GAsyncResult *res, - GError **error) -{ - return MM_PORT (g_task_propagate_pointer (G_TASK (res), error)); -} - -static void -connect_reset_ready (MMBroadbandBearer *self, - GAsyncResult *res, - GTask *task) -{ - Dial3gppContext *ctx; - - ctx = g_task_get_task_data (task); - - MM_BROADBAND_BEARER_GET_CLASS (self)->disconnect_3gpp_finish (self, res, NULL); - - /* When reset is requested, it was either cancelled or an error was stored */ - if (!g_task_return_error_if_cancelled (task)) { - g_assert (ctx->saved_error); - g_task_return_error (task, ctx->saved_error); - ctx->saved_error = NULL; - } - - g_object_unref (task); -} - -static void -connect_reset (GTask *task) -{ - MMBroadbandBearerMbm *self; - Dial3gppContext *ctx; - - self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); - - MM_BROADBAND_BEARER_GET_CLASS (self)->disconnect_3gpp ( - MM_BROADBAND_BEARER (self), - MM_BROADBAND_MODEM (ctx->modem), - ctx->primary, - NULL, - ctx->data, - ctx->cid, - (GAsyncReadyCallback) connect_reset_ready, - task); -} - -static void -process_pending_connect_attempt (MMBroadbandBearerMbm *self, - MMBearerConnectionStatus status) -{ - GTask *task; - Dial3gppContext *ctx; - - /* Recover connection task */ - task = self->priv->connect_pending; - self->priv->connect_pending = NULL; - g_assert (task != NULL); - - ctx = g_task_get_task_data (task); - - if (ctx->poll_id) { - g_source_remove (ctx->poll_id); - ctx->poll_id = 0; - } - - /* Received 'CONNECTED' during a connection attempt? */ - if (status == MM_BEARER_CONNECTION_STATUS_CONNECTED) { - /* If we wanted to get cancelled before, do it now. */ - if (g_cancellable_is_cancelled (g_task_get_cancellable (task))) { - connect_reset (task); - return; - } - - g_task_return_pointer (task, g_object_ref (ctx->data), g_object_unref); - g_object_unref (task); - return; - } - - /* If we wanted to get cancelled before and now we couldn't connect, - * use the cancelled error and return */ - if (g_task_return_error_if_cancelled (task)) { - g_object_unref (task); - return; - } - - /* Otherwise, received 'DISCONNECTED' during a connection attempt? */ - g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Call setup failed"); - g_object_unref (task); -} - -static gboolean connect_poll_cb (MMBroadbandBearerMbm *self); - -static void -connect_poll_ready (MMBaseModem *modem, - GAsyncResult *res, - MMBroadbandBearerMbm *self) -{ - GTask *task; - Dial3gppContext *ctx; - GError *error = NULL; - const gchar *response; - guint state; - - task = g_steal_pointer (&self->priv->connect_pending); - - if (!task) { - mm_obj_dbg (self, "connection context was finished already by an unsolicited message"); - /* Run _finish() to finalize the async call, even if we don't care - * the result */ - mm_base_modem_at_command_full_finish (modem, res, NULL); - return; - } - - ctx = g_task_get_task_data (task); - - response = mm_base_modem_at_command_full_finish (modem, res, &error); - if (!response) { - ctx->saved_error = error; - connect_reset (task); - return; - } - - if (sscanf (response, "*ENAP: %d", &state) == 1 && state == 1) { - /* Success! Connected... */ - g_task_return_pointer (task, g_object_ref (ctx->data), g_object_unref); - g_object_unref (task); - return; - } - - /* Restore pending task and check again in one second */ - self->priv->connect_pending = task; - g_assert (ctx->poll_id == 0); - ctx->poll_id = g_timeout_add_seconds (1, (GSourceFunc) connect_poll_cb, self); -} - -static gboolean -connect_poll_cb (MMBroadbandBearerMbm *self) -{ - GTask *task; - Dial3gppContext *ctx; - - task = g_steal_pointer (&self->priv->connect_pending); - - g_assert (task); - ctx = g_task_get_task_data (task); - - ctx->poll_id = 0; - - /* Complete if we were cancelled */ - if (g_cancellable_is_cancelled (g_task_get_cancellable (task))) { - connect_reset (task); - return G_SOURCE_REMOVE; - } - - /* Too many retries... */ - if (ctx->poll_count > MM_BASE_BEARER_DEFAULT_CONNECTION_TIMEOUT) { - g_assert (!ctx->saved_error); - ctx->saved_error = g_error_new (MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT, - "Connection attempt timed out"); - connect_reset (task); - return G_SOURCE_REMOVE; - } - - /* Restore pending task and poll */ - self->priv->connect_pending = task; - ctx->poll_count++; - mm_base_modem_at_command_full (ctx->modem, - ctx->primary, - "AT*ENAP?", - 3, - FALSE, - FALSE, /* raw */ - g_task_get_cancellable (task), - (GAsyncReadyCallback)connect_poll_ready, - self); - return G_SOURCE_REMOVE; -} - -static void -activate_ready (MMBaseModem *modem, - GAsyncResult *res, - MMBroadbandBearerMbm *self) -{ - GTask *task; - Dial3gppContext *ctx; - GError *error = NULL; - - /* Try to recover the connection context. If none found, it means the - * context was already completed and we have nothing else to do. */ - task = g_steal_pointer (&self->priv->connect_pending); - - if (!task) { - mm_obj_dbg (self, "connection context was finished already by an unsolicited message"); - /* Run _finish() to finalize the async call, even if we don't care - * the result */ - mm_base_modem_at_command_full_finish (modem, res, NULL); - goto out; - } - - /* From now on, if we get cancelled, we'll need to run the connection - * reset ourselves just in case */ - if (!mm_base_modem_at_command_full_finish (modem, res, &error)) { - g_task_return_error (task, error); - g_object_unref (task); - goto out; - } - - ctx = g_task_get_task_data (task); - - /* No unsolicited E2NAP status yet; wait for it and periodically poll - * to handle very old F3507g/MD300 firmware that may not send E2NAP. */ - self->priv->connect_pending = task; - ctx->poll_id = g_timeout_add_seconds (1, (GSourceFunc)connect_poll_cb, self); - - out: - /* Balance refcount with the extra ref we passed to command_full() */ - g_object_unref (self); -} - -static void -activate (GTask *task) -{ - MMBroadbandBearerMbm *self; - Dial3gppContext *ctx; - gchar *command; - - self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); - - /* The unsolicited response to ENAP may come before the OK does. - * We will keep the connection context in the bearer private data so - * that it is accessible from the unsolicited message handler. */ - g_assert (self->priv->connect_pending == NULL); - self->priv->connect_pending = task; - - /* Activate the PDP context and start the data session */ - command = g_strdup_printf ("AT*ENAP=1,%d", ctx->cid); - mm_base_modem_at_command_full (ctx->modem, - ctx->primary, - command, - 10, - FALSE, - FALSE, /* raw */ - g_task_get_cancellable (task), - (GAsyncReadyCallback)activate_ready, - g_object_ref (self)); /* we pass the bearer object! */ - g_free (command); -} - -static void -authenticate_ready (MMBaseModem *modem, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - if (!mm_base_modem_at_command_full_finish (modem, res, &error)) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - activate (task); -} - -static void -authenticate (GTask *task) -{ - MMBroadbandBearerMbm *self; - Dial3gppContext *ctx; - const gchar *user; - const gchar *password; - - self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); - - user = mm_bearer_properties_get_user (mm_base_bearer_peek_config (MM_BASE_BEARER (self))); - password = mm_bearer_properties_get_password (mm_base_bearer_peek_config (MM_BASE_BEARER (self))); - - /* Both user and password are required; otherwise firmware returns an error */ - if (user || password) { - g_autofree gchar *command = NULL; - g_autofree gchar *user_enc = NULL; - g_autofree gchar *password_enc = NULL; - GError *error = NULL; - - user_enc = mm_modem_charset_str_from_utf8 (user, - mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (ctx->modem)), - FALSE, - &error); - if (!user_enc) { - g_prefix_error (&error, "Couldn't convert user to current charset: "); - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - password_enc = mm_modem_charset_str_from_utf8 (password, - mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (ctx->modem)), - FALSE, - &error); - if (!password_enc) { - g_prefix_error (&error, "Couldn't convert password to current charset: "); - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - command = g_strdup_printf ("AT*EIAAUW=%d,1,\"%s\",\"%s\"", - ctx->cid, user_enc, password_enc); - mm_base_modem_at_command_full (ctx->modem, - ctx->primary, - command, - 3, - FALSE, - FALSE, /* raw */ - g_task_get_cancellable (task), - (GAsyncReadyCallback) authenticate_ready, - task); - return; - } - - mm_obj_dbg (self, "authentication not needed"); - activate (task); -} - -static void -dial_3gpp (MMBroadbandBearer *_self, - MMBaseModem *modem, - MMPortSerialAt *primary, - guint cid, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandBearerMbm *self = MM_BROADBAND_BEARER_MBM (_self); - GTask *task; - Dial3gppContext *ctx; - - g_assert (primary != NULL); - - task = g_task_new (self, cancellable, callback, user_data); - - ctx = g_slice_new0 (Dial3gppContext); - ctx->modem = g_object_ref (modem); - ctx->primary = g_object_ref (primary); - ctx->cid = cid; - g_task_set_task_data (task, ctx, (GDestroyNotify)dial_3gpp_context_free); - - /* We need a net data port */ - ctx->data = mm_base_modem_get_best_data_port (modem, MM_PORT_TYPE_NET); - if (!ctx->data) { - g_task_return_new_error (task, - MM_CORE_ERROR, - MM_CORE_ERROR_NOT_FOUND, - "No valid data port found to launch connection"); - g_object_unref (task); - return; - } - - authenticate (task); -} - -/*****************************************************************************/ -/* 3GPP IP config retrieval (sub-step of the 3GPP Connection sequence) */ - -typedef struct { - MMBaseModem *modem; - MMPortSerialAt *primary; - MMBearerIpFamily family; -} GetIpConfig3gppContext; - -static void -get_ip_config_context_free (GetIpConfig3gppContext *ctx) -{ - g_object_unref (ctx->primary); - g_object_unref (ctx->modem); - g_free (ctx); -} - -static gboolean -get_ip_config_3gpp_finish (MMBroadbandBearer *self, - GAsyncResult *res, - MMBearerIpConfig **ipv4_config, - MMBearerIpConfig **ipv6_config, - GError **error) -{ - MMBearerConnectResult *configs; - MMBearerIpConfig *ipv4, *ipv6; - - configs = g_task_propagate_pointer (G_TASK (res), error); - if (!configs) - return FALSE; - - ipv4 = mm_bearer_connect_result_peek_ipv4_config (configs); - ipv6 = mm_bearer_connect_result_peek_ipv6_config (configs); - g_assert (ipv4 || ipv6); - if (ipv4_config && ipv4) - *ipv4_config = g_object_ref (ipv4); - if (ipv6_config && ipv6) - *ipv6_config = g_object_ref (ipv6); - - mm_bearer_connect_result_unref (configs); - return TRUE; -} - -static void -ip_config_ready (MMBaseModem *modem, - GAsyncResult *res, - GTask *task) -{ - GetIpConfig3gppContext *ctx; - MMBearerIpConfig *ipv4_config = NULL; - MMBearerIpConfig *ipv6_config = NULL; - const gchar *response; - GError *error = NULL; - MMBearerConnectResult *connect_result; - - ctx = g_task_get_task_data (task); - - response = mm_base_modem_at_command_full_finish (modem, res, &error); - if (error) { - g_error_free (error); - - /* Fall back to DHCP configuration; early devices don't support *E2IPCFG */ - if (ctx->family == MM_BEARER_IP_FAMILY_IPV4 || ctx->family == MM_BEARER_IP_FAMILY_IPV4V6) { - ipv4_config = mm_bearer_ip_config_new (); - mm_bearer_ip_config_set_method (ipv4_config, MM_BEARER_IP_METHOD_DHCP); - } - if (ctx->family == MM_BEARER_IP_FAMILY_IPV6 || ctx->family == MM_BEARER_IP_FAMILY_IPV4V6) { - ipv6_config = mm_bearer_ip_config_new (); - mm_bearer_ip_config_set_method (ipv6_config, MM_BEARER_IP_METHOD_DHCP); - } - } else { - if (!mm_mbm_parse_e2ipcfg_response (response, - &ipv4_config, - &ipv6_config, - &error)) { - g_task_return_error (task, error); - goto out; - } - - if (!ipv4_config && !ipv6_config) { - g_task_return_new_error (task, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Couldn't get IP config: couldn't parse response '%s'", - response); - goto out; - } - } - - connect_result = mm_bearer_connect_result_new (MM_PORT (ctx->primary), - ipv4_config, - ipv6_config); - g_task_return_pointer (task, - connect_result, - (GDestroyNotify)mm_bearer_connect_result_unref); - -out: - g_object_unref (task); - g_clear_object (&ipv4_config); - g_clear_object (&ipv6_config); -} - -static void -get_ip_config_3gpp (MMBroadbandBearer *self, - MMBroadbandModem *modem, - MMPortSerialAt *primary, - MMPortSerialAt *secondary, - MMPort *data, - guint cid, - MMBearerIpFamily ip_family, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GetIpConfig3gppContext *ctx; - GTask *task; - - ctx = g_new0 (GetIpConfig3gppContext, 1); - ctx->modem = MM_BASE_MODEM (g_object_ref (modem)); - ctx->primary = g_object_ref (primary); - ctx->family = ip_family; - - task = g_task_new (self, NULL, callback, user_data); - g_task_set_task_data (task, ctx, (GDestroyNotify)get_ip_config_context_free); - - mm_base_modem_at_command_full (MM_BASE_MODEM (modem), - primary, - "*E2IPCFG?", - 3, - FALSE, - FALSE, /* raw */ - NULL, /* cancellable */ - (GAsyncReadyCallback)ip_config_ready, - task); -} - -/*****************************************************************************/ -/* 3GPP disconnect */ - -typedef struct { - MMBaseModem *modem; - MMPortSerialAt *primary; - guint poll_count; - guint poll_id; -} DisconnectContext; - -static void -disconnect_context_free (DisconnectContext *ctx) -{ - g_assert (!ctx->poll_id); - g_clear_object (&ctx->primary); - g_clear_object (&ctx->modem); - g_free (ctx); -} - -static gboolean -disconnect_3gpp_finish (MMBroadbandBearer *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -process_pending_disconnect_attempt (MMBroadbandBearerMbm *self, - MMBearerConnectionStatus status) -{ - GTask *task; - DisconnectContext *ctx; - - /* Recover disconnection task */ - task = g_steal_pointer (&self->priv->disconnect_pending); - ctx = g_task_get_task_data (task); - - if (ctx->poll_id) { - g_source_remove (ctx->poll_id); - ctx->poll_id = 0; - } - - /* Received 'DISCONNECTED' during a disconnection attempt? */ - if (status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED) { - mm_obj_dbg (self, "connection disconnect indicated by an unsolicited message"); - g_task_return_boolean (task, TRUE); - } else { - /* Otherwise, report error */ - g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Disconnection failed"); - } - g_object_unref (task); -} - -static gboolean disconnect_poll_cb (MMBroadbandBearerMbm *self); - -static void -disconnect_poll_ready (MMBaseModem *modem, - GAsyncResult *res, - MMBroadbandBearerMbm *self) - -{ - GTask *task; - DisconnectContext *ctx; - GError *error = NULL; - const gchar *response; - guint state; - - task = g_steal_pointer (&self->priv->disconnect_pending); - - if (!task) { - mm_obj_dbg (self, "disconnection context was finished already by an unsolicited message"); - /* Run _finish() to finalize the async call, even if we don't care - * the result */ - mm_base_modem_at_command_full_finish (modem, res, NULL); - goto out; - } - - response = mm_base_modem_at_command_full_finish (modem, res, &error); - if (!response) { - g_task_return_error (task, error); - g_object_unref (task); - goto out; - } - - if (sscanf (response, "*ENAP: %d", &state) == 1 && state == 0) { - /* Disconnected */ - g_task_return_boolean (task, TRUE); - g_object_unref (task); - goto out; - } - - /* Restore pending task and check in 1s */ - self->priv->disconnect_pending = task; - ctx = g_task_get_task_data (task); - g_assert (ctx->poll_id == 0); - ctx->poll_id = g_timeout_add_seconds (1, (GSourceFunc) disconnect_poll_cb, self); - - out: - /* Balance refcount with the extra ref we passed to command_full() */ - g_object_unref (self); -} - -static gboolean -disconnect_poll_cb (MMBroadbandBearerMbm *self) -{ - GTask *task; - DisconnectContext *ctx; - - task = self->priv->disconnect_pending; - self->priv->disconnect_pending = NULL; - - g_assert (task); - ctx = g_task_get_task_data (task); - - ctx->poll_id = 0; - - /* Too many retries... */ - if (ctx->poll_count > MM_BASE_BEARER_DEFAULT_DISCONNECTION_TIMEOUT) { - g_task_return_new_error (task, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT, - "Disconnection attempt timed out"); - g_object_unref (task); - return G_SOURCE_REMOVE; - } - - /* Restore pending task and poll */ - self->priv->disconnect_pending = task; - ctx->poll_count++; - mm_base_modem_at_command_full (ctx->modem, - ctx->primary, - "AT*ENAP?", - 3, - FALSE, - FALSE, /* raw */ - NULL, /* cancellable */ - (GAsyncReadyCallback) disconnect_poll_ready, - g_object_ref (self)); /* we pass the bearer object! */ - return G_SOURCE_REMOVE; -} - -static void -disconnect_enap_ready (MMBaseModem *modem, - GAsyncResult *res, - MMBroadbandBearerMbm *self) -{ - DisconnectContext *ctx; - GTask *task; - GError *error = NULL; - - task = g_steal_pointer (&self->priv->disconnect_pending); - - /* Try to recover the disconnection context. If none found, it means the - * context was already completed and we have nothing else to do. */ - if (!task) { - mm_base_modem_at_command_full_finish (modem, res, NULL); - goto out; - } - - ctx = g_task_get_task_data (task); - - /* Ignore errors for now */ - mm_base_modem_at_command_full_finish (modem, res, &error); - if (error) { - mm_obj_dbg (self, "disconnection failed (not fatal): %s", error->message); - g_error_free (error); - } - - /* No unsolicited E2NAP status yet; wait for it and periodically poll - * to handle very old F3507g/MD300 firmware that may not send E2NAP. */ - self->priv->disconnect_pending = task; - ctx->poll_id = g_timeout_add_seconds (1, (GSourceFunc)disconnect_poll_cb, self); - - out: - /* Balance refcount with the extra ref we passed to command_full() */ - g_object_unref (self); -} - -static void -disconnect_3gpp (MMBroadbandBearer *_self, - MMBroadbandModem *modem, - MMPortSerialAt *primary, - MMPortSerialAt *secondary, - MMPort *data, - guint cid, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandBearerMbm *self = MM_BROADBAND_BEARER_MBM (_self); - GTask *task; - DisconnectContext *ctx; - - g_assert (primary != NULL); - - task = g_task_new (self, NULL, callback, user_data); - - ctx = g_new0 (DisconnectContext, 1); - ctx->modem = MM_BASE_MODEM (g_object_ref (modem)); - ctx->primary = g_object_ref (primary); - g_task_set_task_data (task, ctx, (GDestroyNotify) disconnect_context_free); - - /* The unsolicited response to ENAP may come before the OK does. - * We will keep the disconnection context in the bearer private data so - * that it is accessible from the unsolicited message handler. */ - g_assert (self->priv->disconnect_pending == NULL); - self->priv->disconnect_pending = task; - - mm_base_modem_at_command_full (MM_BASE_MODEM (modem), - primary, - "*ENAP=0", - 3, - FALSE, - FALSE, /* raw */ - NULL, /* cancellable */ - (GAsyncReadyCallback)disconnect_enap_ready, - g_object_ref (self)); /* we pass the bearer object! */ -} - -/*****************************************************************************/ - -static void -report_connection_status (MMBaseBearer *_self, - MMBearerConnectionStatus status, - const GError *connection_error) -{ - MMBroadbandBearerMbm *self = MM_BROADBAND_BEARER_MBM (_self); - - g_assert (status == MM_BEARER_CONNECTION_STATUS_CONNECTED || - status == MM_BEARER_CONNECTION_STATUS_CONNECTION_FAILED || - status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED); - - /* Process pending connection attempt */ - if (self->priv->connect_pending) { - process_pending_connect_attempt (self, status); - return; - } - - /* Process pending disconnection attempt */ - if (self->priv->disconnect_pending) { - process_pending_disconnect_attempt (self, status); - return; - } - - mm_obj_dbg (self, "received spontaneous E2NAP (%s)", - mm_bearer_connection_status_get_string (status)); - - /* Received a random 'DISCONNECTED'...*/ - if (status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED || - status == MM_BEARER_CONNECTION_STATUS_CONNECTION_FAILED) { - /* If no connection/disconnection attempt on-going, make sure we mark ourselves as - * disconnected. Make sure we only pass 'DISCONNECTED' to the parent */ - MM_BASE_BEARER_CLASS (mm_broadband_bearer_mbm_parent_class)->report_connection_status ( - _self, - MM_BEARER_CONNECTION_STATUS_DISCONNECTED, - NULL); - } -} - -/*****************************************************************************/ - -MMBaseBearer * -mm_broadband_bearer_mbm_new_finish (GAsyncResult *res, - GError **error) -{ - GObject *bearer; - GObject *source; - - source = g_async_result_get_source_object (res); - bearer = g_async_initable_new_finish (G_ASYNC_INITABLE (source), res, error); - g_object_unref (source); - - if (!bearer) - return NULL; - - /* Only export valid bearers */ - mm_base_bearer_export (MM_BASE_BEARER (bearer)); - - return MM_BASE_BEARER (bearer); -} - -void -mm_broadband_bearer_mbm_new (MMBroadbandModemMbm *modem, - MMBearerProperties *config, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - g_async_initable_new_async ( - MM_TYPE_BROADBAND_BEARER_MBM, - G_PRIORITY_DEFAULT, - cancellable, - callback, - user_data, - MM_BASE_BEARER_MODEM, modem, - MM_BASE_BEARER_CONFIG, config, - NULL); -} - -static void -mm_broadband_bearer_mbm_init (MMBroadbandBearerMbm *self) -{ - /* Initialize private data */ - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - MM_TYPE_BROADBAND_BEARER_MBM, - MMBroadbandBearerMbmPrivate); -} - -static void -mm_broadband_bearer_mbm_class_init (MMBroadbandBearerMbmClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - MMBaseBearerClass *base_bearer_class = MM_BASE_BEARER_CLASS (klass); - MMBroadbandBearerClass *broadband_bearer_class = MM_BROADBAND_BEARER_CLASS (klass); - - g_type_class_add_private (object_class, sizeof (MMBroadbandBearerMbmPrivate)); - - base_bearer_class->report_connection_status = report_connection_status; - base_bearer_class->load_connection_status = NULL; - base_bearer_class->load_connection_status_finish = NULL; -#if defined WITH_SUSPEND_RESUME - base_bearer_class->reload_connection_status = NULL; - base_bearer_class->reload_connection_status_finish = NULL; -#endif - - broadband_bearer_class->dial_3gpp = dial_3gpp; - broadband_bearer_class->dial_3gpp_finish = dial_3gpp_finish; - broadband_bearer_class->get_ip_config_3gpp = get_ip_config_3gpp; - broadband_bearer_class->get_ip_config_3gpp_finish = get_ip_config_3gpp_finish; - broadband_bearer_class->disconnect_3gpp = disconnect_3gpp; - broadband_bearer_class->disconnect_3gpp_finish = disconnect_3gpp_finish; -} diff --git a/plugins/mbm/mm-broadband-bearer-mbm.h b/plugins/mbm/mm-broadband-bearer-mbm.h deleted file mode 100644 index a05b456c..00000000 --- a/plugins/mbm/mm-broadband-bearer-mbm.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details: - * - * Copyright (C) 2008 - 2010 Ericsson AB - * Copyright (C) 2009 - 2012 Red Hat, Inc. - * Copyright (C) 2012 Lanedo GmbH - * - * Author: Per Hallsmark <per.hallsmark@ericsson.com> - * Bjorn Runaker <bjorn.runaker@ericsson.com> - * Torgny Johansson <torgny.johansson@ericsson.com> - * Jonas Sjöquist <jonas.sjoquist@ericsson.com> - * Dan Williams <dcbw@redhat.com> - * Aleksander Morgado <aleksander@lanedo.com> - */ - -#ifndef MM_BROADBAND_BEARER_MBM_H -#define MM_BROADBAND_BEARER_MBM_H - -#include <glib.h> -#include <glib-object.h> - -#define _LIBMM_INSIDE_MM -#include <libmm-glib.h> - -#include "mm-broadband-bearer.h" -#include "mm-broadband-modem-mbm.h" - -#define MM_TYPE_BROADBAND_BEARER_MBM (mm_broadband_bearer_mbm_get_type ()) -#define MM_BROADBAND_BEARER_MBM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_BEARER_MBM, MMBroadbandBearerMbm)) -#define MM_BROADBAND_BEARER_MBM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_BEARER_MBM, MMBroadbandBearerMbmClass)) -#define MM_IS_BROADBAND_BEARER_MBM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_BEARER_MBM)) -#define MM_IS_BROADBAND_BEARER_MBM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_BEARER_MBM)) -#define MM_BROADBAND_BEARER_MBM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_BEARER_MBM, MMBroadbandBearerMbmClass)) - -typedef struct _MMBroadbandBearerMbm MMBroadbandBearerMbm; -typedef struct _MMBroadbandBearerMbmClass MMBroadbandBearerMbmClass; -typedef struct _MMBroadbandBearerMbmPrivate MMBroadbandBearerMbmPrivate; - -struct _MMBroadbandBearerMbm { - MMBroadbandBearer parent; - MMBroadbandBearerMbmPrivate *priv; -}; - -struct _MMBroadbandBearerMbmClass { - MMBroadbandBearerClass parent; -}; - -GType mm_broadband_bearer_mbm_get_type (void); - -/* Default 3GPP bearer creation implementation */ -void mm_broadband_bearer_mbm_new (MMBroadbandModemMbm *modem, - MMBearerProperties *config, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -MMBaseBearer *mm_broadband_bearer_mbm_new_finish (GAsyncResult *res, - GError **error); - -#endif /* MM_BROADBAND_BEARER_MBM_H */ diff --git a/plugins/mbm/mm-broadband-modem-mbm.c b/plugins/mbm/mm-broadband-modem-mbm.c deleted file mode 100644 index fbc9830c..00000000 --- a/plugins/mbm/mm-broadband-modem-mbm.c +++ /dev/null @@ -1,1583 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Copyright (C) 2008 - 2010 Ericsson AB - * Copyright (C) 2009 - 2012 Red Hat, Inc. - * Copyright (C) 2012 Lanedo GmbH - * - * Author: Per Hallsmark <per.hallsmark@ericsson.com> - * Bjorn Runaker <bjorn.runaker@ericsson.com> - * Torgny Johansson <torgny.johansson@ericsson.com> - * Jonas Sjöquist <jonas.sjoquist@ericsson.com> - * Dan Williams <dcbw@redhat.com> - * Aleksander Morgado <aleksander@lanedo.com> - */ - -#include <config.h> - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <ctype.h> - -#include "ModemManager.h" -#include "mm-log-object.h" -#include "mm-bearer-list.h" -#include "mm-errors-types.h" -#include "mm-modem-helpers.h" -#include "mm-modem-helpers-mbm.h" -#include "mm-broadband-modem-mbm.h" -#include "mm-broadband-bearer-mbm.h" -#include "mm-sim-mbm.h" -#include "mm-base-modem-at.h" -#include "mm-iface-modem.h" -#include "mm-iface-modem-3gpp.h" -#include "mm-iface-modem-location.h" - -/* sets the interval in seconds on how often the card emits the NMEA sentences */ -#define MBM_GPS_NMEA_INTERVAL "5" - -static void iface_modem_init (MMIfaceModem *iface); -static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface); -static void iface_modem_location_init (MMIfaceModemLocation *iface); - -static MMIfaceModem *iface_modem_parent; -static MMIfaceModem3gpp *iface_modem_3gpp_parent; -static MMIfaceModemLocation *iface_modem_location_parent; - -G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbm, mm_broadband_modem_mbm, MM_TYPE_BROADBAND_MODEM, 0, - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)) - -#define MBM_E2NAP_DISCONNECTED 0 -#define MBM_E2NAP_CONNECTED 1 -#define MBM_E2NAP_CONNECTING 2 - -struct _MMBroadbandModemMbmPrivate { - gboolean have_emrdy; - - GRegex *e2nap_regex; - GRegex *e2nap_ext_regex; - GRegex *emrdy_regex; - GRegex *pacsp_regex; - GRegex *estksmenu_regex; - GRegex *estksms_regex; - GRegex *emwi_regex; - GRegex *erinfo_regex; - - MMModemLocationSource enabled_sources; - - guint mbm_mode; -}; - -/*****************************************************************************/ -/* Create Bearer (Modem interface) */ - -static MMBaseBearer * -modem_create_bearer_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_pointer (G_TASK (res), error); -} - -static void -broadband_bearer_mbm_new_ready (GObject *source, - GAsyncResult *res, - GTask *task) -{ - MMBaseBearer *bearer = NULL; - GError *error = NULL; - - bearer = mm_broadband_bearer_mbm_new_finish (res, &error); - if (!bearer) - g_task_return_error (task, error); - else - g_task_return_pointer (task, bearer, g_object_unref); - - g_object_unref (task); -} - -static void -modem_create_bearer (MMIfaceModem *self, - MMBearerProperties *properties, - GAsyncReadyCallback callback, - gpointer user_data) -{ - mm_obj_dbg (self, "creating MBM bearer..."); - mm_broadband_bearer_mbm_new (MM_BROADBAND_MODEM_MBM (self), - properties, - NULL, /* cancellable */ - (GAsyncReadyCallback)broadband_bearer_mbm_new_ready, - g_task_new (self, NULL, callback, user_data)); -} - -/*****************************************************************************/ -/* Create SIM (Modem interface) */ - -static MMBaseSim * -create_sim_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return mm_sim_mbm_new_finish (res, error); -} - -static void -create_sim (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - /* New MBM SIM */ - mm_sim_mbm_new (MM_BASE_MODEM (self), - NULL, /* cancellable */ - callback, - user_data); -} - -/*****************************************************************************/ -/* After SIM unlock (Modem interface) */ - -static gboolean -modem_after_sim_unlock_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static gboolean -after_sim_unlock_wait_cb (GTask *task) -{ - g_task_return_boolean (task, TRUE); - g_object_unref (task); - return G_SOURCE_REMOVE; -} - -static void -modem_after_sim_unlock (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - /* wait so sim pin is done */ - g_timeout_add (500, (GSourceFunc)after_sim_unlock_wait_cb, task); -} - -/*****************************************************************************/ -/* Load supported modes (Modem interface) */ - -static GArray * -load_supported_modes_finish (MMIfaceModem *_self, - GAsyncResult *res, - GError **error) -{ - MMBroadbandModemMbm *self = MM_BROADBAND_MODEM_MBM (_self); - const gchar *response; - guint32 mask = 0; - GArray *combinations; - MMModemModeCombination mode; - - response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); - if (!response) - return FALSE; - - if (!mm_mbm_parse_cfun_test (response, self, &mask, error)) - return FALSE; - - /* Build list of combinations */ - combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 3); - - /* 2G only */ - if (mask & (1 << MBM_NETWORK_MODE_2G)) { - mode.allowed = MM_MODEM_MODE_2G; - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - } - - /* 3G only */ - if (mask & (1 << MBM_NETWORK_MODE_3G)) { - mode.allowed = MM_MODEM_MODE_3G; - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - } - - /* 2G and 3G */ - if (mask & (1 << MBM_NETWORK_MODE_ANY)) { - mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - } - - if (combinations->len == 0) { - g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't load any supported mode"); - g_array_unref (combinations); - return NULL; - } - - return combinations; -} - -static void -load_supported_modes (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - mm_base_modem_at_command (MM_BASE_MODEM (self), - "+CFUN=?", - 3, - FALSE, - callback, - user_data); -} - -/*****************************************************************************/ -/* Load initial allowed/preferred modes (Modem interface) */ - -static gboolean -load_current_modes_finish (MMIfaceModem *_self, - GAsyncResult *res, - MMModemMode *allowed, - MMModemMode *preferred, - GError **error) -{ - MMBroadbandModemMbm *self = MM_BROADBAND_MODEM_MBM (_self); - const gchar *response; - gint mbm_mode = -1; - - g_assert (allowed); - g_assert (preferred); - - response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); - if (!response || !mm_mbm_parse_cfun_query_current_modes (response, allowed, &mbm_mode, error)) - return FALSE; - - /* No settings to set preferred */ - *preferred = MM_MODEM_MODE_NONE; - - if (mbm_mode != -1) - self->priv->mbm_mode = mbm_mode; - - return TRUE; -} - -static void -load_current_modes (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - mm_base_modem_at_command (MM_BASE_MODEM (self), - "+CFUN?", - 3, - FALSE, - callback, - user_data); -} - -/*****************************************************************************/ -/* Set allowed modes (Modem interface) */ - -typedef struct { - gint mbm_mode; -} SetCurrentModesContext; - -static gboolean -set_current_modes_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -allowed_mode_update_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - SetCurrentModesContext *ctx; - GError *error = NULL; - - ctx = g_task_get_task_data (task); - - mm_base_modem_at_command_finish (self, res, &error); - if (error) - /* Let the error be critical. */ - g_task_return_error (task, error); - else { - /* Cache current allowed mode */ - MM_BROADBAND_MODEM_MBM (self)->priv->mbm_mode = ctx->mbm_mode; - g_task_return_boolean (task, TRUE); - } - g_object_unref (task); -} - -static void -set_current_modes (MMIfaceModem *self, - MMModemMode allowed, - MMModemMode preferred, - GAsyncReadyCallback callback, - gpointer user_data) -{ - SetCurrentModesContext *ctx; - GTask *task; - gchar *command; - - ctx = g_new (SetCurrentModesContext, 1); - ctx->mbm_mode = -1; - - task = g_task_new (self, NULL, callback, user_data); - g_task_set_task_data (task, ctx, g_free); - - if (allowed == MM_MODEM_MODE_2G) - ctx->mbm_mode = MBM_NETWORK_MODE_2G; - else if (allowed == MM_MODEM_MODE_3G) - ctx->mbm_mode = MBM_NETWORK_MODE_3G; - else if ((allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G) || - allowed == MM_MODEM_MODE_ANY) && - preferred == MM_MODEM_MODE_NONE) - ctx->mbm_mode = MBM_NETWORK_MODE_ANY; - - if (ctx->mbm_mode < 0) { - gchar *allowed_str; - gchar *preferred_str; - - allowed_str = mm_modem_mode_build_string_from_mask (allowed); - preferred_str = mm_modem_mode_build_string_from_mask (preferred); - g_task_return_new_error (task, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Requested mode (allowed: '%s', preferred: '%s') not " - "supported by the modem.", - allowed_str, - preferred_str); - g_object_unref (task); - g_free (allowed_str); - g_free (preferred_str); - return; - } - - command = g_strdup_printf ("+CFUN=%d", ctx->mbm_mode); - mm_base_modem_at_command ( - MM_BASE_MODEM (self), - command, - 3, - FALSE, - (GAsyncReadyCallback)allowed_mode_update_ready, - task); - g_free (command); -} - -/*****************************************************************************/ -/* Initializing the modem (during first enabling) */ - -static gboolean -enabling_modem_init_finish (MMBroadbandModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -enabling_init_sequence_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - /* Ignore errors */ - mm_base_modem_at_sequence_full_finish (self, res, NULL, NULL); - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static const MMBaseModemAtCommand enabling_modem_init_sequence[] = { - /* Init command */ - { "&F", 3, FALSE, NULL }, - /* Ensure disconnected */ - { "*ENAP=0", 3, FALSE, NULL }, - { NULL } -}; - -static void -run_enabling_init_sequence (GTask *task) -{ - MMBaseModem *self; - - self = g_task_get_source_object (task); - mm_base_modem_at_sequence_full (self, - mm_base_modem_peek_port_primary (self), - enabling_modem_init_sequence, - NULL, /* response_processor_context */ - NULL, /* response_processor_context_free */ - NULL, /* cancellable */ - (GAsyncReadyCallback)enabling_init_sequence_ready, - task); -} - -static void -emrdy_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - /* EMRDY unsolicited response might have happened between the command - * submission and the response. This was seen once: - * - * (ttyACM0): --> 'AT*EMRDY?<CR>' - * (ttyACM0): <-- 'T*EMRD<CR><LF>*EMRDY: 1<CR><LF>Y?' - * - * So suppress the warning if the unsolicited handler handled the response - * before we get here. - */ - if (!mm_base_modem_at_command_finish (self, res, &error)) { - if (g_error_matches (error, - MM_SERIAL_ERROR, - MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) - mm_obj_warn (self, "timed out waiting for EMRDY response"); - else - MM_BROADBAND_MODEM_MBM (self)->priv->have_emrdy = TRUE; - g_error_free (error); - } - - run_enabling_init_sequence (task); -} - -static void -enabling_modem_init (MMBroadbandModem *_self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandModemMbm *self = MM_BROADBAND_MODEM_MBM (_self); - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - /* Modem is ready?, no need to check EMRDY */ - if (self->priv->have_emrdy) { - run_enabling_init_sequence (task); - return; - } - - mm_base_modem_at_command (MM_BASE_MODEM (self), - "*EMRDY?", - 3, - FALSE, - (GAsyncReadyCallback)emrdy_ready, - task); -} - -/*****************************************************************************/ -/* Modem power down (Modem interface) */ - -static gboolean -modem_power_down_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); -} - -static void -modem_power_down (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - /* Use AT+CFUN=4 for power down. It will stop the RF (IMSI detach), and - * keeps access to the SIM */ - mm_base_modem_at_command (MM_BASE_MODEM (self), - "+CFUN=4", - 3, - FALSE, - callback, - user_data); -} - -/*****************************************************************************/ -/* Powering up the modem (Modem interface) */ - -static gboolean -modem_power_up_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - /* By default, errors in the power up command are ignored. */ - mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, NULL); - return TRUE; -} - -static void -modem_power_up (MMIfaceModem *_self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandModemMbm *self = MM_BROADBAND_MODEM_MBM (_self); - gchar *command; - - g_assert (self->priv->mbm_mode == MBM_NETWORK_MODE_ANY || - self->priv->mbm_mode == MBM_NETWORK_MODE_2G || - self->priv->mbm_mode == MBM_NETWORK_MODE_3G); - - command = g_strdup_printf ("+CFUN=%u", self->priv->mbm_mode); - mm_base_modem_at_command (MM_BASE_MODEM (self), - command, - 5, - FALSE, - callback, - user_data); - g_free (command); -} - -/*****************************************************************************/ -/* Power state loading (Modem interface) */ - -static MMModemPowerState -load_power_state_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - const gchar *response; - MMModemPowerState state; - - response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); - if (!response || !mm_mbm_parse_cfun_query_power_state (response, &state, error)) - return MM_MODEM_POWER_STATE_UNKNOWN; - - return state; -} - -static void -load_power_state (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - mm_base_modem_at_command (MM_BASE_MODEM (self), - "+CFUN?", - 3, - FALSE, - callback, - user_data); -} - -/*****************************************************************************/ -/* Reset (Modem interface) */ - -static gboolean -reset_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - /* Ignore errors */ - mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, NULL); - return TRUE; -} - -static void -reset (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - mm_base_modem_at_command (MM_BASE_MODEM (self), - "*E2RESET", - 3, - FALSE, - callback, - user_data); -} - -/*****************************************************************************/ -/* Factory reset (Modem interface) */ - -static gboolean -factory_reset_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - /* Ignore errors */ - mm_base_modem_at_sequence_finish (MM_BASE_MODEM (self), res, NULL, NULL); - return TRUE; -} - -static const MMBaseModemAtCommand factory_reset_sequence[] = { - /* Init command */ - { "&F +CMEE=0", 3, FALSE, NULL }, - { "+COPS=0", 3, FALSE, NULL }, - { "+CR=0", 3, FALSE, NULL }, - { "+CRC=0", 3, FALSE, NULL }, - { "+CREG=0", 3, FALSE, NULL }, - { "+CMER=0", 3, FALSE, NULL }, - { "*EPEE=0", 3, FALSE, NULL }, - { "+CNMI=2, 0, 0, 0, 0", 3, FALSE, NULL }, - { "+CGREG=0", 3, FALSE, NULL }, - { "*EIAD=0", 3, FALSE, NULL }, - { "+CGSMS=3", 3, FALSE, NULL }, - { "+CSCA=\"\",129", 3, FALSE, NULL }, - { NULL } -}; - -static void -factory_reset (MMIfaceModem *self, - const gchar *code, - GAsyncReadyCallback callback, - gpointer user_data) -{ - mm_obj_dbg (self, "ignoring user-provided factory reset code: '%s'", code); - - mm_base_modem_at_sequence (MM_BASE_MODEM (self), - factory_reset_sequence, - NULL, /* response_processor_context */ - NULL, /* response_processor_context_free */ - callback, - user_data); -} - -/*****************************************************************************/ -/* Load unlock retries (Modem interface) */ - -static MMUnlockRetries * -load_unlock_retries_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - MMUnlockRetries *unlock_retries; - const gchar *response; - gint matched; - guint a, b, c ,d; - - response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error); - if (!response) - return NULL; - - matched = sscanf (response, "*EPIN: %d, %d, %d, %d", - &a, &b, &c, &d); - if (matched != 4) { - g_set_error (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Could not parse PIN retries results: '%s'", - response); - return NULL; - } - - if (a > 998) { - g_set_error (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Invalid PIN attempts left: '%u'", - a); - return NULL; - } - - unlock_retries = mm_unlock_retries_new (); - mm_unlock_retries_set (unlock_retries, MM_MODEM_LOCK_SIM_PIN, a); - mm_unlock_retries_set (unlock_retries, MM_MODEM_LOCK_SIM_PUK, b); - mm_unlock_retries_set (unlock_retries, MM_MODEM_LOCK_SIM_PIN2, c); - mm_unlock_retries_set (unlock_retries, MM_MODEM_LOCK_SIM_PUK2, d); - return unlock_retries; -} - -static void -load_unlock_retries (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - mm_base_modem_at_command (MM_BASE_MODEM (self), - "*EPIN?", - 10, - FALSE, - callback, - user_data); -} - -/*****************************************************************************/ -/* Setup/Cleanup unsolicited events (3GPP interface) */ - -typedef struct { - MMBearerConnectionStatus status; -} BearerListReportStatusForeachContext; - -static void -bearer_list_report_status_foreach (MMBaseBearer *bearer, - BearerListReportStatusForeachContext *ctx) -{ - mm_base_bearer_report_connection_status (bearer, ctx->status); -} - -static void -e2nap_received (MMPortSerialAt *port, - GMatchInfo *info, - MMBroadbandModemMbm *self) -{ - MMBearerList *list = NULL; - guint state; - BearerListReportStatusForeachContext ctx; - - if (!mm_get_uint_from_match_info (info, 1, &state)) - return; - - ctx.status = MM_BEARER_CONNECTION_STATUS_UNKNOWN; - - switch (state) { - case MBM_E2NAP_DISCONNECTED: - mm_obj_dbg (self, "disconnected"); - ctx.status = MM_BEARER_CONNECTION_STATUS_DISCONNECTED; - break; - case MBM_E2NAP_CONNECTED: - mm_obj_dbg (self, "connected"); - ctx.status = MM_BEARER_CONNECTION_STATUS_CONNECTED; - break; - case MBM_E2NAP_CONNECTING: - mm_obj_dbg (self, "connecting"); - break; - default: - /* Should not happen */ - mm_obj_dbg (self, "unhandled E2NAP state %d", state); - } - - /* If unknown status, don't try to report anything */ - if (ctx.status == MM_BEARER_CONNECTION_STATUS_UNKNOWN) - return; - - /* If empty bearer list, nothing else to do */ - g_object_get (self, - MM_IFACE_MODEM_BEARER_LIST, &list, - NULL); - if (!list) - return; - - mm_bearer_list_foreach (list, - (MMBearerListForeachFunc)bearer_list_report_status_foreach, - &ctx); - g_object_unref (list); -} - -static void -erinfo_received (MMPortSerialAt *port, - GMatchInfo *info, - MMBroadbandModemMbm *self) -{ - MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; - guint mode; - - if (mm_get_uint_from_match_info (info, 2, &mode)) { - switch (mode) { - case 1: - act = MM_MODEM_ACCESS_TECHNOLOGY_GPRS; - break; - case 2: - act = MM_MODEM_ACCESS_TECHNOLOGY_EDGE; - break; - default: - break; - } - } - - /* 3G modes take precedence */ - if (mm_get_uint_from_match_info (info, 3, &mode)) { - switch (mode) { - case 1: - act = MM_MODEM_ACCESS_TECHNOLOGY_UMTS; - break; - case 2: - act = MM_MODEM_ACCESS_TECHNOLOGY_HSDPA; - break; - case 3: - act = MM_MODEM_ACCESS_TECHNOLOGY_HSPA; - break; - default: - break; - } - } - - mm_iface_modem_update_access_technologies (MM_IFACE_MODEM (self), - act, - MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK); -} - -static void -set_unsolicited_events_handlers (MMBroadbandModemMbm *self, - gboolean enable) -{ - MMPortSerialAt *ports[2]; - guint i; - - ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)); - ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self)); - - /* Enable unsolicited events in given port */ - for (i = 0; i < G_N_ELEMENTS (ports); i++) { - if (!ports[i]) - continue; - - /* Access technology related */ - mm_port_serial_at_add_unsolicited_msg_handler ( - ports[i], - self->priv->erinfo_regex, - enable ? (MMPortSerialAtUnsolicitedMsgFn)erinfo_received : NULL, - enable ? self : NULL, - NULL); - - /* Connection related */ - mm_port_serial_at_add_unsolicited_msg_handler ( - ports[i], - self->priv->e2nap_regex, - enable ? (MMPortSerialAtUnsolicitedMsgFn)e2nap_received : NULL, - enable ? self : NULL, - NULL); - mm_port_serial_at_add_unsolicited_msg_handler ( - ports[i], - self->priv->e2nap_ext_regex, - enable ? (MMPortSerialAtUnsolicitedMsgFn)e2nap_received : NULL, - enable ? self : NULL, - NULL); - } -} - -static gboolean -modem_3gpp_setup_cleanup_unsolicited_events_finish (MMIfaceModem3gpp *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -parent_setup_unsolicited_events_ready (MMIfaceModem3gpp *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - if (!iface_modem_3gpp_parent->setup_unsolicited_events_finish (self, res, &error)) - g_task_return_error (task, error); - else { - /* Our own setup now */ - set_unsolicited_events_handlers (MM_BROADBAND_MODEM_MBM (self), TRUE); - g_task_return_boolean (task, TRUE); - } - g_object_unref (task); -} - -static void -modem_3gpp_setup_unsolicited_events (MMIfaceModem3gpp *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - /* Chain up parent's setup */ - iface_modem_3gpp_parent->setup_unsolicited_events ( - self, - (GAsyncReadyCallback)parent_setup_unsolicited_events_ready, - g_task_new (self, NULL, callback, user_data)); -} - -static void -parent_cleanup_unsolicited_events_ready (MMIfaceModem3gpp *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - if (!iface_modem_3gpp_parent->cleanup_unsolicited_events_finish (self, res, &error)) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - - g_object_unref (task); -} - -static void -modem_3gpp_cleanup_unsolicited_events (MMIfaceModem3gpp *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - /* Our own cleanup first */ - set_unsolicited_events_handlers (MM_BROADBAND_MODEM_MBM (self), FALSE); - - /* And now chain up parent's cleanup */ - iface_modem_3gpp_parent->cleanup_unsolicited_events ( - self, - (GAsyncReadyCallback)parent_cleanup_unsolicited_events_ready, - g_task_new (self, NULL, callback, user_data)); -} - -/*****************************************************************************/ -/* Enabling unsolicited events (3GPP interface) */ - -static gboolean -modem_3gpp_enable_unsolicited_events_finish (MMIfaceModem3gpp *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -own_enable_unsolicited_events_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - mm_base_modem_at_sequence_full_finish (self, res, NULL, &error); - if (error) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - - g_object_unref (task); -} - -static const MMBaseModemAtCommand unsolicited_enable_sequence[] = { - { "*ERINFO=1", 5, FALSE, NULL }, - { "*E2NAP=1", 5, FALSE, NULL }, - { NULL } -}; - -static void -parent_enable_unsolicited_events_ready (MMIfaceModem3gpp *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - if (!iface_modem_3gpp_parent->enable_unsolicited_events_finish (self, res, &error)) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Our own enable now */ - mm_base_modem_at_sequence_full ( - MM_BASE_MODEM (self), - mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)), - unsolicited_enable_sequence, - NULL, /* response_processor_context */ - NULL, /* response_processor_context_free */ - NULL, /* cancellable */ - (GAsyncReadyCallback)own_enable_unsolicited_events_ready, - task); -} - -static void -modem_3gpp_enable_unsolicited_events (MMIfaceModem3gpp *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - /* Chain up parent's enable */ - iface_modem_3gpp_parent->enable_unsolicited_events ( - self, - (GAsyncReadyCallback)parent_enable_unsolicited_events_ready, - g_task_new (self, NULL, callback, user_data)); -} - -/*****************************************************************************/ -/* Disabling unsolicited events (3GPP interface) */ - -static gboolean -modem_3gpp_disable_unsolicited_events_finish (MMIfaceModem3gpp *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -parent_disable_unsolicited_events_ready (MMIfaceModem3gpp *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - if (!iface_modem_3gpp_parent->disable_unsolicited_events_finish (self, res, &error)) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - - g_object_unref (task); -} - -static void -own_disable_unsolicited_events_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - mm_base_modem_at_sequence_full_finish (self, res, NULL, &error); - if (error) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Next, chain up parent's disable */ - iface_modem_3gpp_parent->disable_unsolicited_events ( - MM_IFACE_MODEM_3GPP (self), - (GAsyncReadyCallback)parent_disable_unsolicited_events_ready, - task); -} - -static const MMBaseModemAtCommand unsolicited_disable_sequence[] = { - { "*ERINFO=0", 5, FALSE, NULL }, - { "*E2NAP=0", 5, FALSE, NULL }, - { NULL } -}; - -static void -modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - /* Our own disable first */ - mm_base_modem_at_sequence_full ( - MM_BASE_MODEM (self), - mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)), - unsolicited_disable_sequence, - NULL, /* response_processor_context */ - NULL, /* response_processor_context_free */ - NULL, /* cancellable */ - (GAsyncReadyCallback)own_disable_unsolicited_events_ready, - g_task_new (self, NULL, callback, user_data)); -} - -/*****************************************************************************/ -/* Location capabilities loading (Location interface) */ - -static MMModemLocationSource -location_load_capabilities_finish (MMIfaceModemLocation *self, - GAsyncResult *res, - GError **error) -{ - GError *inner_error = NULL; - gssize value; - - value = g_task_propagate_int (G_TASK (res), &inner_error); - if (inner_error) { - g_propagate_error (error, inner_error); - return MM_MODEM_LOCATION_SOURCE_NONE; - } - return (MMModemLocationSource)value; -} - -static void -parent_load_capabilities_ready (MMIfaceModemLocation *self, - GAsyncResult *res, - GTask *task) -{ - MMModemLocationSource sources; - GError *error = NULL; - - sources = iface_modem_location_parent->load_capabilities_finish (self, res, &error); - if (error) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* not sure how to check if GPS is supported, just allow it */ - if (mm_base_modem_peek_port_gps (MM_BASE_MODEM (self))) - sources |= (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | - MM_MODEM_LOCATION_SOURCE_GPS_RAW | - MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED); - - /* So we're done, complete */ - g_task_return_int (task, sources); - g_object_unref (task); -} - -static void -location_load_capabilities (MMIfaceModemLocation *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - /* Chain up parent's setup */ - iface_modem_location_parent->load_capabilities ( - self, - (GAsyncReadyCallback)parent_load_capabilities_ready, - g_task_new (self, NULL, callback, user_data)); -} - -/*****************************************************************************/ -/* Enable/Disable location gathering (Location interface) */ - -typedef struct { - MMModemLocationSource source; -} LocationGatheringContext; - -/******************************/ -/* Disable location gathering */ - -static gboolean -disable_location_gathering_finish (MMIfaceModemLocation *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -gps_disabled_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - LocationGatheringContext *ctx; - MMPortSerialGps *gps_port; - GError *error = NULL; - - ctx = g_task_get_task_data (task); - - mm_base_modem_at_command_full_finish (self, res, &error); - - /* Only use the GPS port in NMEA/RAW setups */ - if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | - MM_MODEM_LOCATION_SOURCE_GPS_RAW)) { - /* Even if we get an error here, we try to close the GPS port */ - gps_port = mm_base_modem_peek_port_gps (self); - if (gps_port) - mm_port_serial_close (MM_PORT_SERIAL (gps_port)); - } - - if (error) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - - g_object_unref (task); -} - -static void -disable_location_gathering (MMIfaceModemLocation *_self, - MMModemLocationSource source, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandModemMbm *self = MM_BROADBAND_MODEM_MBM (_self); - gboolean stop_gps = FALSE; - LocationGatheringContext *ctx; - GTask *task; - - ctx = g_new (LocationGatheringContext, 1); - ctx->source = source; - - task = g_task_new (self, NULL, callback, user_data); - g_task_set_task_data (task, ctx, g_free); - - /* Only stop GPS engine if no GPS-related sources enabled */ - if (source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | - MM_MODEM_LOCATION_SOURCE_GPS_RAW | - MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)) { - self->priv->enabled_sources &= ~source; - - if (!(self->priv->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | - MM_MODEM_LOCATION_SOURCE_GPS_RAW | - MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED))) - stop_gps = TRUE; - } - - if (stop_gps) { - mm_base_modem_at_command_full (MM_BASE_MODEM (_self), - mm_base_modem_peek_port_primary (MM_BASE_MODEM (_self)), - "AT*E2GPSCTL=0", - 3, - FALSE, - FALSE, /* raw */ - NULL, /* cancellable */ - (GAsyncReadyCallback)gps_disabled_ready, - task); - return; - } - - /* For any other location (e.g. 3GPP), or if still some GPS needed, just return */ - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -/*****************************************************************************/ -/* Enable location gathering (Location interface) */ - -static gboolean -enable_location_gathering_finish (MMIfaceModemLocation *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -gps_enabled_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - LocationGatheringContext *ctx; - GError *error = NULL; - MMPortSerialGps *gps_port; - - if (!mm_base_modem_at_command_full_finish (self, res, &error)) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - ctx = g_task_get_task_data (task); - - /* Only use the GPS port in NMEA/RAW setups */ - if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | - MM_MODEM_LOCATION_SOURCE_GPS_RAW)) { - gps_port = mm_base_modem_peek_port_gps (self); - if (!gps_port || - !mm_port_serial_open (MM_PORT_SERIAL (gps_port), &error)) { - if (error) - g_task_return_error (task, error); - else - g_task_return_new_error (task, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Couldn't open raw GPS serial port"); - } else { - GByteArray *buf; - const gchar *command = "ATE0*E2GPSNPD\r\n"; - - /* We need to send an AT command to the GPS data port to - * toggle it into this data mode. This is a particularity of - * mbm cards where the GPS data port is not hard wired. So - * we need to use the MMPortSerial API here. - */ - buf = g_byte_array_new (); - g_byte_array_append (buf, (const guint8 *) command, strlen (command)); - mm_port_serial_command (MM_PORT_SERIAL (gps_port), - buf, - 3, - FALSE, /* never cached */ - FALSE, /* always queued last */ - NULL, - NULL, - NULL); - g_byte_array_unref (buf); - g_task_return_boolean (task, TRUE); - } - - } else - g_task_return_boolean (task, TRUE); - - g_object_unref (task); -} - -static void -parent_enable_location_gathering_ready (MMIfaceModemLocation *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemMbm *self = MM_BROADBAND_MODEM_MBM (_self); - LocationGatheringContext *ctx; - gboolean start_gps = FALSE; - GError *error = NULL; - - if (!iface_modem_location_parent->enable_location_gathering_finish (_self, res, &error)) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Now our own enabling */ - - /* NMEA and RAW are both enabled in the same way */ - ctx = g_task_get_task_data (task); - if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | - MM_MODEM_LOCATION_SOURCE_GPS_RAW | - MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)) { - /* Only start GPS engine if not done already */ - if (!(self->priv->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | - MM_MODEM_LOCATION_SOURCE_GPS_RAW | - MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED))) - start_gps = TRUE; - self->priv->enabled_sources |= ctx->source; - } - - if (start_gps) { - mm_base_modem_at_command_full (MM_BASE_MODEM (self), - mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)), - "AT*E2GPSCTL=1," MBM_GPS_NMEA_INTERVAL ",0", - 3, - FALSE, - FALSE, /* raw */ - NULL, /* cancellable */ - (GAsyncReadyCallback)gps_enabled_ready, - task); - return; - } - - /* For any other location (e.g. 3GPP), or if GPS already running just return */ - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -enable_location_gathering (MMIfaceModemLocation *self, - MMModemLocationSource source, - GAsyncReadyCallback callback, - gpointer user_data) -{ - LocationGatheringContext *ctx; - GTask *task; - - ctx = g_new (LocationGatheringContext, 1); - ctx->source = source; - - task = g_task_new (self, NULL, callback, user_data); - g_task_set_task_data (task, ctx, g_free); - - /* Chain up parent's gathering enable */ - iface_modem_location_parent->enable_location_gathering (self, - source, - (GAsyncReadyCallback)parent_enable_location_gathering_ready, - task); -} - -/*****************************************************************************/ -/* Setup ports (Broadband modem class) */ - -static void -emrdy_received (MMPortSerialAt *port, - GMatchInfo *info, - MMBroadbandModemMbm *self) -{ - self->priv->have_emrdy = TRUE; -} - -static void -gps_trace_received (MMPortSerialGps *port, - const gchar *trace, - MMIfaceModemLocation *self) -{ - mm_iface_modem_location_gps_update (self, trace); -} - -static void -setup_ports (MMBroadbandModem *_self) -{ - MMBroadbandModemMbm *self = MM_BROADBAND_MODEM_MBM (_self); - MMPortSerialAt *ports[2]; - MMPortSerialGps *gps_data_port; - guint i; - - /* Call parent's setup ports first always */ - MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_mbm_parent_class)->setup_ports (_self); - - ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)); - ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self)); - - /* Setup unsolicited handlers which should be always on */ - for (i = 0; i < G_N_ELEMENTS (ports); i++) { - if (!ports[i]) - continue; - - /* The Ericsson modems always have a free AT command port, so we - * don't need to flash the ports when disconnecting to get back to - * command mode. F5521gw R2A07 resets port properties like echo when - * flashed, leading to confusion. bgo #650740 - */ - g_object_set (G_OBJECT (ports[i]), - MM_PORT_SERIAL_FLASH_OK, FALSE, - NULL); - - mm_port_serial_at_add_unsolicited_msg_handler ( - ports[i], - self->priv->emrdy_regex, - (MMPortSerialAtUnsolicitedMsgFn)emrdy_received, - self, - NULL); - - /* Several unsolicited messages to always ignore... */ - mm_port_serial_at_add_unsolicited_msg_handler ( - ports[i], - self->priv->pacsp_regex, - NULL, NULL, NULL); - - mm_port_serial_at_add_unsolicited_msg_handler ( - ports[i], - self->priv->estksmenu_regex, - NULL, NULL, NULL); - - mm_port_serial_at_add_unsolicited_msg_handler ( - ports[i], - self->priv->estksms_regex, - NULL, NULL, NULL); - - mm_port_serial_at_add_unsolicited_msg_handler ( - ports[i], - self->priv->emwi_regex, - NULL, NULL, NULL); - } - - /* Now reset the unsolicited messages we'll handle when enabled */ - set_unsolicited_events_handlers (MM_BROADBAND_MODEM_MBM (self), FALSE); - - /* NMEA GPS monitoring */ - gps_data_port = mm_base_modem_peek_port_gps (MM_BASE_MODEM (self)); - if (gps_data_port) { - /* make sure GPS is stopped incase it was left enabled */ - mm_base_modem_at_command_full (MM_BASE_MODEM (self), - mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)), - "AT*E2GPSCTL=0", - 3, FALSE, FALSE, NULL, NULL, NULL); - /* Add handler for the NMEA traces */ - mm_port_serial_gps_add_trace_handler (gps_data_port, - (MMPortSerialGpsTraceFn)gps_trace_received, - self, NULL); - } -} - -/*****************************************************************************/ - -MMBroadbandModemMbm * -mm_broadband_modem_mbm_new (const gchar *device, - const gchar **drivers, - const gchar *plugin, - guint16 vendor_id, - guint16 product_id) -{ - return g_object_new (MM_TYPE_BROADBAND_MODEM_MBM, - MM_BASE_MODEM_DEVICE, device, - MM_BASE_MODEM_DRIVERS, drivers, - MM_BASE_MODEM_PLUGIN, plugin, - MM_BASE_MODEM_VENDOR_ID, vendor_id, - MM_BASE_MODEM_PRODUCT_ID, product_id, - /* MBM bearer supports NET only */ - MM_BASE_MODEM_DATA_NET_SUPPORTED, TRUE, - MM_BASE_MODEM_DATA_TTY_SUPPORTED, FALSE, - NULL); -} - -static void -mm_broadband_modem_mbm_init (MMBroadbandModemMbm *self) -{ - /* Initialize private data */ - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - MM_TYPE_BROADBAND_MODEM_MBM, - MMBroadbandModemMbmPrivate); - - /* Prepare regular expressions to setup */ - self->priv->e2nap_regex = g_regex_new ("\\r\\n\\*E2NAP: (\\d)\\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - self->priv->e2nap_ext_regex = g_regex_new ("\\r\\n\\*E2NAP: (\\d),.*\\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - self->priv->emrdy_regex = g_regex_new ("\\r\\n\\*EMRDY: \\d\\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - self->priv->pacsp_regex = g_regex_new ("\\r\\n\\+PACSP(\\d)\\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - self->priv->estksmenu_regex = g_regex_new ("\\R\\*ESTKSMENU:.*\\R", - G_REGEX_RAW | G_REGEX_OPTIMIZE | G_REGEX_MULTILINE | G_REGEX_NEWLINE_CRLF, G_REGEX_MATCH_NEWLINE_CRLF, NULL); - self->priv->estksms_regex = g_regex_new ("\\r\\n\\*ESTKSMS:.*\\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - self->priv->emwi_regex = g_regex_new ("\\r\\n\\*EMWI: (\\d),(\\d).*\\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - self->priv->erinfo_regex = g_regex_new ("\\r\\n\\*ERINFO:\\s*(\\d),(\\d),(\\d).*\\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - - self->priv->mbm_mode = MBM_NETWORK_MODE_ANY; -} - -static void -finalize (GObject *object) -{ - MMBroadbandModemMbm *self = MM_BROADBAND_MODEM_MBM (object); - - g_regex_unref (self->priv->e2nap_regex); - g_regex_unref (self->priv->e2nap_ext_regex); - g_regex_unref (self->priv->emrdy_regex); - g_regex_unref (self->priv->pacsp_regex); - g_regex_unref (self->priv->estksmenu_regex); - g_regex_unref (self->priv->estksms_regex); - g_regex_unref (self->priv->emwi_regex); - g_regex_unref (self->priv->erinfo_regex); - - G_OBJECT_CLASS (mm_broadband_modem_mbm_parent_class)->finalize (object); -} - -static void -iface_modem_init (MMIfaceModem *iface) -{ - iface_modem_parent = g_type_interface_peek_parent (iface); - - iface->create_bearer = modem_create_bearer; - iface->create_bearer_finish = modem_create_bearer_finish; - iface->create_sim = create_sim; - iface->create_sim_finish = create_sim_finish; - iface->modem_after_sim_unlock = modem_after_sim_unlock; - iface->modem_after_sim_unlock_finish = modem_after_sim_unlock_finish; - iface->load_supported_modes = load_supported_modes; - iface->load_supported_modes_finish = load_supported_modes_finish; - iface->load_current_modes = load_current_modes; - iface->load_current_modes_finish = load_current_modes_finish; - iface->set_current_modes = set_current_modes; - iface->set_current_modes_finish = set_current_modes_finish; - iface->reset = reset; - iface->reset_finish = reset_finish; - iface->factory_reset = factory_reset; - iface->factory_reset_finish = factory_reset_finish; - iface->load_unlock_retries = load_unlock_retries; - iface->load_unlock_retries_finish = load_unlock_retries_finish; - iface->load_power_state = load_power_state; - iface->load_power_state_finish = load_power_state_finish; - iface->modem_power_up = modem_power_up; - iface->modem_power_up_finish = modem_power_up_finish; - iface->modem_power_down = modem_power_down; - iface->modem_power_down_finish = modem_power_down_finish; -} - -static void -iface_modem_3gpp_init (MMIfaceModem3gpp *iface) -{ - iface_modem_3gpp_parent = g_type_interface_peek_parent (iface); - - iface->enable_unsolicited_events = modem_3gpp_enable_unsolicited_events; - iface->enable_unsolicited_events_finish = modem_3gpp_enable_unsolicited_events_finish; - iface->disable_unsolicited_events = modem_3gpp_disable_unsolicited_events; - iface->disable_unsolicited_events_finish = modem_3gpp_disable_unsolicited_events_finish; - - iface->setup_unsolicited_events = modem_3gpp_setup_unsolicited_events; - iface->setup_unsolicited_events_finish = modem_3gpp_setup_cleanup_unsolicited_events_finish; - iface->cleanup_unsolicited_events = modem_3gpp_cleanup_unsolicited_events; - iface->cleanup_unsolicited_events_finish = modem_3gpp_setup_cleanup_unsolicited_events_finish; -} - -static void -iface_modem_location_init (MMIfaceModemLocation *iface) -{ - iface_modem_location_parent = g_type_interface_peek_parent (iface); - - iface->load_capabilities = location_load_capabilities; - iface->load_capabilities_finish = location_load_capabilities_finish; - iface->enable_location_gathering = enable_location_gathering; - iface->enable_location_gathering_finish = enable_location_gathering_finish; - iface->disable_location_gathering = disable_location_gathering; - iface->disable_location_gathering_finish = disable_location_gathering_finish; -} - -static void -mm_broadband_modem_mbm_class_init (MMBroadbandModemMbmClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass); - - g_type_class_add_private (object_class, sizeof (MMBroadbandModemMbmPrivate)); - - object_class->finalize = finalize; - broadband_modem_class->setup_ports = setup_ports; - broadband_modem_class->enabling_modem_init = enabling_modem_init; - broadband_modem_class->enabling_modem_init_finish = enabling_modem_init_finish; -} diff --git a/plugins/mbm/mm-broadband-modem-mbm.h b/plugins/mbm/mm-broadband-modem-mbm.h deleted file mode 100644 index 21eeaef5..00000000 --- a/plugins/mbm/mm-broadband-modem-mbm.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details: - * - * Copyright (C) 2008 - 2010 Ericsson AB - * Copyright (C) 2009 - 2012 Red Hat, Inc. - * Copyright (C) 2012 Lanedo GmbH - * - * Author: Per Hallsmark <per.hallsmark@ericsson.com> - * Bjorn Runaker <bjorn.runaker@ericsson.com> - * Torgny Johansson <torgny.johansson@ericsson.com> - * Jonas Sjöquist <jonas.sjoquist@ericsson.com> - * Dan Williams <dcbw@redhat.com> - * Aleksander Morgado <aleksander@lanedo.com> - */ - -#ifndef MM_BROADBAND_MODEM_MBM_H -#define MM_BROADBAND_MODEM_MBM_H - -#include "mm-broadband-modem.h" - -#define MM_TYPE_BROADBAND_MODEM_MBM (mm_broadband_modem_mbm_get_type ()) -#define MM_BROADBAND_MODEM_MBM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_MBM, MMBroadbandModemMbm)) -#define MM_BROADBAND_MODEM_MBM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_MBM, MMBroadbandModemMbmClass)) -#define MM_IS_BROADBAND_MODEM_MBM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_MBM)) -#define MM_IS_BROADBAND_MODEM_MBM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_MBM)) -#define MM_BROADBAND_MODEM_MBM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_MBM, MMBroadbandModemMbmClass)) - -typedef struct _MMBroadbandModemMbm MMBroadbandModemMbm; -typedef struct _MMBroadbandModemMbmClass MMBroadbandModemMbmClass; -typedef struct _MMBroadbandModemMbmPrivate MMBroadbandModemMbmPrivate; - -struct _MMBroadbandModemMbm { - MMBroadbandModem parent; - MMBroadbandModemMbmPrivate *priv; -}; - -struct _MMBroadbandModemMbmClass{ - MMBroadbandModemClass parent; -}; - -GType mm_broadband_modem_mbm_get_type (void); - -MMBroadbandModemMbm *mm_broadband_modem_mbm_new (const gchar *device, - const gchar **drivers, - const gchar *plugin, - guint16 vendor_id, - guint16 product_id); - -#endif /* MM_BROADBAND_MODEM_MBM_H */ diff --git a/plugins/mbm/mm-modem-helpers-mbm.c b/plugins/mbm/mm-modem-helpers-mbm.c deleted file mode 100644 index 846cc4d6..00000000 --- a/plugins/mbm/mm-modem-helpers-mbm.c +++ /dev/null @@ -1,337 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details: - * - * Copyright (C) 2012 Google, Inc. - * Copyright (C) 2012 - 2013 Aleksander Morgado <aleksander@gnu.org> - * Copyright (C) 2014 Dan Williams <dcbw@redhat.com> - */ - -#include <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <arpa/inet.h> -#include <netinet/in.h> - -#include <ModemManager.h> -#define _LIBMM_INSIDE_MM -#include <libmm-glib.h> - -#include "mm-log.h" -#include "mm-modem-helpers.h" -#include "mm-modem-helpers-mbm.h" - -/*****************************************************************************/ -/* *E2IPCFG response parser */ - -static gboolean -validate_address (int family, const char *addr) -{ - struct in6_addr tmp6 = IN6ADDR_ANY_INIT; - - if (inet_pton (family, addr, (void *) &tmp6) != 1) -{ -g_message ("%s: famil '%s'", __func__, addr); - return FALSE; -} - if ((family == AF_INET6) && IN6_IS_ADDR_UNSPECIFIED (&tmp6)) - return FALSE; - return TRUE; -} - -#define E2IPCFG_TAG "*E2IPCFG" - -gboolean -mm_mbm_parse_e2ipcfg_response (const gchar *response, - MMBearerIpConfig **out_ip4_config, - MMBearerIpConfig **out_ip6_config, - GError **error) -{ - MMBearerIpConfig **ip_config = NULL; - gboolean got_address = FALSE; - gboolean got_gw = FALSE; - gboolean got_dns = FALSE; - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - GError *match_error = NULL; - gchar *dns[3] = { 0 }; - guint dns_idx = 0; - int family = AF_INET; - MMBearerIpMethod method = MM_BEARER_IP_METHOD_STATIC; - - g_return_val_if_fail (out_ip4_config, FALSE); - g_return_val_if_fail (out_ip6_config, FALSE); - - if (!response || !g_str_has_prefix (response, E2IPCFG_TAG)) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing " E2IPCFG_TAG " prefix"); - return FALSE; - } - - response = mm_strip_tag (response, "*E2IPCFG: "); - - if (strchr (response, ':')) { - family = AF_INET6; - ip_config = out_ip6_config; - method = MM_BEARER_IP_METHOD_DHCP; - } else if (strchr (response, '.')) { - family = AF_INET; - ip_config = out_ip4_config; - method = MM_BEARER_IP_METHOD_STATIC; - } else { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Failed to detect " E2IPCFG_TAG " address family"); - return FALSE; - } - - /* *E2IPCFG: (1,<IP>)(2,<gateway>)(3,<DNS>)(3,<DNS>) - * - * *E2IPCFG: (1,"46.157.32.246")(2,"46.157.32.243")(3,"193.213.112.4")(3,"130.67.15.198") - * *E2IPCFG: (1,"fe80:0000:0000:0000:0000:0000:e537:1801")(3,"2001:4600:0004:0fff:0000:0000:0000:0054")(3,"2001:4600:0004:1fff:0000:0000:0000:0054") - * *E2IPCFG: (1,"fe80:0000:0000:0000:0000:0027:b7fe:9401")(3,"fd00:976a:0000:0000:0000:0000:0000:0009") - */ - r = g_regex_new ("\\((\\d),\"([0-9a-fA-F.:]+)\"\\)", 0, 0, NULL); - g_assert (r != NULL); - - if (!g_regex_match_full (r, response, -1, 0, 0, &match_info, &match_error)) { - if (match_error) { - g_propagate_error (error, match_error); - g_prefix_error (error, "Could not parse " E2IPCFG_TAG " results: "); - } else { - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Couldn't match " E2IPCFG_TAG " reply"); - } - return FALSE; - } - - *ip_config = mm_bearer_ip_config_new (); - mm_bearer_ip_config_set_method (*ip_config, method); - while (g_match_info_matches (match_info)) { - g_autofree gchar *id = NULL; - g_autofree gchar *str = NULL; - - id = g_match_info_fetch (match_info, 1); - str = g_match_info_fetch (match_info, 2); - - switch (atoi (id)) { - case 1: - if (validate_address (family, str)) { - mm_bearer_ip_config_set_address (*ip_config, str); - mm_bearer_ip_config_set_prefix (*ip_config, (family == AF_INET6) ? 64 : 28); - got_address = TRUE; - } - break; - case 2: - if ((family == AF_INET) && validate_address (family, str)) { - mm_bearer_ip_config_set_gateway (*ip_config, str); - got_gw = TRUE; - } - break; - case 3: - if (validate_address (family, str)) { - dns[dns_idx++] = g_strdup (str); - got_dns = TRUE; - } - break; - default: - break; - } - g_match_info_next (match_info, NULL); - } - - if (got_dns) { - mm_bearer_ip_config_set_dns (*ip_config, (const gchar **) dns); - g_free (dns[0]); - g_free (dns[1]); - } - - if (!got_address || (family == AF_INET && !got_gw)) { - g_object_unref (*ip_config); - *ip_config = NULL; - g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Got incomplete IP configuration from " E2IPCFG_TAG); - return FALSE; - } - - return TRUE; -} - -/*****************************************************************************/ - -#define CFUN_TAG "+CFUN:" - -static void -add_supported_mode (guint mode, - gpointer log_object, - guint32 *mask) -{ - g_assert (mask); - if (mode >= 32) - mm_obj_warn (log_object, "ignored unexpected mode in +CFUN match: %d", mode); - else - *mask |= (1 << mode); -} - -gboolean -mm_mbm_parse_cfun_test (const gchar *response, - gpointer log_object, - guint32 *supported_mask, - GError **error) -{ - gchar **groups; - guint32 mask = 0; - - g_assert (supported_mask); - - if (!response || !g_str_has_prefix (response, CFUN_TAG)) { - g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Missing " CFUN_TAG " prefix"); - return FALSE; - } - - /* - * AT+CFUN=? - * +CFUN: (0,1,4-6),(0,1) - * OK - */ - - /* Strip tag from response */ - response = mm_strip_tag (response, CFUN_TAG); - - /* Split response in (groups) */ - groups = mm_split_string_groups (response); - - /* First group is the one listing supported modes */ - if (groups && groups[0]) { - gchar **supported_modes; - - supported_modes = g_strsplit_set (groups[0], ", ", -1); - if (supported_modes) { - guint i; - - for (i = 0; supported_modes[i]; i++) { - gchar *separator; - guint mode; - - if (!supported_modes[i][0]) - continue; - - /* Check if this is a range that's being given to us */ - separator = strchr (supported_modes[i], '-'); - if (separator) { - gchar *first_str; - gchar *last_str; - guint first; - guint last; - - *separator = '\0'; - first_str = supported_modes[i]; - last_str = separator + 1; - - if (!mm_get_uint_from_str (first_str, &first)) - mm_obj_warn (log_object, "couldn't match range start: '%s'", first_str); - else if (!mm_get_uint_from_str (last_str, &last)) - mm_obj_warn (log_object, "couldn't match range stop: '%s'", last_str); - else if (first >= last) - mm_obj_warn (log_object, "couldn't match range: wrong first '%s' and last '%s' items", first_str, last_str); - else { - for (mode = first; mode <= last; mode++) - add_supported_mode (mode, log_object, &mask); - } - } else { - if (!mm_get_uint_from_str (supported_modes[i], &mode)) - mm_obj_warn (log_object, "couldn't match mode: '%s'", supported_modes[i]); - else - add_supported_mode (mode, log_object, &mask); - } - } - - g_strfreev (supported_modes); - } - } - g_strfreev (groups); - - if (mask) - *supported_mask = mask; - return !!mask; -} - -/*****************************************************************************/ -/* AT+CFUN? response parsers */ - -gboolean -mm_mbm_parse_cfun_query_power_state (const gchar *response, - MMModemPowerState *out_state, - GError **error) -{ - guint state; - - if (!mm_3gpp_parse_cfun_query_response (response, &state, error)) - return FALSE; - - switch (state) { - case MBM_NETWORK_MODE_OFFLINE: - *out_state = MM_MODEM_POWER_STATE_OFF; - return TRUE; - case MBM_NETWORK_MODE_LOW_POWER: - *out_state = MM_MODEM_POWER_STATE_LOW; - return TRUE; - case MBM_NETWORK_MODE_ANY: - case MBM_NETWORK_MODE_2G: - case MBM_NETWORK_MODE_3G: - *out_state = MM_MODEM_POWER_STATE_ON; - return TRUE; - default: - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Unknown +CFUN pòwer state: '%u'", state); - return FALSE; - } -} - -gboolean -mm_mbm_parse_cfun_query_current_modes (const gchar *response, - MMModemMode *allowed, - gint *mbm_mode, - GError **error) -{ - guint state; - - g_assert (mbm_mode); - g_assert (allowed); - - if (!mm_3gpp_parse_cfun_query_response (response, &state, error)) - return FALSE; - - switch (state) { - case MBM_NETWORK_MODE_OFFLINE: - case MBM_NETWORK_MODE_LOW_POWER: - /* Do not update mbm_mode */ - *allowed = MM_MODEM_MODE_NONE; - return TRUE; - case MBM_NETWORK_MODE_2G: - *mbm_mode = MBM_NETWORK_MODE_2G; - *allowed = MM_MODEM_MODE_2G; - return TRUE; - case MBM_NETWORK_MODE_3G: - *mbm_mode = MBM_NETWORK_MODE_3G; - *allowed = MM_MODEM_MODE_3G; - return TRUE; - case MBM_NETWORK_MODE_ANY: - /* Do not update mbm_mode */ - *allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); - return TRUE; - default: - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Unknown +CFUN current mode: '%u'", state); - return FALSE; - } -} diff --git a/plugins/mbm/mm-modem-helpers-mbm.h b/plugins/mbm/mm-modem-helpers-mbm.h deleted file mode 100644 index 3e3bf57a..00000000 --- a/plugins/mbm/mm-modem-helpers-mbm.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details: - * - * Copyright (C) 2014 Dan Williams <dcbw@redhat.com> - */ - -#ifndef MM_MODEM_HELPERS_MBM_H -#define MM_MODEM_HELPERS_MBM_H - -#include "glib.h" - -/* *E2IPCFG response parser */ -gboolean mm_mbm_parse_e2ipcfg_response (const gchar *response, - MMBearerIpConfig **out_ip4_config, - MMBearerIpConfig **out_ip6_config, - GError **error); - -typedef enum { - MBM_NETWORK_MODE_OFFLINE = 0, - MBM_NETWORK_MODE_ANY = 1, - MBM_NETWORK_MODE_LOW_POWER = 4, - MBM_NETWORK_MODE_2G = 5, - MBM_NETWORK_MODE_3G = 6, -} MbmNetworkMode; - -/* AT+CFUN=? test parser - * Returns a bitmask, bit index set for the supported modes reported */ -gboolean mm_mbm_parse_cfun_test (const gchar *response, - gpointer log_object, - guint32 *supported_mask, - GError **error); - -/* AT+CFUN? response parsers */ -gboolean mm_mbm_parse_cfun_query_power_state (const gchar *response, - MMModemPowerState *out_state, - GError **error); -gboolean mm_mbm_parse_cfun_query_current_modes (const gchar *response, - MMModemMode *allowed, - gint *mbm_mode, - GError **error); - -#endif /* MM_MODEM_HELPERS_MBM_H */ diff --git a/plugins/mbm/mm-plugin-mbm.c b/plugins/mbm/mm-plugin-mbm.c deleted file mode 100644 index 6790d8a8..00000000 --- a/plugins/mbm/mm-plugin-mbm.c +++ /dev/null @@ -1,101 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details: - * - * Copyright (C) 2008 Ericsson AB - * Copyright (C) 2012 Lanedo GmbH - * - * Author: Per Hallsmark <per.hallsmark@ericsson.com> - * Author: Aleksander Morgado <aleksander@lanedo.com> - */ - -#include <string.h> -#include <gmodule.h> - -#define _LIBMM_INSIDE_MM -#include <libmm-glib.h> - -#include "mm-log-object.h" -#include "mm-plugin-mbm.h" -#include "mm-broadband-modem-mbm.h" - -#if defined WITH_MBIM -#include "mm-broadband-modem-mbim.h" -#endif - -G_DEFINE_TYPE (MMPluginMbm, mm_plugin_mbm, MM_TYPE_PLUGIN) - -MM_PLUGIN_DEFINE_MAJOR_VERSION -MM_PLUGIN_DEFINE_MINOR_VERSION - -/*****************************************************************************/ - -static MMBaseModem * -create_modem (MMPlugin *self, - const gchar *uid, - const gchar **drivers, - guint16 vendor, - guint16 product, - guint16 subsystem_vendor, - GList *probes, - GError **error) -{ -#if defined WITH_MBIM - if (mm_port_probe_list_has_mbim_port (probes)) { - mm_obj_dbg (self, "MBIM-powered Ericsson modem found..."); - return MM_BASE_MODEM (mm_broadband_modem_mbim_new (uid, - drivers, - mm_plugin_get_name (self), - vendor, - product)); - } -#endif - - return MM_BASE_MODEM (mm_broadband_modem_mbm_new (uid, - drivers, - mm_plugin_get_name (self), - vendor, - product)); -} - -/*****************************************************************************/ - -G_MODULE_EXPORT MMPlugin * -mm_plugin_create (void) -{ - static const gchar *subsystems[] = { "tty", "net", "usbmisc", NULL }; - static const gchar *udev_tags[] = { - "ID_MM_ERICSSON_MBM", - NULL - }; - - return MM_PLUGIN ( - g_object_new (MM_TYPE_PLUGIN_MBM, - MM_PLUGIN_NAME, MM_MODULE_NAME, - MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems, - MM_PLUGIN_ALLOWED_UDEV_TAGS, udev_tags, - MM_PLUGIN_ALLOWED_AT, TRUE, - MM_PLUGIN_ALLOWED_MBIM, TRUE, - NULL)); -} - -static void -mm_plugin_mbm_init (MMPluginMbm *self) -{ -} - -static void -mm_plugin_mbm_class_init (MMPluginMbmClass *klass) -{ - MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass); - - plugin_class->create_modem = create_modem; -} diff --git a/plugins/mbm/mm-plugin-mbm.h b/plugins/mbm/mm-plugin-mbm.h deleted file mode 100644 index ac07d7e1..00000000 --- a/plugins/mbm/mm-plugin-mbm.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details: - * - * Copyright (C) 2008 Ericsson AB - * Copyright (C) 2012 Lanedo GmbH - * - * Author: Per Hallsmark <per.hallsmark@ericsson.com> - */ - -#ifndef MM_PLUGIN_MBM_H -#define MM_PLUGIN_MBM_H - -#include "mm-plugin.h" - -#define MM_TYPE_PLUGIN_MBM (mm_plugin_mbm_get_type ()) -#define MM_PLUGIN_MBM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_MBM, MMPluginMbm)) -#define MM_PLUGIN_MBM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_MBM, MMPluginMbmClass)) -#define MM_IS_PLUGIN_MBM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_MBM)) -#define MM_IS_PLUGIN_MBM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_MBM)) -#define MM_PLUGIN_MBM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_MBM, MMPluginMbmClass)) - -typedef struct { - MMPlugin parent; -} MMPluginMbm; - -typedef struct { - MMPluginClass parent; -} MMPluginMbmClass; - -GType mm_plugin_mbm_get_type (void); - -G_MODULE_EXPORT MMPlugin *mm_plugin_create (void); - -#endif /* MM_PLUGIN_MBM_H */ diff --git a/plugins/mbm/mm-sim-mbm.c b/plugins/mbm/mm-sim-mbm.c deleted file mode 100644 index d3f73954..00000000 --- a/plugins/mbm/mm-sim-mbm.c +++ /dev/null @@ -1,242 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details: - * - * Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org> - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <ctype.h> - -#include <ModemManager.h> -#define _LIBMM_INSIDE_MM -#include <libmm-glib.h> - -#include "mm-log-object.h" -#include "mm-base-modem-at.h" -#include "mm-sim-mbm.h" - -G_DEFINE_TYPE (MMSimMbm, mm_sim_mbm, MM_TYPE_BASE_SIM) - -/*****************************************************************************/ -/* SEND PIN/PUK (Generic implementation) */ - -typedef struct { - MMBaseModem *modem; - guint retries; -} SendPinPukContext; - -static void -send_pin_puk_context_free (SendPinPukContext *ctx) -{ - g_object_unref (ctx->modem); - g_slice_free (SendPinPukContext, ctx); -} - -static gboolean -common_send_pin_puk_finish (MMBaseSim *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void wait_for_unlocked_status (GTask *task); - -static void -cpin_query_ready (MMBaseModem *modem, - GAsyncResult *res, - GTask *task) -{ - - const gchar *result; - - result = mm_base_modem_at_command_finish (modem, res, NULL); - if (result && strstr (result, "READY")) { - /* All done! */ - g_task_return_boolean (task, TRUE); - g_object_unref (task); - return; - } - - /* Need to recheck */ - wait_for_unlocked_status (task); -} - -static gboolean -cpin_query_cb (GTask *task) -{ - SendPinPukContext *ctx; - - ctx = g_task_get_task_data (task); - mm_base_modem_at_command (ctx->modem, - "+CPIN?", - 20, - FALSE, - (GAsyncReadyCallback)cpin_query_ready, - task); - return G_SOURCE_REMOVE; -} - -static void -wait_for_unlocked_status (GTask *task) -{ - MMSimMbm *self; - SendPinPukContext *ctx; - - self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); - - /* Oops... :/ */ - if (ctx->retries == 0) { - g_task_return_new_error (task, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "PIN was sent but modem didn't report unlocked"); - g_object_unref (task); - return; - } - - /* Check status */ - ctx->retries--; - mm_obj_dbg (self, "scheduling lock state check..."); - g_timeout_add_seconds (1, (GSourceFunc)cpin_query_cb, task); -} - -static void -send_pin_puk_ready (MMBaseModem *modem, - GAsyncResult *res, - GTask *task) -{ - SendPinPukContext *ctx; - GError *error = NULL; - - mm_base_modem_at_command_finish (modem, res, &error); - if (error) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* No explicit error sending the PIN/PUK, now check status until we have the - * expected lock status */ - ctx = g_task_get_task_data (task); - ctx->retries = 3; - wait_for_unlocked_status (task); -} - -static void -common_send_pin_puk (MMBaseSim *self, - const gchar *pin, - const gchar *puk, - GAsyncReadyCallback callback, - gpointer user_data) -{ - SendPinPukContext *ctx; - GTask *task; - gchar *command; - - ctx = g_slice_new (SendPinPukContext); - g_object_get (self, - MM_BASE_SIM_MODEM, &ctx->modem, - NULL); - - task = g_task_new (self, NULL, callback, user_data); - g_task_set_task_data (task, ctx, (GDestroyNotify)send_pin_puk_context_free); - - command = (puk ? - g_strdup_printf ("+CPIN=\"%s\",\"%s\"", puk, pin) : - g_strdup_printf ("+CPIN=\"%s\"", pin)); - mm_base_modem_at_command (ctx->modem, - command, - 3, - FALSE, - (GAsyncReadyCallback)send_pin_puk_ready, - task); - g_free (command); -} - -static void -send_puk (MMBaseSim *self, - const gchar *puk, - const gchar *new_pin, - GAsyncReadyCallback callback, - gpointer user_data) -{ - common_send_pin_puk (self, new_pin, puk, callback, user_data); -} - -static void -send_pin (MMBaseSim *self, - const gchar *pin, - GAsyncReadyCallback callback, - gpointer user_data) -{ - common_send_pin_puk (self, pin, NULL, callback, user_data); -} - -/*****************************************************************************/ - -MMBaseSim * -mm_sim_mbm_new_finish (GAsyncResult *res, - GError **error) -{ - GObject *source; - GObject *sim; - - source = g_async_result_get_source_object (res); - sim = g_async_initable_new_finish (G_ASYNC_INITABLE (source), res, error); - g_object_unref (source); - - if (!sim) - return NULL; - - /* Only export valid SIMs */ - mm_base_sim_export (MM_BASE_SIM (sim)); - - return MM_BASE_SIM (sim); -} - -void -mm_sim_mbm_new (MMBaseModem *modem, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - g_async_initable_new_async (MM_TYPE_SIM_MBM, - G_PRIORITY_DEFAULT, - cancellable, - callback, - user_data, - MM_BASE_SIM_MODEM, modem, - "active", TRUE, /* by default always active */ - NULL); -} - -static void -mm_sim_mbm_init (MMSimMbm *self) -{ -} - -static void -mm_sim_mbm_class_init (MMSimMbmClass *klass) -{ - MMBaseSimClass *base_sim_class = MM_BASE_SIM_CLASS (klass); - - base_sim_class->send_pin = send_pin; - base_sim_class->send_pin_finish = common_send_pin_puk_finish; - base_sim_class->send_puk = send_puk; - base_sim_class->send_puk_finish = common_send_pin_puk_finish; -} diff --git a/plugins/mbm/mm-sim-mbm.h b/plugins/mbm/mm-sim-mbm.h deleted file mode 100644 index 1d843242..00000000 --- a/plugins/mbm/mm-sim-mbm.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details: - * - * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org> - */ - -#ifndef MM_SIM_MBM_H -#define MM_SIM_MBM_H - -#include <glib.h> -#include <glib-object.h> - -#include "mm-base-sim.h" - -#define MM_TYPE_SIM_MBM (mm_sim_mbm_get_type ()) -#define MM_SIM_MBM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SIM_MBM, MMSimMbm)) -#define MM_SIM_MBM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SIM_MBM, MMSimMbmClass)) -#define MM_IS_SIM_MBM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SIM_MBM)) -#define MM_IS_SIM_MBM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SIM_MBM)) -#define MM_SIM_MBM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SIM_MBM, MMSimMbmClass)) - -typedef struct _MMSimMbm MMSimMbm; -typedef struct _MMSimMbmClass MMSimMbmClass; - -struct _MMSimMbm { - MMBaseSim parent; -}; - -struct _MMSimMbmClass { - MMBaseSimClass parent; -}; - -GType mm_sim_mbm_get_type (void); - -void mm_sim_mbm_new (MMBaseModem *modem, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -MMBaseSim *mm_sim_mbm_new_finish (GAsyncResult *res, - GError **error); - -#endif /* MM_SIM_MBM_H */ diff --git a/plugins/mbm/tests/test-modem-helpers-mbm.c b/plugins/mbm/tests/test-modem-helpers-mbm.c deleted file mode 100644 index 4169140a..00000000 --- a/plugins/mbm/tests/test-modem-helpers-mbm.c +++ /dev/null @@ -1,268 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details: - * - * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org> - * Copyright (C) 2014 Dan Williams <dcbw@redhat.com> - */ - -#include <glib.h> -#include <glib-object.h> -#include <locale.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#include <ModemManager.h> -#define _LIBMM_INSIDE_MM -#include <libmm-glib.h> - -#include "mm-log-test.h" -#include "mm-modem-helpers.h" -#include "mm-modem-helpers-mbm.h" - -/*****************************************************************************/ -/* Test *E2IPCFG responses */ - -typedef struct { - const gchar *str; - - /* IPv4 */ - const gchar *ipv4_addr; - const gchar *ipv4_gw; - const gchar *ipv4_dns1; - const gchar *ipv4_dns2; - - /* IPv6 */ - const gchar *ipv6_addr; - const gchar *ipv6_dns1; - const gchar *ipv6_dns2; -} E2ipcfgTest; - -static const E2ipcfgTest tests[] = { - { "*E2IPCFG: (1,\"46.157.32.246\")(2,\"46.157.32.243\")(3,\"193.213.112.4\")(3,\"130.67.15.198\")\r\n", - "46.157.32.246", "46.157.32.243", "193.213.112.4", "130.67.15.198", - NULL, NULL }, - - { "*E2IPCFG: (1,\"fe80:0000:0000:0000:0000:0000:e537:1801\")(3,\"2001:4600:0004:0fff:0000:0000:0000:0054\")(3,\"2001:4600:0004:1fff:0000:0000:0000:0054\")\r\n", - NULL, NULL, NULL, NULL, - "fe80:0000:0000:0000:0000:0000:e537:1801", "2001:4600:0004:0fff:0000:0000:0000:0054", "2001:4600:0004:1fff:0000:0000:0000:0054" }, - - { "*E2IPCFG: (1,\"fe80:0000:0000:0000:0000:0027:b7fe:9401\")(3,\"fd00:976a:0000:0000:0000:0000:0000:0009\")\r\n", - NULL, NULL, NULL, NULL, - "fe80:0000:0000:0000:0000:0027:b7fe:9401", "fd00:976a:0000:0000:0000:0000:0000:0009", NULL }, - - { NULL } -}; - -static void -test_e2ipcfg (void) -{ - guint i; - - for (i = 0; tests[i].str; i++) { - gboolean success; - GError *error = NULL; - MMBearerIpConfig *ipv4 = NULL; - MMBearerIpConfig *ipv6 = NULL; - const gchar **dns; - guint dnslen; - - success = mm_mbm_parse_e2ipcfg_response (tests[i].str, &ipv4, &ipv6, &error); - g_assert_no_error (error); - g_assert (success); - - /* IPv4 */ - if (tests[i].ipv4_addr) { - g_assert (ipv4); - g_assert_cmpint (mm_bearer_ip_config_get_method (ipv4), ==, MM_BEARER_IP_METHOD_STATIC); - g_assert_cmpstr (mm_bearer_ip_config_get_address (ipv4), ==, tests[i].ipv4_addr); - g_assert_cmpint (mm_bearer_ip_config_get_prefix (ipv4), ==, 28); - g_assert_cmpstr (mm_bearer_ip_config_get_gateway (ipv4), ==, tests[i].ipv4_gw); - - dns = mm_bearer_ip_config_get_dns (ipv4); - g_assert (dns); - dnslen = g_strv_length ((gchar **) dns); - if (tests[i].ipv4_dns2 != NULL) - g_assert_cmpint (dnslen, ==, 2); - else - g_assert_cmpint (dnslen, ==, 1); - g_assert_cmpstr (dns[0], ==, tests[i].ipv4_dns1); - g_assert_cmpstr (dns[1], ==, tests[i].ipv4_dns2); - g_object_unref (ipv4); - } else - g_assert (ipv4 == NULL); - - /* IPv6 */ - if (tests[i].ipv6_addr) { - struct in6_addr a6; - g_assert (ipv6); - - g_assert_cmpstr (mm_bearer_ip_config_get_address (ipv6), ==, tests[i].ipv6_addr); - g_assert_cmpint (mm_bearer_ip_config_get_prefix (ipv6), ==, 64); - - g_assert (inet_pton (AF_INET6, mm_bearer_ip_config_get_address (ipv6), &a6)); - if (IN6_IS_ADDR_LINKLOCAL (&a6)) - g_assert_cmpint (mm_bearer_ip_config_get_method (ipv6), ==, MM_BEARER_IP_METHOD_DHCP); - else - g_assert_cmpint (mm_bearer_ip_config_get_method (ipv6), ==, MM_BEARER_IP_METHOD_STATIC); - - dns = mm_bearer_ip_config_get_dns (ipv6); - g_assert (dns); - dnslen = g_strv_length ((gchar **) dns); - if (tests[i].ipv6_dns2 != NULL) - g_assert_cmpint (dnslen, ==, 2); - else - g_assert_cmpint (dnslen, ==, 1); - g_assert_cmpstr (dns[0], ==, tests[i].ipv6_dns1); - g_assert_cmpstr (dns[1], ==, tests[i].ipv6_dns2); - g_object_unref (ipv6); - } else - g_assert (ipv6 == NULL); - } -} - -/*****************************************************************************/ -/* Test +CFUN test responses */ - -#define MAX_MODES 32 - -typedef struct { - const gchar *str; - guint32 expected_mask; -} CfunTest; - -static const CfunTest cfun_tests[] = { - { - "+CFUN: (0,1,4-6),(1-0)\r\n", - ((1 << MBM_NETWORK_MODE_OFFLINE) | - (1 << MBM_NETWORK_MODE_ANY) | - (1 << MBM_NETWORK_MODE_LOW_POWER) | - (1 << MBM_NETWORK_MODE_2G) | - (1 << MBM_NETWORK_MODE_3G)) - }, - { - "+CFUN: (0,1,4-6)\r\n", - ((1 << MBM_NETWORK_MODE_OFFLINE) | - (1 << MBM_NETWORK_MODE_ANY) | - (1 << MBM_NETWORK_MODE_LOW_POWER) | - (1 << MBM_NETWORK_MODE_2G) | - (1 << MBM_NETWORK_MODE_3G)) - }, - { - "+CFUN: (0,1,4)\r\n", - ((1 << MBM_NETWORK_MODE_OFFLINE) | - (1 << MBM_NETWORK_MODE_ANY) | - (1 << MBM_NETWORK_MODE_LOW_POWER)) - }, - { - "+CFUN: (0,1)\r\n", - ((1 << MBM_NETWORK_MODE_OFFLINE) | - (1 << MBM_NETWORK_MODE_ANY)) - }, -}; - -static void -test_cfun_test (void) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (cfun_tests); i++) { - guint32 mask; - gboolean success; - GError *error = NULL; - - success = mm_mbm_parse_cfun_test (cfun_tests[i].str, NULL, &mask, &error); - g_assert_no_error (error); - g_assert (success); - g_assert_cmpuint (mask, ==, cfun_tests[i].expected_mask); - } -} - -/*****************************************************************************/ - -typedef struct { - const gchar *str; - MMModemPowerState state; -} CfunQueryPowerStateTest; - -static const CfunQueryPowerStateTest cfun_query_power_state_tests[] = { - { "+CFUN: 0", MM_MODEM_POWER_STATE_OFF }, - { "+CFUN: 1", MM_MODEM_POWER_STATE_ON }, - { "+CFUN: 4", MM_MODEM_POWER_STATE_LOW }, - { "+CFUN: 5", MM_MODEM_POWER_STATE_ON }, - { "+CFUN: 6", MM_MODEM_POWER_STATE_ON }, -}; - -static void -test_cfun_query_power_state (void) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (cfun_query_power_state_tests); i++) { - GError *error = NULL; - gboolean success; - MMModemPowerState state; - - success = mm_mbm_parse_cfun_query_power_state (cfun_query_power_state_tests[i].str, &state, &error); - g_assert_no_error (error); - g_assert (success); - g_assert_cmpuint (cfun_query_power_state_tests[i].state, ==, state); - } -} - -typedef struct { - const gchar *str; - MMModemMode allowed; - gint mbm_mode; -} CfunQueryCurrentModeTest; - -static const CfunQueryCurrentModeTest cfun_query_current_mode_tests[] = { - { "+CFUN: 0", MM_MODEM_MODE_NONE, -1 }, - { "+CFUN: 1", MM_MODEM_MODE_2G | MM_MODEM_MODE_3G, -1 }, - { "+CFUN: 4", MM_MODEM_MODE_NONE, -1 }, - { "+CFUN: 5", MM_MODEM_MODE_2G, MBM_NETWORK_MODE_2G }, - { "+CFUN: 6", MM_MODEM_MODE_3G, MBM_NETWORK_MODE_3G }, -}; - -static void -test_cfun_query_current_modes (void) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (cfun_query_current_mode_tests); i++) { - GError *error = NULL; - gboolean success; - MMModemMode allowed = MM_MODEM_MODE_NONE; - gint mbm_mode = -1; - - success = mm_mbm_parse_cfun_query_current_modes (cfun_query_current_mode_tests[i].str, &allowed, &mbm_mode, &error); - g_assert_no_error (error); - g_assert (success); - g_assert_cmpuint (cfun_query_current_mode_tests[i].allowed, ==, allowed); - g_assert_cmpint (cfun_query_current_mode_tests[i].mbm_mode, ==, mbm_mode); - } -} - -/*****************************************************************************/ - -int main (int argc, char **argv) -{ - setlocale (LC_ALL, ""); - - g_test_init (&argc, &argv, NULL); - - g_test_add_func ("/MM/mbm/e2ipcfg", test_e2ipcfg); - g_test_add_func ("/MM/mbm/cfun/test", test_cfun_test); - g_test_add_func ("/MM/mbm/cfun/query/power-state", test_cfun_query_power_state); - g_test_add_func ("/MM/mbm/cfun/query/current-modes", test_cfun_query_current_modes); - - return g_test_run (); -} |