[PATCH 6/6] bearer-qmi: implement stats loading

Aleksander Morgado aleksander at aleksander.es
Fri Nov 27 05:51:19 PST 2015


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.
---
 src/mm-bearer-qmi.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 154 insertions(+)

diff --git a/src/mm-bearer-qmi.c b/src/mm-bearer-qmi.c
index 2f722e2..cf16066 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,157 @@ 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 bytes_rx;
+    guint64 bytes_tx;
+} ReloadStatsResult;
+
+typedef struct {
+    MMBearerQmi *self;
+    GSimpleAsyncResult *result;
+    QmiMessageWdsGetPacketStatisticsInput *input;
+    ReloadStatsContextStep step;
+    ReloadStatsResult stats;
+} ReloadStatsContext;
+
+static gboolean
+reload_stats_finish (MMBaseBearer *bearer,
+                     guint64 *bytes_rx,
+                     guint64 *bytes_tx,
+                     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 (bytes_rx)
+        *bytes_rx = stats->bytes_rx;
+    if (bytes_tx)
+        *bytes_tx = stats->bytes_tx;
+    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;
+
+    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);
+    } else 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);
+    } else {
+        guint64 tx_bytes_ok = 0;
+        guint64 rx_bytes_ok = 0;
+
+        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.bytes_rx += rx_bytes_ok;
+        ctx->stats.bytes_tx += tx_bytes_ok;
+    }
+
+    if (output)
+        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 +1565,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] =
-- 
2.6.2



More information about the ModemManager-devel mailing list