diff options
-rw-r--r-- | src/plugins/mtk/mm-bearer-mbim-mtk-fibocom.c | 184 | ||||
-rw-r--r-- | src/plugins/mtk/mm-bearer-mbim-mtk-fibocom.h | 3 | ||||
-rw-r--r-- | src/plugins/mtk/mm-broadband-modem-mbim-mtk-fibocom.c | 15 |
3 files changed, 193 insertions, 9 deletions
diff --git a/src/plugins/mtk/mm-bearer-mbim-mtk-fibocom.c b/src/plugins/mtk/mm-bearer-mbim-mtk-fibocom.c index 1effc603..71957a07 100644 --- a/src/plugins/mtk/mm-bearer-mbim-mtk-fibocom.c +++ b/src/plugins/mtk/mm-bearer-mbim-mtk-fibocom.c @@ -19,40 +19,208 @@ #define _LIBMM_INSIDE_MM #include <libmm-glib.h> +#include "mm-log-object.h" #include "mm-bearer-mbim-mtk-fibocom.h" G_DEFINE_TYPE (MMBearerMbimMtkFibocom, mm_bearer_mbim_mtk_fibocom, MM_TYPE_BEARER_MBIM) +struct _MMBearerMbimMtkFibocomPrivate { + /* Whether IP packet filters need to be removed */ + gboolean remove_ip_packet_filters; + gboolean reload_stats_unsupported; +}; + +/*****************************************************************************/ +/* Stats */ + +typedef struct { + guint64 rx_bytes; + guint64 tx_bytes; +} ReloadStatsResult; + +static gboolean +reload_stats_finish (MMBaseBearer *_self, + guint64 *rx_bytes, + guint64 *tx_bytes, + GAsyncResult *res, + GError **error) +{ + MMBearerMbimMtkFibocom *self = MM_BEARER_MBIM_MTK_FIBOCOM (_self); + g_autofree ReloadStatsResult *stats = NULL; + g_autoptr(GError) inner_error = NULL; + + stats = g_task_propagate_pointer (G_TASK (res), &inner_error); + if (!stats) { + /* If filters need to be removed on every stats query, we must never + * return an error, otherwise the upper layers will stop the stats reloading + * logic. Only return an error when filters are not being removed. */ + if (!self->priv->remove_ip_packet_filters) { + g_propagate_error (error, inner_error); + return FALSE; + } + /* Flag as stats reloading being unsupported, we will avoid querying. */ + self->priv->reload_stats_unsupported = TRUE; + } + + if (rx_bytes) + *rx_bytes = stats ? stats->rx_bytes : 0; + if (tx_bytes) + *tx_bytes = stats ? stats->tx_bytes : 0; + return TRUE; +} + +static void +parent_reload_stats_ready (MMBaseBearer *self, + GAsyncResult *res, + GTask *task) +{ + g_autofree ReloadStatsResult *stats = NULL; + GError *error = NULL; + + stats = g_new0 (ReloadStatsResult, 1); + + if (!MM_BASE_BEARER_CLASS (mm_bearer_mbim_mtk_fibocom_parent_class)->reload_stats_finish ( + self, + &stats->rx_bytes, + &stats->tx_bytes, + res, + &error)) + g_task_return_error (task, g_steal_pointer (&error)); + else + g_task_return_pointer (task, g_steal_pointer (&stats), g_free); + g_object_unref (task); +} + +static void +packet_statistics_query (GTask *task) +{ + MMBearerMbimMtkFibocom *self; + + self = g_task_get_source_object (task); + if (self->priv->reload_stats_unsupported) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Skipping stats reloading"); + g_object_unref (task); + return; + } + + /* Chain up parent's stats query */ + MM_BASE_BEARER_CLASS (mm_bearer_mbim_mtk_fibocom_parent_class)->reload_stats ( + MM_BASE_BEARER (self), + (GAsyncReadyCallback) parent_reload_stats_ready, + task); +} + +static void +packet_filters_set_ready (MbimDevice *device, + GAsyncResult *res, + GTask *task) +{ + MMBearerMbim *self; + g_autoptr(GError) error = NULL; + g_autoptr(MbimMessage) response = NULL; + + self = g_task_get_source_object (task); + + response = mbim_device_command_finish (device, res, &error); + if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) + mm_obj_dbg (self, "Couldn't reset IP packet filters: %s", error->message); + + packet_statistics_query (task); +} + +static void +ensure_removed_filters (GTask *task) +{ + MMBearerMbimMtkFibocom *self; + MMPortMbim *port; + g_autoptr(MbimMessage) message = NULL; + g_autoptr(MMBaseModem) modem = NULL; + guint32 session_id; + + self = g_task_get_source_object (task); + + g_object_get (self, + MM_BASE_BEARER_MODEM, &modem, + NULL); + port = mm_broadband_modem_mbim_peek_port_mbim (MM_BROADBAND_MODEM_MBIM (modem)); + if (!port) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Couldn't peek MBIM port"); + g_object_unref (task); + return; + } + + mm_obj_dbg (self, "Resetting IP packet filters..."); + + session_id = mm_bearer_mbim_get_session_id (MM_BEARER_MBIM (self)); + message = mbim_message_ip_packet_filters_set_new (session_id, 0, NULL, NULL); + mbim_device_command (mm_port_mbim_peek_device (port), + message, + 5, + NULL, + (GAsyncReadyCallback)packet_filters_set_ready, + task); +} + +static void +reload_stats (MMBaseBearer *_self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMBearerMbimMtkFibocom *self = MM_BEARER_MBIM_MTK_FIBOCOM (_self); + GTask *task; + + task = g_task_new (self, NULL, callback, user_data); + + if (self->priv->remove_ip_packet_filters) + ensure_removed_filters (task); + else + packet_statistics_query (task); +} + /*****************************************************************************/ MMBaseBearer * mm_bearer_mbim_mtk_fibocom_new (MMBroadbandModemMbim *modem, gboolean is_async_slaac_supported, + gboolean remove_ip_packet_filters, MMBearerProperties *config) { - MMBaseBearer *bearer; + MMBearerMbimMtkFibocom *self; /* The Mbim bearer inherits from MMBaseBearer (so it's not a MMBroadbandBearer) * and that means that the object is not async-initable, so we just use * g_object_new() here */ - bearer = g_object_new (MM_TYPE_BEARER_MBIM_MTK_FIBOCOM, - MM_BASE_BEARER_MODEM, modem, - MM_BASE_BEARER_CONFIG, config, - MM_BEARER_MBIM_ASYNC_SLAAC, is_async_slaac_supported, - NULL); + self = g_object_new (MM_TYPE_BEARER_MBIM_MTK_FIBOCOM, + MM_BASE_BEARER_MODEM, modem, + MM_BASE_BEARER_CONFIG, config, + MM_BEARER_MBIM_ASYNC_SLAAC, is_async_slaac_supported, + NULL); + + self->priv->remove_ip_packet_filters = remove_ip_packet_filters; /* Only export valid bearers */ - mm_base_bearer_export (bearer); + mm_base_bearer_export (MM_BASE_BEARER (self)); - return bearer; + return MM_BASE_BEARER (self); } static void mm_bearer_mbim_mtk_fibocom_init (MMBearerMbimMtkFibocom *self) { + /* Initialize private data */ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_BEARER_MBIM_MTK_FIBOCOM, MMBearerMbimMtkFibocomPrivate); } static void mm_bearer_mbim_mtk_fibocom_class_init (MMBearerMbimMtkFibocomClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MMBaseBearerClass *base_bearer_class = MM_BASE_BEARER_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (MMBearerMbimMtkFibocomPrivate)); + + base_bearer_class->reload_stats = reload_stats; + base_bearer_class->reload_stats_finish = reload_stats_finish; } diff --git a/src/plugins/mtk/mm-bearer-mbim-mtk-fibocom.h b/src/plugins/mtk/mm-bearer-mbim-mtk-fibocom.h index 736d3fc9..7e093a52 100644 --- a/src/plugins/mtk/mm-bearer-mbim-mtk-fibocom.h +++ b/src/plugins/mtk/mm-bearer-mbim-mtk-fibocom.h @@ -33,9 +33,11 @@ typedef struct _MMBearerMbimMtkFibocom MMBearerMbimMtkFibocom; typedef struct _MMBearerMbimMtkFibocomClass MMBearerMbimMtkFibocomClass; +typedef struct _MMBearerMbimMtkFibocomPrivate MMBearerMbimMtkFibocomPrivate; struct _MMBearerMbimMtkFibocom { MMBearerMbim parent; + MMBearerMbimMtkFibocomPrivate *priv; }; struct _MMBearerMbimMtkFibocomClass { @@ -48,6 +50,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMBearerMbimMtkFibocom, g_object_unref) /* MBIM bearer creation implementation */ MMBaseBearer *mm_bearer_mbim_mtk_fibocom_new (MMBroadbandModemMbim *modem, gboolean is_async_slaac_supported, + gboolean remove_ip_packet_filters, MMBearerProperties *config); #endif /* MM_BEARER_MBIM_MTK_FIBOCOM_H */ diff --git a/src/plugins/mtk/mm-broadband-modem-mbim-mtk-fibocom.c b/src/plugins/mtk/mm-broadband-modem-mbim-mtk-fibocom.c index cfcd3616..7ef97b64 100644 --- a/src/plugins/mtk/mm-broadband-modem-mbim-mtk-fibocom.c +++ b/src/plugins/mtk/mm-broadband-modem-mbim-mtk-fibocom.c @@ -42,9 +42,10 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbimMtkFibocom, mm_broadband_modem_mbim_ G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_FIBOCOM, shared_fibocom_init)) struct _MMBroadbandModemMbimMtkFibocomPrivate { - /* Supported features */ + /* Custom MTK/Fibocom bearer behavior */ gboolean is_multiplex_supported; gboolean is_async_slaac_supported; + gboolean remove_ip_packet_filters; }; /*****************************************************************************/ @@ -58,6 +59,9 @@ struct _MMBroadbandModemMbimMtkFibocomPrivate { * versions. */ #define MULTIPLEX_SUPPORTED_VERSION 29, 23, 6 +/* Explicit IP packet filter removal required in old firmware versions. */ +#define IP_PACKET_FILTER_REMOVAL_UNNEEDED_VERSION 29, 23, 6 + static inline gboolean fm350_check_version (guint A1, guint A2, guint A3, guint B1, guint B2, guint B3) @@ -102,6 +106,11 @@ process_fm350_version_features (MMBroadbandModemMbimMtkFibocom *self, self->priv->is_multiplex_supported = fm350_check_version (major, minor, micro, MULTIPLEX_SUPPORTED_VERSION); mm_obj_info (self, "FM350 multiplexing is %ssupported", self->priv->is_multiplex_supported ? "" : "not "); + + /* Check if we need to remove IP packet filters */ + self->priv->remove_ip_packet_filters = !fm350_check_version (major, minor, micro, IP_PACKET_FILTER_REMOVAL_UNNEEDED_VERSION); + mm_obj_info (self, "FM350 %s IP packet filter removal", + self->priv->remove_ip_packet_filters ? "requires" : "does not require"); } /*****************************************************************************/ @@ -171,6 +180,7 @@ create_bearer (MMIfaceModem *_self, self->priv->is_async_slaac_supported ? "supported" : "unsupported"); bearer = mm_bearer_mbim_mtk_fibocom_new (MM_BROADBAND_MODEM_MBIM (self), self->priv->is_async_slaac_supported, + self->priv->remove_ip_packet_filters, properties); g_task_return_pointer (task, bearer, g_object_unref); g_object_unref (task); @@ -230,6 +240,9 @@ mm_broadband_modem_mbim_mtk_fibocom_init (MMBroadbandModemMbimMtkFibocom *self) self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_BROADBAND_MODEM_MBIM_MTK_FIBOCOM, MMBroadbandModemMbimMtkFibocomPrivate); + + /* By default remove, unless we have a new enough version */ + self->priv->remove_ip_packet_filters = TRUE; } static void |