aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2015-11-27 14:30:00 +0100
committerAleksander Morgado <aleksander@aleksander.es>2015-12-07 14:20:54 +0100
commitcb59c6d93edba6f3ddc9db92e03588913b192059 (patch)
treec8653da4d18861d20fc5410014aa601ba1fdfcdd /src
parent3bf118d01a90ac486ebe4ab9ed9c043930feac26 (diff)
bearer-qmi: implement stats loading
Use the "WDS Get Packet Statistics" method to query for the ongoing number of bytes transmitted or received. The QMI implementation uses different WDS clients for IPv4 and IPv6; the stats reported are a combination of the values retrieved from both WDS clients.
Diffstat (limited to 'src')
-rw-r--r--src/mm-bearer-qmi.c158
1 files changed, 158 insertions, 0 deletions
diff --git a/src/mm-bearer-qmi.c b/src/mm-bearer-qmi.c
index 2f722e27..30fa2f91 100644
--- a/src/mm-bearer-qmi.c
+++ b/src/mm-bearer-qmi.c
@@ -11,6 +11,7 @@
* GNU General Public License for more details:
*
* Copyright (C) 2012 Google, Inc.
+ * Copyright (C) 2015 Azimut Electronics
*/
#include <config.h>
@@ -56,6 +57,161 @@ struct _MMBearerQmiPrivate {
};
/*****************************************************************************/
+/* Stats */
+
+typedef enum {
+ RELOAD_STATS_CONTEXT_STEP_FIRST,
+ RELOAD_STATS_CONTEXT_STEP_IPV4,
+ RELOAD_STATS_CONTEXT_STEP_IPV6,
+ RELOAD_STATS_CONTEXT_STEP_LAST,
+} ReloadStatsContextStep;
+
+typedef struct {
+ guint64 rx_bytes;
+ guint64 tx_bytes;
+} ReloadStatsResult;
+
+typedef struct {
+ MMBearerQmi *self;
+ GSimpleAsyncResult *result;
+ QmiMessageWdsGetPacketStatisticsInput *input;
+ ReloadStatsContextStep step;
+ ReloadStatsResult stats;
+} ReloadStatsContext;
+
+static gboolean
+reload_stats_finish (MMBaseBearer *bearer,
+ guint64 *rx_bytes,
+ guint64 *tx_bytes,
+ GAsyncResult *res,
+ GError **error)
+{
+ ReloadStatsResult *stats;
+
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+ return FALSE;
+
+ stats = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
+ if (rx_bytes)
+ *rx_bytes = stats->rx_bytes;
+ if (tx_bytes)
+ *tx_bytes = stats->tx_bytes;
+ return TRUE;
+}
+
+static void
+reload_stats_context_complete_and_free (ReloadStatsContext *ctx)
+{
+ g_simple_async_result_complete (ctx->result);
+ g_object_unref (ctx->result);
+ g_object_unref (ctx->self);
+ qmi_message_wds_get_packet_statistics_input_unref (ctx->input);
+ g_slice_free (ReloadStatsContext, ctx);
+}
+
+static void reload_stats_context_step (ReloadStatsContext *ctx);
+
+static void
+get_packet_statistics_ready (QmiClientWds *client,
+ GAsyncResult *res,
+ ReloadStatsContext *ctx)
+{
+ GError *error = NULL;
+ QmiMessageWdsGetPacketStatisticsOutput *output;
+ guint64 tx_bytes_ok = 0;
+ guint64 rx_bytes_ok = 0;
+
+ output = qmi_client_wds_get_packet_statistics_finish (client, res, &error);
+ if (!output) {
+ g_prefix_error (&error, "QMI operation failed: ");
+ g_simple_async_result_take_error (ctx->result, error);
+ reload_stats_context_complete_and_free (ctx);
+ return;
+ }
+
+ if (!qmi_message_wds_get_packet_statistics_output_get_result (output, &error)) {
+ g_prefix_error (&error, "Couldn't get packet statistics: ");
+ g_simple_async_result_take_error (ctx->result, error);
+ qmi_message_wds_get_packet_statistics_output_unref (output);
+ reload_stats_context_complete_and_free (ctx);
+ return;
+ }
+
+ qmi_message_wds_get_packet_statistics_output_get_tx_bytes_ok (output, &tx_bytes_ok, NULL);
+ qmi_message_wds_get_packet_statistics_output_get_rx_bytes_ok (output, &rx_bytes_ok, NULL);
+ ctx->stats.rx_bytes += rx_bytes_ok;
+ ctx->stats.tx_bytes += tx_bytes_ok;
+
+ qmi_message_wds_get_packet_statistics_output_unref (output);
+
+ /* Go on */
+ ctx->step++;
+ reload_stats_context_step (ctx);
+}
+
+static void
+reload_stats_context_step (ReloadStatsContext *ctx)
+{
+ switch (ctx->step) {
+ case RELOAD_STATS_CONTEXT_STEP_FIRST:
+ /* Fall through */
+ ctx->step++;
+ case RELOAD_STATS_CONTEXT_STEP_IPV4:
+ if (ctx->self->priv->client_ipv4) {
+ qmi_client_wds_get_packet_statistics (QMI_CLIENT_WDS (ctx->self->priv->client_ipv4),
+ ctx->input,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)get_packet_statistics_ready,
+ ctx);
+ return;
+ }
+ ctx->step++;
+ /* Fall through */
+ case RELOAD_STATS_CONTEXT_STEP_IPV6:
+ if (ctx->self->priv->client_ipv6) {
+ qmi_client_wds_get_packet_statistics (QMI_CLIENT_WDS (ctx->self->priv->client_ipv6),
+ ctx->input,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)get_packet_statistics_ready,
+ ctx);
+ return;
+ }
+ ctx->step++;
+ /* Fall through */
+ case RELOAD_STATS_CONTEXT_STEP_LAST:
+ g_simple_async_result_set_op_res_gpointer (ctx->result, &ctx->stats, NULL);
+ reload_stats_context_complete_and_free (ctx);
+ return;
+ }
+}
+
+static void
+reload_stats (MMBaseBearer *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ ReloadStatsContext *ctx;
+
+ ctx = g_slice_new0 (ReloadStatsContext);
+ ctx->self = g_object_ref (self);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ reload_stats);
+ ctx->input = qmi_message_wds_get_packet_statistics_input_new ();
+ qmi_message_wds_get_packet_statistics_input_set_mask (
+ ctx->input,
+ (QMI_WDS_PACKET_STATISTICS_MASK_FLAG_TX_BYTES_OK |
+ QMI_WDS_PACKET_STATISTICS_MASK_FLAG_RX_BYTES_OK),
+ NULL);
+ ctx->step = RELOAD_STATS_CONTEXT_STEP_FIRST;
+
+ reload_stats_context_step (ctx);
+}
+
+/*****************************************************************************/
/* Connect */
typedef enum {
@@ -1413,6 +1569,8 @@ mm_bearer_qmi_class_init (MMBearerQmiClass *klass)
base_bearer_class->disconnect = disconnect;
base_bearer_class->disconnect_finish = disconnect_finish;
base_bearer_class->report_connection_status = report_connection_status;
+ base_bearer_class->reload_stats = reload_stats;
+ base_bearer_class->reload_stats_finish = reload_stats_finish;
/* Properties */
properties[PROP_FORCE_DHCP] =