aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2021-04-04 13:30:53 +0200
committerAleksander Morgado <aleksander@aleksander.es>2021-04-29 10:13:22 +0000
commite2789b18a1847eecd90fe76902300d99c4ebade3 (patch)
treef7828096263c77c60b1dc66e751548839828706a
parentff8e21b535bc43d0ecfb135628711b3c32c47de8 (diff)
libmm-glib,3gpp-profile: new 3GPP profile helper object
Define a new helper object which we're going to use to implement the new profile management interface. The 3GPP profile object provides the list of settings that modems may be able to store in their profile list, e.g. "apn", "ip-type" and so on. Not all modems will be able to support all the settings defined in the profile object, and therefore, when looking for a specific 3GPP profile object with a given set of settings, we must make sure we only compare those settings that are supported by the modem. The profile management implementation will be able to load during runtime a set of "compare flags", specifying which settings should not be checked during the comparison. E.g. a generic AT-based modem that supports only "apn" and "ip-type" will be compared with the NO_APN_TYPE and NO_AUTH flags; and an AT/Icera-based modem (which supports auth settings) will use only NO_APN_TYPE. The settings in the 3GPP profile should be considered a subset of the bearer properties.
-rw-r--r--docs/reference/libmm-glib/libmm-glib-docs.xml4
-rw-r--r--docs/reference/libmm-glib/libmm-glib-sections.txt39
-rw-r--r--libmm-glib/Makefile.am3
-rw-r--r--libmm-glib/libmm-glib.h1
-rw-r--r--libmm-glib/mm-3gpp-profile.c693
-rw-r--r--libmm-glib/mm-3gpp-profile.h131
6 files changed, 871 insertions, 0 deletions
diff --git a/docs/reference/libmm-glib/libmm-glib-docs.xml b/docs/reference/libmm-glib/libmm-glib-docs.xml
index 5b9a04d6..3646e7dd 100644
--- a/docs/reference/libmm-glib/libmm-glib-docs.xml
+++ b/docs/reference/libmm-glib/libmm-glib-docs.xml
@@ -104,6 +104,10 @@
<xi:include href="xml/mm-modem-3gpp-ussd.xml"/>
</section>
<section>
+ <title>Profile management support</title>
+ <xi:include href="xml/mm-3gpp-profile.xml"/>
+ </section>
+ <section>
<title>Location support</title>
<xi:include href="xml/mm-modem-location.xml"/>
<xi:include href="xml/mm-location-3gpp.xml"/>
diff --git a/docs/reference/libmm-glib/libmm-glib-sections.txt b/docs/reference/libmm-glib/libmm-glib-sections.txt
index 327f33e5..16c19faa 100644
--- a/docs/reference/libmm-glib/libmm-glib-sections.txt
+++ b/docs/reference/libmm-glib/libmm-glib-sections.txt
@@ -1533,6 +1533,45 @@ mm_call_audio_format_get_type
</SECTION>
<SECTION>
+<FILE>mm-3gpp-profile</FILE>
+<TITLE>3GPP profile</TITLE>
+MM_3GPP_PROFILE_ID_UNKNOWN
+MM3gppProfile
+mm_3gpp_profile_new
+<SUBSECTION GettersSetters>
+mm_3gpp_profile_get_apn
+mm_3gpp_profile_set_apn
+mm_3gpp_profile_get_apn_type
+mm_3gpp_profile_set_apn_type
+mm_3gpp_profile_get_allowed_auth
+mm_3gpp_profile_set_allowed_auth
+mm_3gpp_profile_get_user
+mm_3gpp_profile_set_user
+mm_3gpp_profile_get_password
+mm_3gpp_profile_set_password
+mm_3gpp_profile_get_ip_type
+mm_3gpp_profile_set_ip_type
+mm_3gpp_profile_get_profile_id
+mm_3gpp_profile_set_profile_id
+<SUBSECTION Private>
+mm_3gpp_profile_new_from_dictionary
+mm_3gpp_profile_new_from_string
+mm_3gpp_profile_consume_string
+mm_3gpp_profile_consume_variant
+mm_3gpp_profile_get_dictionary
+<SUBSECTION Standard>
+MM3gppProfileClass
+MM3gppProfilePrivate
+MM_3GPP_PROFILE
+MM_3GPP_PROFILE_CLASS
+MM_3GPP_PROFILE_GET_CLASS
+MM_IS_3GPP_PROFILE
+MM_IS_3GPP_PROFILE_CLASS
+MM_TYPE_3GPP_PROFILE
+mm_3gpp_profile_get_type
+</SECTION>
+
+<SECTION>
<FILE>mm-enums-types</FILE>
<TITLE>Flags and Enumerations</TITLE>
mm_bearer_type_get_string
diff --git a/libmm-glib/Makefile.am b/libmm-glib/Makefile.am
index f33836f2..36d16505 100644
--- a/libmm-glib/Makefile.am
+++ b/libmm-glib/Makefile.am
@@ -91,6 +91,8 @@ libmm_glib_la_SOURCES = \
mm-call-audio-format.c \
mm-sim-preferred-network.h \
mm-sim-preferred-network.c \
+ mm-3gpp-profile.h \
+ mm-3gpp-profile.c \
$(NULL)
libmm_glib_la_CPPFLAGS = \
@@ -163,6 +165,7 @@ include_HEADERS = \
mm-pco.h \
mm-call-audio-format.h \
mm-sim-preferred-network.h \
+ mm-3gpp-profile.h \
$(NULL)
CLEANFILES =
diff --git a/libmm-glib/libmm-glib.h b/libmm-glib/libmm-glib.h
index 6572b2d3..f288d628 100644
--- a/libmm-glib/libmm-glib.h
+++ b/libmm-glib/libmm-glib.h
@@ -81,6 +81,7 @@
#include <mm-kernel-event-properties.h>
#include <mm-pco.h>
#include <mm-sim-preferred-network.h>
+#include <mm-3gpp-profile.h>
/* generated */
#include <mm-errors-types.h>
diff --git a/libmm-glib/mm-3gpp-profile.c b/libmm-glib/mm-3gpp-profile.c
new file mode 100644
index 00000000..2694239b
--- /dev/null
+++ b/libmm-glib/mm-3gpp-profile.c
@@ -0,0 +1,693 @@
+/* -*- 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) 2021 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#include <string.h>
+
+#include "mm-errors-types.h"
+#include "mm-common-helpers.h"
+#include "mm-3gpp-profile.h"
+
+/**
+ * SECTION: mm-3gpp-profile
+ * @title: MM3gppProfile
+ * @short_description: Helper object to handle 3GPP profile settings.
+ *
+ * The #MM3gppProfile is an object handling the settings associated
+ * to a connection profile stored in the device.
+ */
+
+G_DEFINE_TYPE (MM3gppProfile, mm_3gpp_profile, G_TYPE_OBJECT)
+
+#define PROPERTY_ID "profile-id"
+#define PROPERTY_APN "apn"
+#define PROPERTY_ALLOWED_AUTH "allowed-auth"
+#define PROPERTY_USER "user"
+#define PROPERTY_PASSWORD "password"
+#define PROPERTY_IP_TYPE "ip-type"
+#define PROPERTY_APN_TYPE "apn-type"
+
+struct _MM3gppProfilePrivate {
+ gint profile_id;
+ gchar *apn;
+ MMBearerIpFamily ip_type;
+ MMBearerApnType apn_type;
+
+ /* Optional authentication settings */
+ MMBearerAllowedAuth allowed_auth;
+ gchar *user;
+ gchar *password;
+};
+
+/*****************************************************************************/
+
+static gboolean
+cmp_str (const gchar *a,
+ const gchar *b)
+{
+ /* Strict match */
+ if ((!a && !b) || (a && b && g_strcmp0 (a, b) == 0))
+ return TRUE;
+ /* Additional match, consider NULL and EMPTY string equal */
+ if ((!a && !b[0]) || (!b && !a[0]))
+ return TRUE;
+ return FALSE;
+}
+
+/**
+ * mm_3gpp_profile_cmp: (skip)
+ */
+gboolean
+mm_3gpp_profile_cmp (MM3gppProfile *a,
+ MM3gppProfile *b,
+ GEqualFunc cmp_apn,
+ MM3gppProfileCmpFlags flags)
+{
+ /* When an input cmp_apn() methods is provided to compare the APNs, we must
+ * run it twice, with the input arguments switched, as e.g. the mm_3gpp_cmp_apn_name()
+ * method that may be given here treats both input arguments differently. */
+ if (cmp_apn && !cmp_apn (a->priv->apn, b->priv->apn) && !cmp_apn (b->priv->apn, a->priv->apn))
+ return FALSE;
+ if (!cmp_apn && !cmp_str (a->priv->apn, b->priv->apn))
+ return FALSE;
+ if (!(flags & MM_3GPP_PROFILE_CMP_FLAGS_NO_IP_TYPE) &&
+ (a->priv->ip_type != b->priv->ip_type))
+ return FALSE;
+ if (!(flags & MM_3GPP_PROFILE_CMP_FLAGS_NO_PROFILE_ID) &&
+ (a->priv->profile_id != b->priv->profile_id))
+ return FALSE;
+ if (!(flags & MM_3GPP_PROFILE_CMP_FLAGS_NO_AUTH) &&
+ ((a->priv->allowed_auth != b->priv->allowed_auth) ||
+ (!cmp_str (a->priv->user, b->priv->user)) ||
+ (!cmp_str (a->priv->password, b->priv->password))))
+ return FALSE;
+ if (!(flags & MM_3GPP_PROFILE_CMP_FLAGS_NO_APN_TYPE) &&
+ (a->priv->apn_type != b->priv->apn_type))
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_3gpp_profile_set_profile_id:
+ * @self: a #MM3gppProfile.
+ * @profile_id: Numeric profile id to use, or #MM_3GPP_PROFILE_ID_UNKNOWN.
+ *
+ * Sets the profile id to use.
+ *
+ * If none specified explicitly, #MM_3GPP_PROFILE_ID_UNKNOWN is assumed.
+ *
+ * Since: 1.18
+ */
+void
+mm_3gpp_profile_set_profile_id (MM3gppProfile *self,
+ gint profile_id)
+{
+ g_return_if_fail (MM_IS_3GPP_PROFILE (self));
+
+ self->priv->profile_id = profile_id;
+}
+
+/**
+ * mm_3gpp_profile_get_profile_id:
+ * @self: a #MM3gppProfile.
+ *
+ * Gets the profile id.
+ *
+ * Returns: the profile id..
+ *
+ * Since: 1.18
+ */
+gint
+mm_3gpp_profile_get_profile_id (MM3gppProfile *self)
+{
+ g_return_val_if_fail (MM_IS_3GPP_PROFILE (self), MM_3GPP_PROFILE_ID_UNKNOWN);
+
+ return self->priv->profile_id;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_3gpp_profile_set_apn:
+ * @self: a #MM3gppProfile.
+ * @apn: Name of the access point.
+ *
+ * Sets the name of the access point to use.
+ *
+ * Since: 1.18
+ */
+void
+mm_3gpp_profile_set_apn (MM3gppProfile *self,
+ const gchar *apn)
+{
+ g_return_if_fail (MM_IS_3GPP_PROFILE (self));
+
+ g_free (self->priv->apn);
+ self->priv->apn = g_strdup (apn);
+}
+
+/**
+ * mm_3gpp_profile_get_apn:
+ * @self: a #MM3gppProfile.
+ *
+ * Gets the name of the access point.
+ *
+ * Returns: (transfer none): the access point, or #NULL if not set. Do not free
+ * the returned value, it is owned by @self.
+ *
+ * Since: 1.18
+ */
+const gchar *
+mm_3gpp_profile_get_apn (MM3gppProfile *self)
+{
+ g_return_val_if_fail (MM_IS_3GPP_PROFILE (self), NULL);
+
+ return self->priv->apn;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_3gpp_profile_set_allowed_auth:
+ * @self: a #MM3gppProfile.
+ * @allowed_auth: a bitmask of #MMBearerAllowedAuth values.
+ * %MM_BEARER_ALLOWED_AUTH_UNKNOWN may be given to request the modem-default
+ * method.
+ *
+ * Sets the method to use when authenticating with the access point.
+ *
+ * Since: 1.18
+ */
+void
+mm_3gpp_profile_set_allowed_auth (MM3gppProfile *self,
+ MMBearerAllowedAuth allowed_auth)
+{
+ g_return_if_fail (MM_IS_3GPP_PROFILE (self));
+
+ self->priv->allowed_auth = allowed_auth;
+}
+
+/**
+ * mm_3gpp_profile_get_allowed_auth:
+ * @self: a #MM3gppProfile.
+ *
+ * Gets the methods allowed to use when authenticating with the access point.
+ *
+ * Returns: a bitmask of #MMBearerAllowedAuth values, or
+ * %MM_BEARER_ALLOWED_AUTH_UNKNOWN to request the modem-default method.
+ *
+ * Since: 1.18
+ */
+MMBearerAllowedAuth
+mm_3gpp_profile_get_allowed_auth (MM3gppProfile *self)
+{
+ g_return_val_if_fail (MM_IS_3GPP_PROFILE (self), MM_BEARER_ALLOWED_AUTH_UNKNOWN);
+
+ return self->priv->allowed_auth;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_3gpp_profile_set_user:
+ * @self: a #MM3gppProfile.
+ * @user: the username
+ *
+ * Sets the username used to authenticate with the access point.
+ *
+ * Since: 1.18
+ */
+void
+mm_3gpp_profile_set_user (MM3gppProfile *self,
+ const gchar *user)
+{
+ g_return_if_fail (MM_IS_3GPP_PROFILE (self));
+
+ g_free (self->priv->user);
+ self->priv->user = g_strdup (user);
+}
+
+/**
+ * mm_3gpp_profile_get_user:
+ * @self: a #MM3gppProfile.
+ *
+ * Gets the username used to authenticate with the access point.
+ *
+ * Returns: (transfer none): the username, or #NULL if not set. Do not free the
+ * returned value, it is owned by @self.
+ *
+ * Since: 1.18
+ */
+const gchar *
+mm_3gpp_profile_get_user (MM3gppProfile *self)
+{
+ g_return_val_if_fail (MM_IS_3GPP_PROFILE (self), NULL);
+
+ return self->priv->user;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_3gpp_profile_set_password:
+ * @self: a #MM3gppProfile.
+ * @password: the password
+ *
+ * Sets the password used to authenticate with the access point.
+ *
+ * Since: 1.18
+ */
+void
+mm_3gpp_profile_set_password (MM3gppProfile *self,
+ const gchar *password)
+{
+ g_return_if_fail (MM_IS_3GPP_PROFILE (self));
+
+ g_free (self->priv->password);
+ self->priv->password = g_strdup (password);
+}
+
+/**
+ * mm_3gpp_profile_get_password:
+ * @self: a #MM3gppProfile.
+ *
+ * Gets the password used to authenticate with the access point.
+ *
+ * Returns: (transfer none): the password, or #NULL if not set. Do not free
+ * the returned value, it is owned by @self.
+ *
+ * Since: 1.18
+ */
+const gchar *
+mm_3gpp_profile_get_password (MM3gppProfile *self)
+{
+ g_return_val_if_fail (MM_IS_3GPP_PROFILE (self), NULL);
+
+ return self->priv->password;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_3gpp_profile_set_ip_type:
+ * @self: a #MM3gppProfile.
+ * @ip_type: a #MMBearerIpFamily.
+ *
+ * Sets the IP type to use.
+ *
+ * Since: 1.18
+ */
+void
+mm_3gpp_profile_set_ip_type (MM3gppProfile *self,
+ MMBearerIpFamily ip_type)
+{
+ g_return_if_fail (MM_IS_3GPP_PROFILE (self));
+
+ self->priv->ip_type = ip_type;
+}
+
+/**
+ * mm_3gpp_profile_get_ip_type:
+ * @self: a #MM3gppProfile.
+ *
+ * Gets the IP type to use.
+ *
+ * Returns: a #MMBearerIpFamily.
+ *
+ * Since: 1.18
+ */
+MMBearerIpFamily
+mm_3gpp_profile_get_ip_type (MM3gppProfile *self)
+{
+ g_return_val_if_fail (MM_IS_3GPP_PROFILE (self), MM_BEARER_IP_FAMILY_NONE);
+
+ return self->priv->ip_type;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_3gpp_profile_set_apn_type:
+ * @self: a #MM3gppProfile.
+ * @apn_type: a mask of #MMBearerApnType values.
+ *
+ * Sets the APN types to use.
+ *
+ * Since: 1.18
+ */
+void
+mm_3gpp_profile_set_apn_type (MM3gppProfile *self,
+ MMBearerApnType apn_type)
+{
+ g_return_if_fail (MM_IS_3GPP_PROFILE (self));
+
+ self->priv->apn_type = apn_type;
+}
+
+/**
+ * mm_3gpp_profile_get_apn_type:
+ * @self: a #MM3gppProfile.
+ *
+ * Gets the APN types to use.
+ *
+ * Returns: a mask of #MMBearerApnType values.
+ *
+ * Since: 1.18
+ */
+MMBearerApnType
+mm_3gpp_profile_get_apn_type (MM3gppProfile *self)
+{
+ g_return_val_if_fail (MM_IS_3GPP_PROFILE (self), MM_BEARER_APN_TYPE_NONE);
+
+ return self->priv->apn_type;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_3gpp_profile_get_dictionary: (skip)
+ */
+GVariant *
+mm_3gpp_profile_get_dictionary (MM3gppProfile *self)
+{
+ GVariantBuilder builder;
+
+ /* We do allow NULL */
+ if (!self)
+ return NULL;
+
+ g_return_val_if_fail (MM_IS_3GPP_PROFILE (self), NULL);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_ID,
+ g_variant_new_int32 (self->priv->profile_id));
+
+ if (self->priv->apn)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_APN,
+ g_variant_new_string (self->priv->apn));
+
+ if (self->priv->allowed_auth != MM_BEARER_ALLOWED_AUTH_UNKNOWN)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_ALLOWED_AUTH,
+ g_variant_new_uint32 (self->priv->allowed_auth));
+
+ if (self->priv->user)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_USER,
+ g_variant_new_string (self->priv->user));
+
+ if (self->priv->password)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_PASSWORD,
+ g_variant_new_string (self->priv->password));
+
+ if (self->priv->ip_type != MM_BEARER_IP_FAMILY_NONE)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_IP_TYPE,
+ g_variant_new_uint32 (self->priv->ip_type));
+
+ if (self->priv->apn_type != MM_BEARER_APN_TYPE_NONE)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_APN_TYPE,
+ g_variant_new_uint32 (self->priv->apn_type));
+
+ return g_variant_ref_sink (g_variant_builder_end (&builder));
+}
+
+/*****************************************************************************/
+
+gboolean
+mm_3gpp_profile_consume_string (MM3gppProfile *self,
+ const gchar *key,
+ const gchar *value,
+ GError **error)
+{
+ g_return_val_if_fail (MM_IS_3GPP_PROFILE (self), FALSE);
+
+ if (g_str_equal (key, PROPERTY_ID)) {
+ gint profile_id;
+
+ if (!mm_get_int_from_str (value, &profile_id)) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "invalid profile id value given: %s", value);
+ return FALSE;
+ }
+ mm_3gpp_profile_set_profile_id (self, profile_id);
+ } else if (g_str_equal (key, PROPERTY_APN))
+ mm_3gpp_profile_set_apn (self, value);
+ else if (g_str_equal (key, PROPERTY_ALLOWED_AUTH)) {
+ GError *inner_error = NULL;
+ MMBearerAllowedAuth allowed_auth;
+
+ allowed_auth = mm_common_get_allowed_auth_from_string (value, &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+ mm_3gpp_profile_set_allowed_auth (self, allowed_auth);
+ } else if (g_str_equal (key, PROPERTY_USER))
+ mm_3gpp_profile_set_user (self, value);
+ else if (g_str_equal (key, PROPERTY_PASSWORD))
+ mm_3gpp_profile_set_password (self, value);
+ else if (g_str_equal (key, PROPERTY_IP_TYPE)) {
+ GError *inner_error = NULL;
+ MMBearerIpFamily ip_type;
+
+ ip_type = mm_common_get_ip_type_from_string (value, &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+ mm_3gpp_profile_set_ip_type (self, ip_type);
+ } else if (g_str_equal (key, PROPERTY_APN_TYPE)) {
+ GError *inner_error = NULL;
+ MMBearerApnType apn_type;
+
+ apn_type = mm_common_get_apn_type_from_string (value, &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+ mm_3gpp_profile_set_apn_type (self, apn_type);
+ } else {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_UNSUPPORTED,
+ "Invalid properties string, unsupported key '%s'",
+ key);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+typedef struct {
+ MM3gppProfile *properties;
+ GError *error;
+} ParseKeyValueContext;
+
+static gboolean
+key_value_foreach (const gchar *key,
+ const gchar *value,
+ ParseKeyValueContext *ctx)
+{
+ return mm_3gpp_profile_consume_string (ctx->properties,
+ key,
+ value,
+ &ctx->error);
+}
+
+/**
+ * mm_3gpp_profile_new_from_string: (skip)
+ */
+MM3gppProfile *
+mm_3gpp_profile_new_from_string (const gchar *str,
+ GError **error)
+{
+ ParseKeyValueContext ctx;
+
+ ctx.error = NULL;
+ ctx.properties = mm_3gpp_profile_new ();
+
+ mm_common_parse_key_value_string (str,
+ &ctx.error,
+ (MMParseKeyValueForeachFn)key_value_foreach,
+ &ctx);
+ /* If error, destroy the object */
+ if (ctx.error) {
+ g_propagate_error (error, ctx.error);
+ g_object_unref (ctx.properties);
+ ctx.properties = NULL;
+ }
+
+ return ctx.properties;
+}
+
+/*****************************************************************************/
+
+gboolean
+mm_3gpp_profile_consume_variant (MM3gppProfile *self,
+ const gchar *key,
+ GVariant *value,
+ GError **error)
+{
+ g_return_val_if_fail (MM_IS_3GPP_PROFILE (self), FALSE);
+
+ if (g_str_equal (key, PROPERTY_ID))
+ mm_3gpp_profile_set_profile_id (
+ self,
+ g_variant_get_int32 (value));
+ else if (g_str_equal (key, PROPERTY_APN))
+ mm_3gpp_profile_set_apn (
+ self,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_ALLOWED_AUTH))
+ mm_3gpp_profile_set_allowed_auth (
+ self,
+ g_variant_get_uint32 (value));
+ else if (g_str_equal (key, PROPERTY_USER))
+ mm_3gpp_profile_set_user (
+ self,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_PASSWORD))
+ mm_3gpp_profile_set_password (
+ self,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_IP_TYPE))
+ mm_3gpp_profile_set_ip_type (
+ self,
+ g_variant_get_uint32 (value));
+ else if (g_str_equal (key, PROPERTY_APN_TYPE))
+ mm_3gpp_profile_set_apn_type (
+ self,
+ g_variant_get_uint32 (value));
+ else {
+ /* Set error */
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid self dictionary, unexpected key '%s'",
+ key);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * mm_3gpp_profile_new_from_dictionary: (skip)
+ */
+MM3gppProfile *
+mm_3gpp_profile_new_from_dictionary (GVariant *dictionary,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ GVariantIter iter;
+ gchar *key;
+ GVariant *value;
+ MM3gppProfile *properties;
+
+ properties = mm_3gpp_profile_new ();
+ if (!dictionary)
+ return properties;
+
+ if (!g_variant_is_of_type (dictionary, G_VARIANT_TYPE ("a{sv}"))) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create Bearer properties from dictionary: "
+ "invalid variant type received");
+ g_object_unref (properties);
+ return NULL;
+ }
+
+ g_variant_iter_init (&iter, dictionary);
+ while (!inner_error &&
+ g_variant_iter_next (&iter, "{sv}", &key, &value)) {
+ mm_3gpp_profile_consume_variant (properties, key, value, &inner_error);
+ g_free (key);
+ g_variant_unref (value);
+ }
+
+ /* If error, destroy the object */
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ g_object_unref (properties);
+ properties = NULL;
+ }
+
+ return properties;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_3gpp_profile_new:
+ *
+ * Creates a new empty #MM3gppProfile.
+ *
+ * Returns: (transfer full): a #MM3gppProfile. The returned value should be freed with g_object_unref().
+ *
+ * Since: 1.18
+ */
+MM3gppProfile *
+mm_3gpp_profile_new (void)
+{
+ return MM_3GPP_PROFILE (g_object_new (MM_TYPE_3GPP_PROFILE, NULL));
+}
+
+static void
+mm_3gpp_profile_init (MM3gppProfile *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_3GPP_PROFILE, MM3gppProfilePrivate);
+
+ /* Some defaults */
+ self->priv->profile_id = MM_3GPP_PROFILE_ID_UNKNOWN;
+ self->priv->allowed_auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN;
+ self->priv->ip_type = MM_BEARER_IP_FAMILY_NONE;
+ self->priv->apn_type = MM_BEARER_APN_TYPE_NONE;
+}
+
+static void
+finalize (GObject *object)
+{
+ MM3gppProfile *self = MM_3GPP_PROFILE (object);
+
+ g_free (self->priv->apn);
+ g_free (self->priv->user);
+ g_free (self->priv->password);
+
+ G_OBJECT_CLASS (mm_3gpp_profile_parent_class)->finalize (object);
+}
+
+static void
+mm_3gpp_profile_class_init (MM3gppProfileClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MM3gppProfilePrivate));
+
+ object_class->finalize = finalize;
+}
diff --git a/libmm-glib/mm-3gpp-profile.h b/libmm-glib/mm-3gpp-profile.h
new file mode 100644
index 00000000..a3974a66
--- /dev/null
+++ b/libmm-glib/mm-3gpp-profile.h
@@ -0,0 +1,131 @@
+/* -*- 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) 2021 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#ifndef MM_3GPP_PROFILE_H
+#define MM_3GPP_PROFILE_H
+
+#include <ModemManager.h>
+#include <glib-object.h>
+
+#if !defined (__LIBMM_GLIB_H_INSIDE__) && !defined (LIBMM_GLIB_COMPILATION)
+# error "Only <libmm-glib.h> can be included directly."
+#endif
+
+G_BEGIN_DECLS
+
+/**
+ * MM_3GPP_PROFILE_ID_UNKNOWN:
+ *
+ * This value may be specified in the 'profile-id' property When the user
+ * creates a new #MM3gppProfile, to indicate that the real profile id should
+ * be assigned by the device.
+ */
+#define MM_3GPP_PROFILE_ID_UNKNOWN -1
+
+#define MM_TYPE_3GPP_PROFILE (mm_3gpp_profile_get_type ())
+#define MM_3GPP_PROFILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_3GPP_PROFILE, MM3gppProfile))
+#define MM_3GPP_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_3GPP_PROFILE, MM3gppProfileClass))
+#define MM_IS_3GPP_PROFILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_3GPP_PROFILE))
+#define MM_IS_3GPP_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_3GPP_PROFILE))
+#define MM_3GPP_PROFILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_3GPP_PROFILE, MM3gppProfileClass))
+
+typedef struct _MM3gppProfile MM3gppProfile;
+typedef struct _MM3gppProfileClass MM3gppProfileClass;
+typedef struct _MM3gppProfilePrivate MM3gppProfilePrivate;
+
+/**
+ * MM3gppProfile:
+ *
+ * The #MM3gppProfile structure contains private data and should
+ * only be accessed using the provided API.
+ */
+struct _MM3gppProfile {
+ /*< private >*/
+ GObject parent;
+ MM3gppProfilePrivate *priv;
+};
+
+struct _MM3gppProfileClass {
+ /*< private >*/
+ GObjectClass parent;
+};
+
+GType mm_3gpp_profile_get_type (void);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (MM3gppProfile, g_object_unref)
+
+MM3gppProfile *mm_3gpp_profile_new (void);
+
+void mm_3gpp_profile_set_profile_id (MM3gppProfile *self,
+ gint profile_id);
+void mm_3gpp_profile_set_apn (MM3gppProfile *self,
+ const gchar *apn);
+void mm_3gpp_profile_set_allowed_auth (MM3gppProfile *self,
+ MMBearerAllowedAuth allowed_auth);
+void mm_3gpp_profile_set_user (MM3gppProfile *self,
+ const gchar *user);
+void mm_3gpp_profile_set_password (MM3gppProfile *self,
+ const gchar *password);
+void mm_3gpp_profile_set_ip_type (MM3gppProfile *self,
+ MMBearerIpFamily ip_type);
+void mm_3gpp_profile_set_apn_type (MM3gppProfile *self,
+ MMBearerApnType apn_type);
+
+gint mm_3gpp_profile_get_profile_id (MM3gppProfile *self);
+const gchar *mm_3gpp_profile_get_apn (MM3gppProfile *self);
+MMBearerAllowedAuth mm_3gpp_profile_get_allowed_auth (MM3gppProfile *self);
+const gchar *mm_3gpp_profile_get_user (MM3gppProfile *self);
+const gchar *mm_3gpp_profile_get_password (MM3gppProfile *self);
+MMBearerIpFamily mm_3gpp_profile_get_ip_type (MM3gppProfile *self);
+MMBearerApnType mm_3gpp_profile_get_apn_type (MM3gppProfile *self);
+
+/*****************************************************************************/
+/* ModemManager/libmm-glib/mmcli specific methods */
+
+#if defined (_LIBMM_INSIDE_MM) || \
+ defined (_LIBMM_INSIDE_MMCLI) || \
+ defined (LIBMM_GLIB_COMPILATION)
+
+MM3gppProfile *mm_3gpp_profile_new_from_string (const gchar *str,
+ GError **error);
+MM3gppProfile *mm_3gpp_profile_new_from_dictionary (GVariant *dictionary,
+ GError **error);
+GVariant *mm_3gpp_profile_get_dictionary (MM3gppProfile *self);
+gboolean mm_3gpp_profile_consume_string (MM3gppProfile *self,
+ const gchar *key,
+ const gchar *value,
+ GError **error);
+gboolean mm_3gpp_profile_consume_variant (MM3gppProfile *self,
+ const gchar *key,
+ GVariant *value,
+ GError **error);
+
+typedef enum {
+ MM_3GPP_PROFILE_CMP_FLAGS_NONE = 0,
+ MM_3GPP_PROFILE_CMP_FLAGS_NO_PROFILE_ID = 1 << 1,
+ MM_3GPP_PROFILE_CMP_FLAGS_NO_AUTH = 1 << 2,
+ MM_3GPP_PROFILE_CMP_FLAGS_NO_APN_TYPE = 1 << 3,
+ MM_3GPP_PROFILE_CMP_FLAGS_NO_IP_TYPE = 1 << 4,
+} MM3gppProfileCmpFlags;
+
+gboolean mm_3gpp_profile_cmp (MM3gppProfile *a,
+ MM3gppProfile *b,
+ GEqualFunc cmp_apn,
+ MM3gppProfileCmpFlags flags);
+
+#endif
+
+G_END_DECLS
+
+#endif /* MM_3GPP_PROFILE_H */