aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--src/mm-broadband-modem-qmi.c640
-rw-r--r--src/mm-modem-helpers-qmi.c46
-rw-r--r--src/mm-modem-helpers-qmi.h3
4 files changed, 690 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac
index 5696a3b3..163c4a8b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -401,7 +401,7 @@ dnl-----------------------------------------------------------------------------
dnl QMI support (enabled by default)
dnl
-LIBQMI_VERSION=1.29.3
+LIBQMI_VERSION=1.29.4
AC_ARG_WITH(qmi, AS_HELP_STRING([--without-qmi], [Build without QMI support]), [], [with_qmi=yes])
AM_CONDITIONAL(WITH_QMI, test "x$with_qmi" = "xyes")
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c
index 594ecf5c..d10fdf54 100644
--- a/src/mm-broadband-modem-qmi.c
+++ b/src/mm-broadband-modem-qmi.c
@@ -32,6 +32,7 @@
#include "mm-modem-helpers-qmi.h"
#include "mm-iface-modem.h"
#include "mm-iface-modem-3gpp.h"
+#include "mm-iface-modem-3gpp-profile-manager.h"
#include "mm-iface-modem-3gpp-ussd.h"
#include "mm-iface-modem-cdma.h"
#include "mm-iface-modem-messaging.h"
@@ -48,6 +49,7 @@
static void iface_modem_init (MMIfaceModem *iface);
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
+static void iface_modem_3gpp_profile_manager_init (MMIfaceModem3gppProfileManager *iface);
static void iface_modem_3gpp_ussd_init (MMIfaceModem3gppUssd *iface);
static void iface_modem_cdma_init (MMIfaceModemCdma *iface);
static void iface_modem_messaging_init (MMIfaceModemMessaging *iface);
@@ -63,6 +65,7 @@ static MMIfaceModemMessaging *iface_modem_messaging_parent;
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemQmi, mm_broadband_modem_qmi, MM_TYPE_BROADBAND_MODEM, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP_PROFILE_MANAGER, iface_modem_3gpp_profile_manager_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP_USSD, iface_modem_3gpp_ussd_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_CDMA, iface_modem_cdma_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init)
@@ -101,6 +104,9 @@ struct _MMBroadbandModemQmiPrivate {
/* Index of the WDS profile used as initial EPS bearer */
guint16 default_attach_pdn;
+ /* Support for the APN type mask in profiles */
+ gboolean apn_type_not_supported;
+
/* 3GPP/CDMA registration helpers */
gchar *current_operator_id;
gchar *current_operator_description;
@@ -5504,6 +5510,615 @@ modem_cdma_setup_unsolicited_events (MMIfaceModemCdma *self,
}
/*****************************************************************************/
+/* Check format (3gppProfileManager interface) */
+
+static gboolean
+modem_3gpp_profile_manager_check_format_finish (MMIfaceModem3gppProfileManager *self,
+ GAsyncResult *res,
+ gboolean *new_id,
+ gint *min_profile_id,
+ gint *max_profile_id,
+ GEqualFunc *apn_cmp,
+ MM3gppProfileCmpFlags *profile_cmp_flags,
+ GError **error)
+{
+ if (!g_task_propagate_boolean (G_TASK (res), error)) {
+ g_assert_not_reached ();
+ return FALSE;
+ }
+ /* Generic WDS Create Profile method does NOT allow specifying a specific
+ * profile id */
+ if (new_id)
+ *new_id = FALSE;
+ if (min_profile_id)
+ *min_profile_id = 1;
+ if (max_profile_id)
+ *max_profile_id = G_MAXINT - 1;
+ /* use default string comparison method */
+ if (apn_cmp)
+ *apn_cmp = NULL;
+ /* we support everything! */
+ if (profile_cmp_flags)
+ *profile_cmp_flags = 0;
+ return TRUE;
+}
+
+static void
+modem_3gpp_profile_manager_check_format (MMIfaceModem3gppProfileManager *self,
+ MMBearerIpFamily ip_type,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+/*****************************************************************************/
+/* Get profile (3GPP profile management interface) */
+
+static MM3gppProfile *
+modem_3gpp_profile_manager_get_profile_finish (MMIfaceModem3gppProfileManager *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return MM_3GPP_PROFILE (g_task_propagate_pointer (G_TASK (res), error));
+}
+
+static MM3gppProfile *
+wds_profile_settings_to_3gpp_profile (MMBroadbandModemQmi *self,
+ guint profile_index,
+ QmiMessageWdsGetProfileSettingsOutput *output,
+ GError **error)
+{
+ MM3gppProfile *profile = NULL;
+ const gchar *str;
+ QmiWdsPdpType pdp_type;
+ QmiWdsAuthentication auth;
+ QmiWdsApnTypeMask apn_type;
+
+ profile = mm_3gpp_profile_new ();
+
+ /* On 3GPP modems, the modem seems to force profile-index = pdp-context-number,
+ * and so, we're just going to rely on the profile-index ourselves.*/
+ mm_3gpp_profile_set_profile_id (profile, (gint) profile_index);
+
+ if (qmi_message_wds_get_profile_settings_output_get_apn_name (output, &str, NULL))
+ mm_3gpp_profile_set_apn (profile, str);
+
+ if (qmi_message_wds_get_profile_settings_output_get_pdp_type (output, &pdp_type, NULL))
+ mm_3gpp_profile_set_ip_type (profile, mm_bearer_ip_family_from_qmi_pdp_type (pdp_type));
+
+ if (qmi_message_wds_get_profile_settings_output_get_authentication (output, &auth, NULL))
+ mm_3gpp_profile_set_allowed_auth (profile, mm_bearer_allowed_auth_from_qmi_authentication (auth));
+
+ /* ignore empty user/pass strings */
+ if (qmi_message_wds_get_profile_settings_output_get_username (output, &str, NULL) && str[0])
+ mm_3gpp_profile_set_user (profile, str);
+ if (qmi_message_wds_get_profile_settings_output_get_password (output, &str, NULL) && str[0])
+ mm_3gpp_profile_set_password (profile, str);
+
+ /* If loading APN type TLV fails, flag it as unsupported so that we don't try to use it any
+ * more. */
+ if (qmi_message_wds_get_profile_settings_output_get_apn_type_mask (output, &apn_type, NULL))
+ mm_3gpp_profile_set_apn_type (profile, mm_bearer_apn_type_from_qmi_apn_type (apn_type));
+ else if (!self->priv->apn_type_not_supported) {
+ mm_obj_dbg (self, "APN type flagged as not supported: not given in profile settings");
+ self->priv->apn_type_not_supported = TRUE;
+ }
+
+ return profile;
+}
+
+static void
+get_profile_settings_ready (QmiClientWds *client,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemQmi *self;
+ GError *error = NULL;
+ gint profile_id;
+ gboolean profile_disabled = FALSE;
+ MM3gppProfile *profile;
+ g_autoptr(QmiMessageWdsGetProfileSettingsOutput) output = NULL;
+
+ self = g_task_get_source_object (task);
+ profile_id = GPOINTER_TO_INT (g_task_get_task_data (task));
+
+ output = qmi_client_wds_get_profile_settings_finish (client, res, &error);
+ if (!output || !qmi_message_wds_get_profile_settings_output_get_result (output, &error)) {
+ g_prefix_error (&error, "Couldn't load settings from profile index %u: ", profile_id);
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ /* just ignore the profile if it's disabled */
+ qmi_message_wds_get_profile_settings_output_get_apn_disabled_flag (output, &profile_disabled, NULL);
+ if (profile_disabled) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Profile '%d' is internally disabled", profile_id);
+ g_object_unref (task);
+ return;
+ }
+
+ profile = wds_profile_settings_to_3gpp_profile (self, profile_id, output, &error);
+ if (!profile)
+ g_task_return_error (task, error);
+ else
+ g_task_return_pointer (task, profile, g_object_unref);
+ g_object_unref (task);
+}
+
+static void
+modem_3gpp_profile_manager_get_profile (MMIfaceModem3gppProfileManager *self,
+ gint profile_id,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ QmiClient *client = NULL;
+ g_autoptr(QmiMessageWdsGetProfileSettingsInput) input = NULL;
+
+ if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self),
+ QMI_SERVICE_WDS, &client,
+ callback, user_data))
+ return;
+
+ task = g_task_new (self, NULL, callback, user_data);
+ g_task_set_task_data (task, GINT_TO_POINTER (profile_id), NULL);
+
+ input = qmi_message_wds_get_profile_settings_input_new ();
+ qmi_message_wds_get_profile_settings_input_set_profile_id (
+ input,
+ QMI_WDS_PROFILE_TYPE_3GPP,
+ profile_id,
+ NULL);
+ qmi_client_wds_get_profile_settings (QMI_CLIENT_WDS (client),
+ input,
+ 3,
+ NULL,
+ (GAsyncReadyCallback)get_profile_settings_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* List profiles (3GPP profile management interface) */
+
+typedef struct {
+ GList *profiles;
+ GArray *qmi_profiles;
+ guint i;
+} ListProfilesContext;
+
+static void
+list_profiles_context_free (ListProfilesContext *ctx)
+{
+ g_clear_pointer (&ctx->qmi_profiles, (GDestroyNotify)g_array_unref);
+ mm_3gpp_profile_list_free (ctx->profiles);
+ g_slice_free (ListProfilesContext, ctx);
+}
+
+static gboolean
+modem_3gpp_profile_manager_list_profiles_finish (MMIfaceModem3gppProfileManager *self,
+ GAsyncResult *res,
+ GList **out_profiles,
+ GError **error)
+{
+ ListProfilesContext *ctx;
+
+ if (!g_task_propagate_boolean (G_TASK (res), error))
+ return FALSE;
+
+ ctx = g_task_get_task_data (G_TASK (res));
+ if (out_profiles)
+ *out_profiles = g_steal_pointer (&ctx->profiles);
+ return TRUE;
+}
+
+static void get_next_profile_settings (GTask *task);
+
+static void
+get_next_profile_settings_ready (MMIfaceModem3gppProfileManager *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ ListProfilesContext *ctx;
+ MM3gppProfile *profile;
+ GError *error = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ profile = modem_3gpp_profile_manager_get_profile_finish (self, res, &error);
+ if (!profile) {
+ g_prefix_error (&error, "Couldn't load settings from profile index %u: ", ctx->i);
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ ctx->profiles = g_list_append (ctx->profiles, profile);
+
+ /* Keep on */
+ ctx->i++;
+ get_next_profile_settings (task);
+}
+
+static void
+get_next_profile_settings (GTask *task)
+{
+ MMBroadbandModemQmi *self;
+ ListProfilesContext *ctx;
+ QmiMessageWdsGetProfileListOutputProfileListProfile *current;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ if (ctx->i >= ctx->qmi_profiles->len) {
+ /* All done */
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+
+ current = &g_array_index (ctx->qmi_profiles, QmiMessageWdsGetProfileListOutputProfileListProfile, ctx->i);
+ modem_3gpp_profile_manager_get_profile (MM_IFACE_MODEM_3GPP_PROFILE_MANAGER (self),
+ current->profile_index,
+ (GAsyncReadyCallback)get_next_profile_settings_ready,
+ task);
+}
+
+static void
+get_profile_list_ready (QmiClientWds *client,
+ GAsyncResult *res,
+ GTask *task)
+{
+ ListProfilesContext *ctx;
+ GError *error = NULL;
+ GArray *qmi_profiles = NULL;
+ g_autoptr(QmiMessageWdsGetProfileListOutput) output = NULL;
+
+ ctx = g_slice_new0 (ListProfilesContext);
+ g_task_set_task_data (task, ctx, (GDestroyNotify) list_profiles_context_free);
+
+ output = qmi_client_wds_get_profile_list_finish (client, res, &error);
+ if (!output || !qmi_message_wds_get_profile_list_output_get_result (output, &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ qmi_message_wds_get_profile_list_output_get_profile_list (output, &qmi_profiles, NULL);
+
+ /* empty list? */
+ if (!qmi_profiles || !qmi_profiles->len) {
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+
+ ctx->qmi_profiles = g_array_ref (qmi_profiles);
+ get_next_profile_settings (task);
+}
+
+static void
+modem_3gpp_profile_manager_list_profiles (MMIfaceModem3gppProfileManager *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ QmiClient *client = NULL;
+ g_autoptr(QmiMessageWdsGetProfileListInput) input = NULL;
+
+ if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self),
+ QMI_SERVICE_WDS, &client,
+ callback, user_data))
+ return;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ input = qmi_message_wds_get_profile_list_input_new ();
+ qmi_message_wds_get_profile_list_input_set_profile_type (input, QMI_WDS_PROFILE_TYPE_3GPP, NULL);
+
+ qmi_client_wds_get_profile_list (QMI_CLIENT_WDS (client),
+ input,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)get_profile_list_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* Store profile (3GPP profile management interface) */
+
+typedef struct {
+ QmiClientWds *client;
+ gint profile_id;
+ gchar *apn;
+ gchar *user;
+ gchar *password;
+ QmiWdsApnTypeMask qmi_apn_type;
+ QmiWdsAuthentication qmi_auth;
+ QmiWdsPdpType qmi_pdp_type;
+} StoreProfileContext;
+
+static void
+store_profile_context_free (StoreProfileContext *ctx)
+{
+ g_free (ctx->apn);
+ g_free (ctx->user);
+ g_free (ctx->password);
+ g_clear_object (&ctx->client);
+ g_slice_free (StoreProfileContext, ctx);
+}
+
+static gint
+modem_3gpp_profile_manager_store_profile_finish (MMIfaceModem3gppProfileManager *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ StoreProfileContext *ctx;
+
+ if (!g_task_propagate_boolean (G_TASK (res), error))
+ return MM_3GPP_PROFILE_ID_UNKNOWN;
+
+ ctx = g_task_get_task_data (G_TASK (res));
+ return ctx->profile_id;
+}
+
+static void store_profile_run (GTask *task);
+
+static void
+modify_profile_ready (QmiClientWds *client,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemQmi *self;
+ GError *error = NULL;
+ g_autoptr(QmiMessageWdsModifyProfileOutput) output = NULL;
+
+ self = g_task_get_source_object (task);
+
+ output = qmi_client_wds_modify_profile_finish (client, res, &error);
+ if (!output) {
+ g_task_return_error (task, error);
+ } else if (!qmi_message_wds_modify_profile_output_get_result (output, &error)) {
+ QmiWdsDsProfileError ds_profile_error;
+
+ if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_PROFILE_TYPE) &&
+ !self->priv->apn_type_not_supported) {
+ /* we'll retry the operation without APN type, which is a setting available only
+ * in newer devices. */
+ mm_obj_dbg (self, "APN type flagged as not supported: failed to modify profile");
+ self->priv->apn_type_not_supported = TRUE;
+ g_clear_error (&error);
+ store_profile_run (task);
+ return;
+ }
+ if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_EXTENDED_INTERNAL) &&
+ qmi_message_wds_modify_profile_output_get_extended_error_code (output, &ds_profile_error, NULL)) {
+ g_prefix_error (&error, "DS profile error: %s: ", qmi_wds_ds_profile_error_get_string (ds_profile_error));
+ }
+ g_prefix_error (&error, "Couldn't modify profile: ");
+ g_task_return_error (task, error);
+ } else {
+ g_task_return_boolean (task, TRUE);
+ }
+ g_object_unref (task);
+}
+
+static void
+create_profile_ready (QmiClientWds *client,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemQmi *self;
+ StoreProfileContext *ctx;
+ GError *error = NULL;
+ guint8 profile_index;
+ g_autoptr(QmiMessageWdsCreateProfileOutput) output = NULL;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ output = qmi_client_wds_create_profile_finish (client, res, &error);
+ if (!output) {
+ g_task_return_error (task, error);
+ } else if (!qmi_message_wds_create_profile_output_get_result (output, &error)) {
+ QmiWdsDsProfileError ds_profile_error;
+
+ if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_PROFILE_TYPE) &&
+ !self->priv->apn_type_not_supported) {
+ /* we'll retry the operation without APN type, which is a setting available only
+ * in newer devices. */
+ mm_obj_dbg (self, "APN type flagged as not supported: failed to create profile");
+ self->priv->apn_type_not_supported = TRUE;
+ g_clear_error (&error);
+ store_profile_run (task);
+ return;
+ }
+ if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_EXTENDED_INTERNAL) &&
+ qmi_message_wds_create_profile_output_get_extended_error_code (output, &ds_profile_error, NULL)) {
+ g_prefix_error (&error, "DS profile error: %s: ", qmi_wds_ds_profile_error_get_string (ds_profile_error));
+ }
+ g_prefix_error (&error, "Couldn't create profile: ");
+ g_task_return_error (task, error);
+ } else if (!qmi_message_wds_create_profile_output_get_profile_identifier (output, NULL, &profile_index, &error)) {
+ g_task_return_error (task, error);
+ } else {
+ ctx->profile_id = profile_index;
+ g_task_return_boolean (task, TRUE);
+ }
+ g_object_unref (task);
+}
+
+static void
+store_profile_run (GTask *task)
+{
+ MMBroadbandModemQmi *self;
+ StoreProfileContext *ctx;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ if (ctx->profile_id == MM_3GPP_PROFILE_ID_UNKNOWN) {
+ g_autoptr(QmiMessageWdsCreateProfileInput) input = NULL;
+
+ /* when creating, we cannot select which profile id to use */
+ input = qmi_message_wds_create_profile_input_new ();
+ qmi_message_wds_create_profile_input_set_profile_type (input, QMI_WDS_PROFILE_TYPE_3GPP, NULL);
+ qmi_message_wds_create_profile_input_set_pdp_type (input, ctx->qmi_pdp_type, NULL);
+ qmi_message_wds_create_profile_input_set_apn_name (input, ctx->apn, NULL);
+ qmi_message_wds_create_profile_input_set_authentication (input, ctx->qmi_auth, NULL);
+ qmi_message_wds_create_profile_input_set_username (input, ctx->user, NULL);
+ qmi_message_wds_create_profile_input_set_password (input, ctx->password, NULL);
+ if (!self->priv->apn_type_not_supported)
+ qmi_message_wds_create_profile_input_set_apn_type_mask (input, ctx->qmi_apn_type, NULL);
+
+ qmi_client_wds_create_profile (ctx->client,
+ input,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)create_profile_ready,
+ task);
+ } else {
+ g_autoptr(QmiMessageWdsModifyProfileInput) input = NULL;
+
+ input = qmi_message_wds_modify_profile_input_new ();
+ qmi_message_wds_modify_profile_input_set_profile_identifier (input, QMI_WDS_PROFILE_TYPE_3GPP, ctx->profile_id, NULL);
+ qmi_message_wds_modify_profile_input_set_pdp_type (input, ctx->qmi_pdp_type, NULL);
+ qmi_message_wds_modify_profile_input_set_apn_name (input, ctx->apn, NULL);
+ qmi_message_wds_modify_profile_input_set_authentication (input, ctx->qmi_auth, NULL);
+ qmi_message_wds_modify_profile_input_set_username (input, ctx->user, NULL);
+ qmi_message_wds_modify_profile_input_set_password (input, ctx->password, NULL);
+ if (!self->priv->apn_type_not_supported)
+ qmi_message_wds_modify_profile_input_set_apn_type_mask (input, ctx->qmi_apn_type, NULL);
+
+ qmi_client_wds_modify_profile (ctx->client,
+ input,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)modify_profile_ready,
+ task);
+ }
+}
+
+static void
+modem_3gpp_profile_manager_store_profile (MMIfaceModem3gppProfileManager *self,
+ MM3gppProfile *profile,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ StoreProfileContext *ctx;
+ QmiClient *client = NULL;
+ MMBearerIpFamily ip_type;
+ MMBearerApnType apn_type;
+ MMBearerAllowedAuth allowed_auth;
+
+ if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self),
+ QMI_SERVICE_WDS, &client,
+ callback, user_data))
+ return;
+
+ task = g_task_new (self, NULL, callback, user_data);
+ ctx = g_slice_new0 (StoreProfileContext);
+ ctx->client = g_object_ref (client);
+ g_task_set_task_data (task, ctx, (GDestroyNotify)store_profile_context_free);
+
+ /* Note: may be UNKNOWN */
+ ctx->profile_id = mm_3gpp_profile_get_profile_id (profile);
+
+ ctx->apn = g_strdup (mm_3gpp_profile_get_apn (profile));
+
+ apn_type = mm_3gpp_profile_get_apn_type (profile);
+ ctx->qmi_apn_type = mm_bearer_apn_type_to_qmi_apn_type (apn_type, self);
+
+ ctx->user = g_strdup (mm_3gpp_profile_get_user (profile));
+ ctx->password = g_strdup (mm_3gpp_profile_get_password (profile));
+ allowed_auth = mm_3gpp_profile_get_allowed_auth (profile);
+ if ((allowed_auth != MM_BEARER_ALLOWED_AUTH_UNKNOWN) || ctx->user || ctx->password)
+ ctx->qmi_auth = mm_bearer_allowed_auth_to_qmi_authentication (allowed_auth);
+
+ ip_type = mm_3gpp_profile_get_ip_type (profile);
+ if (!mm_bearer_ip_family_to_qmi_pdp_type (ip_type, &ctx->qmi_pdp_type)) {
+ g_autofree gchar *ip_type_str = NULL;
+
+ ip_type_str = mm_bearer_ip_family_build_string_from_mask (ip_type);
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Invalid IP type specified: %s", ip_type_str);
+ g_object_unref (task);
+ return;
+ }
+
+ store_profile_run (task);
+}
+
+/*****************************************************************************/
+/* Delete profile (3GPP profile management interface) */
+
+static gboolean
+modem_3gpp_profile_manager_delete_profile_finish (MMIfaceModem3gppProfileManager *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+delete_profile_ready (QmiClientWds *client,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ g_autoptr(QmiMessageWdsDeleteProfileOutput) output = NULL;
+
+ output = qmi_client_wds_delete_profile_finish (client, res, &error);
+ if (!output || !qmi_message_wds_delete_profile_output_get_result (output, &error)) {
+ g_prefix_error (&error, "Couldn't delete profile: ");
+ g_task_return_error (task, error);
+ } else
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+modem_3gpp_profile_manager_delete_profile (MMIfaceModem3gppProfileManager *self,
+ MM3gppProfile *profile,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ QmiClient *client = NULL;
+ gint profile_id;
+ g_autoptr(QmiMessageWdsDeleteProfileInput) input = NULL;
+
+ if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self),
+ QMI_SERVICE_WDS, &client,
+ callback, user_data))
+ return;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ profile_id = mm_3gpp_profile_get_profile_id (profile);
+ g_assert (profile_id != MM_3GPP_PROFILE_ID_UNKNOWN);
+
+ mm_obj_dbg (self, "deleting profile '%d'", profile_id);
+
+ input = qmi_message_wds_delete_profile_input_new ();
+ qmi_message_wds_delete_profile_input_set_profile_identifier (input, QMI_WDS_PROFILE_TYPE_3GPP, profile_id, NULL);
+
+ qmi_client_wds_delete_profile (QMI_CLIENT_WDS (client),
+ input,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)delete_profile_ready,
+ task);
+}
+
+/*****************************************************************************/
/* Check support (Messaging interface) */
static gboolean
@@ -10654,6 +11269,31 @@ iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
}
static void
+iface_modem_3gpp_profile_manager_init (MMIfaceModem3gppProfileManager *iface)
+{
+ /* No explicit check support for the profile management feature, just
+ * rely on the generic way to check for support */
+ iface->check_support = NULL;
+ iface->check_support_finish = NULL;
+
+ /* Additional actions */
+ iface->get_profile = modem_3gpp_profile_manager_get_profile;
+ iface->get_profile_finish = modem_3gpp_profile_manager_get_profile_finish;
+ iface->list_profiles = modem_3gpp_profile_manager_list_profiles;
+ iface->list_profiles_finish = modem_3gpp_profile_manager_list_profiles_finish;
+ iface->check_format = modem_3gpp_profile_manager_check_format;
+ iface->check_format_finish = modem_3gpp_profile_manager_check_format_finish;
+ iface->check_activated_profile = NULL;
+ iface->check_activated_profile_finish = NULL;
+ iface->deactivate_profile = NULL;
+ iface->deactivate_profile_finish = NULL;
+ iface->store_profile = modem_3gpp_profile_manager_store_profile;
+ iface->store_profile_finish = modem_3gpp_profile_manager_store_profile_finish;
+ iface->delete_profile = modem_3gpp_profile_manager_delete_profile;
+ iface->delete_profile_finish = modem_3gpp_profile_manager_delete_profile_finish;
+}
+
+static void
iface_modem_3gpp_ussd_init (MMIfaceModem3gppUssd *iface)
{
iface->check_support = modem_3gpp_ussd_check_support;
diff --git a/src/mm-modem-helpers-qmi.c b/src/mm-modem-helpers-qmi.c
index 6e3c5008..2b68ff18 100644
--- a/src/mm-modem-helpers-qmi.c
+++ b/src/mm-modem-helpers-qmi.c
@@ -1550,6 +1550,52 @@ mm_bearer_ip_family_to_qmi_pdp_type (MMBearerIpFamily ip_family,
}
}
+QmiWdsApnTypeMask
+mm_bearer_apn_type_to_qmi_apn_type (MMBearerApnType apn_type,
+ gpointer log_object)
+{
+ guint64 value = 0;
+
+ if (apn_type == MM_BEARER_APN_TYPE_NONE) {
+ mm_obj_dbg (log_object, "using default (internet) APN type");
+ return QMI_WDS_APN_TYPE_MASK_DEFAULT;
+ }
+
+ if (apn_type & MM_BEARER_APN_TYPE_DEFAULT)
+ value |= QMI_WDS_APN_TYPE_MASK_DEFAULT;
+ if (apn_type & MM_BEARER_APN_TYPE_IMS)
+ value |= QMI_WDS_APN_TYPE_MASK_IMS;
+ if (apn_type & MM_BEARER_APN_TYPE_MMS)
+ value |= QMI_WDS_APN_TYPE_MASK_MMS;
+ if (apn_type & MM_BEARER_APN_TYPE_MANAGEMENT)
+ value |= QMI_WDS_APN_TYPE_MASK_FOTA;
+ if (apn_type & MM_BEARER_APN_TYPE_INITIAL)
+ value |= QMI_WDS_APN_TYPE_MASK_IA;
+ if (apn_type & MM_BEARER_APN_TYPE_EMERGENCY)
+ value |= QMI_WDS_APN_TYPE_MASK_EMERGENCY;
+ return value;
+}
+
+MMBearerApnType
+mm_bearer_apn_type_from_qmi_apn_type (QmiWdsApnTypeMask apn_type)
+{
+ MMBearerApnType value = MM_BEARER_APN_TYPE_NONE;
+
+ if (apn_type & QMI_WDS_APN_TYPE_MASK_DEFAULT)
+ value |= MM_BEARER_APN_TYPE_DEFAULT;
+ if (apn_type & QMI_WDS_APN_TYPE_MASK_IMS)
+ value |= MM_BEARER_APN_TYPE_IMS;
+ if (apn_type & QMI_WDS_APN_TYPE_MASK_MMS)
+ value |= MM_BEARER_APN_TYPE_MMS;
+ if (apn_type & QMI_WDS_APN_TYPE_MASK_FOTA)
+ value |= MM_BEARER_APN_TYPE_MANAGEMENT;
+ if (apn_type & QMI_WDS_APN_TYPE_MASK_IA)
+ value |= MM_BEARER_APN_TYPE_INITIAL;
+ if (apn_type & QMI_WDS_APN_TYPE_MASK_EMERGENCY)
+ value |= MM_BEARER_APN_TYPE_EMERGENCY;
+ return value;
+}
+
/*****************************************************************************/
/* QMI/WDA to MM translations */
diff --git a/src/mm-modem-helpers-qmi.h b/src/mm-modem-helpers-qmi.h
index 831418a3..78be0bb5 100644
--- a/src/mm-modem-helpers-qmi.h
+++ b/src/mm-modem-helpers-qmi.h
@@ -120,6 +120,9 @@ MMBearerIpFamily mm_bearer_ip_family_from_qmi_ip_support_type (QmiWdsIpSup
MMBearerIpFamily mm_bearer_ip_family_from_qmi_pdp_type (QmiWdsPdpType pdp_type);
gboolean mm_bearer_ip_family_to_qmi_pdp_type (MMBearerIpFamily ip_family,
QmiWdsPdpType *out_pdp_type);
+QmiWdsApnTypeMask mm_bearer_apn_type_to_qmi_apn_type (MMBearerApnType apn_type,
+ gpointer log_object);
+MMBearerApnType mm_bearer_apn_type_from_qmi_apn_type (QmiWdsApnTypeMask apn_type);
/*****************************************************************************/
/* QMI/WDA to MM translations */