diff options
author | Ben Chan <benchan@chromium.org> | 2018-08-13 12:27:37 -0700 |
---|---|---|
committer | Ben Chan <benchan@chromium.org> | 2018-08-18 13:29:46 -0700 |
commit | 28e64d00181c83fd6cd420c46b6040f7b1afe5fb (patch) | |
tree | 59ba372cd17c3248d7a8d901e2ba41f5a52619d2 /libmm-glib/mm-pco.c | |
parent | 89ffcbdd8db4164a4a1cbea0224b0cc14a3f57b0 (diff) |
libmm-glib: add MMPco for handling raw PCO data
Diffstat (limited to 'libmm-glib/mm-pco.c')
-rw-r--r-- | libmm-glib/mm-pco.c | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/libmm-glib/mm-pco.c b/libmm-glib/mm-pco.c new file mode 100644 index 00000000..07db363d --- /dev/null +++ b/libmm-glib/mm-pco.c @@ -0,0 +1,259 @@ +/* -*- 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 2018 Google LLC. + */ + +#include <string.h> +#include <glib.h> + +#include "mm-enums-types.h" +#include "mm-errors-types.h" +#include "mm-common-helpers.h" +#include "mm-pco.h" + +/** + * SECTION: mm-pco + * @title: MMPco + * @short_description: Helper object to handle 3GPP PCO. + * + * The #MMPco is an object handling the raw 3GPP Protocol Configuration Options + * (PCO) that the modem has received from the network. + * + * This object is retrieved with mm_modem_3gpp_get_pco(). + */ + +G_DEFINE_TYPE (MMPco, mm_pco, G_TYPE_OBJECT); + +struct _MMPcoPrivate { + /* Session ID, signature 'u' */ + guint32 session_id; + /* Flag indicating if the PCO data is complete or partial, signature 'b' */ + gboolean is_complete; + /* Raw PCO data, signature 'ay' */ + GBytes *data; +}; + +/*****************************************************************************/ + +static GBytes * +_g_variant_get_bytes (GVariant *variant) +{ + GByteArray *byte_array; + guint num_bytes; + GVariantIter iter; + guint8 byte; + + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE ("ay"))); + + num_bytes = g_variant_n_children (variant); + if (num_bytes == 0) + return NULL; + + byte_array = g_byte_array_sized_new (num_bytes); + + g_variant_iter_init (&iter, variant); + while (g_variant_iter_loop (&iter, "y", &byte)) + g_byte_array_append (byte_array, &byte, sizeof (byte)); + + return g_byte_array_free_to_bytes (byte_array); +} + +/*****************************************************************************/ + +/** + * mm_pco_get_session_id: + * @self: a #MMPco. + * + * Gets the session ID associated with the PCO. + * + * Returns: the session ID. + */ +guint32 +mm_pco_get_session_id (MMPco *self) +{ + g_return_val_if_fail (MM_IS_PCO (self), G_MAXUINT32); + + return self->priv->session_id; +} + +void +mm_pco_set_session_id (MMPco *self, + guint32 session_id) +{ + g_return_if_fail (MM_IS_PCO (self)); + + self->priv->session_id = session_id; +} + +/*****************************************************************************/ + +/** + * mm_pco_is_complete: + * @self: a #MMPco. + * + * Gets the complete flag that indicates whether the PCO data contains the + * complete PCO structure received from the network. + * + * Returns: %TRUE if the PCO data contains the complete PCO structure, %FALSE otherwise. + */ +gboolean +mm_pco_is_complete (MMPco *self) +{ + g_return_val_if_fail (MM_IS_PCO (self), FALSE); + + return self->priv->is_complete; +} + +void +mm_pco_set_complete (MMPco *self, + gboolean is_complete) +{ + g_return_if_fail (MM_IS_PCO (self)); + + self->priv->is_complete = is_complete; +} + +/*****************************************************************************/ + +/** + * mm_pco_get_data: + * @self: a #MMPco. + * @data_size: (out): Size of the PCO data, if any given. + * + * Gets the PCO data in raw bytes. + * + * Returns: (transfer none): the PCO data, or %NULL if it doesn't contain any. + */ +const guint8 * +mm_pco_get_data (MMPco *self, + gsize *data_size) +{ + g_return_val_if_fail (MM_IS_PCO (self), NULL); + + return g_bytes_get_data (self->priv->data, data_size); +} + +void +mm_pco_set_data (MMPco *self, + const guint8 *data, + gsize data_size) +{ + g_return_if_fail (MM_IS_PCO (self)); + + g_bytes_unref (self->priv->data); + + self->priv->data = (data && data_size) ? g_bytes_new (data, data_size) + : NULL; +} + +/*****************************************************************************/ + +MMPco * +mm_pco_from_variant (GVariant *variant, + GError **error) +{ + MMPco *pco; + GVariant *pco_data = NULL; + + pco = mm_pco_new (); + if (!variant) + return pco; + + if (!g_variant_is_of_type (variant, G_VARIANT_TYPE ("(ubay)"))) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_INVALID_ARGS, + "Cannot create PCO from variant: " + "invalid variant type received"); + g_object_unref (pco); + return NULL; + } + + g_variant_get (variant, "(ub@ay)", + &pco->priv->session_id, + &pco->priv->is_complete, + &pco_data); + + g_bytes_unref (pco->priv->data); + pco->priv->data = _g_variant_get_bytes (pco_data); + g_variant_unref (pco_data); + + return pco; +} + +/*****************************************************************************/ + +GVariant * +mm_pco_to_variant (MMPco *self) +{ + GVariantBuilder builder; + gsize i, pco_data_size; + const guint8 *pco_data; + + /* Allow NULL */ + if (!self) + return NULL; + + g_return_val_if_fail (MM_IS_PCO (self), NULL); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ubay)")); + + g_variant_builder_add (&builder, "u", self->priv->session_id); + g_variant_builder_add (&builder, "b", self->priv->is_complete); + + g_variant_builder_open (&builder, G_VARIANT_TYPE ("ay")); + if (self->priv->data) { + pco_data = g_bytes_get_data (self->priv->data, &pco_data_size); + for (i = 0; i < pco_data_size; ++i) + g_variant_builder_add (&builder, "y", pco_data[i]); + } + g_variant_builder_close (&builder); + + return g_variant_ref_sink (g_variant_builder_end (&builder)); +} + +/*****************************************************************************/ + +MMPco * +mm_pco_new (void) +{ + return (MM_PCO (g_object_new (MM_TYPE_PCO, NULL))); +} + +static void +mm_pco_init (MMPco *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_PCO, MMPcoPrivate); + + self->priv->session_id = G_MAXUINT32; +} + +static void +finalize (GObject *object) +{ + MMPco *self = MM_PCO (object); + + g_bytes_unref (self->priv->data); + + G_OBJECT_CLASS (mm_pco_parent_class)->finalize (object); +} + +static void +mm_pco_class_init (MMPcoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (MMPcoPrivate)); + + object_class->finalize = finalize; +} |